diff options
author | Andras Becsi <andras.becsi@digia.com> | 2014-03-18 13:16:26 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-03-20 15:55:39 +0100 |
commit | 3f0f86b0caed75241fa71c95a5d73bc0164348c5 (patch) | |
tree | 92b9fb00f2e9e90b0be2262093876d4f43b6cd13 /chromium/cc | |
parent | e90d7c4b152c56919d963987e2503f9909a666d2 (diff) | |
download | qtwebengine-chromium-3f0f86b0caed75241fa71c95a5d73bc0164348c5.tar.gz |
Update to new stable branch 1750
This also includes an updated ninja and chromium dependencies
needed on Windows.
Change-Id: Icd597d80ed3fa4425933c9f1334c3c2e31291c42
Reviewed-by: Zoltan Arvai <zarvai@inf.u-szeged.hu>
Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'chromium/cc')
375 files changed, 25850 insertions, 18857 deletions
diff --git a/chromium/cc/DEPS b/chromium/cc/DEPS index 91ebb2067c9..2ae5c7bdef5 100644 --- a/chromium/cc/DEPS +++ b/chromium/cc/DEPS @@ -1,5 +1,10 @@ include_rules = [ "+gpu/GLES2", + "+gpu/command_buffer/client/context_support.h", + "+gpu/command_buffer/client/gles2_interface.h", + "+gpu/command_buffer/client/gles2_interface_stub.h", # for tests + "+gpu/command_buffer/common/gpu_memory_allocation.h", + "+gpu/command_buffer/common/capabilities.h", "+gpu/command_buffer/common/mailbox.h", "+media", "+skia/ext", diff --git a/chromium/cc/PRESUBMIT.py b/chromium/cc/PRESUBMIT.py index 9e84e3f6609..5b8100b8266 100644 --- a/chromium/cc/PRESUBMIT.py +++ b/chromium/cc/PRESUBMIT.py @@ -12,7 +12,6 @@ import re import string CC_SOURCE_FILES=(r'^cc/.*\.(cc|h)$',) -CC_PERF_TEST =(r'^.*_perftest.*\.(cc|h)$',) def CheckChangeLintsClean(input_api, output_api): input_api.cpplint._cpplint_state.ResetErrorCounts() # reset global state @@ -103,35 +102,6 @@ def CheckStdAbs(input_api, output_api, items=missing_std_prefix_files)) return result -def CheckSpamLogging(input_api, - output_api, - white_list=CC_SOURCE_FILES, - black_list=None): - black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST) - source_file_filter = lambda x: input_api.FilterSourceFile(x, - white_list, - black_list) - - log_info = [] - printf = [] - - for f in input_api.AffectedSourceFiles(source_file_filter): - contents = input_api.ReadFile(f, 'rb') - if re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents): - log_info.append(f.LocalPath()) - if re.search(r"\bf?printf\(", contents): - printf.append(f.LocalPath()) - - if log_info: - return [output_api.PresubmitError( - 'These files spam the console log with LOG(INFO):', - items=log_info)] - if printf: - return [output_api.PresubmitError( - 'These files spam the console log with printf/fprintf:', - items=printf)] - return [] - def CheckPassByValue(input_api, output_api, white_list=CC_SOURCE_FILES, @@ -182,18 +152,89 @@ def CheckTodos(input_api, output_api): items=errors)] return [] +def FindUnquotedQuote(contents, pos): + match = re.search(r"(?<!\\)(?P<quote>\")", contents[pos:]) + return -1 if not match else match.start("quote") + pos + +def FindNamespaceInBlock(pos, namespace, contents, whitelist=[]): + open_brace = -1 + close_brace = -1 + quote = -1 + name = -1 + brace_count = 1 + quote_count = 0 + while pos < len(contents) and brace_count > 0: + if open_brace < pos: open_brace = contents.find("{", pos) + if close_brace < pos: close_brace = contents.find("}", pos) + if quote < pos: quote = FindUnquotedQuote(contents, pos) + if name < pos: name = contents.find(("%s::" % namespace), pos) + + if name < 0: + return False # The namespace is not used at all. + if open_brace < 0: + open_brace = len(contents) + if close_brace < 0: + close_brace = len(contents) + if quote < 0: + quote = len(contents) + + next = min(open_brace, min(close_brace, min(quote, name))) + + if next == open_brace: + brace_count += 1 + elif next == close_brace: + brace_count -= 1 + elif next == quote: + quote_count = 0 if quote_count else 1 + elif next == name and not quote_count: + in_whitelist = False + for w in whitelist: + if re.match(w, contents[next:]): + in_whitelist = True + break + if not in_whitelist: + return True + pos = next + 1 + return False + +# Checks for the use of cc:: within the cc namespace, which is usually +# redundant. +def CheckNamespace(input_api, output_api): + errors = [] + + source_file_filter = lambda x: x + for f in input_api.AffectedSourceFiles(source_file_filter): + contents = input_api.ReadFile(f, 'rb') + match = re.search(r'namespace\s*cc\s*{', contents) + if match: + whitelist = [ + r"cc::remove_if\b", + ] + if FindNamespaceInBlock(match.end(), 'cc', contents, whitelist=whitelist): + errors.append(f.LocalPath()) + + if errors: + return [output_api.PresubmitError( + 'Do not use cc:: inside of the cc namespace.', + items=errors)] + return [] + def CheckChangeOnUpload(input_api, output_api): results = [] results += CheckAsserts(input_api, output_api) results += CheckStdAbs(input_api, output_api) - results += CheckSpamLogging(input_api, output_api, black_list=CC_PERF_TEST) results += CheckPassByValue(input_api, output_api) results += CheckChangeLintsClean(input_api, output_api) results += CheckTodos(input_api, output_api) + results += CheckNamespace(input_api, output_api) return results def GetPreferredTrySlaves(project, change): return [ 'linux_layout_rel', - ] + 'win_gpu', + 'linux_gpu', + 'mac_gpu', + 'mac_gpu_retina', + ] diff --git a/chromium/cc/animation/animation.cc b/chromium/cc/animation/animation.cc index b509cfd994f..f21a1d48486 100644 --- a/chromium/cc/animation/animation.cc +++ b/chromium/cc/animation/animation.cc @@ -14,9 +14,7 @@ namespace { // This should match the RunState enum. static const char* const s_runStateNames[] = { - "WaitingForNextTick", "WaitingForTargetAvailability", - "WaitingForStartTime", "WaitingForDeletion", "Starting", "Running", @@ -32,7 +30,10 @@ COMPILE_ASSERT(static_cast<int>(cc::Animation::RunStateEnumSize) == // This should match the TargetProperty enum. static const char* const s_targetPropertyNames[] = { "Transform", - "Opacity" + "Opacity", + "Filter", + "BackgroundColor", + "ScrollOffset" }; COMPILE_ASSERT(static_cast<int>(cc::Animation::TargetPropertyEnumSize) == @@ -91,9 +92,7 @@ void Animation::SetRunState(RunState run_state, double monotonic_time) { group_, is_controlling_instance_ ? "(impl)" : ""); - bool is_waiting_to_start = run_state_ == WaitingForNextTick || - run_state_ == WaitingForTargetAvailability || - run_state_ == WaitingForStartTime || + bool is_waiting_to_start = run_state_ == WaitingForTargetAvailability || run_state_ == Starting; if (is_waiting_to_start && run_state == Running) { @@ -153,7 +152,8 @@ bool Animation::IsFinishedAt(double monotonic_time) const { iterations_ >= 0 && iterations_ * curve_->Duration() <= (monotonic_time - start_time() - - total_paused_time_); + total_paused_time_ + + time_offset_); } double Animation::TrimTimeToCurrentIteration(double monotonic_time) const { @@ -210,12 +210,11 @@ double Animation::TrimTimeToCurrentIteration(double monotonic_time) const { return trimmed; } -scoped_ptr<Animation> Animation::Clone(InstanceType instance_type) const { - return CloneAndInitialize(instance_type, run_state_, start_time_); +scoped_ptr<Animation> Animation::Clone() const { + return CloneAndInitialize(run_state_, start_time_); } -scoped_ptr<Animation> Animation::CloneAndInitialize(InstanceType instance_type, - RunState initial_run_state, +scoped_ptr<Animation> Animation::CloneAndInitialize(RunState initial_run_state, double start_time) const { scoped_ptr<Animation> to_return( new Animation(curve_->Clone(), id_, group_, target_property_)); @@ -226,7 +225,8 @@ scoped_ptr<Animation> Animation::CloneAndInitialize(InstanceType instance_type, to_return->total_paused_time_ = total_paused_time_; to_return->time_offset_ = time_offset_; to_return->alternates_direction_ = alternates_direction_; - to_return->is_controlling_instance_ = instance_type == ControllingInstance; + DCHECK(!to_return->is_controlling_instance_); + to_return->is_controlling_instance_ = true; return to_return.Pass(); } diff --git a/chromium/cc/animation/animation.h b/chromium/cc/animation/animation.h index 990b9ef82cb..c7d53c2745e 100644 --- a/chromium/cc/animation/animation.h +++ b/chromium/cc/animation/animation.h @@ -13,26 +13,21 @@ namespace cc { class AnimationCurve; -// An Animation, contains all the state required to play an AnimationCurve. +// An Animation contains all the state required to play an AnimationCurve. // Specifically, the affected property, the run state (paused, finished, etc.), // loop count, last pause time, and the total time spent paused. class CC_EXPORT Animation { public: - // Animations begin in one of the 'waiting' states. Animations waiting for the - // next tick will start the next time the controller animates. Animations - // waiting for target availibility will run as soon as their target property + // Animations begin in the 'WaitingForTargetAvailability' state. An Animation + // waiting for target availibility will run as soon as its target property // is free (and all the animations animating with it are also able to run). - // Animations waiting for their start time to come have be scheduled to run at - // a particular point in time. When this time arrives, the controller will - // move the animations into the Starting state, and then into the Running - // state. Running animations may toggle between Running and Paused, and may be - // stopped by moving into either the Aborted or Finished states. A Finished - // animation was allowed to run to completion, but an Aborted animation was - // not. + // When this time arrives, the controller will move the animation into the + // Starting state, and then into the Running state. Running animations may + // toggle between Running and Paused, and may be stopped by moving into either + // the Aborted or Finished states. A Finished animation was allowed to run to + // completion, but an Aborted animation was not. enum RunState { - WaitingForNextTick = 0, - WaitingForTargetAvailability, - WaitingForStartTime, + WaitingForTargetAvailability = 0, WaitingForDeletion, Starting, Running, @@ -46,6 +41,9 @@ class CC_EXPORT Animation { enum TargetProperty { Transform = 0, Opacity, + Filter, + BackgroundColor, + ScrollOffset, // This sentinel must be last. TargetPropertyEnumSize }; @@ -120,14 +118,8 @@ class CC_EXPORT Animation { // of iterations, returns the relative time in the current iteration. double TrimTimeToCurrentIteration(double monotonic_time) const; - enum InstanceType { - ControllingInstance = 0, - NonControllingInstance - }; - - scoped_ptr<Animation> Clone(InstanceType instance_type) const; - scoped_ptr<Animation> CloneAndInitialize(InstanceType instance_type, - RunState initial_run_state, + scoped_ptr<Animation> Clone() const; + scoped_ptr<Animation> CloneAndInitialize(RunState initial_run_state, double start_time) const; bool is_controlling_instance() const { return is_controlling_instance_; } diff --git a/chromium/cc/animation/animation_curve.cc b/chromium/cc/animation/animation_curve.cc index cf04da7f396..3acff5d1f62 100644 --- a/chromium/cc/animation/animation_curve.cc +++ b/chromium/cc/animation/animation_curve.cc @@ -5,9 +5,17 @@ #include "cc/animation/animation_curve.h" #include "base/logging.h" +#include "cc/animation/scroll_offset_animation_curve.h" namespace cc { +const ColorAnimationCurve* AnimationCurve::ToColorAnimationCurve() const { + DCHECK(Type() == AnimationCurve::Color); + return static_cast<const ColorAnimationCurve*>(this); +} + +AnimationCurve::CurveType ColorAnimationCurve::Type() const { return Color; } + const FloatAnimationCurve* AnimationCurve::ToFloatAnimationCurve() const { DCHECK(Type() == AnimationCurve::Float); return static_cast<const FloatAnimationCurve*>(this); @@ -36,4 +44,15 @@ AnimationCurve::CurveType FilterAnimationCurve::Type() const { return Filter; } +const ScrollOffsetAnimationCurve* AnimationCurve::ToScrollOffsetAnimationCurve() + const { + DCHECK(Type() == AnimationCurve::ScrollOffset); + return static_cast<const ScrollOffsetAnimationCurve*>(this); +} + +ScrollOffsetAnimationCurve* AnimationCurve::ToScrollOffsetAnimationCurve() { + DCHECK(Type() == AnimationCurve::ScrollOffset); + return static_cast<ScrollOffsetAnimationCurve*>(this); +} + } // namespace cc diff --git a/chromium/cc/animation/animation_curve.h b/chromium/cc/animation/animation_curve.h index f4cdb10560c..9bcccba1294 100644 --- a/chromium/cc/animation/animation_curve.h +++ b/chromium/cc/animation/animation_curve.h @@ -16,15 +16,17 @@ class BoxF; namespace cc { +class ColorAnimationCurve; class FilterAnimationCurve; class FloatAnimationCurve; +class ScrollOffsetAnimationCurve; class TransformAnimationCurve; class TransformOperations; // An animation curve is a function that returns a value given a time. class CC_EXPORT AnimationCurve { public: - enum CurveType { Float, Transform, Filter }; + enum CurveType { Color, Float, Transform, Filter, ScrollOffset }; virtual ~AnimationCurve() {} @@ -32,9 +34,23 @@ class CC_EXPORT AnimationCurve { virtual CurveType Type() const = 0; virtual scoped_ptr<AnimationCurve> Clone() const = 0; + const ColorAnimationCurve* ToColorAnimationCurve() const; const FloatAnimationCurve* ToFloatAnimationCurve() const; const TransformAnimationCurve* ToTransformAnimationCurve() const; const FilterAnimationCurve* ToFilterAnimationCurve() const; + const ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve() const; + + ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve(); +}; + +class CC_EXPORT ColorAnimationCurve : public AnimationCurve { + public: + virtual ~ColorAnimationCurve() {} + + virtual SkColor GetValue(double t) const = 0; + + // Partial Animation implementation. + virtual CurveType Type() const OVERRIDE; }; class CC_EXPORT FloatAnimationCurve : public AnimationCurve { diff --git a/chromium/cc/animation/animation_delegate.h b/chromium/cc/animation/animation_delegate.h index c9367b8546a..f1176a36a46 100644 --- a/chromium/cc/animation/animation_delegate.h +++ b/chromium/cc/animation/animation_delegate.h @@ -5,12 +5,23 @@ #ifndef CC_ANIMATION_ANIMATION_DELEGATE_H_ #define CC_ANIMATION_ANIMATION_DELEGATE_H_ +#include "base/time/time.h" +#include "cc/animation/animation.h" + namespace cc { class AnimationDelegate { public: - virtual void NotifyAnimationStarted(double time) = 0; - virtual void NotifyAnimationFinished(double time) = 0; + // TODO(ajuma): Remove wall_clock_time once the legacy implementation of + // CSS animations and transitions in Blink is removed. + virtual void NotifyAnimationStarted( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) = 0; + virtual void NotifyAnimationFinished( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) = 0; protected: virtual ~AnimationDelegate() {} diff --git a/chromium/cc/animation/animation_events.h b/chromium/cc/animation/animation_events.h index 1fd742c9a8b..e0cf73645c9 100644 --- a/chromium/cc/animation/animation_events.h +++ b/chromium/cc/animation/animation_events.h @@ -9,12 +9,13 @@ #include "cc/animation/animation.h" #include "cc/base/cc_export.h" +#include "cc/output/filter_operations.h" #include "ui/gfx/transform.h" namespace cc { struct CC_EXPORT AnimationEvent { - enum Type { Started, Finished, PropertyUpdate }; + enum Type { Started, Finished, Aborted, PropertyUpdate }; AnimationEvent(Type type, int layer_id, @@ -30,6 +31,7 @@ struct CC_EXPORT AnimationEvent { bool is_impl_only; float opacity; gfx::Transform transform; + FilterOperations filters; }; typedef std::vector<AnimationEvent> AnimationEventsVector; diff --git a/chromium/cc/animation/animation_unittest.cc b/chromium/cc/animation/animation_unittest.cc index 23d41697679..8223cee5855 100644 --- a/chromium/cc/animation/animation_unittest.cc +++ b/chromium/cc/animation/animation_unittest.cc @@ -78,6 +78,16 @@ TEST(AnimationTest, TrimTimeTimeOffset) { EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0)); } +TEST(AnimationTest, TrimTimeNegativeTimeOffset) { + scoped_ptr<Animation> anim(CreateAnimation(1)); + anim->set_time_offset(-4); + + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0)); + EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(4.0)); + EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(4.5)); + EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(5.0)); +} + TEST(AnimationTest, TrimTimePauseResume) { scoped_ptr<Animation> anim(CreateAnimation(1)); anim->SetRunState(Animation::Running, 0.0); @@ -171,18 +181,39 @@ TEST(AnimationTest, IsFinishedAtInfiniteIterations) { EXPECT_FALSE(anim->IsFinishedAt(1.5)); } +TEST(AnimationTest, IsFinishedNegativeTimeOffset) { + scoped_ptr<Animation> anim(CreateAnimation(1)); + anim->set_time_offset(-0.5); + anim->SetRunState(Animation::Running, 0.0); + + EXPECT_FALSE(anim->IsFinishedAt(-1.0)); + EXPECT_FALSE(anim->IsFinishedAt(0.0)); + EXPECT_FALSE(anim->IsFinishedAt(0.5)); + EXPECT_FALSE(anim->IsFinishedAt(1.0)); + EXPECT_TRUE(anim->IsFinishedAt(1.5)); + EXPECT_TRUE(anim->IsFinishedAt(2.0)); + EXPECT_TRUE(anim->IsFinishedAt(2.5)); +} + +TEST(AnimationTest, IsFinishedPositiveTimeOffset) { + scoped_ptr<Animation> anim(CreateAnimation(1)); + anim->set_time_offset(0.5); + anim->SetRunState(Animation::Running, 0.0); + + EXPECT_FALSE(anim->IsFinishedAt(-1.0)); + EXPECT_FALSE(anim->IsFinishedAt(0.0)); + EXPECT_TRUE(anim->IsFinishedAt(0.5)); + EXPECT_TRUE(anim->IsFinishedAt(1.0)); +} + TEST(AnimationTest, IsFinishedAtNotRunning) { scoped_ptr<Animation> anim(CreateAnimation(0)); anim->SetRunState(Animation::Running, 0.0); EXPECT_TRUE(anim->IsFinishedAt(0.0)); anim->SetRunState(Animation::Paused, 0.0); EXPECT_FALSE(anim->IsFinishedAt(0.0)); - anim->SetRunState(Animation::WaitingForNextTick, 0.0); - EXPECT_FALSE(anim->IsFinishedAt(0.0)); anim->SetRunState(Animation::WaitingForTargetAvailability, 0.0); EXPECT_FALSE(anim->IsFinishedAt(0.0)); - anim->SetRunState(Animation::WaitingForStartTime, 0.0); - EXPECT_FALSE(anim->IsFinishedAt(0.0)); anim->SetRunState(Animation::Finished, 0.0); EXPECT_TRUE(anim->IsFinishedAt(0.0)); anim->SetRunState(Animation::Aborted, 0.0); @@ -195,12 +226,8 @@ TEST(AnimationTest, IsFinished) { EXPECT_FALSE(anim->is_finished()); anim->SetRunState(Animation::Paused, 0.0); EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::WaitingForNextTick, 0.0); - EXPECT_FALSE(anim->is_finished()); anim->SetRunState(Animation::WaitingForTargetAvailability, 0.0); EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::WaitingForStartTime, 0.0); - EXPECT_FALSE(anim->is_finished()); anim->SetRunState(Animation::Finished, 0.0); EXPECT_TRUE(anim->is_finished()); anim->SetRunState(Animation::Aborted, 0.0); @@ -213,12 +240,8 @@ TEST(AnimationTest, IsFinishedNeedsSynchronizedStartTime) { EXPECT_FALSE(anim->is_finished()); anim->SetRunState(Animation::Paused, 2.0); EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::WaitingForNextTick, 2.0); - EXPECT_FALSE(anim->is_finished()); anim->SetRunState(Animation::WaitingForTargetAvailability, 2.0); EXPECT_FALSE(anim->is_finished()); - anim->SetRunState(Animation::WaitingForStartTime, 2.0); - EXPECT_FALSE(anim->is_finished()); anim->SetRunState(Animation::Finished, 0.0); EXPECT_TRUE(anim->is_finished()); anim->SetRunState(Animation::Aborted, 0.0); diff --git a/chromium/cc/animation/keyframed_animation_curve.cc b/chromium/cc/animation/keyframed_animation_curve.cc index 14dfd9c8446..d855decbaf9 100644 --- a/chromium/cc/animation/keyframed_animation_curve.cc +++ b/chromium/cc/animation/keyframed_animation_curve.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "cc/animation/keyframed_animation_curve.h" +#include "ui/gfx/animation/tween.h" #include "ui/gfx/box_f.h" namespace cc { @@ -26,6 +27,17 @@ void InsertKeyframe(scoped_ptr<Keyframe> keyframe, keyframes.push_back(keyframe.Pass()); } +template <class Keyframes> +float GetProgress(double t, size_t i, const Keyframes& keyframes) { + float progress = + static_cast<float>((t - keyframes[i]->Time()) / + (keyframes[i + 1]->Time() - keyframes[i]->Time())); + + if (keyframes[i]->timing_function()) + progress = keyframes[i]->timing_function()->GetValue(progress); + return progress; +} + scoped_ptr<TimingFunction> CloneTimingFunction( const TimingFunction* timing_function) { DCHECK(timing_function); @@ -46,6 +58,31 @@ double Keyframe::Time() const { return time_; } +scoped_ptr<ColorKeyframe> ColorKeyframe::Create( + double time, + SkColor value, + scoped_ptr<TimingFunction> timing_function) { + return make_scoped_ptr( + new ColorKeyframe(time, value, timing_function.Pass())); +} + +ColorKeyframe::ColorKeyframe(double time, + SkColor value, + scoped_ptr<TimingFunction> timing_function) + : Keyframe(time, timing_function.Pass()), + value_(value) {} + +ColorKeyframe::~ColorKeyframe() {} + +SkColor ColorKeyframe::Value() const { return value_; } + +scoped_ptr<ColorKeyframe> ColorKeyframe::Clone() const { + scoped_ptr<TimingFunction> func; + if (timing_function()) + func = CloneTimingFunction(timing_function()); + return ColorKeyframe::Create(Time(), Value(), func.Pass()); +} + scoped_ptr<FloatKeyframe> FloatKeyframe::Create( double time, float value, @@ -127,6 +164,53 @@ scoped_ptr<FilterKeyframe> FilterKeyframe::Clone() const { return FilterKeyframe::Create(Time(), Value(), func.Pass()); } +scoped_ptr<KeyframedColorAnimationCurve> KeyframedColorAnimationCurve:: + Create() { + return make_scoped_ptr(new KeyframedColorAnimationCurve); +} + +KeyframedColorAnimationCurve::KeyframedColorAnimationCurve() {} + +KeyframedColorAnimationCurve::~KeyframedColorAnimationCurve() {} + +void KeyframedColorAnimationCurve::AddKeyframe( + scoped_ptr<ColorKeyframe> keyframe) { + InsertKeyframe(keyframe.Pass(), keyframes_); +} + +double KeyframedColorAnimationCurve::Duration() const { + return keyframes_.back()->Time() - keyframes_.front()->Time(); +} + +scoped_ptr<AnimationCurve> KeyframedColorAnimationCurve::Clone() const { + scoped_ptr<KeyframedColorAnimationCurve> to_return( + KeyframedColorAnimationCurve::Create()); + for (size_t i = 0; i < keyframes_.size(); ++i) + to_return->AddKeyframe(keyframes_[i]->Clone()); + return to_return.PassAs<AnimationCurve>(); +} + +SkColor KeyframedColorAnimationCurve::GetValue(double t) const { + if (t <= keyframes_.front()->Time()) + return keyframes_.front()->Value(); + + if (t >= keyframes_.back()->Time()) + return keyframes_.back()->Value(); + + size_t i = 0; + for (; i < keyframes_.size() - 1; ++i) { + if (t < keyframes_[i + 1]->Time()) + break; + } + + float progress = GetProgress(t, i, keyframes_); + + return gfx::Tween::ColorValueBetween( + progress, keyframes_[i]->Value(), keyframes_[i + 1]->Value()); +} + +// KeyframedFloatAnimationCurve + scoped_ptr<KeyframedFloatAnimationCurve> KeyframedFloatAnimationCurve:: Create() { return make_scoped_ptr(new KeyframedFloatAnimationCurve); @@ -166,12 +250,7 @@ float KeyframedFloatAnimationCurve::GetValue(double t) const { break; } - float progress = - static_cast<float>((t - keyframes_[i]->Time()) / - (keyframes_[i+1]->Time() - keyframes_[i]->Time())); - - if (keyframes_[i]->timing_function()) - progress = keyframes_[i]->timing_function()->GetValue(progress); + float progress = GetProgress(t, i, keyframes_); return keyframes_[i]->Value() + (keyframes_[i+1]->Value() - keyframes_[i]->Value()) * progress; diff --git a/chromium/cc/animation/keyframed_animation_curve.h b/chromium/cc/animation/keyframed_animation_curve.h index 5892dc70e58..4b5ac3bf307 100644 --- a/chromium/cc/animation/keyframed_animation_curve.h +++ b/chromium/cc/animation/keyframed_animation_curve.h @@ -31,6 +31,26 @@ class CC_EXPORT Keyframe { DISALLOW_COPY_AND_ASSIGN(Keyframe); }; +class CC_EXPORT ColorKeyframe : public Keyframe { + public: + static scoped_ptr<ColorKeyframe> Create( + double time, + SkColor value, + scoped_ptr<TimingFunction> timing_function); + virtual ~ColorKeyframe(); + + SkColor Value() const; + + scoped_ptr<ColorKeyframe> Clone() const; + + private: + ColorKeyframe(double time, + SkColor value, + scoped_ptr<TimingFunction> timing_function); + + SkColor value_; +}; + class CC_EXPORT FloatKeyframe : public Keyframe { public: static scoped_ptr<FloatKeyframe> Create( @@ -93,6 +113,32 @@ class CC_EXPORT FilterKeyframe : public Keyframe { FilterOperations value_; }; +class CC_EXPORT KeyframedColorAnimationCurve : public ColorAnimationCurve { + public: + // It is required that the keyframes be sorted by time. + static scoped_ptr<KeyframedColorAnimationCurve> Create(); + + virtual ~KeyframedColorAnimationCurve(); + + void AddKeyframe(scoped_ptr<ColorKeyframe> keyframe); + + // AnimationCurve implementation + virtual double Duration() const OVERRIDE; + virtual scoped_ptr<AnimationCurve> Clone() const OVERRIDE; + + // BackgrounColorAnimationCurve implementation + virtual SkColor GetValue(double t) const OVERRIDE; + + private: + KeyframedColorAnimationCurve(); + + // Always sorted in order of increasing time. No two keyframes have the + // same time. + ScopedPtrVector<ColorKeyframe> keyframes_; + + DISALLOW_COPY_AND_ASSIGN(KeyframedColorAnimationCurve); +}; + class CC_EXPORT KeyframedFloatAnimationCurve : public FloatAnimationCurve { public: // It is required that the keyframes be sorted by time. diff --git a/chromium/cc/animation/keyframed_animation_curve_unittest.cc b/chromium/cc/animation/keyframed_animation_curve_unittest.cc index 48f511c0317..63e98668021 100644 --- a/chromium/cc/animation/keyframed_animation_curve_unittest.cc +++ b/chromium/cc/animation/keyframed_animation_curve_unittest.cc @@ -7,13 +7,15 @@ #include "cc/animation/transform_operations.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/animation/tween.h" #include "ui/gfx/box_f.h" +#include "ui/gfx/test/color_util.h" namespace cc { namespace { -void ExpectTranslateX(double translate_x, const gfx::Transform& transform) { - EXPECT_FLOAT_EQ(translate_x, transform.matrix().getDouble(0, 3)); +void ExpectTranslateX(SkMScalar translate_x, const gfx::Transform& transform) { + EXPECT_FLOAT_EQ(translate_x, transform.matrix().get(0, 3)); } void ExpectBrightness(double brightness, const FilterOperations& filter) { @@ -22,6 +24,98 @@ void ExpectBrightness(double brightness, const FilterOperations& filter) { EXPECT_FLOAT_EQ(brightness, filter.at(0).amount()); } +// Tests that a color animation with one keyframe works as expected. +TEST(KeyframedAnimationCurveTest, OneColorKeyFrame) { + SkColor color = SkColorSetARGB(255, 255, 255, 255); + scoped_ptr<KeyframedColorAnimationCurve> curve( + KeyframedColorAnimationCurve::Create()); + curve->AddKeyframe( + ColorKeyframe::Create(0.0, color, scoped_ptr<TimingFunction>())); + + EXPECT_SKCOLOR_EQ(color, curve->GetValue(-1.f)); + EXPECT_SKCOLOR_EQ(color, curve->GetValue(0.f)); + EXPECT_SKCOLOR_EQ(color, curve->GetValue(0.5f)); + EXPECT_SKCOLOR_EQ(color, curve->GetValue(1.f)); + EXPECT_SKCOLOR_EQ(color, curve->GetValue(2.f)); +} + +// Tests that a color animation with two keyframes works as expected. +TEST(KeyframedAnimationCurveTest, TwoColorKeyFrame) { + SkColor color_a = SkColorSetARGB(255, 255, 0, 0); + SkColor color_b = SkColorSetARGB(255, 0, 255, 0); + SkColor color_midpoint = gfx::Tween::ColorValueBetween(0.5, color_a, color_b); + scoped_ptr<KeyframedColorAnimationCurve> curve( + KeyframedColorAnimationCurve::Create()); + curve->AddKeyframe( + ColorKeyframe::Create(0.0, color_a, scoped_ptr<TimingFunction>())); + curve->AddKeyframe( + ColorKeyframe::Create(1.0, color_b, scoped_ptr<TimingFunction>())); + + EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f)); + EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f)); + EXPECT_SKCOLOR_EQ(color_midpoint, curve->GetValue(0.5f)); + EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.f)); + EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(2.f)); +} + +// Tests that a color animation with three keyframes works as expected. +TEST(KeyframedAnimationCurveTest, ThreeColorKeyFrame) { + SkColor color_a = SkColorSetARGB(255, 255, 0, 0); + SkColor color_b = SkColorSetARGB(255, 0, 255, 0); + SkColor color_c = SkColorSetARGB(255, 0, 0, 255); + SkColor color_midpoint1 = + gfx::Tween::ColorValueBetween(0.5, color_a, color_b); + SkColor color_midpoint2 = + gfx::Tween::ColorValueBetween(0.5, color_b, color_c); + scoped_ptr<KeyframedColorAnimationCurve> curve( + KeyframedColorAnimationCurve::Create()); + curve->AddKeyframe( + ColorKeyframe::Create(0.0, color_a, scoped_ptr<TimingFunction>())); + curve->AddKeyframe( + ColorKeyframe::Create(1.0, color_b, scoped_ptr<TimingFunction>())); + curve->AddKeyframe( + ColorKeyframe::Create(2.0, color_c, scoped_ptr<TimingFunction>())); + + EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f)); + EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f)); + EXPECT_SKCOLOR_EQ(color_midpoint1, curve->GetValue(0.5f)); + EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.f)); + EXPECT_SKCOLOR_EQ(color_midpoint2, curve->GetValue(1.5f)); + EXPECT_SKCOLOR_EQ(color_c, curve->GetValue(2.f)); + EXPECT_SKCOLOR_EQ(color_c, curve->GetValue(3.f)); +} + +// Tests that a colro animation with multiple keys at a given time works sanely. +TEST(KeyframedAnimationCurveTest, RepeatedColorKeyFrame) { + SkColor color_a = SkColorSetARGB(255, 64, 0, 0); + SkColor color_b = SkColorSetARGB(255, 192, 0, 0); + + scoped_ptr<KeyframedColorAnimationCurve> curve( + KeyframedColorAnimationCurve::Create()); + curve->AddKeyframe( + ColorKeyframe::Create(0.0, color_a, scoped_ptr<TimingFunction>())); + curve->AddKeyframe( + ColorKeyframe::Create(1.0, color_a, scoped_ptr<TimingFunction>())); + curve->AddKeyframe( + ColorKeyframe::Create(1.0, color_b, scoped_ptr<TimingFunction>())); + curve->AddKeyframe( + ColorKeyframe::Create(2.0, color_b, scoped_ptr<TimingFunction>())); + + EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f)); + EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f)); + EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.5f)); + + SkColor value = curve->GetValue(1.0f); + EXPECT_EQ(255u, SkColorGetA(value)); + int red_value = SkColorGetR(value); + EXPECT_LE(64, red_value); + EXPECT_GE(192, red_value); + + EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.5f)); + EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(2.f)); + EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(3.f)); +} + // Tests that a float animation with one keyframe works as expected. TEST(KeyframedAnimationCurveTest, OneFloatKeyframe) { scoped_ptr<KeyframedFloatAnimationCurve> curve( @@ -185,8 +279,8 @@ TEST(KeyframedAnimationCurveTest, RepeatedTransformKeyTimes) { // There is a discontinuity at 1. Any value between 4 and 6 is valid. gfx::Transform value = curve->GetValue(1.f); - EXPECT_GE(value.matrix().getDouble(0.f, 3.f), 4); - EXPECT_LE(value.matrix().getDouble(0.f, 3.f), 6); + EXPECT_GE(value.matrix().get(0, 3), 4.f); + EXPECT_LE(value.matrix().get(0, 3), 6.f); ExpectTranslateX(6.f, curve->GetValue(1.5f)); ExpectTranslateX(6.f, curve->GetValue(2.f)); diff --git a/chromium/cc/animation/layer_animation_controller.cc b/chromium/cc/animation/layer_animation_controller.cc index 04920acc6ef..e1ab6464a1f 100644 --- a/chromium/cc/animation/layer_animation_controller.cc +++ b/chromium/cc/animation/layer_animation_controller.cc @@ -11,18 +11,21 @@ #include "cc/animation/animation_registrar.h" #include "cc/animation/keyframed_animation_curve.h" #include "cc/animation/layer_animation_value_observer.h" +#include "cc/animation/layer_animation_value_provider.h" +#include "cc/animation/scroll_offset_animation_curve.h" #include "cc/base/scoped_ptr_algorithm.h" +#include "cc/output/filter_operations.h" #include "ui/gfx/box_f.h" #include "ui/gfx/transform.h" namespace cc { LayerAnimationController::LayerAnimationController(int id) - : force_sync_(false), - registrar_(0), + : registrar_(0), id_(id), is_active_(false), last_tick_time_(0), + value_provider_(NULL), layer_animation_delegate_(NULL) {} LayerAnimationController::~LayerAnimationController() { @@ -82,29 +85,21 @@ void LayerAnimationController::RemoveAnimation( int animation_id, Animation::TargetProperty target_property) { ScopedPtrVector<Animation>& animations = active_animations_; - animations.erase(cc::remove_if(&animations, - animations.begin(), - animations.end(), - HasAnimationIdAndProperty(animation_id, - target_property)), - animations.end()); + animations.erase( + cc::remove_if(&animations, + animations.begin(), + animations.end(), + HasAnimationIdAndProperty(animation_id, target_property)), + animations.end()); UpdateActivation(NormalActivation); } -// According to render layer backing, these are for testing only. -void LayerAnimationController::SuspendAnimations(double monotonic_time) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (!active_animations_[i]->is_finished()) - active_animations_[i]->SetRunState(Animation::Paused, monotonic_time); - } -} - -// Looking at GraphicsLayerCA, this appears to be the analog to -// SuspendAnimations, which is for testing. -void LayerAnimationController::ResumeAnimations(double monotonic_time) { +void LayerAnimationController::AbortAnimations( + Animation::TargetProperty target_property) { for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::Paused) - active_animations_[i]->SetRunState(Animation::Running, monotonic_time); + if (active_animations_[i]->target_property() == target_property && + !active_animations_[i]->is_finished()) + active_animations_[i]->SetRunState(Animation::Aborted, last_tick_time_); } } @@ -113,32 +108,27 @@ void LayerAnimationController::ResumeAnimations(double monotonic_time) { void LayerAnimationController::PushAnimationUpdatesTo( LayerAnimationController* controller_impl) { DCHECK(this != controller_impl); - if (force_sync_) { - ReplaceImplThreadAnimations(controller_impl); - force_sync_ = false; - } else { - PurgeAnimationsMarkedForDeletion(); - PushNewAnimationsToImplThread(controller_impl); - - // Remove finished impl side animations only after pushing, - // and only after the animations are deleted on the main thread - // this insures we will never push an animation twice. - RemoveAnimationsCompletedOnMainThread(controller_impl); - - PushPropertiesToImplThread(controller_impl); - } + if (!has_any_animation() && !controller_impl->has_any_animation()) + return; + PurgeAnimationsMarkedForDeletion(); + PushNewAnimationsToImplThread(controller_impl); + + // Remove finished impl side animations only after pushing, + // and only after the animations are deleted on the main thread + // this insures we will never push an animation twice. + RemoveAnimationsCompletedOnMainThread(controller_impl); + + PushPropertiesToImplThread(controller_impl); controller_impl->UpdateActivation(NormalActivation); UpdateActivation(NormalActivation); } void LayerAnimationController::Animate(double monotonic_time) { + DCHECK(monotonic_time); if (!HasValueObserver()) return; - StartAnimationsWaitingForNextTick(monotonic_time); - StartAnimationsWaitingForStartTime(monotonic_time); - StartAnimationsWaitingForTargetAvailability(monotonic_time); - ResolveConflicts(monotonic_time); + StartAnimations(monotonic_time); TickAnimations(monotonic_time); last_tick_time_ = monotonic_time; } @@ -154,27 +144,58 @@ void LayerAnimationController::AccumulatePropertyUpdates( if (!animation->is_impl_only()) continue; - if (animation->target_property() == Animation::Opacity) { - AnimationEvent event(AnimationEvent::PropertyUpdate, - id_, - animation->group(), - Animation::Opacity, - monotonic_time); - event.opacity = animation->curve()->ToFloatAnimationCurve()->GetValue( - monotonic_time); - event.is_impl_only = true; - events->push_back(event); - } else if (animation->target_property() == Animation::Transform) { - AnimationEvent event(AnimationEvent::PropertyUpdate, - id_, - animation->group(), - Animation::Transform, - monotonic_time); - event.transform = - animation->curve()->ToTransformAnimationCurve()->GetValue( - monotonic_time); - event.is_impl_only = true; - events->push_back(event); + double trimmed = animation->TrimTimeToCurrentIteration(monotonic_time); + switch (animation->target_property()) { + case Animation::Opacity: { + AnimationEvent event(AnimationEvent::PropertyUpdate, + id_, + animation->group(), + Animation::Opacity, + monotonic_time); + event.opacity = animation->curve()->ToFloatAnimationCurve()->GetValue( + trimmed); + event.is_impl_only = true; + events->push_back(event); + break; + } + + case Animation::Transform: { + AnimationEvent event(AnimationEvent::PropertyUpdate, + id_, + animation->group(), + Animation::Transform, + monotonic_time); + event.transform = + animation->curve()->ToTransformAnimationCurve()->GetValue(trimmed); + event.is_impl_only = true; + events->push_back(event); + break; + } + + case Animation::Filter: { + AnimationEvent event(AnimationEvent::PropertyUpdate, + id_, + animation->group(), + Animation::Filter, + monotonic_time); + event.filters = animation->curve()->ToFilterAnimationCurve()->GetValue( + trimmed); + event.is_impl_only = true; + events->push_back(event); + break; + } + + case Animation::BackgroundColor: { break; } + + case Animation::ScrollOffset: { + // Impl-side changes to scroll offset are already sent back to the + // main thread (e.g. for user-driven scrolling), so a PropertyUpdate + // isn't needed. + break; + } + + case Animation::TargetPropertyEnumSize: + NOTREACHED(); } } } @@ -191,7 +212,7 @@ void LayerAnimationController::UpdateState(bool start_ready_animations, MarkAnimationsForDeletion(last_tick_time_, events); if (start_ready_animations) { - StartAnimationsWaitingForTargetAvailability(last_tick_time_); + StartAnimations(last_tick_time_); PromoteStartedAnimations(last_tick_time_, events); } @@ -261,11 +282,14 @@ void LayerAnimationController::SetAnimationRegistrar( void LayerAnimationController::NotifyAnimationStarted( const AnimationEvent& event, double wall_clock_time) { + base::TimeTicks monotonic_time = base::TimeTicks::FromInternalValue( + event.monotonic_time * base::Time::kMicrosecondsPerSecond); if (event.is_impl_only) { FOR_EACH_OBSERVER(LayerAnimationEventObserver, event_observers_, OnAnimationStarted(event)); if (layer_animation_delegate_) - layer_animation_delegate_->NotifyAnimationStarted(wall_clock_time); + layer_animation_delegate_->NotifyAnimationStarted( + wall_clock_time, monotonic_time, event.target_property); return; } @@ -280,7 +304,8 @@ void LayerAnimationController::NotifyAnimationStarted( FOR_EACH_OBSERVER(LayerAnimationEventObserver, event_observers_, OnAnimationStarted(event)); if (layer_animation_delegate_) - layer_animation_delegate_->NotifyAnimationStarted(wall_clock_time); + layer_animation_delegate_->NotifyAnimationStarted( + wall_clock_time, monotonic_time, event.target_property); return; } @@ -290,9 +315,12 @@ void LayerAnimationController::NotifyAnimationStarted( void LayerAnimationController::NotifyAnimationFinished( const AnimationEvent& event, double wall_clock_time) { + base::TimeTicks monotonic_time = base::TimeTicks::FromInternalValue( + event.monotonic_time * base::Time::kMicrosecondsPerSecond); if (event.is_impl_only) { if (layer_animation_delegate_) - layer_animation_delegate_->NotifyAnimationFinished(wall_clock_time); + layer_animation_delegate_->NotifyAnimationFinished( + wall_clock_time, monotonic_time, event.target_property); return; } @@ -301,13 +329,25 @@ void LayerAnimationController::NotifyAnimationFinished( active_animations_[i]->target_property() == event.target_property) { active_animations_[i]->set_received_finished_event(true); if (layer_animation_delegate_) - layer_animation_delegate_->NotifyAnimationFinished(wall_clock_time); + layer_animation_delegate_->NotifyAnimationFinished( + wall_clock_time, monotonic_time, event.target_property); return; } } } +void LayerAnimationController::NotifyAnimationAborted( + const AnimationEvent& event) { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->group() == event.group_id && + active_animations_[i]->target_property() == event.target_property) { + active_animations_[i]->SetRunState(Animation::Aborted, + event.monotonic_time); + } + } +} + void LayerAnimationController::NotifyAnimationPropertyUpdate( const AnimationEvent& event) { switch (event.target_property) { @@ -389,12 +429,27 @@ void LayerAnimationController::PushNewAnimationsToImplThread( if (!active_animations_[i]->needs_synchronized_start_time()) continue; + // Scroll animations always start at the current scroll offset. + if (active_animations_[i]->target_property() == Animation::ScrollOffset) { + gfx::Vector2dF current_scroll_offset; + if (controller_impl->value_provider_) { + current_scroll_offset = + controller_impl->value_provider_->ScrollOffsetForAnimation(); + } else { + // The owning layer isn't yet in the active tree, so the main thread + // scroll offset will be up-to-date. + current_scroll_offset = value_provider_->ScrollOffsetForAnimation(); + } + active_animations_[i]->curve()->ToScrollOffsetAnimationCurve() + ->SetInitialValue(current_scroll_offset); + } + // The new animation should be set to run as soon as possible. Animation::RunState initial_run_state = Animation::WaitingForTargetAvailability; double start_time = 0; scoped_ptr<Animation> to_add(active_animations_[i]->CloneAndInitialize( - Animation::ControllingInstance, initial_run_state, start_time)); + initial_run_state, start_time)); DCHECK(!to_add->needs_synchronized_start_time()); controller_impl->AddAnimation(to_add.Pass()); } @@ -444,25 +499,7 @@ void LayerAnimationController::PushPropertiesToImplThread( } } -void LayerAnimationController::StartAnimationsWaitingForNextTick( - double monotonic_time) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::WaitingForNextTick) - active_animations_[i]->SetRunState(Animation::Starting, monotonic_time); - } -} - -void LayerAnimationController::StartAnimationsWaitingForStartTime( - double monotonic_time) { - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::WaitingForStartTime && - active_animations_[i]->start_time() <= monotonic_time) - active_animations_[i]->SetRunState(Animation::Starting, monotonic_time); - } -} - -void LayerAnimationController::StartAnimationsWaitingForTargetAvailability( - double monotonic_time) { +void LayerAnimationController::StartAnimations(double monotonic_time) { // First collect running properties. TargetProperties blocked_properties; for (size_t i = 0; i < active_animations_.size(); ++i) { @@ -537,47 +574,38 @@ void LayerAnimationController::PromoteStartedAnimations( void LayerAnimationController::MarkFinishedAnimations(double monotonic_time) { for (size_t i = 0; i < active_animations_.size(); ++i) { if (active_animations_[i]->IsFinishedAt(monotonic_time) && + active_animations_[i]->run_state() != Animation::Aborted && active_animations_[i]->run_state() != Animation::WaitingForDeletion) active_animations_[i]->SetRunState(Animation::Finished, monotonic_time); } } -void LayerAnimationController::ResolveConflicts(double monotonic_time) { - // Find any animations that are animating the same property and resolve the - // confict. We could eventually blend, but for now we'll just abort the - // previous animation (where 'previous' means: (1) has a prior start time or - // (2) has an equal start time, but was added to the queue earlier, i.e., - // has a lower index in active_animations_). - for (size_t i = 0; i < active_animations_.size(); ++i) { - if (active_animations_[i]->run_state() == Animation::Starting || - active_animations_[i]->run_state() == Animation::Running) { - for (size_t j = i + 1; j < active_animations_.size(); ++j) { - if ((active_animations_[j]->run_state() == Animation::Starting || - active_animations_[j]->run_state() == Animation::Running) && - active_animations_[i]->target_property() == - active_animations_[j]->target_property()) { - if (active_animations_[i]->start_time() > - active_animations_[j]->start_time()) { - active_animations_[j]->SetRunState(Animation::Aborted, - monotonic_time); - } else { - active_animations_[i]->SetRunState(Animation::Aborted, - monotonic_time); - } - } - } - } - } -} - void LayerAnimationController::MarkAnimationsForDeletion( double monotonic_time, AnimationEventsVector* events) { + bool marked_animations_for_deletions = false; + // Non-aborted animations are marked for deletion after a corresponding // AnimationEvent::Finished event is sent or received. This means that if // we don't have an events vector, we must ensure that non-aborted animations // have received a finished event before marking them for deletion. for (size_t i = 0; i < active_animations_.size(); i++) { int group_id = active_animations_[i]->group(); + if (active_animations_[i]->run_state() == Animation::Aborted) { + if (events && !active_animations_[i]->is_impl_only()) { + AnimationEvent aborted_event( + AnimationEvent::Aborted, + id_, + group_id, + active_animations_[i]->target_property(), + monotonic_time); + events->push_back(aborted_event); + } + active_animations_[i]->SetRunState(Animation::WaitingForDeletion, + monotonic_time); + marked_animations_for_deletions = true; + continue; + } + bool all_anims_with_same_id_are_finished = false; // Since deleting an animation on the main thread leads to its deletion @@ -587,9 +615,8 @@ void LayerAnimationController::MarkAnimationsForDeletion( events || active_animations_[i]->received_finished_event(); // If an animation is finished, and not already marked for deletion, // find out if all other animations in the same group are also finished. - if (active_animations_[i]->run_state() == Animation::Aborted || - (active_animations_[i]->run_state() == Animation::Finished && - animation_i_will_send_or_has_received_finish_event)) { + if (active_animations_[i]->run_state() == Animation::Finished && + animation_i_will_send_or_has_received_finish_event) { all_anims_with_same_id_are_finished = true; for (size_t j = 0; j < active_animations_.size(); ++j) { bool animation_j_will_send_or_has_received_finish_event = @@ -608,7 +635,8 @@ void LayerAnimationController::MarkAnimationsForDeletion( // group_id (and send along animation finished notifications, if // necessary). for (size_t j = i; j < active_animations_.size(); j++) { - if (group_id == active_animations_[j]->group()) { + if (active_animations_[j]->group() == group_id && + active_animations_[j]->run_state() != Animation::Aborted) { if (events) { AnimationEvent finished_event( AnimationEvent::Finished, @@ -623,8 +651,11 @@ void LayerAnimationController::MarkAnimationsForDeletion( monotonic_time); } } + marked_animations_for_deletions = true; } } + if (marked_animations_for_deletions) + NotifyObserversAnimationWaitingForDeletion(); } static bool IsWaitingForDeletion(Animation* animation) { @@ -640,29 +671,6 @@ void LayerAnimationController::PurgeAnimationsMarkedForDeletion() { animations.end()); } -void LayerAnimationController::ReplaceImplThreadAnimations( - LayerAnimationController* controller_impl) const { - controller_impl->active_animations_.clear(); - for (size_t i = 0; i < active_animations_.size(); ++i) { - scoped_ptr<Animation> to_add; - if (active_animations_[i]->needs_synchronized_start_time()) { - // We haven't received an animation started notification yet, so it - // is important that we add it in a 'waiting' and not 'running' state. - Animation::RunState initial_run_state = - Animation::WaitingForTargetAvailability; - double start_time = 0; - to_add = active_animations_[i]->CloneAndInitialize( - Animation::ControllingInstance, - initial_run_state, start_time).Pass(); - } else { - to_add = active_animations_[i]->Clone( - Animation::ControllingInstance).Pass(); - } - - controller_impl->AddAnimation(to_add.Pass()); - } -} - void LayerAnimationController::TickAnimations(double monotonic_time) { for (size_t i = 0; i < active_animations_.size(); ++i) { if (active_animations_[i]->run_state() == Animation::Starting || @@ -689,7 +697,30 @@ void LayerAnimationController::TickAnimations(double monotonic_time) { break; } - // Do nothing for sentinel value. + case Animation::Filter: { + const FilterAnimationCurve* filter_animation_curve = + active_animations_[i]->curve()->ToFilterAnimationCurve(); + const FilterOperations filter = + filter_animation_curve->GetValue(trimmed); + NotifyObserversFilterAnimated(filter); + break; + } + + case Animation::BackgroundColor: { + // Not yet implemented. + break; + } + + case Animation::ScrollOffset: { + const ScrollOffsetAnimationCurve* scroll_offset_animation_curve = + active_animations_[i]->curve()->ToScrollOffsetAnimationCurve(); + const gfx::Vector2dF scroll_offset = + scroll_offset_animation_curve->GetValue(trimmed); + NotifyObserversScrollOffsetAnimated(scroll_offset); + break; + } + + // Do nothing for sentinel value. case Animation::TargetPropertyEnumSize: NOTREACHED(); } @@ -700,11 +731,19 @@ void LayerAnimationController::TickAnimations(double monotonic_time) { void LayerAnimationController::UpdateActivation(UpdateActivationType type) { bool force = type == ForceActivation; if (registrar_) { - if (!active_animations_.empty() && (!is_active_ || force)) + bool was_active = is_active_; + is_active_ = false; + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->run_state() != Animation::WaitingForDeletion) { + is_active_ = true; + break; + } + } + + if (is_active_ && (!was_active || force)) registrar_->DidActivateAnimationController(this); - else if (active_animations_.empty() && (is_active_ || force)) + else if (!is_active_ && (was_active || force)) registrar_->DidDeactivateAnimationController(this); - is_active_ = !active_animations_.empty(); } } @@ -721,6 +760,26 @@ void LayerAnimationController::NotifyObserversTransformAnimated( OnTransformAnimated(transform)); } +void LayerAnimationController::NotifyObserversFilterAnimated( + const FilterOperations& filters) { + FOR_EACH_OBSERVER(LayerAnimationValueObserver, + value_observers_, + OnFilterAnimated(filters)); +} + +void LayerAnimationController::NotifyObserversScrollOffsetAnimated( + gfx::Vector2dF scroll_offset) { + FOR_EACH_OBSERVER(LayerAnimationValueObserver, + value_observers_, + OnScrollOffsetAnimated(scroll_offset)); +} + +void LayerAnimationController::NotifyObserversAnimationWaitingForDeletion() { + FOR_EACH_OBSERVER(LayerAnimationValueObserver, + value_observers_, + OnAnimationWaitingForDeletion()); +} + bool LayerAnimationController::HasValueObserver() { if (value_observers_.might_have_observers()) { ObserverListBase<LayerAnimationValueObserver>::Iterator it( diff --git a/chromium/cc/animation/layer_animation_controller.h b/chromium/cc/animation/layer_animation_controller.h index 4138704af66..564a5933e7f 100644 --- a/chromium/cc/animation/layer_animation_controller.h +++ b/chromium/cc/animation/layer_animation_controller.h @@ -27,8 +27,10 @@ namespace cc { class Animation; class AnimationDelegate; class AnimationRegistrar; +class FilterOperations; class KeyframeValueList; class LayerAnimationValueObserver; +class LayerAnimationValueProvider; class CC_EXPORT LayerAnimationController : public base::RefCounted<LayerAnimationController> { @@ -37,18 +39,16 @@ class CC_EXPORT LayerAnimationController int id() const { return id_; } - // These methods are virtual for testing. - virtual void AddAnimation(scoped_ptr<Animation> animation); - virtual void PauseAnimation(int animation_id, double time_offset); - virtual void RemoveAnimation(int animation_id); - virtual void RemoveAnimation(int animation_id, - Animation::TargetProperty target_property); - virtual void SuspendAnimations(double monotonic_time); - virtual void ResumeAnimations(double monotonic_time); + void AddAnimation(scoped_ptr<Animation> animation); + void PauseAnimation(int animation_id, double time_offset); + void RemoveAnimation(int animation_id); + void RemoveAnimation(int animation_id, + Animation::TargetProperty target_property); + void AbortAnimations(Animation::TargetProperty target_property); // Ensures that the list of active animations on the main thread and the impl // thread are kept in sync. This function does not take ownership of the impl - // thread controller. + // thread controller. This method is virtual for testing. virtual void PushAnimationUpdatesTo( LayerAnimationController* controller_impl); @@ -80,10 +80,6 @@ class CC_EXPORT LayerAnimationController // the future. bool IsAnimatingProperty(Animation::TargetProperty target_property) const; - // If a sync is forced, then the next time animation updates are pushed to the - // impl thread, all animations will be transferred. - void set_force_sync() { force_sync_ = true; } - void SetAnimationRegistrar(AnimationRegistrar* registrar); AnimationRegistrar* animation_registrar() { return registrar_; } @@ -91,6 +87,7 @@ class CC_EXPORT LayerAnimationController double wall_clock_time); void NotifyAnimationFinished(const AnimationEvent& event, double wall_clock_time); + void NotifyAnimationAborted(const AnimationEvent& event); void NotifyAnimationPropertyUpdate(const AnimationEvent& event); void AddValueObserver(LayerAnimationValueObserver* observer); @@ -99,6 +96,15 @@ class CC_EXPORT LayerAnimationController void AddEventObserver(LayerAnimationEventObserver* observer); void RemoveEventObserver(LayerAnimationEventObserver* observer); + void set_value_provider(LayerAnimationValueProvider* provider) { + value_provider_ = provider; + } + + void remove_value_provider(LayerAnimationValueProvider* provider) { + if (value_provider_ == provider) + value_provider_ = NULL; + } + void set_layer_animation_delegate(AnimationDelegate* delegate) { layer_animation_delegate_ = delegate; } @@ -120,13 +126,8 @@ class CC_EXPORT LayerAnimationController LayerAnimationController* controller_impl) const; void PushPropertiesToImplThread( LayerAnimationController* controller_impl) const; - void ReplaceImplThreadAnimations( - LayerAnimationController* controller_impl) const; - void StartAnimationsWaitingForNextTick(double monotonic_time); - void StartAnimationsWaitingForStartTime(double monotonic_time); - void StartAnimationsWaitingForTargetAvailability(double monotonic_time); - void ResolveConflicts(double monotonic_time); + void StartAnimations(double monotonic_time); void PromoteStartedAnimations(double monotonic_time, AnimationEventsVector* events); void MarkFinishedAnimations(double monotonic_time); @@ -144,13 +145,14 @@ class CC_EXPORT LayerAnimationController void NotifyObserversOpacityAnimated(float opacity); void NotifyObserversTransformAnimated(const gfx::Transform& transform); + void NotifyObserversFilterAnimated(const FilterOperations& filter); + void NotifyObserversScrollOffsetAnimated(gfx::Vector2dF scroll_offset); + + void NotifyObserversAnimationWaitingForDeletion(); bool HasValueObserver(); bool HasActiveValueObserver(); - // If this is true, we force a sync to the impl thread. - bool force_sync_; - AnimationRegistrar* registrar_; int id_; ScopedPtrVector<Animation> active_animations_; @@ -163,6 +165,8 @@ class CC_EXPORT LayerAnimationController ObserverList<LayerAnimationValueObserver> value_observers_; ObserverList<LayerAnimationEventObserver> event_observers_; + LayerAnimationValueProvider* value_provider_; + AnimationDelegate* layer_animation_delegate_; DISALLOW_COPY_AND_ASSIGN(LayerAnimationController); diff --git a/chromium/cc/animation/layer_animation_controller_unittest.cc b/chromium/cc/animation/layer_animation_controller_unittest.cc index e55c53c07f3..f7918cd2bf3 100644 --- a/chromium/cc/animation/layer_animation_controller_unittest.cc +++ b/chromium/cc/animation/layer_animation_controller_unittest.cc @@ -7,7 +7,9 @@ #include "cc/animation/animation.h" #include "cc/animation/animation_curve.h" #include "cc/animation/animation_delegate.h" +#include "cc/animation/animation_registrar.h" #include "cc/animation/keyframed_animation_curve.h" +#include "cc/animation/scroll_offset_animation_curve.h" #include "cc/animation/transform_operations.h" #include "cc/test/animation_test_common.h" #include "testing/gmock/include/gmock/gmock.h" @@ -18,6 +20,11 @@ namespace cc { namespace { +// A LayerAnimationController cannot be ticked at 0.0, since an animation +// with start time 0.0 is treated as an animation whose start time has +// not yet been set. +const double kInitialTickTime = 1.0; + scoped_ptr<Animation> CreateAnimation(scoped_ptr<AnimationCurve> curve, int id, Animation::TargetProperty property) { @@ -72,7 +79,7 @@ TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) { Animation::Opacity)->run_state()); AnimationEventsVector events; - controller_impl->Animate(1.0); + controller_impl->Animate(kInitialTickTime); controller_impl->UpdateState(true, &events); // Synchronize the start times. @@ -84,7 +91,7 @@ TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) { Animation::Opacity)->start_time()); // Start the animation on the main thread. Should not affect the start time. - controller->Animate(1.5); + controller->Animate(kInitialTickTime + 0.5); controller->UpdateState(true, NULL); EXPECT_EQ(controller->GetAnimation(group_id, Animation::Opacity)->start_time(), @@ -92,7 +99,88 @@ TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) { Animation::Opacity)->start_time()); } -TEST(LayerAnimationControllerTest, SyncPauseAndResume) { +// Tests that controllers activate and deactivate as expected. +TEST(LayerAnimationControllerTest, Activation) { + scoped_ptr<AnimationRegistrar> registrar = AnimationRegistrar::Create(); + scoped_ptr<AnimationRegistrar> registrar_impl = AnimationRegistrar::Create(); + + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddValueObserver(&dummy_impl); + FakeLayerAnimationValueObserver dummy; + scoped_refptr<LayerAnimationController> controller( + LayerAnimationController::Create(0)); + controller->AddValueObserver(&dummy); + scoped_ptr<AnimationEventsVector> events( + make_scoped_ptr(new AnimationEventsVector)); + + controller->SetAnimationRegistrar(registrar.get()); + controller_impl->SetAnimationRegistrar(registrar_impl.get()); + EXPECT_EQ(1u, registrar->all_animation_controllers().size()); + EXPECT_EQ(1u, registrar_impl->all_animation_controllers().size()); + + // Initially, both controllers should be inactive. + EXPECT_EQ(0u, registrar->active_animation_controllers().size()); + EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size()); + + AddOpacityTransitionToController(controller.get(), 1, 0, 1, false); + // The main thread controller should now be active. + EXPECT_EQ(1u, registrar->active_animation_controllers().size()); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + // Both controllers should now be active. + EXPECT_EQ(1u, registrar->active_animation_controllers().size()); + EXPECT_EQ(1u, registrar_impl->active_animation_controllers().size()); + + controller_impl->Animate(kInitialTickTime); + controller_impl->UpdateState(true, events.get()); + EXPECT_EQ(1u, events->size()); + controller->NotifyAnimationStarted((*events)[0], 0.0); + + EXPECT_EQ(1u, registrar->active_animation_controllers().size()); + EXPECT_EQ(1u, registrar_impl->active_animation_controllers().size()); + + controller->Animate(kInitialTickTime + 0.5); + controller->UpdateState(true, NULL); + EXPECT_EQ(1u, registrar->active_animation_controllers().size()); + + controller->Animate(kInitialTickTime + 1.0); + controller->UpdateState(true, NULL); + EXPECT_EQ(Animation::Finished, + controller->GetAnimation(Animation::Opacity)->run_state()); + EXPECT_EQ(1u, registrar->active_animation_controllers().size()); + + events.reset(new AnimationEventsVector); + controller_impl->Animate(kInitialTickTime + 1.5); + controller_impl->UpdateState(true, events.get()); + + EXPECT_EQ(Animation::WaitingForDeletion, + controller_impl->GetAnimation(Animation::Opacity)->run_state()); + // The impl thread controller should have de-activated. + EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size()); + + EXPECT_EQ(1u, events->size()); + controller->NotifyAnimationFinished((*events)[0], 0.0); + controller->Animate(kInitialTickTime + 1.5); + controller->UpdateState(true, NULL); + + EXPECT_EQ(Animation::WaitingForDeletion, + controller->GetAnimation(Animation::Opacity)->run_state()); + // The main thread controller should have de-activated. + EXPECT_EQ(0u, registrar->active_animation_controllers().size()); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_FALSE(controller->has_any_animation()); + EXPECT_FALSE(controller_impl->has_any_animation()); + EXPECT_EQ(0u, registrar->active_animation_controllers().size()); + EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size()); + + controller->SetAnimationRegistrar(NULL); + controller_impl->SetAnimationRegistrar(NULL); +} + +TEST(LayerAnimationControllerTest, SyncPause) { FakeLayerAnimationValueObserver dummy_impl; scoped_refptr<LayerAnimationController> controller_impl( LayerAnimationController::Create(0)); @@ -106,6 +194,7 @@ TEST(LayerAnimationControllerTest, SyncPauseAndResume) { AddOpacityTransitionToController(controller.get(), 1, 0, 1, false); int group_id = controller->GetAnimation(Animation::Opacity)->group(); + int animation_id = controller->GetAnimation(Animation::Opacity)->id(); controller->PushAnimationUpdatesTo(controller_impl.get()); @@ -116,9 +205,9 @@ TEST(LayerAnimationControllerTest, SyncPauseAndResume) { // Start the animations on each controller. AnimationEventsVector events; - controller_impl->Animate(0.0); + controller_impl->Animate(kInitialTickTime); controller_impl->UpdateState(true, &events); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, NULL); EXPECT_EQ(Animation::Running, controller_impl->GetAnimation(group_id, @@ -128,7 +217,7 @@ TEST(LayerAnimationControllerTest, SyncPauseAndResume) { Animation::Opacity)->run_state()); // Pause the main-thread animation. - controller->SuspendAnimations(1.0); + controller->PauseAnimation(animation_id, kInitialTickTime + 1.0); EXPECT_EQ(Animation::Paused, controller->GetAnimation(group_id, Animation::Opacity)->run_state()); @@ -138,18 +227,6 @@ TEST(LayerAnimationControllerTest, SyncPauseAndResume) { EXPECT_EQ(Animation::Paused, controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state()); - - // Resume the main-thread animation. - controller->ResumeAnimations(2.0); - EXPECT_EQ(Animation::Running, - controller->GetAnimation(group_id, - Animation::Opacity)->run_state()); - - // The pause run state change should make it to the impl thread controller. - controller->PushAnimationUpdatesTo(controller_impl.get()); - EXPECT_EQ(Animation::Running, - controller_impl->GetAnimation(group_id, - Animation::Opacity)->run_state()); } TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) { @@ -176,8 +253,11 @@ TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) { Animation::Opacity)->run_state()); // Notify main thread controller that the animation has started. - AnimationEvent animation_started_event( - AnimationEvent::Started, 0, group_id, Animation::Opacity, 0); + AnimationEvent animation_started_event(AnimationEvent::Started, + 0, + group_id, + Animation::Opacity, + kInitialTickTime); controller->NotifyAnimationStarted(animation_started_event, 0.0); // Force animation to complete on impl thread. @@ -207,11 +287,11 @@ TEST(LayerAnimationControllerTest, AnimationsAreDeleted) { controller_impl->AddValueObserver(&dummy_impl); AddOpacityTransitionToController(controller.get(), 1.0, 0.0f, 1.0f, false); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, NULL); controller->PushAnimationUpdatesTo(controller_impl.get()); - controller_impl->Animate(0.5); + controller_impl->Animate(kInitialTickTime + 0.5); controller_impl->UpdateState(true, events.get()); // There should be a Started event for the animation. @@ -219,13 +299,18 @@ TEST(LayerAnimationControllerTest, AnimationsAreDeleted) { EXPECT_EQ(AnimationEvent::Started, (*events)[0].type); controller->NotifyAnimationStarted((*events)[0], 0.0); - controller->Animate(1.0); + controller->Animate(kInitialTickTime + 1.0); controller->UpdateState(true, NULL); + EXPECT_FALSE(dummy.animation_waiting_for_deletion()); + EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion()); + events.reset(new AnimationEventsVector); - controller_impl->Animate(2.0); + controller_impl->Animate(kInitialTickTime + 2.0); controller_impl->UpdateState(true, events.get()); + EXPECT_TRUE(dummy_impl.animation_waiting_for_deletion()); + // There should be a Finished event for the animation. EXPECT_EQ(1u, events->size()); EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type); @@ -236,8 +321,9 @@ TEST(LayerAnimationControllerTest, AnimationsAreDeleted) { controller->NotifyAnimationFinished((*events)[0], 0.0); - controller->Animate(3.0); + controller->Animate(kInitialTickTime + 3.0); controller->UpdateState(true, NULL); + EXPECT_TRUE(dummy.animation_waiting_for_deletion()); controller->PushAnimationUpdatesTo(controller_impl.get()); @@ -272,14 +358,14 @@ TEST(LayerAnimationControllerTest, TrivialTransition) { Animation::Opacity)); controller->AddAnimation(to_add.Pass()); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); // A non-impl-only animation should not generate property updates. const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); EXPECT_FALSE(event); - controller->Animate(1.0); + controller->Animate(kInitialTickTime + 1.0); controller->UpdateState(true, events.get()); EXPECT_EQ(1.f, dummy.opacity()); EXPECT_FALSE(controller->HasActiveAnimation()); @@ -302,7 +388,7 @@ TEST(LayerAnimationControllerTest, TrivialTransitionOnImpl) { to_add->set_is_impl_only(true); controller_impl->AddAnimation(to_add.Pass()); - controller_impl->Animate(0.0); + controller_impl->Animate(kInitialTickTime); controller_impl->UpdateState(true, events.get()); EXPECT_TRUE(controller_impl->HasActiveAnimation()); EXPECT_EQ(0.f, dummy_impl.opacity()); @@ -311,7 +397,7 @@ TEST(LayerAnimationControllerTest, TrivialTransitionOnImpl) { GetMostRecentPropertyUpdateEvent(events.get()); EXPECT_EQ(0.f, start_opacity_event->opacity); - controller_impl->Animate(1.0); + controller_impl->Animate(kInitialTickTime + 1.0); controller_impl->UpdateState(true, events.get()); EXPECT_EQ(1.f, dummy_impl.opacity()); EXPECT_FALSE(controller_impl->HasActiveAnimation()); @@ -339,11 +425,11 @@ TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) { // Create simple Transform animation. TransformOperations operations; - curve->AddKeyframe(TransformKeyframe::Create( - 0, operations, scoped_ptr<cc::TimingFunction>())); + curve->AddKeyframe( + TransformKeyframe::Create(0, operations, scoped_ptr<TimingFunction>())); operations.AppendTranslate(delta_x, delta_y, 0); - curve->AddKeyframe(TransformKeyframe::Create( - 1, operations, scoped_ptr<cc::TimingFunction>())); + curve->AddKeyframe( + TransformKeyframe::Create(1, operations, scoped_ptr<TimingFunction>())); scoped_ptr<Animation> animation(Animation::Create( curve.PassAs<AnimationCurve>(), 1, 0, Animation::Transform)); @@ -351,7 +437,7 @@ TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) { controller_impl->AddAnimation(animation.Pass()); // Run animation. - controller_impl->Animate(0.0); + controller_impl->Animate(kInitialTickTime); controller_impl->UpdateState(true, events.get()); EXPECT_TRUE(controller_impl->HasActiveAnimation()); EXPECT_EQ(gfx::Transform(), dummy_impl.transform()); @@ -365,7 +451,7 @@ TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) { gfx::Transform expected_transform; expected_transform.Translate(delta_x, delta_y); - controller_impl->Animate(1.0); + controller_impl->Animate(kInitialTickTime + 1.0); controller_impl->UpdateState(true, events.get()); EXPECT_EQ(expected_transform, dummy_impl.transform()); EXPECT_FALSE(controller_impl->HasActiveAnimation()); @@ -376,17 +462,321 @@ TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) { EXPECT_TRUE(end_transform_event->is_impl_only); } +TEST(LayerAnimationControllerTest, FilterTransition) { + scoped_ptr<AnimationEventsVector> events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + scoped_refptr<LayerAnimationController> controller( + LayerAnimationController::Create(0)); + controller->AddValueObserver(&dummy); + + scoped_ptr<KeyframedFilterAnimationCurve> curve( + KeyframedFilterAnimationCurve::Create()); + + FilterOperations start_filters; + start_filters.Append(FilterOperation::CreateBrightnessFilter(1.f)); + curve->AddKeyframe( + FilterKeyframe::Create(0, start_filters, scoped_ptr<TimingFunction>())); + FilterOperations end_filters; + end_filters.Append(FilterOperation::CreateBrightnessFilter(2.f)); + curve->AddKeyframe( + FilterKeyframe::Create(1, end_filters, scoped_ptr<TimingFunction>())); + + scoped_ptr<Animation> animation(Animation::Create( + curve.PassAs<AnimationCurve>(), 1, 0, Animation::Filter)); + controller->AddAnimation(animation.Pass()); + + controller->Animate(kInitialTickTime); + controller->UpdateState(true, events.get()); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(start_filters, dummy.filters()); + // A non-impl-only animation should not generate property updates. + const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + + controller->Animate(kInitialTickTime + 0.5); + controller->UpdateState(true, events.get()); + EXPECT_EQ(1u, dummy.filters().size()); + EXPECT_EQ(FilterOperation::CreateBrightnessFilter(1.5f), + dummy.filters().at(0)); + event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + + controller->Animate(kInitialTickTime + 1.0); + controller->UpdateState(true, events.get()); + EXPECT_EQ(end_filters, dummy.filters()); + EXPECT_FALSE(controller->HasActiveAnimation()); + event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); +} + +TEST(LayerAnimationControllerTest, FilterTransitionOnImplOnly) { + scoped_ptr<AnimationEventsVector> events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddValueObserver(&dummy_impl); + + scoped_ptr<KeyframedFilterAnimationCurve> curve( + KeyframedFilterAnimationCurve::Create()); + + // Create simple Filter animation. + FilterOperations start_filters; + start_filters.Append(FilterOperation::CreateBrightnessFilter(1.f)); + curve->AddKeyframe( + FilterKeyframe::Create(0, start_filters, scoped_ptr<TimingFunction>())); + FilterOperations end_filters; + end_filters.Append(FilterOperation::CreateBrightnessFilter(2.f)); + curve->AddKeyframe( + FilterKeyframe::Create(1, end_filters, scoped_ptr<TimingFunction>())); + + scoped_ptr<Animation> animation(Animation::Create( + curve.PassAs<AnimationCurve>(), 1, 0, Animation::Filter)); + animation->set_is_impl_only(true); + controller_impl->AddAnimation(animation.Pass()); + + // Run animation. + controller_impl->Animate(kInitialTickTime); + controller_impl->UpdateState(true, events.get()); + EXPECT_TRUE(controller_impl->HasActiveAnimation()); + EXPECT_EQ(start_filters, dummy_impl.filters()); + EXPECT_EQ(2u, events->size()); + const AnimationEvent* start_filter_event = + GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_TRUE(start_filter_event); + EXPECT_EQ(start_filters, start_filter_event->filters); + EXPECT_TRUE(start_filter_event->is_impl_only); + + controller_impl->Animate(kInitialTickTime + 1.0); + controller_impl->UpdateState(true, events.get()); + EXPECT_EQ(end_filters, dummy_impl.filters()); + EXPECT_FALSE(controller_impl->HasActiveAnimation()); + EXPECT_EQ(4u, events->size()); + const AnimationEvent* end_filter_event = + GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_TRUE(end_filter_event); + EXPECT_EQ(end_filters, end_filter_event->filters); + EXPECT_TRUE(end_filter_event->is_impl_only); +} + +TEST(LayerAnimationControllerTest, ScrollOffsetTransition) { + FakeLayerAnimationValueObserver dummy_impl; + FakeLayerAnimationValueProvider dummy_provider_impl; + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddValueObserver(&dummy_impl); + controller_impl->set_value_provider(&dummy_provider_impl); + scoped_ptr<AnimationEventsVector> events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + FakeLayerAnimationValueProvider dummy_provider; + scoped_refptr<LayerAnimationController> controller( + LayerAnimationController::Create(0)); + controller->AddValueObserver(&dummy); + controller->set_value_provider(&dummy_provider); + + gfx::Vector2dF initial_value(100.f, 300.f); + gfx::Vector2dF target_value(300.f, 200.f); + scoped_ptr<ScrollOffsetAnimationCurve> curve( + ScrollOffsetAnimationCurve::Create( + target_value, + EaseInOutTimingFunction::Create().Pass())); + + scoped_ptr<Animation> animation(Animation::Create( + curve.PassAs<AnimationCurve>(), 1, 0, Animation::ScrollOffset)); + animation->set_needs_synchronized_start_time(true); + controller->AddAnimation(animation.Pass()); + + dummy_provider_impl.set_scroll_offset(initial_value); + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset)); + double duration = controller_impl->GetAnimation( + Animation::ScrollOffset)->curve()->Duration(); + + EXPECT_EQ( + duration, + controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration()); + + controller->Animate(kInitialTickTime); + controller->UpdateState(true, NULL); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(initial_value, dummy.scroll_offset()); + + controller_impl->Animate(kInitialTickTime); + controller_impl->UpdateState(true, events.get()); + EXPECT_TRUE(controller_impl->HasActiveAnimation()); + EXPECT_EQ(initial_value, dummy_impl.scroll_offset()); + // Scroll offset animations should not generate property updates. + const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + + controller->NotifyAnimationStarted((*events)[0], 0.0); + controller->Animate(kInitialTickTime + duration/2.0); + controller->UpdateState(true, NULL); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(200.f, 250.f), dummy.scroll_offset()); + + controller_impl->Animate(kInitialTickTime + duration/2.0); + controller_impl->UpdateState(true, events.get()); + EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(200.f, 250.f), + dummy_impl.scroll_offset()); + event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + + controller_impl->Animate(kInitialTickTime + duration); + controller_impl->UpdateState(true, events.get()); + EXPECT_VECTOR2DF_EQ(target_value, dummy_impl.scroll_offset()); + EXPECT_FALSE(controller_impl->HasActiveAnimation()); + event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + + controller->Animate(kInitialTickTime + duration); + controller->UpdateState(true, NULL); + EXPECT_VECTOR2DF_EQ(target_value, dummy.scroll_offset()); + EXPECT_FALSE(controller->HasActiveAnimation()); +} + +// Ensure that when the impl controller doesn't have a value provider, +// the main-thread controller's value provider is used to obtain the intial +// scroll offset. +TEST(LayerAnimationControllerTest, ScrollOffsetTransitionNoImplProvider) { + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddValueObserver(&dummy_impl); + scoped_ptr<AnimationEventsVector> events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy; + FakeLayerAnimationValueProvider dummy_provider; + scoped_refptr<LayerAnimationController> controller( + LayerAnimationController::Create(0)); + controller->AddValueObserver(&dummy); + controller->set_value_provider(&dummy_provider); + + gfx::Vector2dF initial_value(500.f, 100.f); + gfx::Vector2dF target_value(300.f, 200.f); + scoped_ptr<ScrollOffsetAnimationCurve> curve( + ScrollOffsetAnimationCurve::Create( + target_value, + EaseInOutTimingFunction::Create().Pass())); + + scoped_ptr<Animation> animation(Animation::Create( + curve.PassAs<AnimationCurve>(), 1, 0, Animation::ScrollOffset)); + animation->set_needs_synchronized_start_time(true); + controller->AddAnimation(animation.Pass()); + + dummy_provider.set_scroll_offset(initial_value); + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset)); + double duration = controller_impl->GetAnimation( + Animation::ScrollOffset)->curve()->Duration(); + + EXPECT_EQ( + duration, + controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration()); + + controller->Animate(kInitialTickTime); + controller->UpdateState(true, NULL); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_EQ(initial_value, dummy.scroll_offset()); + + controller_impl->Animate(kInitialTickTime); + controller_impl->UpdateState(true, events.get()); + EXPECT_TRUE(controller_impl->HasActiveAnimation()); + EXPECT_EQ(initial_value, dummy_impl.scroll_offset()); + // Scroll offset animations should not generate property updates. + const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + + controller->NotifyAnimationStarted((*events)[0], 0.0); + controller->Animate(kInitialTickTime + duration/2.0); + controller->UpdateState(true, NULL); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(400.f, 150.f), dummy.scroll_offset()); + + controller_impl->Animate(kInitialTickTime + duration/2.0); + controller_impl->UpdateState(true, events.get()); + EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(400.f, 150.f), + dummy_impl.scroll_offset()); + event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + + controller_impl->Animate(kInitialTickTime + duration); + controller_impl->UpdateState(true, events.get()); + EXPECT_VECTOR2DF_EQ(target_value, dummy_impl.scroll_offset()); + EXPECT_FALSE(controller_impl->HasActiveAnimation()); + event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + + controller->Animate(kInitialTickTime + duration); + controller->UpdateState(true, NULL); + EXPECT_VECTOR2DF_EQ(target_value, dummy.scroll_offset()); + EXPECT_FALSE(controller->HasActiveAnimation()); +} + +TEST(LayerAnimationControllerTest, ScrollOffsetTransitionOnImplOnly) { + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddValueObserver(&dummy_impl); + scoped_ptr<AnimationEventsVector> events( + make_scoped_ptr(new AnimationEventsVector)); + + gfx::Vector2dF initial_value(100.f, 300.f); + gfx::Vector2dF target_value(300.f, 200.f); + scoped_ptr<ScrollOffsetAnimationCurve> curve( + ScrollOffsetAnimationCurve::Create( + target_value, + EaseInOutTimingFunction::Create().Pass())); + curve->SetInitialValue(initial_value); + double duration = curve->Duration(); + + scoped_ptr<Animation> animation(Animation::Create( + curve.PassAs<AnimationCurve>(), 1, 0, Animation::ScrollOffset)); + animation->set_is_impl_only(true); + controller_impl->AddAnimation(animation.Pass()); + + controller_impl->Animate(kInitialTickTime); + controller_impl->UpdateState(true, events.get()); + EXPECT_TRUE(controller_impl->HasActiveAnimation()); + EXPECT_EQ(initial_value, dummy_impl.scroll_offset()); + // Scroll offset animations should not generate property updates. + const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + + controller_impl->Animate(kInitialTickTime + duration/2.0); + controller_impl->UpdateState(true, events.get()); + EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(200.f, 250.f), + dummy_impl.scroll_offset()); + event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); + + controller_impl->Animate(kInitialTickTime + duration); + controller_impl->UpdateState(true, events.get()); + EXPECT_VECTOR2DF_EQ(target_value, dummy_impl.scroll_offset()); + EXPECT_FALSE(controller_impl->HasActiveAnimation()); + event = GetMostRecentPropertyUpdateEvent(events.get()); + EXPECT_FALSE(event); +} + class FakeAnimationDelegate : public AnimationDelegate { public: FakeAnimationDelegate() : started_(false), finished_(false) {} - virtual void NotifyAnimationStarted(double time) OVERRIDE { + virtual void NotifyAnimationStarted( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { started_ = true; } - virtual void NotifyAnimationFinished(double time) OVERRIDE { + virtual void NotifyAnimationFinished( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { finished_ = true; } @@ -423,7 +813,7 @@ TEST(LayerAnimationControllerTest, to_add->set_is_impl_only(true); controller_impl->AddAnimation(to_add.Pass()); - controller_impl->Animate(0.0); + controller_impl->Animate(kInitialTickTime); controller_impl->UpdateState(true, events.get()); // We should receive 2 events (a started notification and a property update). @@ -440,7 +830,7 @@ TEST(LayerAnimationControllerTest, EXPECT_TRUE(delegate.started()); events.reset(new AnimationEventsVector); - controller_impl->Animate(1.0); + controller_impl->Animate(kInitialTickTime + 1.0); controller_impl->UpdateState(true, events.get()); // We should receive 2 events (a finished notification and a property update). @@ -477,24 +867,27 @@ TEST(LayerAnimationControllerTest, // We should pause at the first keyframe indefinitely waiting for that // animation to start. controller->AddAnimation(to_add.Pass()); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.0); + controller->Animate(kInitialTickTime + 1.0); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(2.0); + controller->Animate(kInitialTickTime + 2.0); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); // Send the synchronized start time. - controller->NotifyAnimationStarted( - AnimationEvent(AnimationEvent::Started, 0, 1, Animation::Opacity, 2), - 0.0); - controller->Animate(5.0); + controller->NotifyAnimationStarted(AnimationEvent(AnimationEvent::Started, + 0, + 1, + Animation::Opacity, + kInitialTickTime + 2), + 0.0); + controller->Animate(kInitialTickTime + 5.0); controller->UpdateState(true, events.get()); EXPECT_EQ(1.f, dummy.opacity()); EXPECT_FALSE(controller->HasActiveAnimation()); @@ -519,15 +912,15 @@ TEST(LayerAnimationControllerTest, TrivialQueuing) { 2, Animation::Opacity)); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.0); + controller->Animate(kInitialTickTime + 1.0); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(1.f, dummy.opacity()); - controller->Animate(2.0); + controller->Animate(kInitialTickTime + 2.0); controller->UpdateState(true, events.get()); EXPECT_EQ(0.5f, dummy.opacity()); EXPECT_FALSE(controller->HasActiveAnimation()); @@ -545,7 +938,7 @@ TEST(LayerAnimationControllerTest, Interrupt) { scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), 1, Animation::Opacity)); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); @@ -555,16 +948,16 @@ TEST(LayerAnimationControllerTest, Interrupt) { new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(), 2, Animation::Opacity)); - to_add->SetRunState(Animation::WaitingForNextTick, 0); + controller->AbortAnimations(Animation::Opacity); controller->AddAnimation(to_add.Pass()); - // Since the animation was in the WaitingForNextTick state, it should start + // Since the previous animation was aborted, the new animation should start // right in this call to animate. - controller->Animate(0.5); + controller->Animate(kInitialTickTime + 0.5); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(1.f, dummy.opacity()); - controller->Animate(1.5); + controller->Animate(kInitialTickTime + 1.5); controller->UpdateState(true, events.get()); EXPECT_EQ(0.5f, dummy.opacity()); EXPECT_FALSE(controller->HasActiveAnimation()); @@ -593,17 +986,17 @@ TEST(LayerAnimationControllerTest, ScheduleTogetherWhenAPropertyIsBlocked) { 2, Animation::Opacity)); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_EQ(0.f, dummy.opacity()); EXPECT_TRUE(controller->HasActiveAnimation()); - controller->Animate(1.0); + controller->Animate(kInitialTickTime + 1.0); controller->UpdateState(true, events.get()); // Should not have started the float transition yet. EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); // The float animation should have started at time 1 and should be done. - controller->Animate(2.0); + controller->Animate(kInitialTickTime + 2.0); controller->UpdateState(true, events.get()); EXPECT_EQ(1.f, dummy.opacity()); EXPECT_FALSE(controller->HasActiveAnimation()); @@ -635,14 +1028,14 @@ TEST(LayerAnimationControllerTest, ScheduleTogetherWithAnAnimWaiting) { Animation::Opacity)); // Animations with id 1 should both start now. - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); // The opacity animation should have finished at time 1, but the group // of animations with id 1 don't finish until time 2 because of the length // of the transform animation. - controller->Animate(2.0); + controller->Animate(kInitialTickTime + 2.0); controller->UpdateState(true, events.get()); // Should not have started the float transition yet. EXPECT_TRUE(controller->HasActiveAnimation()); @@ -650,139 +1043,9 @@ TEST(LayerAnimationControllerTest, ScheduleTogetherWithAnAnimWaiting) { // The second opacity animation should start at time 2 and should be done by // time 3. - controller->Animate(3.0); - controller->UpdateState(true, events.get()); - EXPECT_EQ(0.5f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); -} - -// Tests scheduling an animation to start in the future. -TEST(LayerAnimationControllerTest, ScheduleAnimation) { - scoped_ptr<AnimationEventsVector> events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr<LayerAnimationController> controller( - LayerAnimationController::Create(0)); - controller->AddValueObserver(&dummy); - - scoped_ptr<Animation> to_add(CreateAnimation( - scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - to_add->SetRunState(Animation::WaitingForStartTime, 0); - to_add->set_start_time(1.f); - controller->AddAnimation(to_add.Pass()); - - controller->Animate(0.0); + controller->Animate(kInitialTickTime + 3.0); controller->UpdateState(true, events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.0); - controller->UpdateState(true, events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(2.0); - controller->UpdateState(true, events.get()); - EXPECT_EQ(1.f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); -} - -// Tests scheduling an animation to start in the future that's interrupting a -// running animation. -TEST(LayerAnimationControllerTest, - ScheduledAnimationInterruptsRunningAnimation) { - scoped_ptr<AnimationEventsVector> events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr<LayerAnimationController> controller( - LayerAnimationController::Create(0)); - controller->AddValueObserver(&dummy); - - controller->AddAnimation(CreateAnimation( - scoped_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - - scoped_ptr<Animation> to_add(CreateAnimation( - scoped_ptr<AnimationCurve>( - new FakeFloatTransition(1.0, 0.5f, 0.f)).Pass(), - 2, - Animation::Opacity)); - to_add->SetRunState(Animation::WaitingForStartTime, 0); - to_add->set_start_time(1.f); - controller->AddAnimation(to_add.Pass()); - - // First 2s opacity transition should start immediately. - controller->Animate(0.0); - controller->UpdateState(true, events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(0.5); - controller->UpdateState(true, events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.25f, dummy.opacity()); - controller->Animate(1.0); - controller->UpdateState(true, events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.5f, dummy.opacity()); - controller->Animate(2.0); - controller->UpdateState(true, events.get()); - EXPECT_EQ(0.f, dummy.opacity()); - EXPECT_FALSE(controller->HasActiveAnimation()); -} - -// Tests scheduling an animation to start in the future that interrupts a -// running animation and there is yet another animation queued to start later. -TEST(LayerAnimationControllerTest, - ScheduledAnimationInterruptsRunningAnimationWithAnimInQueue) { - scoped_ptr<AnimationEventsVector> events( - make_scoped_ptr(new AnimationEventsVector)); - FakeLayerAnimationValueObserver dummy; - scoped_refptr<LayerAnimationController> controller( - LayerAnimationController::Create(0)); - controller->AddValueObserver(&dummy); - - controller->AddAnimation(CreateAnimation( - scoped_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), - 1, - Animation::Opacity)); - - scoped_ptr<Animation> to_add(CreateAnimation( - scoped_ptr<AnimationCurve>( - new FakeFloatTransition(2.0, 0.5f, 0.f)).Pass(), - 2, - Animation::Opacity)); - to_add->SetRunState(Animation::WaitingForStartTime, 0); - to_add->set_start_time(1.f); - controller->AddAnimation(to_add.Pass()); - - controller->AddAnimation(CreateAnimation( - scoped_ptr<AnimationCurve>( - new FakeFloatTransition(1.0, 0.f, 0.75f)).Pass(), - 3, - Animation::Opacity)); - - // First 2s opacity transition should start immediately. - controller->Animate(0.0); - controller->UpdateState(true, events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(0.5); - controller->UpdateState(true, events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.25f, dummy.opacity()); - EXPECT_TRUE(controller->HasActiveAnimation()); - controller->Animate(1.0); - controller->UpdateState(true, events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.5f, dummy.opacity()); - controller->Animate(3.0); - controller->UpdateState(true, events.get()); - EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(4.0); - controller->UpdateState(true, events.get()); - EXPECT_EQ(0.75f, dummy.opacity()); EXPECT_FALSE(controller->HasActiveAnimation()); } @@ -802,33 +1065,33 @@ TEST(LayerAnimationControllerTest, TrivialLooping) { to_add->set_iterations(3); controller->AddAnimation(to_add.Pass()); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.25); + controller->Animate(kInitialTickTime + 1.25); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.25f, dummy.opacity()); - controller->Animate(1.75); + controller->Animate(kInitialTickTime + 1.75); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); - controller->Animate(2.25); + controller->Animate(kInitialTickTime + 2.25); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.25f, dummy.opacity()); - controller->Animate(2.75); + controller->Animate(kInitialTickTime + 2.75); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); - controller->Animate(3.0); + controller->Animate(kInitialTickTime + 3.0); controller->UpdateState(true, events.get()); EXPECT_FALSE(controller->HasActiveAnimation()); EXPECT_EQ(1.f, dummy.opacity()); // Just be extra sure. - controller->Animate(4.0); + controller->Animate(kInitialTickTime + 4.0); controller->UpdateState(true, events.get()); EXPECT_EQ(1.f, dummy.opacity()); } @@ -850,31 +1113,31 @@ TEST(LayerAnimationControllerTest, InfiniteLooping) { to_add->set_iterations(-1); controller->AddAnimation(to_add.Pass()); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.25); + controller->Animate(kInitialTickTime + 1.25); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.25f, dummy.opacity()); - controller->Animate(1.75); + controller->Animate(kInitialTickTime + 1.75); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); - controller->Animate(1073741824.25); + controller->Animate(kInitialTickTime + 1073741824.25); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.25f, dummy.opacity()); - controller->Animate(1073741824.75); + controller->Animate(kInitialTickTime + 1073741824.75); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); controller->GetAnimation(id, Animation::Opacity)->SetRunState( - Animation::Aborted, 0.75); + Animation::Aborted, kInitialTickTime + 0.75); EXPECT_FALSE(controller->HasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); } @@ -894,33 +1157,33 @@ TEST(LayerAnimationControllerTest, PauseResume) { id, Animation::Opacity)); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(0.5); + controller->Animate(kInitialTickTime + 0.5); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.5f, dummy.opacity()); EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); controller->GetAnimation(id, Animation::Opacity)->SetRunState( - Animation::Paused, 0.5); + Animation::Paused, kInitialTickTime + 0.5); - controller->Animate(1024); + controller->Animate(kInitialTickTime + 1024.0); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.5f, dummy.opacity()); EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); controller->GetAnimation(id, Animation::Opacity)->SetRunState( - Animation::Running, 1024); + Animation::Running, kInitialTickTime + 1024); - controller->Animate(1024.25); + controller->Animate(kInitialTickTime + 1024.25); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); - controller->Animate(1024.5); + controller->Animate(kInitialTickTime + 1024.5); controller->UpdateState(true, events.get()); EXPECT_FALSE(controller->HasActiveAnimation()); EXPECT_EQ(1.f, dummy.opacity()); @@ -949,29 +1212,29 @@ TEST(LayerAnimationControllerTest, AbortAGroupedAnimation) { 2, Animation::Opacity)); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(1.0); + controller->Animate(kInitialTickTime + 1.0); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.5f, dummy.opacity()); EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); controller->GetAnimation(id, Animation::Opacity)->SetRunState( - Animation::Aborted, 1); - controller->Animate(1.0); + Animation::Aborted, kInitialTickTime + 1.0); + controller->Animate(kInitialTickTime + 1.0); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(1.f, dummy.opacity()); - controller->Animate(2.0); + controller->Animate(kInitialTickTime + 2.0); controller->UpdateState(true, events.get()); EXPECT_TRUE(!controller->HasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); } -TEST(LayerAnimationControllerTest, ForceSyncWhenSynchronizedStartTimeNeeded) { +TEST(LayerAnimationControllerTest, PushUpdatesWhenSynchronizedStartTimeNeeded) { FakeLayerAnimationValueObserver dummy_impl; scoped_refptr<LayerAnimationController> controller_impl( LayerAnimationController::Create(0)); @@ -990,15 +1253,13 @@ TEST(LayerAnimationControllerTest, ForceSyncWhenSynchronizedStartTimeNeeded) { to_add->set_needs_synchronized_start_time(true); controller->AddAnimation(to_add.Pass()); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_TRUE(controller->HasActiveAnimation()); Animation* active_animation = controller->GetAnimation(0, Animation::Opacity); EXPECT_TRUE(active_animation); EXPECT_TRUE(active_animation->needs_synchronized_start_time()); - controller->set_force_sync(); - controller->PushAnimationUpdatesTo(controller_impl.get()); active_animation = controller_impl->GetAnimation(0, Animation::Opacity); @@ -1021,7 +1282,7 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) { 1, Animation::Transform)); - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); controller->AddAnimation(CreateAnimation( @@ -1030,9 +1291,9 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) { Animation::Opacity)); // Animate but don't UpdateState. - controller->Animate(1.0); + controller->Animate(kInitialTickTime + 1.0); - controller->Animate(2.0); + controller->Animate(kInitialTickTime + 2.0); events.reset(new AnimationEventsVector); controller->UpdateState(true, events.get()); @@ -1044,7 +1305,7 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) { EXPECT_TRUE(controller->HasActiveAnimation()); EXPECT_EQ(0.f, dummy.opacity()); - controller->Animate(3.0); + controller->Animate(kInitialTickTime + 3.0); controller->UpdateState(true, events.get()); // The float tranisition should now be done. @@ -1070,7 +1331,7 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) { // Without an observer, the animation shouldn't progress to the Starting // state. - controller->Animate(0.0); + controller->Animate(kInitialTickTime); controller->UpdateState(true, events.get()); EXPECT_EQ(0u, events->size()); EXPECT_EQ(Animation::WaitingForTargetAvailability, @@ -1081,7 +1342,7 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) { // With only an inactive observer, the animation should progress to the // Starting state and get ticked at its starting point, but should not // progress to Running. - controller->Animate(1.0); + controller->Animate(kInitialTickTime + 1.0); controller->UpdateState(true, events.get()); EXPECT_EQ(0u, events->size()); EXPECT_EQ(Animation::Starting, @@ -1090,7 +1351,7 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) { // Even when already in the Starting state, the animation should stay // there, and shouldn't be ticked past its starting point. - controller->Animate(2.0); + controller->Animate(kInitialTickTime + 2.0); controller->UpdateState(true, events.get()); EXPECT_EQ(0u, events->size()); EXPECT_EQ(Animation::Starting, @@ -1101,7 +1362,7 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) { // Now that an active observer has been added, the animation should still // initially tick at its starting point, but should now progress to Running. - controller->Animate(3.0); + controller->Animate(kInitialTickTime + 3.0); controller->UpdateState(true, events.get()); EXPECT_EQ(1u, events->size()); EXPECT_EQ(Animation::Running, @@ -1110,7 +1371,7 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) { EXPECT_EQ(0.5f, dummy.opacity()); // The animation should now tick past its starting point. - controller->Animate(3.5); + controller->Animate(kInitialTickTime + 3.5); EXPECT_NE(0.5f, inactive_dummy.opacity()); EXPECT_NE(0.5f, dummy.opacity()); } @@ -1154,16 +1415,16 @@ TEST(LayerAnimationControllerTest, AnimatedBounds) { EXPECT_EQ(gfx::BoxF(1.f, 2.f, -4.f, 13.f, 19.f, 20.f).ToString(), bounds.ToString()); - controller_impl->GetAnimation(1, Animation::Transform)->SetRunState( - cc::Animation::Finished, 0.0); + controller_impl->GetAnimation(1, Animation::Transform) + ->SetRunState(Animation::Finished, 0.0); // Only the unfinished animation should affect the animated bounds. EXPECT_TRUE(controller_impl->AnimatedBoundsForBox(box, &bounds)); EXPECT_EQ(gfx::BoxF(1.f, 2.f, -4.f, 7.f, 16.f, 20.f).ToString(), bounds.ToString()); - controller_impl->GetAnimation(2, Animation::Transform)->SetRunState( - cc::Animation::Finished, 0.0); + controller_impl->GetAnimation(2, Animation::Transform) + ->SetRunState(Animation::Finished, 0.0); // There are no longer any running animations. EXPECT_TRUE(controller_impl->AnimatedBoundsForBox(box, &bounds)); @@ -1173,9 +1434,11 @@ TEST(LayerAnimationControllerTest, AnimatedBounds) { scoped_ptr<KeyframedTransformAnimationCurve> curve3( KeyframedTransformAnimationCurve::Create()); TransformOperations operations3; + gfx::Transform transform3; + transform3.Scale3d(1.0, 2.0, 3.0); curve3->AddKeyframe(TransformKeyframe::Create( 0.0, operations3, scoped_ptr<TimingFunction>())); - operations3.AppendSkew(1.0, 2.0); + operations3.AppendMatrix(transform3); curve3->AddKeyframe(TransformKeyframe::Create( 1.0, operations3, scoped_ptr<TimingFunction>())); animation = Animation::Create( @@ -1184,5 +1447,242 @@ TEST(LayerAnimationControllerTest, AnimatedBounds) { EXPECT_FALSE(controller_impl->AnimatedBoundsForBox(box, &bounds)); } +// Tests that AbortAnimations aborts all animations targeting the specified +// property. +TEST(LayerAnimationControllerTest, AbortAnimations) { + FakeLayerAnimationValueObserver dummy; + scoped_refptr<LayerAnimationController> controller( + LayerAnimationController::Create(0)); + controller->AddValueObserver(&dummy); + + // Start with several animations, and allow some of them to reach the finished + // state. + controller->AddAnimation(CreateAnimation( + scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), + 1, + Animation::Transform)); + controller->AddAnimation(CreateAnimation( + scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 2, + Animation::Opacity)); + controller->AddAnimation(CreateAnimation( + scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), + 3, + Animation::Transform)); + controller->AddAnimation(CreateAnimation( + scoped_ptr<AnimationCurve>(new FakeTransformTransition(2.0)).Pass(), + 4, + Animation::Transform)); + controller->AddAnimation(CreateAnimation( + scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 5, + Animation::Opacity)); + + controller->Animate(kInitialTickTime); + controller->UpdateState(true, NULL); + controller->Animate(kInitialTickTime + 1.0); + controller->UpdateState(true, NULL); + + EXPECT_EQ(Animation::Finished, + controller->GetAnimation(1, Animation::Transform)->run_state()); + EXPECT_EQ(Animation::Finished, + controller->GetAnimation(2, Animation::Opacity)->run_state()); + EXPECT_EQ(Animation::Running, + controller->GetAnimation(3, Animation::Transform)->run_state()); + EXPECT_EQ(Animation::WaitingForTargetAvailability, + controller->GetAnimation(4, Animation::Transform)->run_state()); + EXPECT_EQ(Animation::Running, + controller->GetAnimation(5, Animation::Opacity)->run_state()); + + controller->AbortAnimations(Animation::Transform); + + // Only un-finished Transform animations should have been aborted. + EXPECT_EQ(Animation::Finished, + controller->GetAnimation(1, Animation::Transform)->run_state()); + EXPECT_EQ(Animation::Finished, + controller->GetAnimation(2, Animation::Opacity)->run_state()); + EXPECT_EQ(Animation::Aborted, + controller->GetAnimation(3, Animation::Transform)->run_state()); + EXPECT_EQ(Animation::Aborted, + controller->GetAnimation(4, Animation::Transform)->run_state()); + EXPECT_EQ(Animation::Running, + controller->GetAnimation(5, Animation::Opacity)->run_state()); +} + +// An animation aborted on the main thread should get deleted on both threads. +TEST(LayerAnimationControllerTest, MainThreadAbortedAnimationGetsDeleted) { + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddValueObserver(&dummy_impl); + FakeLayerAnimationValueObserver dummy; + scoped_refptr<LayerAnimationController> controller( + LayerAnimationController::Create(0)); + controller->AddValueObserver(&dummy); + + AddOpacityTransitionToController(controller.get(), 1.0, 0.f, 1.f, false); + int group_id = controller->GetAnimation(Animation::Opacity)->group(); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)); + + controller->AbortAnimations(Animation::Opacity); + EXPECT_EQ(Animation::Aborted, + controller->GetAnimation(Animation::Opacity)->run_state()); + EXPECT_FALSE(dummy.animation_waiting_for_deletion()); + EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion()); + + controller->Animate(kInitialTickTime); + controller->UpdateState(true, NULL); + EXPECT_TRUE(dummy.animation_waiting_for_deletion()); + EXPECT_EQ(Animation::WaitingForDeletion, + controller->GetAnimation(Animation::Opacity)->run_state()); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_FALSE(controller->GetAnimation(group_id, Animation::Opacity)); + EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)); +} + +// An animation aborted on the impl thread should get deleted on both threads. +TEST(LayerAnimationControllerTest, ImplThreadAbortedAnimationGetsDeleted) { + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddValueObserver(&dummy_impl); + FakeLayerAnimationValueObserver dummy; + scoped_refptr<LayerAnimationController> controller( + LayerAnimationController::Create(0)); + controller->AddValueObserver(&dummy); + + AddOpacityTransitionToController(controller.get(), 1.0, 0.f, 1.f, false); + int group_id = controller->GetAnimation(Animation::Opacity)->group(); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)); + + controller_impl->AbortAnimations(Animation::Opacity); + EXPECT_EQ(Animation::Aborted, + controller_impl->GetAnimation(Animation::Opacity)->run_state()); + EXPECT_FALSE(dummy.animation_waiting_for_deletion()); + EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion()); + + AnimationEventsVector events; + controller_impl->Animate(kInitialTickTime); + controller_impl->UpdateState(true, &events); + EXPECT_TRUE(dummy_impl.animation_waiting_for_deletion()); + EXPECT_EQ(1u, events.size()); + EXPECT_EQ(AnimationEvent::Aborted, events[0].type); + EXPECT_EQ(Animation::WaitingForDeletion, + controller_impl->GetAnimation(Animation::Opacity)->run_state()); + + controller->NotifyAnimationAborted(events[0]); + EXPECT_EQ(Animation::Aborted, + controller->GetAnimation(Animation::Opacity)->run_state()); + + controller->Animate(kInitialTickTime + 0.5); + controller->UpdateState(true, NULL); + EXPECT_TRUE(dummy.animation_waiting_for_deletion()); + EXPECT_EQ(Animation::WaitingForDeletion, + controller->GetAnimation(Animation::Opacity)->run_state()); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_FALSE(controller->GetAnimation(group_id, Animation::Opacity)); + EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)); +} + +// Ensure that we only generate Finished events for animations in a group +// once all animations in that group are finished. +TEST(LayerAnimationControllerTest, FinishedEventsForGroup) { + scoped_ptr<AnimationEventsVector> events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddValueObserver(&dummy_impl); + + // Add two animations with the same group id but different durations. + controller_impl->AddAnimation(CreateAnimation( + scoped_ptr<AnimationCurve>(new FakeTransformTransition(2.0)).Pass(), + 1, + Animation::Transform)); + controller_impl->AddAnimation(CreateAnimation( + scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + + controller_impl->Animate(kInitialTickTime); + controller_impl->UpdateState(true, events.get()); + + // Both animations should have started. + EXPECT_EQ(2u, events->size()); + EXPECT_EQ(AnimationEvent::Started, (*events)[0].type); + EXPECT_EQ(AnimationEvent::Started, (*events)[1].type); + + events.reset(new AnimationEventsVector); + controller_impl->Animate(kInitialTickTime + 1.0); + controller_impl->UpdateState(true, events.get()); + + // The opacity animation should be finished, but should not have generated + // a Finished event yet. + EXPECT_EQ(0u, events->size()); + EXPECT_EQ(Animation::Finished, + controller_impl->GetAnimation(1, Animation::Opacity)->run_state()); + EXPECT_EQ(Animation::Running, + controller_impl->GetAnimation(1, + Animation::Transform)->run_state()); + + controller_impl->Animate(kInitialTickTime + 2.0); + controller_impl->UpdateState(true, events.get()); + + // Both animations should have generated Finished events. + EXPECT_EQ(2u, events->size()); + EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type); + EXPECT_EQ(AnimationEvent::Finished, (*events)[1].type); +} + +// Ensure that when a group has a mix of aborted and finished animations, +// we generate a Finished event for the finished animation and an Aborted +// event for the aborted animation. +TEST(LayerAnimationControllerTest, FinishedAndAbortedEventsForGroup) { + scoped_ptr<AnimationEventsVector> events( + make_scoped_ptr(new AnimationEventsVector)); + FakeLayerAnimationValueObserver dummy_impl; + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddValueObserver(&dummy_impl); + + // Add two animations with the same group id. + controller_impl->AddAnimation(CreateAnimation( + scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), + 1, + Animation::Transform)); + controller_impl->AddAnimation(CreateAnimation( + scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + + controller_impl->Animate(kInitialTickTime); + controller_impl->UpdateState(true, events.get()); + + // Both animations should have started. + EXPECT_EQ(2u, events->size()); + EXPECT_EQ(AnimationEvent::Started, (*events)[0].type); + EXPECT_EQ(AnimationEvent::Started, (*events)[1].type); + + controller_impl->AbortAnimations(Animation::Opacity); + + events.reset(new AnimationEventsVector); + controller_impl->Animate(kInitialTickTime + 1.0); + controller_impl->UpdateState(true, events.get()); + + // We should have exactly 2 events: a Finished event for the tranform + // animation, and an Aborted event for the opacity animation. + EXPECT_EQ(2u, events->size()); + EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type); + EXPECT_EQ(Animation::Transform, (*events)[0].target_property); + EXPECT_EQ(AnimationEvent::Aborted, (*events)[1].type); + EXPECT_EQ(Animation::Opacity, (*events)[1].target_property); +} + } // namespace } // namespace cc diff --git a/chromium/cc/animation/layer_animation_value_observer.h b/chromium/cc/animation/layer_animation_value_observer.h index ca3cafaf129..d21ade80f48 100644 --- a/chromium/cc/animation/layer_animation_value_observer.h +++ b/chromium/cc/animation/layer_animation_value_observer.h @@ -13,8 +13,11 @@ class CC_EXPORT LayerAnimationValueObserver { public: virtual ~LayerAnimationValueObserver() {} + virtual void OnFilterAnimated(const FilterOperations& filters) = 0; virtual void OnOpacityAnimated(float opacity) = 0; virtual void OnTransformAnimated(const gfx::Transform& transform) = 0; + virtual void OnScrollOffsetAnimated(gfx::Vector2dF scroll_offset) = 0; + virtual void OnAnimationWaitingForDeletion() = 0; virtual bool IsActive() const = 0; }; diff --git a/chromium/cc/animation/layer_animation_value_provider.h b/chromium/cc/animation/layer_animation_value_provider.h new file mode 100644 index 00000000000..c81496883ed --- /dev/null +++ b/chromium/cc/animation/layer_animation_value_provider.h @@ -0,0 +1,25 @@ +// Copyright 2013 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 CC_ANIMATION_LAYER_ANIMATION_VALUE_PROVIDER_H_ +#define CC_ANIMATION_LAYER_ANIMATION_VALUE_PROVIDER_H_ + +#include "cc/base/cc_export.h" +#include "ui/gfx/vector2d_f.h" + +namespace cc { + +// A LayerAnimationValueProvider is used for determining the starting value +// for animations that start at their 'current' value rather than at a +// pre-specified value. +class CC_EXPORT LayerAnimationValueProvider { + public: + virtual ~LayerAnimationValueProvider() {} + + virtual gfx::Vector2dF ScrollOffsetForAnimation() const = 0; +}; + +} // namespace cc + +#endif // CC_ANIMATION_LAYER_ANIMATION_VALUE_PROVIDER_H_ diff --git a/chromium/cc/animation/scroll_offset_animation_curve.cc b/chromium/cc/animation/scroll_offset_animation_curve.cc new file mode 100644 index 00000000000..362aa1ed548 --- /dev/null +++ b/chromium/cc/animation/scroll_offset_animation_curve.cc @@ -0,0 +1,80 @@ +// Copyright 2013 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 "cc/animation/scroll_offset_animation_curve.h" + +#include <algorithm> +#include <cmath> + +#include "base/logging.h" +#include "cc/animation/timing_function.h" +#include "ui/gfx/animation/tween.h" + +const double kDurationDivisor = 60.0; + +namespace cc { + +scoped_ptr<ScrollOffsetAnimationCurve> ScrollOffsetAnimationCurve::Create( + gfx::Vector2dF target_value, + scoped_ptr<TimingFunction> timing_function) { + return make_scoped_ptr( + new ScrollOffsetAnimationCurve(target_value, timing_function.Pass())); +} + +ScrollOffsetAnimationCurve::ScrollOffsetAnimationCurve( + gfx::Vector2dF target_value, + scoped_ptr<TimingFunction> timing_function) + : target_value_(target_value), + duration_(0.0), + timing_function_(timing_function.Pass()) {} + +ScrollOffsetAnimationCurve::~ScrollOffsetAnimationCurve() {} + +void ScrollOffsetAnimationCurve::SetInitialValue(gfx::Vector2dF initial_value) { + initial_value_ = initial_value; + + // The duration of a scroll animation depends on the size of the scroll. + // The exact relationship between the size and the duration isn't specified + // by the CSSOM View smooth scroll spec and is instead left up to user agents + // to decide. The calculation performed here will very likely be further + // tweaked before the smooth scroll API ships. + float delta_x = std::abs(target_value_.x() - initial_value_.x()); + float delta_y = std::abs(target_value_.y() - initial_value_.y()); + float max_delta = std::max(delta_x, delta_y); + duration_ = std::sqrt(max_delta)/kDurationDivisor; +} + +gfx::Vector2dF ScrollOffsetAnimationCurve::GetValue(double t) const { + if (t <= 0) + return initial_value_; + + if (t >= duration_) + return target_value_; + + double progress = timing_function_->GetValue(t / duration_); + return gfx::Vector2dF(gfx::Tween::FloatValueBetween( + progress, initial_value_.x(), target_value_.x()), + gfx::Tween::FloatValueBetween( + progress, initial_value_.y(), target_value_.y())); +} + +double ScrollOffsetAnimationCurve::Duration() const { + return duration_; +} + +AnimationCurve::CurveType ScrollOffsetAnimationCurve::Type() const { + return ScrollOffset; +} + +scoped_ptr<AnimationCurve> ScrollOffsetAnimationCurve::Clone() const { + scoped_ptr<TimingFunction> timing_function( + static_cast<TimingFunction*>(timing_function_->Clone().release())); + scoped_ptr<ScrollOffsetAnimationCurve> curve_clone = + Create(target_value_, timing_function.Pass()); + curve_clone->initial_value_ = initial_value_; + curve_clone->duration_ = duration_; + return curve_clone.PassAs<AnimationCurve>(); +} + +} // namespace cc diff --git a/chromium/cc/animation/scroll_offset_animation_curve.h b/chromium/cc/animation/scroll_offset_animation_curve.h new file mode 100644 index 00000000000..ba4661518e8 --- /dev/null +++ b/chromium/cc/animation/scroll_offset_animation_curve.h @@ -0,0 +1,47 @@ +// Copyright 2013 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 CC_ANIMATION_SCROLL_OFFSET_ANIMATION_CURVE_H_ +#define CC_ANIMATION_SCROLL_OFFSET_ANIMATION_CURVE_H_ + +#include "base/memory/scoped_ptr.h" +#include "cc/animation/animation_curve.h" +#include "cc/base/cc_export.h" + +namespace cc { + +class TimingFunction; + +class CC_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve { + public: + static scoped_ptr<ScrollOffsetAnimationCurve> Create( + gfx::Vector2dF target_value, + scoped_ptr<TimingFunction> timing_function); + + virtual ~ScrollOffsetAnimationCurve(); + + void SetInitialValue(gfx::Vector2dF initial_value); + gfx::Vector2dF GetValue(double t) const; + + // AnimationCurve implementation + virtual double Duration() const OVERRIDE; + virtual CurveType Type() const OVERRIDE; + virtual scoped_ptr<AnimationCurve> Clone() const OVERRIDE; + + private: + ScrollOffsetAnimationCurve(gfx::Vector2dF target_value, + scoped_ptr <TimingFunction> timing_function); + + gfx::Vector2dF initial_value_; + gfx::Vector2dF target_value_; + double duration_; + + scoped_ptr<TimingFunction> timing_function_; + + DISALLOW_COPY_AND_ASSIGN(ScrollOffsetAnimationCurve); +}; + +} // namespace cc + +#endif // CC_ANIMATION_SCROLL_OFFSET_ANIMATION_CURVE_H_ diff --git a/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc b/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc new file mode 100644 index 00000000000..63445d965dc --- /dev/null +++ b/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc @@ -0,0 +1,123 @@ +// Copyright 2013 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 "cc/animation/scroll_offset_animation_curve.h" + +#include "cc/animation/timing_function.h" +#include "cc/test/geometry_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +TEST(ScrollOffsetAnimationCurveTest, Duration) { + gfx::Vector2dF target_value(100.f, 200.f); + scoped_ptr<ScrollOffsetAnimationCurve> curve( + ScrollOffsetAnimationCurve::Create( + target_value, + EaseInOutTimingFunction::Create().Pass())); + + curve->SetInitialValue(target_value); + EXPECT_DOUBLE_EQ(0.0, curve->Duration()); + + // x decreases, y stays the same. + curve->SetInitialValue(gfx::Vector2dF(136.f, 200.f)); + EXPECT_DOUBLE_EQ(0.1, curve->Duration()); + + // x increases, y stays the same. + curve->SetInitialValue(gfx::Vector2dF(19.f, 200.f)); + EXPECT_DOUBLE_EQ(0.15, curve->Duration()); + + // x stays the same, y decreases. + curve->SetInitialValue(gfx::Vector2dF(100.f, 344.f)); + EXPECT_DOUBLE_EQ(0.2, curve->Duration()); + + // x stays the same, y increases. + curve->SetInitialValue(gfx::Vector2dF(100.f, 191.f)); + EXPECT_DOUBLE_EQ(0.05, curve->Duration()); + + // x decreases, y decreases. + curve->SetInitialValue(gfx::Vector2dF(32500.f, 500.f)); + EXPECT_DOUBLE_EQ(3.0, curve->Duration()); + + // x decreases, y increases. + curve->SetInitialValue(gfx::Vector2dF(150.f, 119.f)); + EXPECT_DOUBLE_EQ(0.15, curve->Duration()); + + // x increases, y decreases. + curve->SetInitialValue(gfx::Vector2dF(0.f, 14600.f)); + EXPECT_DOUBLE_EQ(2.0, curve->Duration()); + + // x increases, y increases. + curve->SetInitialValue(gfx::Vector2dF(95.f, 191.f)); + EXPECT_DOUBLE_EQ(0.05, curve->Duration()); +} + +TEST(ScrollOffsetAnimationCurveTest, GetValue) { + gfx::Vector2dF initial_value(2.f, 40.f); + gfx::Vector2dF target_value(10.f, 20.f); + scoped_ptr<ScrollOffsetAnimationCurve> curve( + ScrollOffsetAnimationCurve::Create( + target_value, + EaseInOutTimingFunction::Create().Pass())); + curve->SetInitialValue(initial_value); + + double duration = curve->Duration(); + EXPECT_GT(curve->Duration(), 0); + EXPECT_LT(curve->Duration(), 0.1); + + EXPECT_EQ(AnimationCurve::ScrollOffset, curve->Type()); + EXPECT_EQ(duration, curve->Duration()); + + EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(-1.0)); + EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(0.0)); + EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(6.f, 30.f), curve->GetValue(duration/2.0)); + EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration)); + EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration+1.0)); + + // Verify that GetValue takes the timing function into account. + gfx::Vector2dF value = curve->GetValue(duration/4.0); + EXPECT_NEAR(3.0333f, value.x(), 0.00015f); + EXPECT_NEAR(37.4168f, value.y(), 0.00015f); +} + +// Verify that a clone behaves exactly like the original. +TEST(ScrollOffsetAnimationCurveTest, Clone) { + gfx::Vector2dF initial_value(2.f, 40.f); + gfx::Vector2dF target_value(10.f, 20.f); + scoped_ptr<ScrollOffsetAnimationCurve> curve( + ScrollOffsetAnimationCurve::Create( + target_value, + EaseInOutTimingFunction::Create().Pass())); + curve->SetInitialValue(initial_value); + double duration = curve->Duration(); + + scoped_ptr<AnimationCurve> clone(curve->Clone().Pass()); + + EXPECT_EQ(AnimationCurve::ScrollOffset, clone->Type()); + EXPECT_EQ(duration, clone->Duration()); + + EXPECT_VECTOR2DF_EQ(initial_value, + clone->ToScrollOffsetAnimationCurve()->GetValue(-1.0)); + EXPECT_VECTOR2DF_EQ(initial_value, + clone->ToScrollOffsetAnimationCurve()->GetValue(0.0)); + EXPECT_VECTOR2DF_EQ( + gfx::Vector2dF(6.f, 30.f), + clone->ToScrollOffsetAnimationCurve()->GetValue(duration / 2.0)); + EXPECT_VECTOR2DF_EQ( + target_value, + clone->ToScrollOffsetAnimationCurve()->GetValue(duration)); + EXPECT_VECTOR2DF_EQ( + target_value, + clone->ToScrollOffsetAnimationCurve()->GetValue(duration + 1.0)); + + // Verify that the timing function was cloned correctly. + gfx::Vector2dF value = + clone->ToScrollOffsetAnimationCurve()->GetValue(duration / 4.0); + EXPECT_NEAR(3.0333f, value.x(), 0.00015f); + EXPECT_NEAR(37.4168f, value.y(), 0.00015f); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/animation/scrollbar_animation_controller.h b/chromium/cc/animation/scrollbar_animation_controller.h index d3667f10bca..ecef4fb2d97 100644 --- a/chromium/cc/animation/scrollbar_animation_controller.h +++ b/chromium/cc/animation/scrollbar_animation_controller.h @@ -24,9 +24,11 @@ class CC_EXPORT ScrollbarAnimationController { virtual bool Animate(base::TimeTicks now) = 0; virtual void DidScrollGestureBegin() = 0; virtual void DidScrollGestureEnd(base::TimeTicks now) = 0; + virtual void DidMouseMoveOffScrollbar(base::TimeTicks now) = 0; // Returns true if we should start an animation. virtual bool DidScrollUpdate(base::TimeTicks now) = 0; + virtual bool DidMouseMoveNear(base::TimeTicks now, float distance) = 0; }; } // namespace cc diff --git a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc index eafcca08d51..863959b84c2 100644 --- a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc +++ b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc @@ -65,6 +65,11 @@ void ScrollbarAnimationControllerLinearFade::DidScrollGestureEnd( scroll_gesture_in_progress_ = false; } +void ScrollbarAnimationControllerLinearFade::DidMouseMoveOffScrollbar( + base::TimeTicks now) { + // Ignore mouse move events. +} + bool ScrollbarAnimationControllerLinearFade::DidScrollUpdate( base::TimeTicks now) { ApplyOpacityToScrollbars(1.0f); @@ -80,6 +85,12 @@ bool ScrollbarAnimationControllerLinearFade::DidScrollUpdate( return true; } +bool ScrollbarAnimationControllerLinearFade::DidMouseMoveNear( + base::TimeTicks now, float distance) { + // Ignore mouse move events. + return false; +} + float ScrollbarAnimationControllerLinearFade::OpacityAtTime( base::TimeTicks now) { if (scroll_gesture_has_scrolled_) diff --git a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h index eca4c4f86f0..85cdada5156 100644 --- a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h +++ b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h @@ -29,7 +29,9 @@ class CC_EXPORT ScrollbarAnimationControllerLinearFade virtual bool Animate(base::TimeTicks now) OVERRIDE; virtual void DidScrollGestureBegin() OVERRIDE; virtual void DidScrollGestureEnd(base::TimeTicks now) OVERRIDE; + virtual void DidMouseMoveOffScrollbar(base::TimeTicks now) OVERRIDE; virtual bool DidScrollUpdate(base::TimeTicks now) OVERRIDE; + virtual bool DidMouseMoveNear(base::TimeTicks now, float distance) OVERRIDE; protected: ScrollbarAnimationControllerLinearFade(LayerImpl* scroll_layer, diff --git a/chromium/cc/animation/scrollbar_animation_controller_thinning.cc b/chromium/cc/animation/scrollbar_animation_controller_thinning.cc index fcacfaab4a3..3de75989d0e 100644 --- a/chromium/cc/animation/scrollbar_animation_controller_thinning.cc +++ b/chromium/cc/animation/scrollbar_animation_controller_thinning.cc @@ -10,14 +10,22 @@ #include "cc/layers/layer_impl.h" #include "cc/layers/scrollbar_layer_impl_base.h" +namespace { +const float kIdleThicknessScale = 0.4f; +const float kIdleOpacity = 0.7f; +const float kDefaultMouseMoveDistanceToTriggerAnimation = 25.f; +const int kDefaultAnimationDelay = 500; +const int kDefaultAnimationDuration = 300; +} + namespace cc { scoped_ptr<ScrollbarAnimationControllerThinning> ScrollbarAnimationControllerThinning::Create(LayerImpl* scroll_layer) { return make_scoped_ptr(new ScrollbarAnimationControllerThinning( scroll_layer, - base::TimeDelta::FromMilliseconds(500), - base::TimeDelta::FromMilliseconds(300))); + base::TimeDelta::FromMilliseconds(kDefaultAnimationDelay), + base::TimeDelta::FromMilliseconds(kDefaultAnimationDuration))); } scoped_ptr<ScrollbarAnimationControllerThinning> @@ -33,9 +41,17 @@ ScrollbarAnimationControllerThinning::ScrollbarAnimationControllerThinning( base::TimeDelta animation_duration) : ScrollbarAnimationController(), scroll_layer_(scroll_layer), - scroll_gesture_in_progress_(false), + mouse_is_over_scrollbar_(false), + mouse_is_near_scrollbar_(false), + thickness_change_(NONE), + opacity_change_(NONE), + should_delay_animation_(false), animation_delay_(animation_delay), - animation_duration_(animation_duration) {} + animation_duration_(animation_duration), + mouse_move_distance_to_trigger_animation_( + kDefaultMouseMoveDistanceToTriggerAnimation) { + ApplyOpacityAndThumbThicknessScale(kIdleOpacity, kIdleThicknessScale); +} ScrollbarAnimationControllerThinning::~ScrollbarAnimationControllerThinning() { } @@ -46,6 +62,8 @@ bool ScrollbarAnimationControllerThinning::IsAnimating() const { base::TimeDelta ScrollbarAnimationControllerThinning::DelayBeforeStart( base::TimeTicks now) const { + if (!should_delay_animation_) + return base::TimeDelta(); if (now > last_awaken_time_ + animation_delay_) return base::TimeDelta(); return animation_delay_ - (now - last_awaken_time_); @@ -57,58 +75,107 @@ bool ScrollbarAnimationControllerThinning::Animate(base::TimeTicks now) { float thumb_thickness_scale = ThumbThicknessScaleAtAnimationProgress( progress); ApplyOpacityAndThumbThicknessScale(opacity, thumb_thickness_scale); - if (progress == 1.f) + if (progress == 1.f) { + opacity_change_ = NONE; + thickness_change_ = NONE; last_awaken_time_ = base::TimeTicks(); + } return IsAnimating() && DelayBeforeStart(now) == base::TimeDelta(); } void ScrollbarAnimationControllerThinning::DidScrollGestureBegin() { - ApplyOpacityAndThumbThicknessScale(1, 1); - last_awaken_time_ = base::TimeTicks(); - scroll_gesture_in_progress_ = true; } void ScrollbarAnimationControllerThinning::DidScrollGestureEnd( base::TimeTicks now) { +} + +void ScrollbarAnimationControllerThinning::DidMouseMoveOffScrollbar( + base::TimeTicks now) { + mouse_is_over_scrollbar_ = false; + mouse_is_near_scrollbar_ = false; last_awaken_time_ = now; - scroll_gesture_in_progress_ = false; + should_delay_animation_ = false; + opacity_change_ = DECREASE; + thickness_change_ = DECREASE; } bool ScrollbarAnimationControllerThinning::DidScrollUpdate( base::TimeTicks now) { - ApplyOpacityAndThumbThicknessScale(1, 1); + ApplyOpacityAndThumbThicknessScale( + 1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale); last_awaken_time_ = now; + should_delay_animation_ = true; + if (!mouse_is_over_scrollbar_) + opacity_change_ = DECREASE; + return true; +} + +bool ScrollbarAnimationControllerThinning::DidMouseMoveNear( + base::TimeTicks now, float distance) { + bool mouse_is_over_scrollbar = distance == 0.0; + bool mouse_is_near_scrollbar = + distance < mouse_move_distance_to_trigger_animation_; + + if (mouse_is_over_scrollbar == mouse_is_over_scrollbar_ && + mouse_is_near_scrollbar == mouse_is_near_scrollbar_) + return false; + + if (mouse_is_over_scrollbar_ != mouse_is_over_scrollbar) { + mouse_is_over_scrollbar_ = mouse_is_over_scrollbar; + opacity_change_ = mouse_is_over_scrollbar_ ? INCREASE : DECREASE; + } + + if (mouse_is_near_scrollbar_ != mouse_is_near_scrollbar) { + mouse_is_near_scrollbar_ = mouse_is_near_scrollbar; + thickness_change_ = mouse_is_near_scrollbar_ ? INCREASE : DECREASE; + } + + last_awaken_time_ = now; + should_delay_animation_ = false; return true; } float ScrollbarAnimationControllerThinning::AnimationProgressAtTime( base::TimeTicks now) { - if (scroll_gesture_in_progress_) - return 0; - if (last_awaken_time_.is_null()) return 1; base::TimeDelta delta = now - last_awaken_time_; - float progress = (delta - animation_delay_).InSecondsF() / - animation_duration_.InSecondsF(); + if (should_delay_animation_) + delta -= animation_delay_; + float progress = delta.InSecondsF() / animation_duration_.InSecondsF(); return std::max(std::min(progress, 1.f), 0.f); } float ScrollbarAnimationControllerThinning::OpacityAtAnimationProgress( float progress) { - const float kIdleOpacity = 0.7f; - - return ((1 - kIdleOpacity) * (1.f - progress)) + kIdleOpacity; + if (opacity_change_ == NONE) + return mouse_is_over_scrollbar_ ? 1.f : kIdleOpacity; + float factor = opacity_change_ == INCREASE ? progress : (1.f - progress); + float ret = ((1.f - kIdleOpacity) * factor) + kIdleOpacity; + return ret; } float ScrollbarAnimationControllerThinning::ThumbThicknessScaleAtAnimationProgress( float progress) { - const float kIdleThicknessScale = 0.4f; + if (thickness_change_ == NONE) + return mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale; + float factor = thickness_change_ == INCREASE ? progress : (1.f - progress); + return ((1.f - kIdleThicknessScale) * factor) + kIdleThicknessScale; +} - return ((1 - kIdleThicknessScale) * (1.f - progress)) + kIdleThicknessScale; +float ScrollbarAnimationControllerThinning::AdjustScale( + float new_value, + float current_value, + AnimationChange animation_change) { + if (animation_change == INCREASE && current_value > new_value) + return current_value; + if (animation_change == DECREASE && current_value < new_value) + return current_value; + return new_value; } void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale( @@ -116,16 +183,25 @@ void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale( ScrollbarLayerImplBase* horizontal_scrollbar = scroll_layer_->horizontal_scrollbar_layer(); if (horizontal_scrollbar) { - horizontal_scrollbar->SetOpacity(opacity); - horizontal_scrollbar->set_thumb_thickness_scale_factor( - thumb_thickness_scale); + horizontal_scrollbar->SetOpacity( + AdjustScale(opacity, horizontal_scrollbar->opacity(), opacity_change_)); + horizontal_scrollbar->SetThumbThicknessScaleFactor( + AdjustScale( + thumb_thickness_scale, + horizontal_scrollbar->thumb_thickness_scale_factor(), + thickness_change_)); } ScrollbarLayerImplBase* vertical_scrollbar = scroll_layer_->vertical_scrollbar_layer(); if (vertical_scrollbar) { - vertical_scrollbar->SetOpacity(opacity); - vertical_scrollbar->set_thumb_thickness_scale_factor(thumb_thickness_scale); + vertical_scrollbar->SetOpacity( + AdjustScale(opacity, vertical_scrollbar->opacity(), opacity_change_)); + vertical_scrollbar->SetThumbThicknessScaleFactor( + AdjustScale( + thumb_thickness_scale, + vertical_scrollbar->thumb_thickness_scale_factor(), + thickness_change_)); } } diff --git a/chromium/cc/animation/scrollbar_animation_controller_thinning.h b/chromium/cc/animation/scrollbar_animation_controller_thinning.h index 0211479ef9a..07b4515ec31 100644 --- a/chromium/cc/animation/scrollbar_animation_controller_thinning.h +++ b/chromium/cc/animation/scrollbar_animation_controller_thinning.h @@ -26,6 +26,12 @@ class CC_EXPORT ScrollbarAnimationControllerThinning virtual ~ScrollbarAnimationControllerThinning(); + void set_mouse_move_distance_for_test(float distance) { + mouse_move_distance_to_trigger_animation_ = distance; + } + bool mouse_is_over_scrollbar() const { return mouse_is_over_scrollbar_; } + bool mouse_is_near_scrollbar() const { return mouse_is_near_scrollbar_; } + // ScrollbarAnimationController overrides. virtual bool IsAnimating() const OVERRIDE; virtual base::TimeDelta DelayBeforeStart(base::TimeTicks now) const OVERRIDE; @@ -33,7 +39,9 @@ class CC_EXPORT ScrollbarAnimationControllerThinning virtual bool Animate(base::TimeTicks now) OVERRIDE; virtual void DidScrollGestureBegin() OVERRIDE; virtual void DidScrollGestureEnd(base::TimeTicks now) OVERRIDE; + virtual void DidMouseMoveOffScrollbar(base::TimeTicks now) OVERRIDE; virtual bool DidScrollUpdate(base::TimeTicks now) OVERRIDE; + virtual bool DidMouseMoveNear(base::TimeTicks now, float distance) OVERRIDE; protected: ScrollbarAnimationControllerThinning(LayerImpl* scroll_layer, @@ -41,21 +49,41 @@ class CC_EXPORT ScrollbarAnimationControllerThinning base::TimeDelta animation_duration); private: + // Describes whether the current animation should INCREASE (darken / thicken) + // a bar or DECREASE it (lighten / thin). + enum AnimationChange { + NONE, + INCREASE, + DECREASE + }; // Returns how far through the animation we are as a progress value from // 0 to 1. float AnimationProgressAtTime(base::TimeTicks now); float OpacityAtAnimationProgress(float progress); float ThumbThicknessScaleAtAnimationProgress(float progress); + float AdjustScale(float new_value, + float current_value, + AnimationChange animation_change); void ApplyOpacityAndThumbThicknessScale(float opacity, float thumb_thickness_scale); LayerImpl* scroll_layer_; base::TimeTicks last_awaken_time_; - bool scroll_gesture_in_progress_; - + bool mouse_is_over_scrollbar_; + bool mouse_is_near_scrollbar_; + // Are we narrowing or thickening the bars. + AnimationChange thickness_change_; + // Are we darkening or lightening the bars. + AnimationChange opacity_change_; + // Should the animation be delayed or start immediately. + bool should_delay_animation_; + // If |should_delay_animation_| is true, delay the animation by this amount. base::TimeDelta animation_delay_; + // The time for the animation to run. base::TimeDelta animation_duration_; + // How close should the mouse be to the scrollbar before we thicken it. + float mouse_move_distance_to_trigger_animation_; DISALLOW_COPY_AND_ASSIGN(ScrollbarAnimationControllerThinning); }; diff --git a/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc index c83bdc81b39..c915632f2fc 100644 --- a/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc +++ b/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc @@ -43,106 +43,194 @@ class ScrollbarAnimationControllerThinningTest : public testing::Test { scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_; }; +// Check initialization of scrollbar. TEST_F(ScrollbarAnimationControllerThinningTest, Idle) { scrollbar_controller_->Animate(base::TimeTicks()); EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); } -TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByScrollGesture) { +// Scroll content. Confirm the scrollbar gets dark and then becomes light +// after stopping. +TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) { base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->DidScrollGestureBegin(); - EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + // Scrollbar doesn't change size if triggered by scroll. + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); - time += base::TimeDelta::FromSeconds(100); + time += base::TimeDelta::FromSeconds(1); + EXPECT_EQ(1, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); - scrollbar_controller_->DidScrollGestureEnd(time); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); - EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + // Subsequent scroll restarts animation. + EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); time += base::TimeDelta::FromSeconds(1); + EXPECT_EQ(1, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->Animate(time); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); - scrollbar_controller_->DidScrollGestureBegin(); - scrollbar_controller_->DidScrollGestureEnd(time); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); +} +// Initiate a scroll when the pointer is already near the scrollbar. It should +// remain thick. +TEST_F(ScrollbarAnimationControllerThinningTest, ScrollWithMouseNear) { + base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); + + scrollbar_controller_->DidMouseMoveNear(time, 1); + time += base::TimeDelta::FromSeconds(3); scrollbar_controller_->Animate(time); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + + EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + // Scrollbar should still be thick. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + time += base::TimeDelta::FromSeconds(5); + scrollbar_controller_->Animate(time); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); +} + +// Move the pointer near the scrollbar. Confirm it gets thick and narrow when +// moved away. +TEST_F(ScrollbarAnimationControllerThinningTest, MouseNear) { + base::TimeTicks time; + time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->DidMouseMoveNear(time, 1); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + + // Should animate to thickened but not darken. time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); + + time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->Animate(time); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); + + time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->Animate(time); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + // Subsequent moves should not change anything. + scrollbar_controller_->DidMouseMoveNear(time, 1); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + + // Now move away from bar. + time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->DidMouseMoveNear(time, 26); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + + // Animate to narrow. time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); } -TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) { +// Move the pointer over the scrollbar. Make sure it gets thick and dark +// and that it gets thin and light when moved away. +TEST_F(ScrollbarAnimationControllerThinningTest, MouseOver) { base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); - EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); + scrollbar_controller_->DidMouseMoveNear(time, 0); EXPECT_TRUE(scrollbar_controller_->IsAnimating()); - EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + + // Should animate to thickened and darkened. + time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); - EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); + EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + // Subsequent moves should not change anything. + scrollbar_controller_->DidMouseMoveNear(time, 0); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + + // Now move away from bar. time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->Animate(time); + scrollbar_controller_->DidMouseMoveNear(time, 26); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + // Animate to narrow. time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); @@ -154,31 +242,90 @@ TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) { EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); - EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); + scrollbar_controller_->Animate(time); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); +} + +// First move the pointer near the scrollbar, then over it, then back near +// then far away. Confirm that first the bar gets thick, then dark, then light, +// then narrow. +TEST_F(ScrollbarAnimationControllerThinningTest, MouseNearThenOver) { + base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->DidMouseMoveNear(time, 1); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + + // Should animate to thickened but not darken. + time += base::TimeDelta::FromSeconds(3); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + + // Now move over. + scrollbar_controller_->DidMouseMoveNear(time, 0); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + + // Should animate to darkened. + time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->Animate(time); + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + + time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->Animate(time); + EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + + // This is tricky. The DidMouseMoveOffScrollbar() is sent before the + // subsequent DidMouseMoveNear(), if the mouse moves in that direction. + // This results in the thumb thinning. We want to make sure that when the + // thumb starts expanding it doesn't first narrow to the idle thinness. + time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->DidMouseMoveOffScrollbar(time); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); + scrollbar_controller_->DidMouseMoveNear(time, 1); + // A new animation is kicked off. + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + + time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->Animate(time); + // We will initiate the narrowing again, but it won't get decremented until + // the new animation catches up to it. + EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); + // Now the thickness should be increasing, but it shouldn't happen until the + // animation catches up. + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); + time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); + // The thickness now gets big again. + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + // The thickness now gets big again. + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); } } // namespace diff --git a/chromium/cc/animation/transform_operation.cc b/chromium/cc/animation/transform_operation.cc index 93f40f37f1a..e4d0dadf0eb 100644 --- a/chromium/cc/animation/transform_operation.cc +++ b/chromium/cc/animation/transform_operation.cc @@ -2,17 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Needed on Windows to get |M_PI| from <cmath> +#ifdef _WIN32 +#define _USE_MATH_DEFINES +#endif + #include <algorithm> #include <cmath> #include <limits> #include "base/logging.h" #include "cc/animation/transform_operation.h" +#include "cc/animation/transform_operations.h" #include "ui/gfx/box_f.h" +#include "ui/gfx/transform_util.h" #include "ui/gfx/vector3d_f.h" namespace { -const SkMScalar kAngleEpsilon = 1e-4; +const SkMScalar kAngleEpsilon = 1e-4f; } namespace cc { @@ -158,11 +165,19 @@ bool TransformOperation::BlendTransformOperations( SkMScalar from_perspective_depth = IsOperationIdentity(from) ? std::numeric_limits<SkMScalar>::max() : from->perspective_depth; - SkMScalar to_perspective_depth = IsOperationIdentity(to) - ? std::numeric_limits<SkMScalar>::max() - : to->perspective_depth; - result->ApplyPerspectiveDepth(BlendSkMScalars( - from_perspective_depth, to_perspective_depth, progress)); + SkMScalar to_perspective_depth = + IsOperationIdentity(to) ? std::numeric_limits<SkMScalar>::max() + : to->perspective_depth; + if (from_perspective_depth == 0.f || to_perspective_depth == 0.f) + return false; + + SkMScalar blended_perspective_depth = BlendSkMScalars( + 1.f / from_perspective_depth, 1.f / to_perspective_depth, progress); + + if (blended_perspective_depth == 0.f) + return false; + + result->ApplyPerspectiveDepth(1.f / blended_perspective_depth); break; } case TransformOperation::TransformOperationMatrix: { @@ -185,28 +200,167 @@ bool TransformOperation::BlendTransformOperations( return true; } -static void ApplyScaleToBox(float x_scale, - float y_scale, - float z_scale, - gfx::BoxF* box) { - if (x_scale < 0) - box->set_x(-box->right()); - if (y_scale < 0) - box->set_y(-box->bottom()); - if (z_scale < 0) - box->set_z(-box->front()); - box->Scale(std::abs(x_scale), std::abs(y_scale), std::abs(z_scale)); +// If p = (px, py) is a point in the plane being rotated about (0, 0, nz), this +// function computes the angles we would have to rotate from p to get to +// (length(p), 0), (-length(p), 0), (0, length(p)), (0, -length(p)). If nz is +// negative, these angles will need to be reversed. +static void FindCandidatesInPlane(float px, + float py, + float nz, + double* candidates, + int* num_candidates) { + double phi = atan2(px, py); + *num_candidates = 4; + candidates[0] = phi; + for (int i = 1; i < *num_candidates; ++i) + candidates[i] = candidates[i - 1] + M_PI_2; + if (nz < 0.f) { + for (int i = 0; i < *num_candidates; ++i) + candidates[i] *= -1.f; + } } -static void UnionBoxWithZeroScale(gfx::BoxF* box) { - float min_x = std::min(box->x(), 0.f); - float min_y = std::min(box->y(), 0.f); - float min_z = std::min(box->z(), 0.f); - float max_x = std::max(box->right(), 0.f); - float max_y = std::max(box->bottom(), 0.f); - float max_z = std::max(box->front(), 0.f); - *box = gfx::BoxF( - min_x, min_y, min_z, max_x - min_x, max_y - min_y, max_z - min_z); +static float RadiansToDegrees(float radians) { + return (180.f * radians) / M_PI; +} + +static float DegreesToRadians(float degrees) { + return (M_PI * degrees) / 180.f; +} + +static void BoundingBoxForArc(const gfx::Point3F& point, + const TransformOperation* from, + const TransformOperation* to, + SkMScalar min_progress, + SkMScalar max_progress, + gfx::BoxF* box) { + const TransformOperation* exemplar = from ? from : to; + gfx::Vector3dF axis(exemplar->rotate.axis.x, + exemplar->rotate.axis.y, + exemplar->rotate.axis.z); + + const bool x_is_zero = axis.x() == 0.f; + const bool y_is_zero = axis.y() == 0.f; + const bool z_is_zero = axis.z() == 0.f; + + // We will have at most 6 angles to test (excluding from->angle and + // to->angle). + static const int kMaxNumCandidates = 6; + double candidates[kMaxNumCandidates]; + int num_candidates = kMaxNumCandidates; + + if (x_is_zero && y_is_zero && z_is_zero) + return; + + SkMScalar from_angle = from ? from->rotate.angle : 0.f; + SkMScalar to_angle = to ? to->rotate.angle : 0.f; + + // If the axes of rotation are pointing in opposite directions, we need to + // flip one of the angles. Note, if both |from| and |to| exist, then axis will + // correspond to |from|. + if (from && to) { + gfx::Vector3dF other_axis( + to->rotate.axis.x, to->rotate.axis.y, to->rotate.axis.z); + if (gfx::DotProduct(axis, other_axis) < 0.f) + to_angle *= -1.f; + } + + float min_degrees = + SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, min_progress)); + float max_degrees = + SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, max_progress)); + if (max_degrees < min_degrees) + std::swap(min_degrees, max_degrees); + + gfx::Transform from_transform; + from_transform.RotateAbout(axis, min_degrees); + gfx::Transform to_transform; + to_transform.RotateAbout(axis, max_degrees); + + *box = gfx::BoxF(); + + gfx::Point3F point_rotated_from = point; + from_transform.TransformPoint(&point_rotated_from); + gfx::Point3F point_rotated_to = point; + to_transform.TransformPoint(&point_rotated_to); + + box->set_origin(point_rotated_from); + box->ExpandTo(point_rotated_to); + + if (x_is_zero && y_is_zero) { + FindCandidatesInPlane( + point.x(), point.y(), axis.z(), candidates, &num_candidates); + } else if (x_is_zero && z_is_zero) { + FindCandidatesInPlane( + point.z(), point.x(), axis.y(), candidates, &num_candidates); + } else if (y_is_zero && z_is_zero) { + FindCandidatesInPlane( + point.y(), point.z(), axis.x(), candidates, &num_candidates); + } else { + gfx::Vector3dF normal = axis; + normal.Scale(1.f / normal.Length()); + + // First, find center of rotation. + gfx::Point3F origin; + gfx::Vector3dF to_point = point - origin; + gfx::Point3F center = + origin + gfx::ScaleVector3d(normal, gfx::DotProduct(to_point, normal)); + + // Now we need to find two vectors in the plane of rotation. One pointing + // towards point and another, perpendicular vector in the plane. + gfx::Vector3dF v1 = point - center; + float v1_length = v1.Length(); + if (v1_length == 0.f) + return; + + v1.Scale(1.f / v1_length); + + gfx::Vector3dF v2 = gfx::CrossProduct(normal, v1); + + // Now figure out where (1, 0, 0) and (0, 0, 1) project on the rotation + // plane. + gfx::Point3F px(1.f, 0.f, 0.f); + gfx::Vector3dF to_px = px - center; + gfx::Point3F px_projected = + px - gfx::ScaleVector3d(normal, gfx::DotProduct(to_px, normal)); + gfx::Vector3dF vx = px_projected - origin; + + gfx::Point3F pz(0.f, 0.f, 1.f); + gfx::Vector3dF to_pz = pz - center; + gfx::Point3F pz_projected = + pz - ScaleVector3d(normal, gfx::DotProduct(to_pz, normal)); + gfx::Vector3dF vz = pz_projected - origin; + + double phi_x = atan2(gfx::DotProduct(v2, vx), gfx::DotProduct(v1, vx)); + double phi_z = atan2(gfx::DotProduct(v2, vz), gfx::DotProduct(v1, vz)); + + candidates[0] = atan2(normal.y(), normal.x() * normal.z()) + phi_x; + candidates[1] = candidates[0] + M_PI; + candidates[2] = atan2(-normal.z(), normal.x() * normal.y()) + phi_x; + candidates[3] = candidates[2] + M_PI; + candidates[4] = atan2(normal.y(), -normal.x() * normal.z()) + phi_z; + candidates[5] = candidates[4] + M_PI; + } + + double min_radians = DegreesToRadians(min_degrees); + double max_radians = DegreesToRadians(max_degrees); + + for (int i = 0; i < num_candidates; ++i) { + double radians = candidates[i]; + while (radians < min_radians) + radians += 2.0 * M_PI; + while (radians > max_radians) + radians -= 2.0 * M_PI; + if (radians < min_radians) + continue; + + gfx::Transform rotation; + rotation.RotateAbout(axis, RadiansToDegrees(radians)); + gfx::Point3F rotated = point; + rotation.TransformPoint(&rotated); + + box->ExpandTo(rotated); + } } bool TransformOperation::BlendedBoundsForBox(const gfx::BoxF& box, @@ -230,80 +384,53 @@ bool TransformOperation::BlendedBoundsForBox(const gfx::BoxF& box, interpolation_type = to->type; switch (interpolation_type) { - case TransformOperation::TransformOperationTranslate: { - SkMScalar from_x, from_y, from_z; - if (is_identity_from) { - from_x = from_y = from_z = 0.0; - } else { - from_x = from->translate.x; - from_y = from->translate.y; - from_z = from->translate.z; - } - SkMScalar to_x, to_y, to_z; - if (is_identity_to) { - to_x = to_y = to_z = 0.0; - } else { - to_x = to->translate.x; - to_y = to->translate.y; - to_z = to->translate.z; - } + case TransformOperation::TransformOperationIdentity: *bounds = box; - *bounds += gfx::Vector3dF(BlendSkMScalars(from_x, to_x, min_progress), - BlendSkMScalars(from_y, to_y, min_progress), - BlendSkMScalars(from_z, to_z, min_progress)); - gfx::BoxF bounds_max = box; - bounds_max += gfx::Vector3dF(BlendSkMScalars(from_x, to_x, max_progress), - BlendSkMScalars(from_y, to_y, max_progress), - BlendSkMScalars(from_z, to_z, max_progress)); - bounds->Union(bounds_max); return true; - } + case TransformOperation::TransformOperationTranslate: + case TransformOperation::TransformOperationSkew: + case TransformOperation::TransformOperationPerspective: case TransformOperation::TransformOperationScale: { - SkMScalar from_x, from_y, from_z; - if (is_identity_from) { - from_x = from_y = from_z = 1.0; - } else { - from_x = from->scale.x; - from_y = from->scale.y; - from_z = from->scale.z; - } - SkMScalar to_x, to_y, to_z; - if (is_identity_to) { - to_x = to_y = to_z = 1.0; - } else { - to_x = to->scale.x; - to_y = to->scale.y; - to_z = to->scale.z; - } + gfx::Transform from_transform; + gfx::Transform to_transform; + if (!BlendTransformOperations(from, to, min_progress, &from_transform) || + !BlendTransformOperations(from, to, max_progress, &to_transform)) + return false; + *bounds = box; - ApplyScaleToBox( - SkMScalarToFloat(BlendSkMScalars(from_x, to_x, min_progress)), - SkMScalarToFloat(BlendSkMScalars(from_y, to_y, min_progress)), - SkMScalarToFloat(BlendSkMScalars(from_z, to_z, min_progress)), - bounds); - gfx::BoxF bounds_max = box; - ApplyScaleToBox( - SkMScalarToFloat(BlendSkMScalars(from_x, to_x, max_progress)), - SkMScalarToFloat(BlendSkMScalars(from_y, to_y, max_progress)), - SkMScalarToFloat(BlendSkMScalars(from_z, to_z, max_progress)), - &bounds_max); - if (!bounds->IsEmpty() && !bounds_max.IsEmpty()) { - bounds->Union(bounds_max); - } else if (!bounds->IsEmpty()) { - UnionBoxWithZeroScale(bounds); - } else if (!bounds_max.IsEmpty()) { - UnionBoxWithZeroScale(&bounds_max); - *bounds = bounds_max; - } + from_transform.TransformBox(bounds); + + gfx::BoxF to_box = box; + to_transform.TransformBox(&to_box); + bounds->ExpandTo(to_box); return true; } - case TransformOperation::TransformOperationIdentity: - *bounds = box; + case TransformOperation::TransformOperationRotate: { + SkMScalar axis_x = 0; + SkMScalar axis_y = 0; + SkMScalar axis_z = 1; + SkMScalar from_angle = 0; + if (!ShareSameAxis(from, to, &axis_x, &axis_y, &axis_z, &from_angle)) + return false; + + bool first_point = true; + for (int i = 0; i < 8; ++i) { + gfx::Point3F corner = box.origin(); + corner += gfx::Vector3dF(i & 1 ? box.width() : 0.f, + i & 2 ? box.height() : 0.f, + i & 4 ? box.depth() : 0.f); + gfx::BoxF box_for_arc; + BoundingBoxForArc( + corner, from, to, min_progress, max_progress, &box_for_arc); + if (first_point) + *bounds = box_for_arc; + else + bounds->Union(box_for_arc); + first_point = false; + } return true; - case TransformOperation::TransformOperationRotate: - case TransformOperation::TransformOperationSkew: - case TransformOperation::TransformOperationPerspective: + } case TransformOperation::TransformOperationMatrix: return false; } diff --git a/chromium/cc/animation/transform_operations_unittest.cc b/chromium/cc/animation/transform_operations_unittest.cc index a7e4c510a52..831ce71ce37 100644 --- a/chromium/cc/animation/transform_operations_unittest.cc +++ b/chromium/cc/animation/transform_operations_unittest.cc @@ -4,11 +4,14 @@ #include <limits> +#include "base/basictypes.h" #include "base/memory/scoped_vector.h" #include "cc/animation/transform_operations.h" #include "cc/test/geometry_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/animation/tween.h" #include "ui/gfx/box_f.h" +#include "ui/gfx/rect_conversions.h" #include "ui/gfx/vector3d_f.h" namespace cc { @@ -568,8 +571,7 @@ TEST(TransformOperationTest, BlendPerspectiveFromIdentity) { SkMScalar progress = 0.5f; gfx::Transform expected; - expected.ApplyPerspectiveDepth(500 + - 0.5 * std::numeric_limits<SkMScalar>::max()); + expected.ApplyPerspectiveDepth(2000); EXPECT_TRANSFORMATION_MATRIX_EQ( expected, operations.Blend(*identity_operations[i], progress)); @@ -660,8 +662,7 @@ TEST(TransformOperationTest, BlendPerspectiveToIdentity) { SkMScalar progress = 0.5f; gfx::Transform expected; - expected.ApplyPerspectiveDepth(500 + - 0.5 * std::numeric_limits<SkMScalar>::max()); + expected.ApplyPerspectiveDepth(2000); EXPECT_TRANSFORMATION_MATRIX_EQ( expected, identity_operations[i]->Blend(operations, progress)); @@ -676,13 +677,13 @@ TEST(TransformOperationTest, ExtrapolatePerspectiveBlending) { operations2.AppendPerspective(500); gfx::Transform expected; - expected.ApplyPerspectiveDepth(250); + expected.ApplyPerspectiveDepth(400); EXPECT_TRANSFORMATION_MATRIX_EQ( expected, operations1.Blend(operations2, -0.5)); expected.MakeIdentity(); - expected.ApplyPerspectiveDepth(1250); + expected.ApplyPerspectiveDepth(2000); EXPECT_TRANSFORMATION_MATRIX_EQ( expected, operations1.Blend(operations2, 1.5)); @@ -840,6 +841,384 @@ TEST(TransformOperationTest, BlendedBoundsWithZeroScale) { EXPECT_EQ(gfx::BoxF().ToString(), bounds.ToString()); } +TEST(TransformOperationTest, BlendedBoundsForRotationTrivial) { + TransformOperations operations_from; + operations_from.AppendRotate(0.f, 0.f, 1.f, 0.f); + TransformOperations operations_to; + operations_to.AppendRotate(0.f, 0.f, 1.f, 360.f); + + float sqrt_2 = sqrt(2.f); + gfx::BoxF box( + -sqrt_2, -sqrt_2, 0.f, sqrt_2, sqrt_2, 0.f); + gfx::BoxF bounds; + + // Since we're rotating 360 degrees, any box with dimensions between 0 and + // 2 * sqrt(2) should give the same result. + float sizes[] = { 0.f, 0.1f, sqrt_2, 2.f * sqrt_2 }; + for (size_t i = 0; i < arraysize(sizes); ++i) { + box.set_size(sizes[i], sizes[i], 0.f); + SkMScalar min_progress = 0.f; + SkMScalar max_progress = 1.f; + EXPECT_TRUE(operations_to.BlendedBoundsForBox( + box, operations_from, min_progress, max_progress, &bounds)); + EXPECT_EQ(gfx::BoxF(-2.f, -2.f, 0.f, 4.f, 4.f, 0.f).ToString(), + bounds.ToString()); + } +} + +TEST(TransformOperationTest, BlendedBoundsForRotationAllExtrema) { + // If the normal is out of the plane, we can have up to 6 extrema (a min/max + // in each dimension) between the endpoints of the arc. This test ensures that + // we consider all 6. + TransformOperations operations_from; + operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f); + TransformOperations operations_to; + operations_to.AppendRotate(1.f, 1.f, 1.f, 390.f); + + gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f); + gfx::BoxF bounds; + + float min = -1.f / 3.f; + float max = 1.f; + float size = max - min; + EXPECT_TRUE(operations_to.BlendedBoundsForBox( + box, operations_from, 0.f, 1.f, &bounds)); + EXPECT_EQ(gfx::BoxF(min, min, min, size, size, size).ToString(), + bounds.ToString()); +} + +TEST(TransformOperationTest, BlendedBoundsForRotationDifferentAxes) { + // We can handle rotations about a single axis. If the axes are different, + // we revert to matrix interpolation for which inflated bounds cannot be + // computed. + TransformOperations operations_from; + operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f); + TransformOperations operations_to_same; + operations_to_same.AppendRotate(1.f, 1.f, 1.f, 390.f); + TransformOperations operations_to_opposite; + operations_to_opposite.AppendRotate(-1.f, -1.f, -1.f, 390.f); + TransformOperations operations_to_different; + operations_to_different.AppendRotate(1.f, 3.f, 1.f, 390.f); + + gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f); + gfx::BoxF bounds; + + EXPECT_TRUE(operations_to_same.BlendedBoundsForBox( + box, operations_from, 0.f, 1.f, &bounds)); + EXPECT_TRUE(operations_to_opposite.BlendedBoundsForBox( + box, operations_from, 0.f, 1.f, &bounds)); + EXPECT_FALSE(operations_to_different.BlendedBoundsForBox( + box, operations_from, 0.f, 1.f, &bounds)); +} + +TEST(TransformOperationTest, BlendedBoundsForRotationPointOnAxis) { + // Checks that if the point to rotate is sitting on the axis of rotation, that + // it does not get affected. + TransformOperations operations_from; + operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f); + TransformOperations operations_to; + operations_to.AppendRotate(1.f, 1.f, 1.f, 390.f); + + gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f); + gfx::BoxF bounds; + + EXPECT_TRUE(operations_to.BlendedBoundsForBox( + box, operations_from, 0.f, 1.f, &bounds)); + EXPECT_EQ(box.ToString(), bounds.ToString()); +} + +// This would have been best as anonymous structs, but |arraysize| does not get +// along with anonymous structs (and using ARRAYSIZE_UNSAFE seemed like a worse +// option). +struct ProblematicAxisTest { + float x; + float y; + float z; + gfx::BoxF expected; +}; + +TEST(TransformOperationTest, BlendedBoundsForRotationProblematicAxes) { + // Zeros in the components of the axis of rotation turned out to be tricky to + // deal with in practice. This function tests some potentially problematic + // axes to ensure sane behavior. + + // Some common values used in the expected boxes. + float dim1 = 0.292893f; + float dim2 = sqrt(2.f); + float dim3 = 2.f * dim2; + + ProblematicAxisTest tests[] = { + { 0.f, 0.f, 0.f, gfx::BoxF(1.f, 1.f, 1.f, 0.f, 0.f, 0.f) }, + { 1.f, 0.f, 0.f, gfx::BoxF(1.f, -dim2, -dim2, 0.f, dim3, dim3) }, + { 0.f, 1.f, 0.f, gfx::BoxF(-dim2, 1.f, -dim2, dim3, 0.f, dim3) }, + { 0.f, 0.f, 1.f, gfx::BoxF(-dim2, -dim2, 1.f, dim3, dim3, 0.f) }, + { 1.f, 1.f, 0.f, gfx::BoxF(dim1, dim1, -1.f, dim2, dim2, 2.f) }, + { 0.f, 1.f, 1.f, gfx::BoxF(-1.f, dim1, dim1, 2.f, dim2, dim2) }, + { 1.f, 0.f, 1.f, gfx::BoxF(dim1, -1.f, dim1, dim2, 2.f, dim2) } + }; + + for (size_t i = 0; i < arraysize(tests); ++i) { + float x = tests[i].x; + float y = tests[i].y; + float z = tests[i].z; + TransformOperations operations_from; + operations_from.AppendRotate(x, y, z, 0.f); + TransformOperations operations_to; + operations_to.AppendRotate(x, y, z, 360.f); + gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f); + gfx::BoxF bounds; + + EXPECT_TRUE(operations_to.BlendedBoundsForBox( + box, operations_from, 0.f, 1.f, &bounds)); + EXPECT_EQ(tests[i].expected.ToString(), bounds.ToString()); + } +} + +// These would have been best as anonymous structs, but |arraysize| does not get +// along with anonymous structs (and using ARRAYSIZE_UNSAFE seemed like a worse +// option). +struct TestAxis { + float x; + float y; + float z; +}; + +struct TestAngles { + float theta_from; + float theta_to; +}; + +struct TestProgress { + float min_progress; + float max_progress; +}; + +static void ExpectBoxesApproximatelyEqual(const gfx::BoxF& lhs, + const gfx::BoxF& rhs, + float tolerance) { + EXPECT_NEAR(lhs.x(), rhs.x(), tolerance); + EXPECT_NEAR(lhs.y(), rhs.y(), tolerance); + EXPECT_NEAR(lhs.z(), rhs.z(), tolerance); + EXPECT_NEAR(lhs.width(), rhs.width(), tolerance); + EXPECT_NEAR(lhs.height(), rhs.height(), tolerance); + EXPECT_NEAR(lhs.depth(), rhs.depth(), tolerance); +} + +static void EmpiricallyTestBounds(const TransformOperations& from, + const TransformOperations& to, + SkMScalar min_progress, + SkMScalar max_progress, + bool test_containment_only) { + gfx::BoxF box(200.f, 500.f, 100.f, 100.f, 300.f, 200.f); + gfx::BoxF bounds; + EXPECT_TRUE( + to.BlendedBoundsForBox(box, from, min_progress, max_progress, &bounds)); + + bool first_time = true; + gfx::BoxF empirical_bounds; + static const size_t kNumSteps = 10; + for (size_t step = 0; step < kNumSteps; ++step) { + float t = step / (kNumSteps - 1.f); + t = gfx::Tween::FloatValueBetween(t, min_progress, max_progress); + gfx::Transform partial_transform = to.Blend(from, t); + gfx::BoxF transformed = box; + partial_transform.TransformBox(&transformed); + + if (first_time) { + empirical_bounds = transformed; + first_time = false; + } else { + empirical_bounds.Union(transformed); + } + } + + if (test_containment_only) { + gfx::BoxF unified_bounds = bounds; + unified_bounds.Union(empirical_bounds); + // Convert to the screen space rects these boxes represent. + gfx::Rect bounds_rect = ToEnclosingRect( + gfx::RectF(bounds.x(), bounds.y(), bounds.width(), bounds.height())); + gfx::Rect unified_bounds_rect = + ToEnclosingRect(gfx::RectF(unified_bounds.x(), + unified_bounds.y(), + unified_bounds.width(), + unified_bounds.height())); + EXPECT_EQ(bounds_rect.ToString(), unified_bounds_rect.ToString()); + } else { + // Our empirical estimate will be a little rough since we're only doing + // 100 samples. + static const float kTolerance = 1e-2f; + ExpectBoxesApproximatelyEqual(empirical_bounds, bounds, kTolerance); + } +} + +static void EmpiricallyTestBoundsEquality(const TransformOperations& from, + const TransformOperations& to, + SkMScalar min_progress, + SkMScalar max_progress) { + EmpiricallyTestBounds(from, to, min_progress, max_progress, false); +} + +static void EmpiricallyTestBoundsContainment(const TransformOperations& from, + const TransformOperations& to, + SkMScalar min_progress, + SkMScalar max_progress) { + EmpiricallyTestBounds(from, to, min_progress, max_progress, true); +} + +TEST(TransformOperationTest, BlendedBoundsForRotationEmpiricalTests) { + // Sets up various axis angle combinations, computes the bounding box and + // empirically tests that the transformed bounds are indeed contained by the + // computed bounding box. + + TestAxis axes[] = { + { 1.f, 1.f, 1.f }, + { -1.f, -1.f, -1.f }, + { -1.f, 2.f, 3.f }, + { 1.f, -2.f, 3.f }, + { 1.f, 2.f, -3.f }, + { 0.f, 0.f, 0.f }, + { 1.f, 0.f, 0.f }, + { 0.f, 1.f, 0.f }, + { 0.f, 0.f, 1.f }, + { 1.f, 1.f, 0.f }, + { 0.f, 1.f, 1.f }, + { 1.f, 0.f, 1.f }, + { -1.f, 0.f, 0.f }, + { 0.f, -1.f, 0.f }, + { 0.f, 0.f, -1.f }, + { -1.f, -1.f, 0.f }, + { 0.f, -1.f, -1.f }, + { -1.f, 0.f, -1.f } + }; + + TestAngles angles[] = { + { 5.f, 10.f }, + { 10.f, 5.f }, + { 0.f, 360.f }, + { 20.f, 180.f }, + { -20.f, -180.f }, + { 180.f, -220.f }, + { 220.f, 320.f } + }; + + // We can go beyond the range [0, 1] (the bezier might slide out of this range + // at either end), but since the first and last knots are at (0, 0) and (1, 1) + // we will never go within it, so these tests are sufficient. + TestProgress progress[] = { + { 0.f, 1.f }, + { -.25f, 1.25f }, + }; + + for (size_t i = 0; i < arraysize(axes); ++i) { + for (size_t j = 0; j < arraysize(angles); ++j) { + for (size_t k = 0; k < arraysize(progress); ++k) { + float x = axes[i].x; + float y = axes[i].y; + float z = axes[i].z; + TransformOperations operations_from; + operations_from.AppendRotate(x, y, z, angles[j].theta_from); + TransformOperations operations_to; + operations_to.AppendRotate(x, y, z, angles[j].theta_to); + EmpiricallyTestBoundsContainment(operations_from, + operations_to, + progress[k].min_progress, + progress[k].max_progress); + } + } + } +} + +TEST(TransformOperationTest, PerspectiveMatrixAndTransformBlendingEquivalency) { + TransformOperations from_operations; + from_operations.AppendPerspective(200); + + TransformOperations to_operations; + to_operations.AppendPerspective(1000); + + gfx::Transform from_transform; + from_transform.ApplyPerspectiveDepth(200); + + gfx::Transform to_transform; + to_transform.ApplyPerspectiveDepth(1000); + + static const int steps = 20; + for (int i = 0; i < steps; ++i) { + double progress = static_cast<double>(i) / (steps - 1); + + gfx::Transform blended_matrix = to_transform; + EXPECT_TRUE(blended_matrix.Blend(from_transform, progress)); + + gfx::Transform blended_transform = + to_operations.Blend(from_operations, progress); + + EXPECT_TRANSFORMATION_MATRIX_EQ(blended_matrix, blended_transform); + } +} + +struct TestPerspectiveDepths { + float from_depth; + float to_depth; +}; + +TEST(TransformOperationTest, BlendedBoundsForPerspective) { + TestPerspectiveDepths perspective_depths[] = { + { 600.f, 400.f }, + { 800.f, 1000.f }, + { 800.f, std::numeric_limits<float>::infinity() }, + }; + + TestProgress progress[] = { + { 0.f, 1.f }, + { -0.1f, 1.1f }, + }; + + for (size_t i = 0; i < arraysize(perspective_depths); ++i) { + for (size_t j = 0; j < arraysize(progress); ++j) { + TransformOperations operations_from; + operations_from.AppendPerspective(perspective_depths[i].from_depth); + TransformOperations operations_to; + operations_to.AppendPerspective(perspective_depths[i].to_depth); + EmpiricallyTestBoundsEquality(operations_from, + operations_to, + progress[j].min_progress, + progress[j].max_progress); + } + } +} + +struct TestSkews { + float from_x; + float from_y; + float to_x; + float to_y; +}; + +TEST(TransformOperationTest, BlendedBoundsForSkew) { + TestSkews skews[] = { + { 1.f, 0.5f, 0.5f, 1.f }, + { 2.f, 1.f, 0.5f, 0.5f }, + }; + + TestProgress progress[] = { + { 0.f, 1.f }, + { -0.1f, 1.1f }, + }; + + for (size_t i = 0; i < arraysize(skews); ++i) { + for (size_t j = 0; j < arraysize(progress); ++j) { + TransformOperations operations_from; + operations_from.AppendSkew(skews[i].from_x, skews[i].from_y); + TransformOperations operations_to; + operations_to.AppendSkew(skews[i].to_x, skews[i].to_y); + EmpiricallyTestBoundsEquality(operations_from, + operations_to, + progress[j].min_progress, + progress[j].max_progress); + } + } +} + TEST(TransformOperationTest, BlendedBoundsForSequence) { TransformOperations operations_from; operations_from.AppendTranslate(2.0, 4.0, -1.0); diff --git a/chromium/cc/base/float_quad_unittest.cc b/chromium/cc/base/float_quad_unittest.cc index 186624eec34..c2186fd81b4 100644 --- a/chromium/cc/base/float_quad_unittest.cc +++ b/chromium/cc/base/float_quad_unittest.cc @@ -15,15 +15,15 @@ namespace { TEST(FloatQuadTest, IsRectilinearTest) { const int kNumRectilinear = 8; gfx::Transform rectilinear_trans[kNumRectilinear]; - rectilinear_trans[1].Rotate(90.0); - rectilinear_trans[2].Rotate(180.0); - rectilinear_trans[3].Rotate(270.0); - rectilinear_trans[4].SkewX(0.00000000001); - rectilinear_trans[5].SkewY(0.00000000001); - rectilinear_trans[6].Scale(0.00001, 0.00001); - rectilinear_trans[6].Rotate(180.0); - rectilinear_trans[7].Scale(100000, 100000); - rectilinear_trans[7].Rotate(180.0); + rectilinear_trans[1].Rotate(90.f); + rectilinear_trans[2].Rotate(180.f); + rectilinear_trans[3].Rotate(270.f); + rectilinear_trans[4].SkewX(0.00000000001f); + rectilinear_trans[5].SkewY(0.00000000001f); + rectilinear_trans[6].Scale(0.00001f, 0.00001f); + rectilinear_trans[6].Rotate(180.f); + rectilinear_trans[7].Scale(100000.f, 100000.f); + rectilinear_trans[7].Rotate(180.f); gfx::QuadF original( gfx::RectF(0.01010101f, 0.01010101f, 100.01010101f, 100.01010101f)); @@ -38,16 +38,16 @@ TEST(FloatQuadTest, IsRectilinearTest) { const int kNumNonRectilinear = 10; gfx::Transform non_rectilinear_trans[kNumNonRectilinear]; - non_rectilinear_trans[0].Rotate(359.999); - non_rectilinear_trans[1].Rotate(0.0000001); - non_rectilinear_trans[2].Rotate(89.999999); - non_rectilinear_trans[3].Rotate(90.0000001); - non_rectilinear_trans[4].Rotate(179.999999); - non_rectilinear_trans[5].Rotate(180.0000001); - non_rectilinear_trans[6].Rotate(269.999999); - non_rectilinear_trans[7].Rotate(270.0000001); - non_rectilinear_trans[8].SkewX(0.00001); - non_rectilinear_trans[9].SkewY(0.00001); + non_rectilinear_trans[0].Rotate(359.9999f); + non_rectilinear_trans[1].Rotate(0.0000001f); + non_rectilinear_trans[2].Rotate(89.9999f); + non_rectilinear_trans[3].Rotate(90.00001f); + non_rectilinear_trans[4].Rotate(179.9999f); + non_rectilinear_trans[5].Rotate(180.00001f); + non_rectilinear_trans[6].Rotate(269.9999f); + non_rectilinear_trans[7].Rotate(270.0001f); + non_rectilinear_trans[8].SkewX(0.00001f); + non_rectilinear_trans[9].SkewY(0.00001f); for (int i = 0; i < kNumNonRectilinear; ++i) { bool clipped = false; diff --git a/chromium/cc/base/invalidation_region.cc b/chromium/cc/base/invalidation_region.cc index 2c39d25ba06..6a8f97f78fe 100644 --- a/chromium/cc/base/invalidation_region.cc +++ b/chromium/cc/base/invalidation_region.cc @@ -19,14 +19,6 @@ InvalidationRegion::InvalidationRegion() {} InvalidationRegion::~InvalidationRegion() {} void InvalidationRegion::Swap(Region* region) { - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Renderer4.InvalidationRegionApproximateRectCount", - region_.GetRegionComplexity(), - 1, - 5000, - 50); - - SimplifyIfNeeded(); region_.Swap(region); } @@ -35,9 +27,8 @@ void InvalidationRegion::Clear() { } void InvalidationRegion::Union(gfx::Rect rect) { - // TODO(vmpstr): We should simplify the region after Union() after we get a - // good idea of what kind of regions are typical (from the UMA histogram). region_.Union(rect); + SimplifyIfNeeded(); } void InvalidationRegion::SimplifyIfNeeded() { diff --git a/chromium/cc/base/invalidation_region.h b/chromium/cc/base/invalidation_region.h index fd061e8cba3..33be80332ff 100644 --- a/chromium/cc/base/invalidation_region.h +++ b/chromium/cc/base/invalidation_region.h @@ -22,6 +22,7 @@ class CC_EXPORT InvalidationRegion { void Swap(Region* region); void Clear(); void Union(gfx::Rect rect); + bool IsEmpty() const { return region_.IsEmpty(); } private: void SimplifyIfNeeded(); diff --git a/chromium/cc/base/latency_info_swap_promise.cc b/chromium/cc/base/latency_info_swap_promise.cc new file mode 100644 index 00000000000..41c0e997d11 --- /dev/null +++ b/chromium/cc/base/latency_info_swap_promise.cc @@ -0,0 +1,50 @@ +// Copyright 2013 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 "cc/base/latency_info_swap_promise.h" + +#include "base/logging.h" + +namespace { + ui::LatencyComponentType DidNotSwapReasonToLatencyComponentType( + cc::SwapPromise::DidNotSwapReason reason) { + switch (reason) { + case cc::SwapPromise::DID_NOT_SWAP_UNKNOWN: + case cc::SwapPromise::SWAP_FAILS: + return ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT; + case cc::SwapPromise::COMMIT_FAILS: + return ui::INPUT_EVENT_LATENCY_TERMINATED_COMMIT_FAILED_COMPONENT; + case cc::SwapPromise::SWAP_PROMISE_LIST_OVERFLOW: + return ui::LATENCY_INFO_LIST_TERMINATED_OVERFLOW_COMPONENT; + } + NOTREACHED() << "Unhandled DidNotSwapReason."; + return ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT; + } +} // namespace + +namespace cc { + +LatencyInfoSwapPromise::LatencyInfoSwapPromise(const ui::LatencyInfo& latency) + : latency_(latency) { +} + +LatencyInfoSwapPromise::~LatencyInfoSwapPromise() { +} + +void LatencyInfoSwapPromise::DidSwap(CompositorFrameMetadata* metadata) { + DCHECK(!latency_.terminated); + // TODO(miletus): Append the |latency_| into metadata's LatencyInfo list + // once we remove LatencyInfo merge in GPU side. + metadata->latency_info.MergeWith(latency_); +} + +void LatencyInfoSwapPromise::DidNotSwap(DidNotSwapReason reason) { + latency_.AddLatencyNumber(DidNotSwapReasonToLatencyComponentType(reason), + 0, 0); + // TODO(miletus): Turn this back on once per-event LatencyInfo tracking + // is enabled in GPU side. + // DCHECK(latency_.terminated); +} + +} // namespace cc diff --git a/chromium/cc/base/latency_info_swap_promise.h b/chromium/cc/base/latency_info_swap_promise.h new file mode 100644 index 00000000000..1a2b1d6b206 --- /dev/null +++ b/chromium/cc/base/latency_info_swap_promise.h @@ -0,0 +1,28 @@ +// Copyright 2013 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 CC_BASE_LATENCY_INFO_SWAP_PROMISE_H_ +#define CC_BASE_LATENCY_INFO_SWAP_PROMISE_H_ + +#include "base/compiler_specific.h" +#include "cc/base/swap_promise.h" +#include "ui/events/latency_info.h" + +namespace cc { + +class CC_EXPORT LatencyInfoSwapPromise : public SwapPromise { + public: + explicit LatencyInfoSwapPromise(const ui::LatencyInfo& latency_info); + virtual ~LatencyInfoSwapPromise(); + + virtual void DidSwap(CompositorFrameMetadata* metadata) OVERRIDE; + virtual void DidNotSwap(DidNotSwapReason reason) OVERRIDE; + + private: + ui::LatencyInfo latency_; +}; + +} // namespace cc + +#endif // CC_BASE_LATENCY_INFO_SWAP_PROMISE_H_ diff --git a/chromium/cc/base/latency_info_swap_promise_monitor.cc b/chromium/cc/base/latency_info_swap_promise_monitor.cc new file mode 100644 index 00000000000..0f2ff7481bb --- /dev/null +++ b/chromium/cc/base/latency_info_swap_promise_monitor.cc @@ -0,0 +1,43 @@ +// Copyright 2013 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 "cc/base/latency_info_swap_promise_monitor.h" + +#include "cc/base/latency_info_swap_promise.h" +#include "cc/trees/layer_tree_host.h" +#include "cc/trees/layer_tree_host_impl.h" +#include "cc/trees/layer_tree_impl.h" + +namespace cc { + +LatencyInfoSwapPromiseMonitor::LatencyInfoSwapPromiseMonitor( + ui::LatencyInfo* latency, + LayerTreeHost* layer_tree_host, + LayerTreeHostImpl* layer_tree_host_impl) + : SwapPromiseMonitor(layer_tree_host, layer_tree_host_impl), + latency_(latency) {} + +LatencyInfoSwapPromiseMonitor::~LatencyInfoSwapPromiseMonitor() {} + +void LatencyInfoSwapPromiseMonitor::OnSetNeedsCommitOnMain() { + if (!latency_->FindLatency( + ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, 0)) { + latency_->AddLatencyNumber( + ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, 0); + scoped_ptr<SwapPromise> swap_promise(new LatencyInfoSwapPromise(*latency_)); + layer_tree_host_->QueueSwapPromise(swap_promise.Pass()); + } +} + +void LatencyInfoSwapPromiseMonitor::OnSetNeedsRedrawOnImpl() { + if (!latency_->FindLatency( + ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, 0)) { + latency_->AddLatencyNumber( + ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, 0); + scoped_ptr<SwapPromise> swap_promise(new LatencyInfoSwapPromise(*latency_)); + layer_tree_host_impl_->active_tree()->QueueSwapPromise(swap_promise.Pass()); + } +} + +} // namespace cc diff --git a/chromium/cc/base/latency_info_swap_promise_monitor.h b/chromium/cc/base/latency_info_swap_promise_monitor.h new file mode 100644 index 00000000000..a463fdbeeff --- /dev/null +++ b/chromium/cc/base/latency_info_swap_promise_monitor.h @@ -0,0 +1,36 @@ +// Copyright 2013 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 "base/compiler_specific.h" +#include "cc/base/swap_promise_monitor.h" + +#ifndef CC_BASE_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_ +#define CC_BASE_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_ + +namespace ui { +struct LatencyInfo; +} // namespace ui + +namespace cc { + +// A LatencyInfoSwapPromiseMonitor queues a LatencyInfoSwapPromise into +// LayerTreeHost or LayerTreeHostImpl if there is compositor state change +// while it is being mointored. +class CC_EXPORT LatencyInfoSwapPromiseMonitor : public SwapPromiseMonitor { + public: + LatencyInfoSwapPromiseMonitor(ui::LatencyInfo* latency, + LayerTreeHost* layer_tree_host, + LayerTreeHostImpl* layer_tree_host_impl); + virtual ~LatencyInfoSwapPromiseMonitor(); + + virtual void OnSetNeedsCommitOnMain() OVERRIDE; + virtual void OnSetNeedsRedrawOnImpl() OVERRIDE; + + private: + ui::LatencyInfo* latency_; +}; + +} // namespace cc + +#endif // CC_BASE_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_ diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc index 40b8d11c68c..7a1bc1a8674 100644 --- a/chromium/cc/base/math_util.cc +++ b/chromium/cc/base/math_util.cc @@ -72,13 +72,13 @@ static HomogeneousCoordinate ComputeClippedPointForEdge( // w plane when this is called. DCHECK(h1.ShouldBeClipped() ^ h2.ShouldBeClipped()); - SkMScalar w = 0.00001; // or any positive non-zero small epsilon - + // ...or any positive non-zero small epsilon + SkMScalar w = 0.00001f; SkMScalar t = (w - h1.w()) / (h2.w() - h1.w()); - SkMScalar x = (1 - t) * h1.x() + t * h2.x(); - SkMScalar y = (1 - t) * h1.y() + t * h2.y(); - SkMScalar z = (1 - t) * h1.z() + t * h2.z(); + SkMScalar x = (SK_MScalar1 - t) * h1.x() + t * h2.x(); + SkMScalar y = (SK_MScalar1 - t) * h1.y() + t * h2.y(); + SkMScalar z = (SK_MScalar1 - t) * h1.z() + t * h2.z(); return HomogeneousCoordinate(x, y, z, w); } @@ -466,6 +466,13 @@ gfx::RectF MathUtil::ScaleRectProportional(const gfx::RectF& input_outer_rect, } static inline float ScaleOnAxis(double a, double b, double c) { + if (!b && !c) + return a; + if (!a && !c) + return b; + if (!a && !b) + return c; + // Do the sqrt as a double to not lose precision. return static_cast<float>(std::sqrt(a * a + b * b + c * c)); } @@ -583,6 +590,17 @@ scoped_ptr<base::Value> MathUtil::AsValue(const gfx::Transform& transform) { return res.PassAs<base::Value>(); } +scoped_ptr<base::Value> MathUtil::AsValue(const gfx::BoxF& box) { + scoped_ptr<base::ListValue> res(new base::ListValue()); + res->AppendInteger(box.x()); + res->AppendInteger(box.y()); + res->AppendInteger(box.z()); + res->AppendInteger(box.width()); + res->AppendInteger(box.height()); + res->AppendInteger(box.depth()); + return res.PassAs<base::Value>(); +} + scoped_ptr<base::Value> MathUtil::AsValueSafely(double value) { return scoped_ptr<base::Value>(base::Value::CreateDoubleValue( std::min(value, std::numeric_limits<double>::max()))); diff --git a/chromium/cc/base/math_util.h b/chromium/cc/base/math_util.h index 7912f8a8a25..baceb7058fe 100644 --- a/chromium/cc/base/math_util.h +++ b/chromium/cc/base/math_util.h @@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" +#include "ui/gfx/box_f.h" #include "ui/gfx/point3_f.h" #include "ui/gfx/point_f.h" #include "ui/gfx/size.h" @@ -39,24 +40,24 @@ struct HomogeneousCoordinate { bool ShouldBeClipped() const { return w() <= 0.0; } gfx::PointF CartesianPoint2d() const { - if (w() == 1.0) + if (w() == SK_MScalar1) return gfx::PointF(x(), y()); // For now, because this code is used privately only by MathUtil, it should // never be called when w == 0, and we do not yet need to handle that case. DCHECK(w()); - SkMScalar inv_w = 1.0 / w(); + SkMScalar inv_w = SK_MScalar1 / w(); return gfx::PointF(x() * inv_w, y() * inv_w); } gfx::Point3F CartesianPoint3d() const { - if (w() == 1) + if (w() == SK_MScalar1) return gfx::Point3F(x(), y(), z()); // For now, because this code is used privately only by MathUtil, it should // never be called when w == 0, and we do not yet need to handle that case. DCHECK(w()); - SkMScalar inv_w = 1.0 / w(); + SkMScalar inv_w = SK_MScalar1 / w(); return gfx::Point3F(x() * inv_w, y() * inv_w, z() * inv_w); } @@ -172,6 +173,7 @@ class CC_EXPORT MathUtil { static scoped_ptr<base::Value> AsValue(const gfx::QuadF& q); static scoped_ptr<base::Value> AsValue(const gfx::RectF& rect); static scoped_ptr<base::Value> AsValue(const gfx::Transform& transform); + static scoped_ptr<base::Value> AsValue(const gfx::BoxF& box); // Returns a base::Value representation of the floating point value. // If the value is inf, returns max double/float representation. diff --git a/chromium/cc/base/math_util_unittest.cc b/chromium/cc/base/math_util_unittest.cc index d62280ddb5f..6e276c25d64 100644 --- a/chromium/cc/base/math_util_unittest.cc +++ b/chromium/cc/base/math_util_unittest.cc @@ -22,7 +22,7 @@ TEST(MathUtilTest, ProjectionOfPerpendicularPlane) { gfx::Transform transform; transform.MakeIdentity(); - transform.matrix().setDouble(2, 2, 0); + transform.matrix().set(2, 2, 0); gfx::RectF rect = gfx::RectF(0, 0, 1, 1); gfx::RectF projected_rect = MathUtil::ProjectClippedRect(transform, rect); @@ -44,8 +44,10 @@ TEST(MathUtilTest, EnclosingClippedRectUsesCorrectInitialBounds) { // then the enclosing clipped rect will be computed incorrectly. gfx::RectF result = MathUtil::ComputeEnclosingClippedRect(h1, h2, h3, h4); - EXPECT_FLOAT_RECT_EQ(gfx::RectF(gfx::PointF(-100, -100), gfx::SizeF(90, 90)), - result); + // Due to floating point math in ComputeClippedPointForEdge this result + // is fairly imprecise. 0.15f was empirically determined. + EXPECT_RECT_NEAR( + gfx::RectF(gfx::PointF(-100, -100), gfx::SizeF(90, 90)), result, 0.15f); } TEST(MathUtilTest, EnclosingRectOfVerticesUsesCorrectInitialBounds) { diff --git a/chromium/cc/base/ref_counted_managed.h b/chromium/cc/base/ref_counted_managed.h new file mode 100644 index 00000000000..8bb836f0159 --- /dev/null +++ b/chromium/cc/base/ref_counted_managed.h @@ -0,0 +1,65 @@ +// Copyright 2013 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 CC_BASE_REF_COUNTED_MANAGED_H_ +#define CC_BASE_REF_COUNTED_MANAGED_H_ + +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "cc/base/cc_export.h" + +namespace cc { + +template <typename T> class RefCountedManaged; + +template <typename T> +class CC_EXPORT RefCountedManager { + protected: + RefCountedManager() : live_object_count_(0) {} + ~RefCountedManager() { + CHECK_EQ(0, live_object_count_); + } + + virtual void Release(T* object) = 0; + + private: + friend class RefCountedManaged<T>; + int live_object_count_; +}; + +template <typename T> +class CC_EXPORT RefCountedManaged : public base::subtle::RefCountedBase { + public: + explicit RefCountedManaged(RefCountedManager<T>* manager) + : manager_(manager) { + manager_->live_object_count_++; + } + + void AddRef() const { + base::subtle::RefCountedBase::AddRef(); + } + + void Release() { + if (base::subtle::RefCountedBase::Release()) { + DCHECK_GT(manager_->live_object_count_, 0); + manager_->live_object_count_--; + + // This must be the last statement in case manager deletes + // the object immediately. + manager_->Release(static_cast<T*>(this)); + } + } + + protected: + ~RefCountedManaged() {} + + private: + RefCountedManager<T>* manager_; + + DISALLOW_COPY_AND_ASSIGN(RefCountedManaged<T>); +}; + +} // namespace cc + +#endif // CC_BASE_REF_COUNTED_MANAGED_H_ diff --git a/chromium/cc/base/scoped_ptr_vector.h b/chromium/cc/base/scoped_ptr_vector.h index 856e2f51cd1..288cb6fa47b 100644 --- a/chromium/cc/base/scoped_ptr_vector.h +++ b/chromium/cc/base/scoped_ptr_vector.h @@ -140,6 +140,13 @@ class ScopedPtrVector { data_.insert(position, tmp_data.begin(), tmp_data.end()); } + template <typename Predicate> + iterator partition(Predicate predicate) { + typename std::vector<T*>::iterator first = begin(); + typename std::vector<T*>::iterator last = end(); + return static_cast<iterator>(std::partition(first, last, predicate)); + } + void swap(ScopedPtrVector<T>& other) { data_.swap(other.data_); } diff --git a/chromium/cc/base/scoped_ptr_vector_unittest.cc b/chromium/cc/base/scoped_ptr_vector_unittest.cc index 4e450b9c823..8190b37b83b 100644 --- a/chromium/cc/base/scoped_ptr_vector_unittest.cc +++ b/chromium/cc/base/scoped_ptr_vector_unittest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <set> + #include "cc/base/scoped_ptr_vector.h" #include "testing/gmock/include/gmock/gmock.h" @@ -17,6 +19,11 @@ class Data { int data_; }; +class IsOddPredicate { + public: + bool operator()(const Data* data) { return (data->data() % 2) == 1; } +}; + TEST(ScopedPtrVectorTest, PushBack) { ScopedPtrVector<Data> v; @@ -68,5 +75,31 @@ TEST(ScopedPtrVectorTest, InsertAndTake) { EXPECT_EQ(NULL, v2[2]); } +TEST(ScopedPtrVectorTest, Partition) { + ScopedPtrVector<Data> v; + v.push_back(Data::Create(1)); + v.push_back(Data::Create(2)); + v.push_back(Data::Create(3)); + v.push_back(Data::Create(4)); + v.push_back(Data::Create(5)); + + ScopedPtrVector<Data>::iterator it = v.partition(IsOddPredicate()); + std::set<int> odd_numbers; + for (ScopedPtrVector<Data>::iterator second_it = v.begin(); + second_it != it; + ++second_it) { + EXPECT_EQ(1, (*second_it)->data() % 2); + odd_numbers.insert((*second_it)->data()); + } + EXPECT_EQ(3u, odd_numbers.size()); + + std::set<int> even_numbers; + for (; it != v.end(); ++it) { + EXPECT_EQ(0, (*it)->data() % 2); + even_numbers.insert((*it)->data()); + } + EXPECT_EQ(2u, even_numbers.size()); +} + } // namespace } // namespace cc diff --git a/chromium/cc/base/swap_promise.h b/chromium/cc/base/swap_promise.h new file mode 100644 index 00000000000..36a5b130a50 --- /dev/null +++ b/chromium/cc/base/swap_promise.h @@ -0,0 +1,50 @@ +// Copyright 2013 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 CC_BASE_SWAP_PROMISE_H_ +#define CC_BASE_SWAP_PROMISE_H_ + +#include "cc/output/compositor_frame_metadata.h" + +namespace cc { + +const unsigned int kMaxQueuedSwapPromiseNumber = 100; + +// When a change to the compositor's state/invalidation/whatever happens, a +// Swap Promise can be inserted into LayerTreeHost/LayerTreeImpl, to track +// whether the compositor's reply to the new state/invaliadtion/whatever is +// completed in the compositor, i.e. the compositor knows it has been sent +// to its output or not. +// +// If the new compositor state is sent to the output, SwapPromise::DidSwap() +// will be called, and if the compositor fails to send its new state to the +// output, SwapPromise::DidNotSwap() will be called. +// +// Client wishes to use SwapPromise should have a subclass that defines +// the behavior of DidSwap() and DidNotSwap(). Notice that the promise can +// be broken at either main or impl thread, e.g. commit fails on main thread, +// new frame data has no actual damage so LayerTreeHostImpl::SwapBuffers() +// bails out early on impl thread, so don't assume that DidSwap() and +// DidNotSwap() are called at a particular thread. It is better to let the +// subclass carry thread-safe member data and operate on that member data in +// DidSwap() and DidNotSwap(). +class CC_EXPORT SwapPromise { + public: + enum DidNotSwapReason { + DID_NOT_SWAP_UNKNOWN, + SWAP_FAILS, + COMMIT_FAILS, + SWAP_PROMISE_LIST_OVERFLOW, + }; + + SwapPromise() {} + virtual ~SwapPromise() {} + + virtual void DidSwap(CompositorFrameMetadata* metadata) = 0; + virtual void DidNotSwap(DidNotSwapReason reason) = 0; +}; + +} // namespace cc + +#endif // CC_BASE_SWAP_PROMISE_H_ diff --git a/chromium/cc/base/swap_promise_monitor.cc b/chromium/cc/base/swap_promise_monitor.cc new file mode 100644 index 00000000000..0c04f35ebc4 --- /dev/null +++ b/chromium/cc/base/swap_promise_monitor.cc @@ -0,0 +1,31 @@ +// Copyright 2013 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 "base/logging.h" +#include "cc/base/swap_promise_monitor.h" +#include "cc/trees/layer_tree_host.h" +#include "cc/trees/layer_tree_host_impl.h" + +namespace cc { + +SwapPromiseMonitor::SwapPromiseMonitor(LayerTreeHost* layer_tree_host, + LayerTreeHostImpl* layer_tree_host_impl) + : layer_tree_host_(layer_tree_host), + layer_tree_host_impl_(layer_tree_host_impl) { + DCHECK((layer_tree_host && !layer_tree_host_impl) || + (!layer_tree_host && layer_tree_host_impl)); + if (layer_tree_host_) + layer_tree_host_->InsertSwapPromiseMonitor(this); + if (layer_tree_host_impl_) + layer_tree_host_impl_->InsertSwapPromiseMonitor(this); +} + +SwapPromiseMonitor::~SwapPromiseMonitor() { + if (layer_tree_host_) + layer_tree_host_->RemoveSwapPromiseMonitor(this); + if (layer_tree_host_impl_) + layer_tree_host_impl_->RemoveSwapPromiseMonitor(this); +} + +} // namespace cc diff --git a/chromium/cc/base/swap_promise_monitor.h b/chromium/cc/base/swap_promise_monitor.h new file mode 100644 index 00000000000..21a159ad32a --- /dev/null +++ b/chromium/cc/base/swap_promise_monitor.h @@ -0,0 +1,44 @@ +// Copyright 2013 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 CC_BASE_SWAP_PROMISE_MONITOR_H_ +#define CC_BASE_SWAP_PROMISE_MONITOR_H_ + +#include "cc/base/cc_export.h" + +namespace cc { + +class LayerTreeHost; +class LayerTreeHostImpl; + +// A SwapPromiseMonitor is used to monitor compositor state change that +// should be associated with a SwapPromise, e.g. SetNeedsCommit() is +// called on main thread or SetNeedsRedraw() is called on impl thread. +// Creating a SwapPromiseMonitor will insert itself into a LayerTreeHost +// or LayerTreeHostImpl. You must provide a pointer to the appropriate +// structure to the monitor (and only one of the two). Notification of +// compositor state change will be sent through OnSetNeedsCommitOnMain() +// or OnSetNeedsRedrawOnImpl(). When SwapPromiseMonitor is destroyed, it +// will unregister itself from LayerTreeHost or LayerTreeHostImpl. +class CC_EXPORT SwapPromiseMonitor { + public: + // If the monitor lives on the main thread, pass in layer_tree_host + // and set layer_tree_host_impl to NULL. + // If the monitor lives on the impl thread, pass in layer_tree_host_impl + // and set layer_tree_host to NULL. + SwapPromiseMonitor(LayerTreeHost* layer_tree_host, + LayerTreeHostImpl* layer_tree_host_impl); + virtual ~SwapPromiseMonitor(); + + virtual void OnSetNeedsCommitOnMain() = 0; + virtual void OnSetNeedsRedrawOnImpl() = 0; + + protected: + LayerTreeHost* layer_tree_host_; + LayerTreeHostImpl* layer_tree_host_impl_; +}; + +} // namespace cc + +#endif // CC_BASE_SWAP_PROMISE_MONITOR_H_ diff --git a/chromium/cc/base/switches.cc b/chromium/cc/base/switches.cc index 87e10ce0089..ddba9cbd444 100644 --- a/chromium/cc/base/switches.cc +++ b/chromium/cc/base/switches.cc @@ -36,10 +36,10 @@ const char kEnableImplSidePainting[] = "enable-impl-side-painting"; const char kEnableTopControlsPositionCalculation[] = "enable-top-controls-position-calculation"; -// For any layers that can get drawn directly to screen, draw them with the Skia -// GPU backend. Only valid with gl rendering + threaded compositing + impl-side -// painting. -const char kForceDirectLayerDrawing[] = "force-direct-layer-drawing"; +// Allow heuristics to determine when a layer tile should be drawn with +// the Skia GPU backend. Only valid with GPU accelerated compositing + +// impl-side painting. +const char kEnableGPURasterization[] = "enable-gpu-rasterization"; // The height of the movable top controls. const char kTopControlsHeight[] = "top-controls-height"; @@ -62,10 +62,6 @@ const char kTraceOverdraw[] = "trace-overdraw"; // complete, such as --slow-down-raster-scale-factor=25. const char kSlowDownRasterScaleFactor[] = "slow-down-raster-scale-factor"; -// The scale factor for low resolution tile contents. -const char kLowResolutionContentsScaleFactor[] = - "low-resolution-contents-scale-factor"; - // Max tiles allowed for each tilings interest area. const char kMaxTilesForInterestArea[] = "max-tiles-for-interest-area"; @@ -101,6 +97,10 @@ const char kUIShowCompositedLayerBorders[] = "ui-show-layer-borders"; const char kShowFPSCounter[] = "show-fps-counter"; const char kUIShowFPSCounter[] = "ui-show-fps-counter"; +// Renders a border that represents the bounding box for the layer's animation. +const char kShowLayerAnimationBounds[] = "show-layer-animation-bounds"; +const char kUIShowLayerAnimationBounds[] = "ui-show-layer-animation-bounds"; + // Show rects in the HUD around layers whose properties have changed. const char kShowPropertyChangedRects[] = "show-property-changed-rects"; const char kUIShowPropertyChangedRects[] = "ui-show-property-changed-rects"; @@ -141,14 +141,21 @@ const char kDisableMapImage[] = "disable-map-image"; // Prevents the layer tree unit tests from timing out. const char kCCLayerTreeTestNoTimeout[] = "cc-layer-tree-test-no-timeout"; +// Makes pixel tests write their output instead of read it. +const char kCCRebaselinePixeltests[] = "cc-rebaseline-pixeltests"; + // Disable textures using RGBA_4444 layout. const char kDisable4444Textures[] = "disable-4444-textures"; +// Disable touch hit testing in the compositor. +const char kDisableCompositorTouchHitTesting[] = + "disable-compositor-touch-hit-testing"; + bool IsLCDTextEnabled() { const CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(cc::switches::kDisableLCDText)) + if (command_line->HasSwitch(switches::kDisableLCDText)) return false; - else if (command_line->HasSwitch(cc::switches::kEnableLCDText)) + else if (command_line->HasSwitch(switches::kEnableLCDText)) return true; #if defined(OS_ANDROID) @@ -158,12 +165,13 @@ bool IsLCDTextEnabled() { #endif } -bool IsImplSidePaintingEnabled() { +namespace { +bool CheckImplSidePaintingStatus() { const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch(cc::switches::kDisableImplSidePainting)) + if (command_line.HasSwitch(switches::kDisableImplSidePainting)) return false; - else if (command_line.HasSwitch(cc::switches::kEnableImplSidePainting)) + else if (command_line.HasSwitch(switches::kEnableImplSidePainting)) return true; #if defined(OS_ANDROID) @@ -173,12 +181,29 @@ bool IsImplSidePaintingEnabled() { #endif } +bool CheckGPURasterizationStatus() { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + return command_line.HasSwitch(switches::kEnableGPURasterization); +} + +} // namespace + +bool IsImplSidePaintingEnabled() { + static bool enabled = CheckImplSidePaintingStatus(); + return enabled; +} + +bool IsGPURasterizationEnabled() { + static bool enabled = CheckGPURasterizationStatus(); + return enabled; +} + bool IsMapImageEnabled() { const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch(cc::switches::kDisableMapImage)) + if (command_line.HasSwitch(switches::kDisableMapImage)) return false; - else if (command_line.HasSwitch(cc::switches::kEnableMapImage)) + else if (command_line.HasSwitch(switches::kEnableMapImage)) return true; return false; diff --git a/chromium/cc/base/switches.h b/chromium/cc/base/switches.h index 97fe833390c..19cba57bb98 100644 --- a/chromium/cc/base/switches.h +++ b/chromium/cc/base/switches.h @@ -24,7 +24,7 @@ CC_EXPORT extern const char kDisableCompositedAntialiasing[]; CC_EXPORT extern const char kEnableLCDText[]; CC_EXPORT extern const char kEnableImplSidePainting[]; CC_EXPORT extern const char kEnableTopControlsPositionCalculation[]; -CC_EXPORT extern const char kForceDirectLayerDrawing[]; +CC_EXPORT extern const char kEnableGPURasterization[]; CC_EXPORT extern const char kJankInsteadOfCheckerboard[]; CC_EXPORT extern const char kNumRasterThreads[]; CC_EXPORT extern const char kTopControlsHeight[]; @@ -32,7 +32,6 @@ CC_EXPORT extern const char kTopControlsHideThreshold[]; CC_EXPORT extern const char kTraceOverdraw[]; CC_EXPORT extern const char kTopControlsShowThreshold[]; CC_EXPORT extern const char kSlowDownRasterScaleFactor[]; -CC_EXPORT extern const char kLowResolutionContentsScaleFactor[]; CC_EXPORT extern const char kCompositeToMailbox[]; CC_EXPORT extern const char kMaxTilesForInterestArea[]; CC_EXPORT extern const char kMaxUnusedResourceMemoryUsagePercentage[]; @@ -42,6 +41,7 @@ CC_EXPORT extern const char kStrictLayerPropertyChangeChecking[]; CC_EXPORT extern const char kEnableMapImage[]; CC_EXPORT extern const char kDisableMapImage[]; CC_EXPORT extern const char kDisable4444Textures[]; +CC_EXPORT extern const char kDisableCompositorTouchHitTesting[]; // Switches for both the renderer and ui compositors. CC_EXPORT extern const char kUIDisablePartialSwap[]; @@ -53,6 +53,8 @@ CC_EXPORT extern const char kShowCompositedLayerBorders[]; CC_EXPORT extern const char kUIShowCompositedLayerBorders[]; CC_EXPORT extern const char kShowFPSCounter[]; CC_EXPORT extern const char kUIShowFPSCounter[]; +CC_EXPORT extern const char kShowLayerAnimationBounds[]; +CC_EXPORT extern const char kUIShowLayerAnimationBounds[]; CC_EXPORT extern const char kShowPropertyChangedRects[]; CC_EXPORT extern const char kUIShowPropertyChangedRects[]; CC_EXPORT extern const char kShowSurfaceDamageRects[]; @@ -68,9 +70,11 @@ CC_EXPORT extern const char kUIShowNonOccludingRects[]; // Unit test related. CC_EXPORT extern const char kCCLayerTreeTestNoTimeout[]; +CC_EXPORT extern const char kCCRebaselinePixeltests[]; CC_EXPORT bool IsLCDTextEnabled(); CC_EXPORT bool IsImplSidePaintingEnabled(); +CC_EXPORT bool IsGPURasterizationEnabled(); CC_EXPORT bool IsMapImageEnabled(); } // namespace switches diff --git a/chromium/cc/base/util.h b/chromium/cc/base/util.h index 1d716ae2a42..bd511786dca 100644 --- a/chromium/cc/base/util.h +++ b/chromium/cc/base/util.h @@ -8,6 +8,9 @@ #include <limits> #include "base/basictypes.h" +#include "cc/resources/resource_provider.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" namespace cc { @@ -24,6 +27,36 @@ template <typename T> T RoundDown(T n, T mul) { : ((n - mul + 1) / mul) * mul; } +inline GLenum GLDataType(ResourceFormat format) { + DCHECK_LE(format, RESOURCE_FORMAT_MAX); + static const unsigned format_gl_data_type[RESOURCE_FORMAT_MAX + 1] = { + GL_UNSIGNED_BYTE, // RGBA_8888 + GL_UNSIGNED_SHORT_4_4_4_4, // RGBA_4444 + GL_UNSIGNED_BYTE, // BGRA_8888 + GL_UNSIGNED_BYTE, // LUMINANCE_8 + GL_UNSIGNED_SHORT_5_6_5, // RGB_565, + GL_UNSIGNED_BYTE // ETC1 + }; + return format_gl_data_type[format]; +} + +inline GLenum GLDataFormat(ResourceFormat format) { + DCHECK_LE(format, RESOURCE_FORMAT_MAX); + static const unsigned format_gl_data_format[RESOURCE_FORMAT_MAX + 1] = { + GL_RGBA, // RGBA_8888 + GL_RGBA, // RGBA_4444 + GL_BGRA_EXT, // BGRA_8888 + GL_LUMINANCE, // LUMINANCE_8 + GL_RGB, // RGB_565 + GL_ETC1_RGB8_OES // ETC1 + }; + return format_gl_data_format[format]; +} + +inline GLenum GLInternalFormat(ResourceFormat format) { + return GLDataFormat(format); +} + } // namespace cc #endif // CC_BASE_UTIL_H_ diff --git a/chromium/cc/cc.gyp b/chromium/cc/cc.gyp index ffc86153f29..7af063df2a6 100644 --- a/chromium/cc/cc.gyp +++ b/chromium/cc/cc.gyp @@ -17,8 +17,9 @@ '<(DEPTH)/media/media.gyp:media', '<(DEPTH)/skia/skia.gyp:skia', '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink_minimal', + '<(DEPTH)/ui/events/events.gyp:events_base', + '<(DEPTH)/ui/gfx/gfx.gyp:gfx', '<(DEPTH)/ui/gl/gl.gyp:gl', - '<(DEPTH)/ui/ui.gyp:ui', ], 'defines': [ 'CC_IMPLEMENTATION=1', @@ -41,6 +42,9 @@ 'animation/layer_animation_controller.h', 'animation/layer_animation_event_observer.h', 'animation/layer_animation_value_observer.h', + 'animation/layer_animation_value_provider.h', + 'animation/scroll_offset_animation_curve.cc', + 'animation/scroll_offset_animation_curve.h', 'animation/scrollbar_animation_controller.h', 'animation/scrollbar_animation_controller_linear_fade.cc', 'animation/scrollbar_animation_controller_linear_fade.h', @@ -55,46 +59,68 @@ 'base/completion_event.h', 'base/invalidation_region.cc', 'base/invalidation_region.h', + 'base/latency_info_swap_promise.cc', + 'base/latency_info_swap_promise.h', + 'base/latency_info_swap_promise_monitor.cc', + 'base/latency_info_swap_promise_monitor.h', 'base/math_util.cc', 'base/math_util.h', + 'base/ref_counted_managed.h', 'base/region.cc', 'base/region.h', 'base/scoped_ptr_algorithm.h', 'base/scoped_ptr_deque.h', 'base/scoped_ptr_vector.h', + 'base/swap_promise.h', + 'base/swap_promise_monitor.cc', + 'base/swap_promise_monitor.h', 'base/switches.cc', 'base/switches.h', 'base/tiling_data.cc', 'base/tiling_data.h', 'base/util.h', + 'debug/benchmark_instrumentation.cc', + 'debug/benchmark_instrumentation.h', 'debug/debug_colors.cc', 'debug/debug_colors.h', 'debug/debug_rect_history.cc', 'debug/debug_rect_history.h', 'debug/devtools_instrumentation.h', - 'debug/fake_web_graphics_context_3d.cc', - 'debug/fake_web_graphics_context_3d.h', 'debug/frame_rate_counter.cc', 'debug/frame_rate_counter.h', 'debug/layer_tree_debug_state.cc', 'debug/layer_tree_debug_state.h', + 'debug/micro_benchmark.cc', + 'debug/micro_benchmark.h', + 'debug/micro_benchmark_impl.cc', + 'debug/micro_benchmark_impl.h', + 'debug/micro_benchmark_controller.cc', + 'debug/micro_benchmark_controller.h', + 'debug/micro_benchmark_controller_impl.cc', + 'debug/micro_benchmark_controller_impl.h', 'debug/overdraw_metrics.cc', 'debug/overdraw_metrics.h', 'debug/paint_time_counter.cc', 'debug/paint_time_counter.h', + 'debug/picture_record_benchmark.cc', + 'debug/picture_record_benchmark.h', + 'debug/rasterize_and_record_benchmark.cc', + 'debug/rasterize_and_record_benchmark.h', + 'debug/rasterize_and_record_benchmark_impl.cc', + 'debug/rasterize_and_record_benchmark_impl.h', 'debug/rendering_stats.cc', 'debug/rendering_stats.h', 'debug/rendering_stats_instrumentation.cc', 'debug/rendering_stats_instrumentation.h', 'debug/ring_buffer.h', - 'debug/test_context_provider.cc', - 'debug/test_context_provider.h', - 'debug/test_web_graphics_context_3d.cc', - 'debug/test_web_graphics_context_3d.h', 'debug/traced_picture.cc', 'debug/traced_picture.h', 'debug/traced_value.cc', 'debug/traced_value.h', + 'debug/unittest_only_benchmark.cc', + 'debug/unittest_only_benchmark.h', + 'debug/unittest_only_benchmark_impl.cc', + 'debug/unittest_only_benchmark_impl.h', 'input/input_handler.h', 'input/page_scale_animation.cc', 'input/page_scale_animation.h', @@ -108,9 +134,12 @@ 'layers/content_layer_client.h', 'layers/contents_scaling_layer.cc', 'layers/contents_scaling_layer.h', + 'layers/delegated_frame_provider.cc', + 'layers/delegated_frame_provider.h', + 'layers/delegated_frame_resource_collection.cc', + 'layers/delegated_frame_resource_collection.h', 'layers/delegated_renderer_layer.cc', 'layers/delegated_renderer_layer.h', - 'layers/delegated_renderer_layer_client.h', 'layers/delegated_renderer_layer_impl.cc', 'layers/delegated_renderer_layer_impl.h', 'layers/draw_properties.h', @@ -178,6 +207,10 @@ 'layers/tiled_layer.h', 'layers/tiled_layer_impl.cc', 'layers/tiled_layer_impl.h', + 'layers/ui_resource_layer.cc', + 'layers/ui_resource_layer.h', + 'layers/ui_resource_layer_impl.cc', + 'layers/ui_resource_layer_impl.h', 'layers/video_frame_provider.h', 'layers/video_frame_provider_client_impl.cc', 'layers/video_frame_provider_client_impl.h', @@ -272,6 +305,8 @@ 'resources/caching_bitmap_content_layer_updater.h', 'resources/content_layer_updater.cc', 'resources/content_layer_updater.h', + 'resources/etc1_pixel_ref.cc', + 'resources/etc1_pixel_ref.h', 'resources/image_layer_updater.cc', 'resources/image_layer_updater.h', 'resources/image_raster_worker_pool.cc', @@ -334,12 +369,13 @@ 'resources/scoped_resource.h', 'resources/scoped_ui_resource.cc', 'resources/scoped_ui_resource.h', + 'resources/shared_bitmap.cc', + 'resources/shared_bitmap.h', + 'resources/shared_bitmap_manager.h', 'resources/single_release_callback.cc', 'resources/single_release_callback.h', 'resources/skpicture_content_layer_updater.cc', 'resources/skpicture_content_layer_updater.h', - 'resources/sync_point_helper.cc', - 'resources/sync_point_helper.h', 'resources/texture_mailbox.cc', 'resources/texture_mailbox.h', 'resources/texture_mailbox_deleter.cc', @@ -355,6 +391,8 @@ 'resources/ui_resource_bitmap.cc', 'resources/ui_resource_bitmap.h', 'resources/ui_resource_client.h', + 'resources/ui_resource_request.cc', + 'resources/ui_resource_request.h', 'resources/video_resource_updater.cc', 'resources/video_resource_updater.h', 'resources/worker_pool.cc', @@ -363,8 +401,6 @@ 'scheduler/delay_based_time_source.h', 'scheduler/frame_rate_controller.cc', 'scheduler/frame_rate_controller.h', - 'scheduler/rate_limiter.cc', - 'scheduler/rate_limiter.h', 'scheduler/rolling_time_delta_history.cc', 'scheduler/rolling_time_delta_history.h', 'scheduler/scheduler.cc', diff --git a/chromium/cc/cc_tests.gyp b/chromium/cc/cc_tests.gyp index f271a7074be..4974ad39e18 100644 --- a/chromium/cc/cc_tests.gyp +++ b/chromium/cc/cc_tests.gyp @@ -9,6 +9,7 @@ 'animation/animation_unittest.cc', 'animation/keyframed_animation_curve_unittest.cc', 'animation/layer_animation_controller_unittest.cc', + 'animation/scroll_offset_animation_curve_unittest.cc', 'animation/scrollbar_animation_controller_linear_fade_unittest.cc', 'animation/scrollbar_animation_controller_thinning_unittest.cc', 'animation/timing_function_unittest.cc', @@ -19,11 +20,15 @@ 'base/scoped_ptr_vector_unittest.cc', 'base/tiling_data_unittest.cc', 'base/util_unittest.cc', + 'debug/micro_benchmark_controller_unittest.cc', 'input/top_controls_manager_unittest.cc', 'layers/content_layer_unittest.cc', 'layers/contents_scaling_layer_unittest.cc', + 'layers/delegated_frame_provider_unittest.cc', + 'layers/delegated_frame_resource_collection_unittest.cc', 'layers/delegated_renderer_layer_impl_unittest.cc', 'layers/heads_up_display_unittest.cc', + 'layers/heads_up_display_layer_impl_unittest.cc', 'layers/layer_impl_unittest.cc', 'layers/layer_iterator_unittest.cc', 'layers/layer_position_constraint_unittest.cc', @@ -39,12 +44,13 @@ 'layers/texture_layer_unittest.cc', 'layers/tiled_layer_impl_unittest.cc', 'layers/tiled_layer_unittest.cc', + 'layers/ui_resource_layer_impl_unittest.cc', + 'layers/ui_resource_layer_unittest.cc', 'output/delegating_renderer_unittest.cc', 'output/filter_operations_unittest.cc', 'output/gl_renderer_unittest.cc', 'output/output_surface_unittest.cc', 'output/renderer_pixeltest.cc', - 'output/render_surface_filters_unittest.cc', 'output/shader_unittest.cc', 'output/software_renderer_unittest.cc', 'quads/draw_quad_unittest.cc', @@ -72,18 +78,21 @@ 'scheduler/scheduler_state_machine_unittest.cc', 'scheduler/scheduler_unittest.cc', 'scheduler/texture_uploader_unittest.cc', - 'test/fake_web_graphics_context_3d_unittest.cc', + 'test/layer_tree_json_parser_unittest.cc', + 'test/test_web_graphics_context_3d_unittest.cc', 'trees/damage_tracker_unittest.cc', 'trees/layer_sorter_unittest.cc', 'trees/layer_tree_host_common_unittest.cc', 'trees/layer_tree_host_impl_unittest.cc', + 'trees/layer_tree_host_pixeltest_blending.cc', 'trees/layer_tree_host_pixeltest_filters.cc', 'trees/layer_tree_host_pixeltest_masks.cc', 'trees/layer_tree_host_pixeltest_on_demand_raster.cc', 'trees/layer_tree_host_pixeltest_readback.cc', - 'trees/layer_tree_host_unittest_animation.cc', 'trees/layer_tree_host_unittest.cc', + 'trees/layer_tree_host_unittest_animation.cc', 'trees/layer_tree_host_unittest_context.cc', + 'trees/layer_tree_host_unittest_copyrequest.cc', 'trees/layer_tree_host_unittest_damage.cc', 'trees/layer_tree_host_unittest_delegated.cc', 'trees/layer_tree_host_unittest_occlusion.cc', @@ -108,12 +117,18 @@ 'test/fake_delegated_renderer_layer_impl.cc', 'test/fake_delegated_renderer_layer_impl.h', 'test/fake_impl_proxy.h', + 'test/fake_layer_tree_host.cc', + 'test/fake_layer_tree_host.h', 'test/fake_layer_tree_host_client.cc', 'test/fake_layer_tree_host_client.h', 'test/fake_layer_tree_host_impl.cc', + 'test/fake_layer_tree_host_impl.h', 'test/fake_layer_tree_host_impl_client.cc', 'test/fake_layer_tree_host_impl_client.h', - 'test/fake_layer_tree_host_impl.h', + 'test/fake_output_surface.cc', + 'test/fake_output_surface.h', + 'test/fake_output_surface_client.cc', + 'test/fake_output_surface_client.h', 'test/fake_painted_scrollbar_layer.cc', 'test/fake_painted_scrollbar_layer.h', 'test/fake_picture_layer.cc', @@ -127,54 +142,70 @@ 'test/fake_proxy.cc', 'test/fake_proxy.h', 'test/fake_rendering_stats_instrumentation.h', + 'test/fake_scoped_ui_resource.cc', + 'test/fake_scoped_ui_resource.h', 'test/fake_scrollbar.cc', 'test/fake_scrollbar.h', 'test/fake_tile_manager.cc', 'test/fake_tile_manager.h', - 'test/fake_tile_manager_client.h', 'test/fake_tile_manager_client.cc', - 'test/fake_output_surface.cc', - 'test/fake_output_surface.h', - 'test/fake_output_surface_client.cc', - 'test/fake_output_surface_client.h', - 'test/fake_scoped_ui_resource.cc', - 'test/fake_scoped_ui_resource.h', + 'test/fake_tile_manager_client.h', + 'test/fake_ui_resource_layer_tree_host_impl.cc', + 'test/fake_ui_resource_layer_tree_host_impl.h', 'test/fake_video_frame_provider.cc', 'test/fake_video_frame_provider.h', + 'test/fake_web_graphics_context_3d.cc', + 'test/fake_web_graphics_context_3d.h', 'test/geometry_test_utils.cc', 'test/geometry_test_utils.h', 'test/impl_side_painting_settings.h', 'test/layer_test_common.cc', 'test/layer_test_common.h', + 'test/layer_tree_json_parser.cc', + 'test/layer_tree_json_parser.h', 'test/layer_tree_pixel_test.cc', 'test/layer_tree_pixel_test.h', 'test/layer_tree_test.cc', 'test/layer_tree_test.h', - 'test/layer_tree_json_parser.cc', - 'test/layer_tree_json_parser.h', 'test/mock_quad_culler.cc', 'test/mock_quad_culler.h', 'test/occlusion_tracker_test_common.h', + 'test/ordered_texture_map.cc', + 'test/ordered_texture_map.h', 'test/paths.cc', 'test/paths.h', + 'test/pixel_comparator.cc', + 'test/pixel_comparator.h', 'test/pixel_test.cc', 'test/pixel_test.h', 'test/pixel_test_output_surface.cc', 'test/pixel_test_output_surface.h', 'test/pixel_test_software_output_device.cc', 'test/pixel_test_software_output_device.h', + 'test/pixel_test_utils.cc', + 'test/pixel_test_utils.h', 'test/render_pass_test_common.cc', 'test/render_pass_test_common.h', 'test/render_pass_test_utils.cc', 'test/render_pass_test_utils.h', 'test/scheduler_test_common.cc', 'test/scheduler_test_common.h', - 'test/solid_color_content_layer_client.h', - 'test/solid_color_content_layer_client.cc', 'test/skia_common.cc', 'test/skia_common.h', + 'test/solid_color_content_layer_client.cc', + 'test/solid_color_content_layer_client.h', + 'test/test_context_provider.cc', + 'test/test_context_provider.h', + 'test/test_context_support.cc', + 'test/test_context_support.h', + 'test/test_gles2_interface.cc', + 'test/test_gles2_interface.h', + 'test/test_texture.cc', + 'test/test_texture.h', 'test/test_tile_priorities.cc', 'test/test_tile_priorities.h', + 'test/test_web_graphics_context_3d.cc', + 'test/test_web_graphics_context_3d.h', 'test/tiled_layer_test_common.cc', 'test/tiled_layer_test_common.h', ], @@ -186,15 +217,16 @@ 'dependencies': [ '../base/base.gyp:test_support_base', '../gpu/gpu.gyp:gpu', + '../gpu/gpu.gyp:gpu_unittest_utils', '../media/media.gyp:media', '../skia/skia.gyp:skia', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', - '../ui/ui.gyp:ui', + '../ui/events/events.gyp:events_base', + '../ui/gfx/gfx.gyp:gfx', '../webkit/common/gpu/webkit_gpu.gyp:webkit_gpu', 'cc.gyp:cc', 'cc_test_support', - 'cc_test_utils', ], 'sources': [ 'test/run_all_unittests.cc', @@ -235,23 +267,27 @@ 'type': '<(gtest_target_type)', 'dependencies': [ '../base/base.gyp:test_support_base', + '../gpu/gpu.gyp:gpu', + '../gpu/gpu.gyp:gpu_unittest_utils', '../media/media.gyp:media', '../skia/skia.gyp:skia', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', '../testing/perf/perf_test.gyp:*', - '../ui/ui.gyp:ui', + '../ui/gfx/gfx.gyp:gfx', 'cc.gyp:cc', 'cc_test_support', ], 'sources': [ + 'layers/layer_perftest.cc', 'resources/picture_layer_tiling_perftest.cc', 'resources/raster_worker_pool_perftest.cc', 'resources/tile_manager_perftest.cc', 'resources/worker_pool_perftest.cc', 'test/cc_test_suite.cc', 'test/lap_timer.cc', - 'test/run_all_unittests.cc', + 'test/run_all_perftests.cc', + 'trees/layer_tree_host_common_perftest.cc', 'trees/layer_tree_host_perftest.cc', ], 'include_dirs': [ @@ -287,13 +323,17 @@ '..', ], 'dependencies': [ + '../base/base.gyp:base', + '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + '../gpu/gpu.gyp:gpu_unittest_utils', '../skia/skia.gyp:skia', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', '../third_party/WebKit/public/blink.gyp:blink_minimal', '../third_party/mesa/mesa.gyp:osmesa', + '../ui/gfx/gfx.gyp:gfx', '../ui/gl/gl.gyp:gl', - '../ui/ui.gyp:ui', + '../ui/ui_unittests.gyp:ui_test_support', ], 'sources': [ '<@(cc_tests_support_files)', @@ -301,23 +341,6 @@ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. 'msvs_disabled_warnings': [ 4267, ], }, - { - 'target_name': 'cc_test_utils', - 'type': 'static_library', - 'include_dirs': [ - '..' - ], - 'sources': [ - 'test/pixel_comparator.cc', - 'test/pixel_comparator.h', - 'test/pixel_test_utils.cc', - 'test/pixel_test_utils.h', - ], - 'dependencies': [ - '../skia/skia.gyp:skia', - '../ui/ui.gyp:ui', # for png_codec - ], - }, ], 'conditions': [ # Special target to wrap a gtest_target_type==shared_library diff --git a/chromium/cc/debug/OWNERS b/chromium/cc/debug/OWNERS index a46edeee25d..2de2d9b11bd 100644 --- a/chromium/cc/debug/OWNERS +++ b/chromium/cc/debug/OWNERS @@ -2,3 +2,6 @@ per-file benchmark_instrumentation.h=set noparent per-file benchmark_instrumentation.h=ernstm@chromium.org per-file benchmark_instrumentation.h=nduca@chromium.org +per-file benchmark_instrumentation.cc=set noparent +per-file benchmark_instrumentation.cc=ernstm@chromium.org +per-file benchmark_instrumentation.cc=nduca@chromium.org diff --git a/chromium/cc/debug/benchmark_instrumentation.cc b/chromium/cc/debug/benchmark_instrumentation.cc new file mode 100644 index 00000000000..bf2b0222720 --- /dev/null +++ b/chromium/cc/debug/benchmark_instrumentation.cc @@ -0,0 +1,30 @@ +// Copyright 2013 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 "base/debug/trace_event.h" +#include "cc/debug/benchmark_instrumentation.h" + +namespace cc { + +// Please do not change the trace events in this file without updating +// tools/perf/measurements/rendering_stats.py accordingly. +// The benchmarks search for events and their arguments by name. + +void BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent( + const MainThreadRenderingStats& stats) { + TRACE_EVENT_INSTANT1("benchmark", + "BenchmarkInstrumentation::MainThreadRenderingStats", + TRACE_EVENT_SCOPE_THREAD, + "data", stats.AsTraceableData()); +} + +void BenchmarkInstrumentation::IssueImplThreadRenderingStatsEvent( + const ImplThreadRenderingStats& stats) { + TRACE_EVENT_INSTANT1("benchmark", + "BenchmarkInstrumentation::ImplThreadRenderingStats", + TRACE_EVENT_SCOPE_THREAD, + "data", stats.AsTraceableData()); +} + +} // namespace cc diff --git a/chromium/cc/debug/benchmark_instrumentation.h b/chromium/cc/debug/benchmark_instrumentation.h index 615fbe90622..2614814914c 100644 --- a/chromium/cc/debug/benchmark_instrumentation.h +++ b/chromium/cc/debug/benchmark_instrumentation.h @@ -5,28 +5,18 @@ #ifndef CC_DEBUG_BENCHMARK_INSTRUMENTATION_H_ #define CC_DEBUG_BENCHMARK_INSTRUMENTATION_H_ -#include "base/debug/trace_event.h" +#include "cc/debug/rendering_stats.h" namespace cc { -namespace benchmark_instrumentation { -// Please do not change the string constants in this file (or the TRACE_EVENT -// calls that use them) without updating -// tools/perf/measurements/rasterize_and_record_benchmark.py accordingly. -// The benchmark searches for events and their arguments by name. -const char kCategory[] = "cc,benchmark"; -const char kSourceFrameNumber[] = "source_frame_number"; -const char kData[] = "data"; -const char kWidth[] = "width"; -const char kHeight[] = "height"; -const char kNumPixelsRasterized[] = "num_pixels_rasterized"; -const char kLayerTreeHostUpdateLayers[] = "LayerTreeHost::UpdateLayers"; -const char kPictureLayerUpdate[] = "PictureLayer::Update"; -const char kRunRasterOnThread[] = "RasterWorkerPoolTaskImpl::RunRasterOnThread"; -const char kRecordLoop[] = "RecordLoop"; -const char kRasterLoop[] = "RasterLoop"; -const char kPictureRecord[] = "Picture::Record"; -const char kPictureRaster[] = "Picture::Raster"; -} // namespace benchmark_instrumentation + +class CC_EXPORT BenchmarkInstrumentation { + public: + static void IssueMainThreadRenderingStatsEvent( + const MainThreadRenderingStats& stats); + static void IssueImplThreadRenderingStatsEvent( + const ImplThreadRenderingStats& stats); +}; + } // namespace cc #endif // CC_DEBUG_BENCHMARK_INSTRUMENTATION_H_ diff --git a/chromium/cc/debug/debug_colors.cc b/chromium/cc/debug/debug_colors.cc index e6f3e28a238..9fee7551b3d 100644 --- a/chromium/cc/debug/debug_colors.cc +++ b/chromium/cc/debug/debug_colors.cc @@ -253,6 +253,15 @@ SkColor DebugColors::NonFastScrollableRectFillColor() { return SkColorSetARGB(30, 238, 163, 59); } +// Animation bounds are lime-green. +SkColor DebugColors::LayerAnimationBoundsBorderColor() { + return SkColorSetARGB(255, 112, 229, 0); +} +int DebugColors::LayerAnimationBoundsBorderWidth() { return 2; } +SkColor DebugColors::LayerAnimationBoundsFillColor() { + return SkColorSetARGB(30, 112, 229, 0); +} + // Non-Painted rects in cyan. SkColor DebugColors::NonPaintedFillColor() { return SK_ColorCYAN; } diff --git a/chromium/cc/debug/debug_colors.h b/chromium/cc/debug/debug_colors.h index a1335e37e96..9edfb377bad 100644 --- a/chromium/cc/debug/debug_colors.h +++ b/chromium/cc/debug/debug_colors.h @@ -106,6 +106,10 @@ class DebugColors { static int NonFastScrollableRectBorderWidth(); static SkColor NonFastScrollableRectFillColor(); + static SkColor LayerAnimationBoundsBorderColor(); + static int LayerAnimationBoundsBorderWidth(); + static SkColor LayerAnimationBoundsFillColor(); + static SkColor NonPaintedFillColor(); static SkColor MissingPictureFillColor(); static SkColor PictureBorderColor(); diff --git a/chromium/cc/debug/debug_rect_history.cc b/chromium/cc/debug/debug_rect_history.cc index 24ba86eae59..679beafdbb4 100644 --- a/chromium/cc/debug/debug_rect_history.cc +++ b/chromium/cc/debug/debug_rect_history.cc @@ -58,6 +58,9 @@ void DebugRectHistory::SaveDebugRectsForCurrentFrame( if (debug_state.show_non_occluding_rects) SaveNonOccludingRects(non_occluding_screen_space_rects); + + if (debug_state.show_layer_animation_bounds_rects) + SaveLayerAnimationBoundsRects(render_surface_layer_list); } void DebugRectHistory::SavePaintRects(LayerImpl* layer) { @@ -105,8 +108,7 @@ void DebugRectHistory::SavePropertyChangedRects( if (layer->LayerIsAlwaysDamaged()) continue; - if (layer->LayerPropertyChanged() || - layer->LayerSurfacePropertyChanged()) { + if (layer->LayerPropertyChanged()) { debug_rects_.push_back( DebugRect(PROPERTY_CHANGED_RECT_TYPE, MathUtil::MapClippedRect( @@ -233,4 +235,28 @@ void DebugRectHistory::SaveNonFastScrollableRectsCallback(LayerImpl* layer) { } } +void DebugRectHistory::SaveLayerAnimationBoundsRects( + const LayerImplList& render_surface_layer_list) { + typedef LayerIterator<LayerImpl, + LayerImplList, + RenderSurfaceImpl, + LayerIteratorActions::FrontToBack> LayerIteratorType; + LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list); + for (LayerIteratorType it = + LayerIteratorType::Begin(&render_surface_layer_list); + it != end; ++it) { + if (!it.represents_itself()) + continue; + gfx::BoxF inflated_bounds; + if (!(*it)->GetAnimationBounds(&inflated_bounds)) + continue; + + debug_rects_.push_back(DebugRect(ANIMATION_BOUNDS_RECT_TYPE, + gfx::RectF(inflated_bounds.x(), + inflated_bounds.y(), + inflated_bounds.width(), + inflated_bounds.height()))); + } +} + } // namespace cc diff --git a/chromium/cc/debug/debug_rect_history.h b/chromium/cc/debug/debug_rect_history.h index 346148a93fc..0dae431bd5f 100644 --- a/chromium/cc/debug/debug_rect_history.h +++ b/chromium/cc/debug/debug_rect_history.h @@ -53,6 +53,7 @@ enum DebugRectType { TOUCH_EVENT_HANDLER_RECT_TYPE, WHEEL_EVENT_HANDLER_RECT_TYPE, NON_FAST_SCROLLABLE_RECT_TYPE, + ANIMATION_BOUNDS_RECT_TYPE, }; struct DebugRect { @@ -103,6 +104,8 @@ class DebugRectHistory { void SaveWheelEventHandlerRectsCallback(LayerImpl* layer); void SaveNonFastScrollableRects(LayerImpl* layer); void SaveNonFastScrollableRectsCallback(LayerImpl* layer); + void SaveLayerAnimationBoundsRects( + const LayerImplList& render_surface_layer_list); std::vector<DebugRect> debug_rects_; diff --git a/chromium/cc/debug/devtools_instrumentation.h b/chromium/cc/debug/devtools_instrumentation.h index eea9e62f02a..3caa81ea6d5 100644 --- a/chromium/cc/debug/devtools_instrumentation.h +++ b/chromium/cc/debug/devtools_instrumentation.h @@ -12,17 +12,18 @@ namespace devtools_instrumentation { namespace internal { const char kCategory[] = "cc,devtools"; +const char kFrameId[] = "frameId"; const char kLayerId[] = "layerId"; const char kLayerTreeId[] = "layerTreeId"; const char kPixelRefId[] = "pixelRefId"; const char kImageDecodeTask[] = "ImageDecodeTask"; -} +const char kBeginFrame[] = "BeginFrame"; +const char kActivateLayerTree[] = "ActivateLayerTree"; +} // namespace internal -const char kPaintLayer[] = "PaintLayer"; const char kRasterTask[] = "RasterTask"; const char kPaintSetup[] = "PaintSetup"; -const char kUpdateLayer[] = "UpdateLayer"; class ScopedLayerTask { public: @@ -57,10 +58,11 @@ class ScopedLayerTreeTask { public: ScopedLayerTreeTask(const char* event_name, int layer_id, - uint64 tree_id) + int layer_tree_host_id) : event_name_(event_name) { TRACE_EVENT_BEGIN2(internal::kCategory, event_name_, - internal::kLayerId, layer_id, internal::kLayerTreeId, tree_id); + internal::kLayerId, layer_id, + internal::kLayerTreeId, layer_tree_host_id); } ~ScopedLayerTreeTask() { TRACE_EVENT_END0(internal::kCategory, event_name_); @@ -84,6 +86,21 @@ struct ScopedLayerObjectTracker DISALLOW_COPY_AND_ASSIGN(ScopedLayerObjectTracker); }; +inline void didActivateLayerTree(int layer_tree_host_id, int frame_id) { + TRACE_EVENT_INSTANT2(internal::kCategory, + internal::kActivateLayerTree, + TRACE_EVENT_SCOPE_THREAD, + internal::kLayerTreeId, layer_tree_host_id, + internal::kFrameId, frame_id); +} + +inline void didBeginFrame(int layer_tree_host_id) { + TRACE_EVENT_INSTANT1(internal::kCategory, + internal::kBeginFrame, + TRACE_EVENT_SCOPE_THREAD, + internal::kLayerTreeId, layer_tree_host_id); +} + } // namespace devtools_instrumentation } // namespace cc diff --git a/chromium/cc/debug/fake_web_graphics_context_3d.cc b/chromium/cc/debug/fake_web_graphics_context_3d.cc deleted file mode 100644 index f493dc1d854..00000000000 --- a/chromium/cc/debug/fake_web_graphics_context_3d.cc +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2013 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 "cc/debug/fake_web_graphics_context_3d.h" - -#include "base/logging.h" -#include "third_party/khronos/GLES2/gl2.h" - -using WebKit::WGC3Dboolean; -using WebKit::WGC3Denum; -using WebKit::WebGLId; -using WebKit::WebGraphicsContext3D; - -namespace cc { - -FakeWebGraphicsContext3D::FakeWebGraphicsContext3D() - : WebKit::WebGraphicsContext3D() { -} - -FakeWebGraphicsContext3D::~FakeWebGraphicsContext3D() { -} - -bool FakeWebGraphicsContext3D::makeContextCurrent() { - return true; -} - -int FakeWebGraphicsContext3D::width() { - return 1; -} - -int FakeWebGraphicsContext3D::height() { - return 1; -} - -void FakeWebGraphicsContext3D::reshape(int width, int height) { -} - -bool FakeWebGraphicsContext3D::isGLES2Compliant() { - return false; -} - -WebGLId FakeWebGraphicsContext3D::getPlatformTextureId() { - return 0; -} - -bool FakeWebGraphicsContext3D::isContextLost() { - return false; -} - -WGC3Denum FakeWebGraphicsContext3D::getGraphicsResetStatusARB() { - return GL_NO_ERROR; -} - -void* FakeWebGraphicsContext3D::mapBufferSubDataCHROMIUM( - WGC3Denum target, - WebKit::WGC3Dintptr offset, - WebKit::WGC3Dsizeiptr size, - WGC3Denum access) { - return 0; -} - -void* FakeWebGraphicsContext3D::mapTexSubImage2DCHROMIUM( - WGC3Denum target, - WebKit::WGC3Dint level, - WebKit::WGC3Dint xoffset, - WebKit::WGC3Dint yoffset, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height, - WGC3Denum format, - WGC3Denum type, - WGC3Denum access) { - return 0; -} - -WebKit::WebString FakeWebGraphicsContext3D::getRequestableExtensionsCHROMIUM() { - return WebKit::WebString(); -} - -WGC3Denum FakeWebGraphicsContext3D::checkFramebufferStatus( - WGC3Denum target) { - return GL_FRAMEBUFFER_COMPLETE; -} - -bool FakeWebGraphicsContext3D::getActiveAttrib( - WebGLId program, - WebKit::WGC3Duint index, - ActiveInfo&) { - return false; -} - -bool FakeWebGraphicsContext3D::getActiveUniform( - WebGLId program, - WebKit::WGC3Duint index, - ActiveInfo&) { - return false; -} - -WebKit::WGC3Dint FakeWebGraphicsContext3D::getAttribLocation( - WebGLId program, - const WebKit::WGC3Dchar* name) { - return 0; -} - -WebGraphicsContext3D::Attributes - FakeWebGraphicsContext3D::getContextAttributes() { - return WebGraphicsContext3D::Attributes(); -} - -WGC3Denum FakeWebGraphicsContext3D::getError() { - return 0; -} - -void FakeWebGraphicsContext3D::getIntegerv( - WGC3Denum pname, - WebKit::WGC3Dint* value) { - if (pname == GL_MAX_TEXTURE_SIZE) - *value = 1024; - else if (pname == GL_ACTIVE_TEXTURE) - *value = GL_TEXTURE0; -} - -void FakeWebGraphicsContext3D::getProgramiv( - WebGLId program, - WGC3Denum pname, - WebKit::WGC3Dint* value) { - if (pname == GL_LINK_STATUS) - *value = 1; -} - -WebKit::WebString FakeWebGraphicsContext3D::getProgramInfoLog( - WebGLId program) { - return WebKit::WebString(); -} - -void FakeWebGraphicsContext3D::getShaderiv( - WebGLId shader, - WGC3Denum pname, - WebKit::WGC3Dint* value) { - if (pname == GL_COMPILE_STATUS) - *value = 1; -} - -WebKit::WebString FakeWebGraphicsContext3D::getShaderInfoLog( - WebGLId shader) { - return WebKit::WebString(); -} - -void FakeWebGraphicsContext3D::getShaderPrecisionFormat( - WebKit::WGC3Denum shadertype, - WebKit::WGC3Denum precisiontype, - WebKit::WGC3Dint* range, - WebKit::WGC3Dint* precision) { - // Return the minimum precision requirements of the GLES specificatin. - switch (precisiontype) { - case GL_LOW_INT: - range[0] = 8; - range[1] = 8; - *precision = 0; - break; - case GL_MEDIUM_INT: - range[0] = 10; - range[1] = 10; - *precision = 0; - break; - case GL_HIGH_INT: - range[0] = 16; - range[1] = 16; - *precision = 0; - break; - case GL_LOW_FLOAT: - range[0] = 8; - range[1] = 8; - *precision = 8; - break; - case GL_MEDIUM_FLOAT: - range[0] = 14; - range[1] = 14; - *precision = 10; - break; - case GL_HIGH_FLOAT: - range[0] = 62; - range[1] = 62; - *precision = 16; - break; - default: - NOTREACHED(); - break; - } -} - -WebKit::WebString FakeWebGraphicsContext3D::getShaderSource( - WebGLId shader) { - return WebKit::WebString(); -} - -WebKit::WebString FakeWebGraphicsContext3D::getString(WGC3Denum name) { - return WebKit::WebString(); -} - -WebKit::WGC3Dint FakeWebGraphicsContext3D::getUniformLocation( - WebGLId program, - const WebKit::WGC3Dchar* name) { - return 0; -} - -WebKit::WGC3Dsizeiptr FakeWebGraphicsContext3D::getVertexAttribOffset( - WebKit::WGC3Duint index, - WGC3Denum pname) { - return 0; -} - -WGC3Dboolean FakeWebGraphicsContext3D::isBuffer( - WebGLId buffer) { - return false; -} - -WGC3Dboolean FakeWebGraphicsContext3D::isEnabled( - WGC3Denum cap) { - return false; -} - -WGC3Dboolean FakeWebGraphicsContext3D::isFramebuffer( - WebGLId framebuffer) { - return false; -} - -WGC3Dboolean FakeWebGraphicsContext3D::isProgram( - WebGLId program) { - return false; -} - -WGC3Dboolean FakeWebGraphicsContext3D::isRenderbuffer( - WebGLId renderbuffer) { - return false; -} - -WGC3Dboolean FakeWebGraphicsContext3D::isShader( - WebGLId shader) { - return false; -} - -WGC3Dboolean FakeWebGraphicsContext3D::isTexture( - WebGLId texture) { - return false; -} - -WebGLId FakeWebGraphicsContext3D::createBuffer() { - return 1; -} - -void FakeWebGraphicsContext3D::deleteBuffer(WebKit::WebGLId id) { -} - -WebGLId FakeWebGraphicsContext3D::createFramebuffer() { - return 1; -} - -void FakeWebGraphicsContext3D::deleteFramebuffer(WebKit::WebGLId id) { -} - -WebGLId FakeWebGraphicsContext3D::createProgram() { - return 1; -} - -void FakeWebGraphicsContext3D::deleteProgram(WebKit::WebGLId id) { -} - -WebGLId FakeWebGraphicsContext3D::createRenderbuffer() { - return 1; -} - -void FakeWebGraphicsContext3D::deleteRenderbuffer(WebKit::WebGLId id) { -} - -WebGLId FakeWebGraphicsContext3D::createShader(WGC3Denum) { - return 1; -} - -void FakeWebGraphicsContext3D::deleteShader(WebKit::WebGLId id) { -} - -WebGLId FakeWebGraphicsContext3D::createTexture() { - return 1; -} - -void FakeWebGraphicsContext3D::deleteTexture(WebGLId texture_id) { -} - -void FakeWebGraphicsContext3D::attachShader(WebGLId program, WebGLId shader) { -} - -void FakeWebGraphicsContext3D::useProgram(WebGLId program) { -} - -void FakeWebGraphicsContext3D::bindBuffer(WGC3Denum target, WebGLId buffer) { -} - -void FakeWebGraphicsContext3D::bindFramebuffer( - WGC3Denum target, WebGLId framebuffer) { -} - -void FakeWebGraphicsContext3D::bindRenderbuffer( - WGC3Denum target, WebGLId renderbuffer) { -} - -void FakeWebGraphicsContext3D::bindTexture( - WGC3Denum target, WebGLId texture_id) { -} - -WebGLId FakeWebGraphicsContext3D::createQueryEXT() { - return 1; -} - -WGC3Dboolean FakeWebGraphicsContext3D::isQueryEXT(WebGLId query) { - return true; -} - -void FakeWebGraphicsContext3D::endQueryEXT(WebKit::WGC3Denum target) { -} - -void FakeWebGraphicsContext3D::getQueryObjectuivEXT( - WebKit::WebGLId query, - WebKit::WGC3Denum pname, - WebKit::WGC3Duint* params) { -} - -void FakeWebGraphicsContext3D::setContextLostCallback( - WebGraphicsContextLostCallback* callback) { -} - -void FakeWebGraphicsContext3D::loseContextCHROMIUM(WGC3Denum current, - WGC3Denum other) { -} - -WebKit::WGC3Duint FakeWebGraphicsContext3D::createImageCHROMIUM( - WebKit::WGC3Dsizei width, WebKit::WGC3Dsizei height, - WebKit::WGC3Denum internalformat) { - return 0; -} - -void* FakeWebGraphicsContext3D::mapImageCHROMIUM(WebKit::WGC3Duint image_id, - WebKit::WGC3Denum access) { - return 0; -} - -} // namespace cc diff --git a/chromium/cc/debug/fake_web_graphics_context_3d.h b/chromium/cc/debug/fake_web_graphics_context_3d.h deleted file mode 100644 index 04c983de006..00000000000 --- a/chromium/cc/debug/fake_web_graphics_context_3d.h +++ /dev/null @@ -1,608 +0,0 @@ -// Copyright 2013 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 CC_DEBUG_FAKE_WEB_GRAPHICS_CONTEXT_3D_H_ -#define CC_DEBUG_FAKE_WEB_GRAPHICS_CONTEXT_3D_H_ - -#include <string> - -#include "base/compiler_specific.h" -#include "cc/base/cc_export.h" -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" - -namespace cc { - -// WebGraphicsContext3D base class for use in unit tests. -// All operations are no-ops (returning 0 if necessary). -class CC_EXPORT FakeWebGraphicsContext3D - : public NON_EXPORTED_BASE(WebKit::WebGraphicsContext3D) { - public: - FakeWebGraphicsContext3D(); - virtual ~FakeWebGraphicsContext3D(); - - virtual bool makeContextCurrent(); - - virtual int width(); - virtual int height(); - - virtual void reshape(int width, int height); - - virtual bool isGLES2Compliant(); - - virtual WebKit::WebGLId getPlatformTextureId(); - - virtual void prepareTexture() {} - - virtual void postSubBufferCHROMIUM(int x, int y, int width, int height) {} - - virtual void synthesizeGLError(WebKit::WGC3Denum) {} - - virtual bool isContextLost(); - virtual WebKit::WGC3Denum getGraphicsResetStatusARB(); - - virtual void* mapBufferSubDataCHROMIUM( - WebKit::WGC3Denum target, - WebKit::WGC3Dintptr offset, - WebKit::WGC3Dsizeiptr size, - WebKit::WGC3Denum access); - - virtual void unmapBufferSubDataCHROMIUM(const void*) {} - virtual void* mapTexSubImage2DCHROMIUM( - WebKit::WGC3Denum target, - WebKit::WGC3Dint level, - WebKit::WGC3Dint xoffset, - WebKit::WGC3Dint yoffset, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height, - WebKit::WGC3Denum format, - WebKit::WGC3Denum type, - WebKit::WGC3Denum access); - virtual void unmapTexSubImage2DCHROMIUM(const void*) {} - - virtual void setVisibilityCHROMIUM(bool visible) {} - - virtual void discardFramebufferEXT( - WebKit::WGC3Denum target, - WebKit::WGC3Dsizei num_attachments, - const WebKit::WGC3Denum* attachments) {} - - virtual WebKit::WebString getRequestableExtensionsCHROMIUM(); - virtual void requestExtensionCHROMIUM(const char*) {} - - virtual void blitFramebufferCHROMIUM( - WebKit::WGC3Dint src_x0, - WebKit::WGC3Dint src_y0, - WebKit::WGC3Dint src_x1, - WebKit::WGC3Dint src_y1, - WebKit::WGC3Dint dst_x0, - WebKit::WGC3Dint dst_y0, - WebKit::WGC3Dint dst_x1, - WebKit::WGC3Dint dst_y1, - WebKit::WGC3Dbitfield mask, - WebKit::WGC3Denum filter) {} - virtual void renderbufferStorageMultisampleCHROMIUM( - WebKit::WGC3Denum target, - WebKit::WGC3Dsizei samples, - WebKit::WGC3Denum internalformat, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height) {} - - virtual void activeTexture(WebKit::WGC3Denum texture) {} - virtual void attachShader(WebKit::WebGLId program, WebKit::WebGLId shader); - virtual void bindAttribLocation( - WebKit::WebGLId program, - WebKit::WGC3Duint index, - const WebKit::WGC3Dchar* name) {} - virtual void bindBuffer(WebKit::WGC3Denum target, WebKit::WebGLId buffer); - virtual void bindFramebuffer( - WebKit::WGC3Denum target, WebKit::WebGLId framebuffer); - virtual void bindRenderbuffer( - WebKit::WGC3Denum target, WebKit::WebGLId renderbuffer); - virtual void bindTexture( - WebKit::WGC3Denum target, - WebKit::WebGLId texture_id); - virtual void blendColor( - WebKit::WGC3Dclampf red, - WebKit::WGC3Dclampf green, - WebKit::WGC3Dclampf blue, - WebKit::WGC3Dclampf alpha) {} - virtual void blendEquation(WebKit::WGC3Denum mode) {} - virtual void blendEquationSeparate( - WebKit::WGC3Denum mode_rgb, - WebKit::WGC3Denum mode_alpha) {} - virtual void blendFunc( - WebKit::WGC3Denum sfactor, - WebKit::WGC3Denum dfactor) {} - virtual void blendFuncSeparate( - WebKit::WGC3Denum src_rgb, - WebKit::WGC3Denum dst_rgb, - WebKit::WGC3Denum src_alpha, - WebKit::WGC3Denum dst_alpha) {} - - virtual void bufferData( - WebKit::WGC3Denum target, - WebKit::WGC3Dsizeiptr size, - const void* data, - WebKit::WGC3Denum usage) {} - virtual void bufferSubData( - WebKit::WGC3Denum target, - WebKit::WGC3Dintptr offset, - WebKit::WGC3Dsizeiptr size, - const void* data) {} - - virtual WebKit::WGC3Denum checkFramebufferStatus(WebKit::WGC3Denum target); - - virtual void clear(WebKit::WGC3Dbitfield mask) {} - virtual void clearColor( - WebKit::WGC3Dclampf red, - WebKit::WGC3Dclampf green, - WebKit::WGC3Dclampf blue, - WebKit::WGC3Dclampf alpha) {} - virtual void clearDepth(WebKit::WGC3Dclampf depth) {} - virtual void clearStencil(WebKit::WGC3Dint s) {} - virtual void colorMask( - WebKit::WGC3Dboolean red, - WebKit::WGC3Dboolean green, - WebKit::WGC3Dboolean blue, - WebKit::WGC3Dboolean alpha) {} - virtual void compileShader(WebKit::WebGLId shader) {} - - virtual void compressedTexImage2D( - WebKit::WGC3Denum target, - WebKit::WGC3Dint level, - WebKit::WGC3Denum internal_format, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height, - WebKit::WGC3Dint border, - WebKit::WGC3Dsizei image_size, - const void* data) {} - virtual void compressedTexSubImage2D( - WebKit::WGC3Denum target, - WebKit::WGC3Dint level, - WebKit::WGC3Dint xoffset, - WebKit::WGC3Dint yoffset, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height, - WebKit::WGC3Denum format, - WebKit::WGC3Dsizei image_size, - const void* data) {} - virtual void copyTexImage2D( - WebKit::WGC3Denum target, - WebKit::WGC3Dint level, - WebKit::WGC3Denum internalformat, - WebKit::WGC3Dint x, - WebKit::WGC3Dint y, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height, - WebKit::WGC3Dint border) {} - virtual void copyTexSubImage2D( - WebKit::WGC3Denum target, - WebKit::WGC3Dint level, - WebKit::WGC3Dint xoffset, - WebKit::WGC3Dint yoffset, - WebKit::WGC3Dint x, - WebKit::WGC3Dint y, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height) {} - virtual void cullFace(WebKit::WGC3Denum mode) {} - virtual void depthFunc(WebKit::WGC3Denum func) {} - virtual void depthMask(WebKit::WGC3Dboolean flag) {} - virtual void depthRange( - WebKit::WGC3Dclampf z_near, - WebKit::WGC3Dclampf z_far) {} - virtual void detachShader(WebKit::WebGLId program, WebKit::WebGLId shader) {} - virtual void disable(WebKit::WGC3Denum cap) {} - virtual void disableVertexAttribArray(WebKit::WGC3Duint index) {} - virtual void drawArrays( - WebKit::WGC3Denum mode, - WebKit::WGC3Dint first, - WebKit::WGC3Dsizei count) {} - virtual void drawElements( - WebKit::WGC3Denum mode, - WebKit::WGC3Dsizei count, - WebKit::WGC3Denum type, - WebKit::WGC3Dintptr offset) {} - - virtual void enable(WebKit::WGC3Denum cap) {} - virtual void enableVertexAttribArray(WebKit::WGC3Duint index) {} - virtual void finish() {} - virtual void flush() {} - virtual void framebufferRenderbuffer( - WebKit::WGC3Denum target, - WebKit::WGC3Denum attachment, - WebKit::WGC3Denum renderbuffertarget, - WebKit::WebGLId renderbuffer) {} - virtual void framebufferTexture2D( - WebKit::WGC3Denum target, - WebKit::WGC3Denum attachment, - WebKit::WGC3Denum textarget, - WebKit::WebGLId texture, - WebKit::WGC3Dint level) {} - virtual void frontFace(WebKit::WGC3Denum mode) {} - virtual void generateMipmap(WebKit::WGC3Denum target) {} - - virtual bool getActiveAttrib( - WebKit::WebGLId program, - WebKit::WGC3Duint index, ActiveInfo&); - virtual bool getActiveUniform( - WebKit::WebGLId program, - WebKit::WGC3Duint index, - ActiveInfo&); - virtual void getAttachedShaders( - WebKit::WebGLId program, - WebKit::WGC3Dsizei max_count, - WebKit::WGC3Dsizei* count, - WebKit::WebGLId* shaders) {} - virtual WebKit::WGC3Dint getAttribLocation( - WebKit::WebGLId program, - const WebKit::WGC3Dchar* name); - virtual void getBooleanv( - WebKit::WGC3Denum pname, - WebKit::WGC3Dboolean* value) {} - virtual void getBufferParameteriv( - WebKit::WGC3Denum target, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* value) {} - virtual Attributes getContextAttributes(); - virtual WebKit::WGC3Denum getError(); - virtual void getFloatv( - WebKit::WGC3Denum pname, - WebKit::WGC3Dfloat* value) {} - virtual void getFramebufferAttachmentParameteriv( - WebKit::WGC3Denum target, - WebKit::WGC3Denum attachment, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* value) {} - - virtual void getIntegerv( - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* value); - - virtual void getProgramiv( - WebKit::WebGLId program, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* value); - - virtual WebKit::WebString getProgramInfoLog(WebKit::WebGLId program); - virtual void getRenderbufferParameteriv( - WebKit::WGC3Denum target, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* value) {} - - virtual void getShaderiv( - WebKit::WebGLId shader, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* value); - - virtual WebKit::WebString getShaderInfoLog(WebKit::WebGLId shader); - virtual void getShaderPrecisionFormat( - WebKit::WGC3Denum shadertype, - WebKit::WGC3Denum precisiontype, - WebKit::WGC3Dint* range, - WebKit::WGC3Dint* precision); - virtual WebKit::WebString getShaderSource(WebKit::WebGLId shader); - virtual WebKit::WebString getString(WebKit::WGC3Denum name); - virtual void getTexParameterfv( - WebKit::WGC3Denum target, - WebKit::WGC3Denum pname, - WebKit::WGC3Dfloat* value) {} - virtual void getTexParameteriv( - WebKit::WGC3Denum target, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* value) {} - virtual void getUniformfv( - WebKit::WebGLId program, - WebKit::WGC3Dint location, - WebKit::WGC3Dfloat* value) {} - virtual void getUniformiv( - WebKit::WebGLId program, - WebKit::WGC3Dint location, - WebKit::WGC3Dint* value) {} - virtual WebKit::WGC3Dint getUniformLocation( - WebKit::WebGLId program, - const WebKit::WGC3Dchar* name); - virtual void getVertexAttribfv( - WebKit::WGC3Duint index, - WebKit::WGC3Denum pname, - WebKit::WGC3Dfloat* value) {} - virtual void getVertexAttribiv( - WebKit::WGC3Duint index, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* value) {} - virtual WebKit::WGC3Dsizeiptr getVertexAttribOffset( - WebKit::WGC3Duint index, - WebKit::WGC3Denum pname); - - virtual void hint(WebKit::WGC3Denum target, WebKit::WGC3Denum mode) {} - virtual WebKit::WGC3Dboolean isBuffer(WebKit::WebGLId buffer); - virtual WebKit::WGC3Dboolean isEnabled(WebKit::WGC3Denum cap); - virtual WebKit::WGC3Dboolean isFramebuffer(WebKit::WebGLId framebuffer); - virtual WebKit::WGC3Dboolean isProgram(WebKit::WebGLId program); - virtual WebKit::WGC3Dboolean isRenderbuffer(WebKit::WebGLId renderbuffer); - virtual WebKit::WGC3Dboolean isShader(WebKit::WebGLId shader); - virtual WebKit::WGC3Dboolean isTexture(WebKit::WebGLId texture); - virtual void lineWidth(WebKit::WGC3Dfloat) {} - virtual void linkProgram(WebKit::WebGLId program) {} - virtual void pixelStorei(WebKit::WGC3Denum pname, WebKit::WGC3Dint param) {} - virtual void polygonOffset( - WebKit::WGC3Dfloat factor, - WebKit::WGC3Dfloat units) {} - - virtual void readPixels( - WebKit::WGC3Dint x, - WebKit::WGC3Dint y, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height, - WebKit::WGC3Denum format, - WebKit::WGC3Denum type, - void* pixels) {} - - virtual void releaseShaderCompiler() {} - - virtual void renderbufferStorage( - WebKit::WGC3Denum target, - WebKit::WGC3Denum internalformat, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height) {} - virtual void sampleCoverage( - WebKit::WGC3Dclampf value, - WebKit::WGC3Dboolean invert) {} - virtual void scissor( - WebKit::WGC3Dint x, - WebKit::WGC3Dint y, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height) {} - virtual void shaderSource( - WebKit::WebGLId shader, - const WebKit::WGC3Dchar* string) {} - virtual void stencilFunc( - WebKit::WGC3Denum func, - WebKit::WGC3Dint ref, - WebKit::WGC3Duint mask) {} - virtual void stencilFuncSeparate( - WebKit::WGC3Denum face, - WebKit::WGC3Denum func, - WebKit::WGC3Dint ref, - WebKit::WGC3Duint mask) {} - virtual void stencilMask(WebKit::WGC3Duint mask) {} - virtual void stencilMaskSeparate( - WebKit::WGC3Denum face, - WebKit::WGC3Duint mask) {} - virtual void stencilOp( - WebKit::WGC3Denum fail, - WebKit::WGC3Denum zfail, - WebKit::WGC3Denum zpass) {} - virtual void stencilOpSeparate( - WebKit::WGC3Denum face, - WebKit::WGC3Denum fail, - WebKit::WGC3Denum zfail, - WebKit::WGC3Denum zpass) {} - - virtual void texImage2D( - WebKit::WGC3Denum target, - WebKit::WGC3Dint level, - WebKit::WGC3Denum internalformat, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height, - WebKit::WGC3Dint border, - WebKit::WGC3Denum format, - WebKit::WGC3Denum type, - const void* pixels) {} - - virtual void texParameterf( - WebKit::WGC3Denum target, - WebKit::WGC3Denum pname, - WebKit::WGC3Dfloat param) {} - virtual void texParameteri( - WebKit::WGC3Denum target, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint param) {} - - virtual void texSubImage2D( - WebKit::WGC3Denum target, - WebKit::WGC3Dint level, - WebKit::WGC3Dint xoffset, - WebKit::WGC3Dint yoffset, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height, - WebKit::WGC3Denum format, - WebKit::WGC3Denum type, - const void* pixels) {} - - virtual void uniform1f(WebKit::WGC3Dint location, WebKit::WGC3Dfloat x) {} - virtual void uniform1fv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - const WebKit::WGC3Dfloat* v) {} - virtual void uniform1i(WebKit::WGC3Dint location, WebKit::WGC3Dint x) {} - virtual void uniform1iv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - const WebKit::WGC3Dint* v) {} - virtual void uniform2f( - WebKit::WGC3Dint location, - WebKit::WGC3Dfloat x, - WebKit::WGC3Dfloat y) {} - virtual void uniform2fv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - const WebKit::WGC3Dfloat* v) {} - virtual void uniform2i( - WebKit::WGC3Dint location, - WebKit::WGC3Dint x, - WebKit::WGC3Dint y) {} - virtual void uniform2iv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - const WebKit::WGC3Dint* v) {} - virtual void uniform3f( - WebKit::WGC3Dint location, - WebKit::WGC3Dfloat x, - WebKit::WGC3Dfloat y, - WebKit::WGC3Dfloat z) {} - virtual void uniform3fv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - const WebKit::WGC3Dfloat* v) {} - virtual void uniform3i( - WebKit::WGC3Dint location, - WebKit::WGC3Dint x, - WebKit::WGC3Dint y, - WebKit::WGC3Dint z) {} - virtual void uniform3iv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - const WebKit::WGC3Dint* v) {} - virtual void uniform4f( - WebKit::WGC3Dint location, - WebKit::WGC3Dfloat x, - WebKit::WGC3Dfloat y, - WebKit::WGC3Dfloat z, - WebKit::WGC3Dfloat w) {} - virtual void uniform4fv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - const WebKit::WGC3Dfloat* v) {} - virtual void uniform4i( - WebKit::WGC3Dint location, - WebKit::WGC3Dint x, - WebKit::WGC3Dint y, - WebKit::WGC3Dint z, - WebKit::WGC3Dint w) {} - virtual void uniform4iv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - const WebKit::WGC3Dint* v) {} - virtual void uniformMatrix2fv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - WebKit::WGC3Dboolean transpose, - const WebKit::WGC3Dfloat* value) {} - virtual void uniformMatrix3fv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - WebKit::WGC3Dboolean transpose, - const WebKit::WGC3Dfloat* value) {} - virtual void uniformMatrix4fv( - WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - WebKit::WGC3Dboolean transpose, - const WebKit::WGC3Dfloat* value) {} - - virtual void useProgram(WebKit::WebGLId program); - virtual void validateProgram(WebKit::WebGLId program) {} - - virtual void vertexAttrib1f(WebKit::WGC3Duint index, WebKit::WGC3Dfloat x) {} - virtual void vertexAttrib1fv( - WebKit::WGC3Duint index, - const WebKit::WGC3Dfloat* values) {} - virtual void vertexAttrib2f( - WebKit::WGC3Duint index, - WebKit::WGC3Dfloat x, - WebKit::WGC3Dfloat y) {} - virtual void vertexAttrib2fv( - WebKit::WGC3Duint index, - const WebKit::WGC3Dfloat* values) {} - virtual void vertexAttrib3f( - WebKit::WGC3Duint index, - WebKit::WGC3Dfloat x, - WebKit::WGC3Dfloat y, - WebKit::WGC3Dfloat z) {} - virtual void vertexAttrib3fv( - WebKit::WGC3Duint index, - const WebKit::WGC3Dfloat* values) {} - virtual void vertexAttrib4f( - WebKit::WGC3Duint index, - WebKit::WGC3Dfloat x, - WebKit::WGC3Dfloat y, - WebKit::WGC3Dfloat z, - WebKit::WGC3Dfloat w) {} - virtual void vertexAttrib4fv( - WebKit::WGC3Duint index, - const WebKit::WGC3Dfloat* values) {} - virtual void vertexAttribPointer( - WebKit::WGC3Duint index, - WebKit::WGC3Dint size, - WebKit::WGC3Denum type, - WebKit::WGC3Dboolean normalized, - WebKit::WGC3Dsizei stride, - WebKit::WGC3Dintptr offset) {} - - virtual void viewport( - WebKit::WGC3Dint x, - WebKit::WGC3Dint y, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height) {} - - virtual WebKit::WebGLId createBuffer(); - virtual WebKit::WebGLId createFramebuffer(); - virtual WebKit::WebGLId createProgram(); - virtual WebKit::WebGLId createRenderbuffer(); - virtual WebKit::WebGLId createShader(WebKit::WGC3Denum); - virtual WebKit::WebGLId createTexture(); - - virtual void deleteBuffer(WebKit::WebGLId id); - virtual void deleteFramebuffer(WebKit::WebGLId id); - virtual void deleteProgram(WebKit::WebGLId id); - virtual void deleteRenderbuffer(WebKit::WebGLId id); - virtual void deleteShader(WebKit::WebGLId id); - virtual void deleteTexture(WebKit::WebGLId texture_id); - - virtual void texStorage2DEXT( - WebKit::WGC3Denum target, - WebKit::WGC3Dint levels, - WebKit::WGC3Duint internalformat, - WebKit::WGC3Dint width, - WebKit::WGC3Dint height) {} - - virtual WebKit::WebGLId createQueryEXT(); - virtual void deleteQueryEXT(WebKit::WebGLId query) {} - virtual WebKit::WGC3Dboolean isQueryEXT(WebKit::WebGLId query); - virtual void beginQueryEXT( - WebKit::WGC3Denum target, - WebKit::WebGLId query) {} - virtual void endQueryEXT(WebKit::WGC3Denum target); - virtual void getQueryivEXT( - WebKit::WGC3Denum target, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* params) {} - virtual void getQueryObjectuivEXT( - WebKit::WebGLId query, - WebKit::WGC3Denum pname, - WebKit::WGC3Duint* params); - - virtual void setContextLostCallback( - WebGraphicsContextLostCallback* callback); - - virtual void loseContextCHROMIUM(WebKit::WGC3Denum current, - WebKit::WGC3Denum other); - - virtual void drawBuffersEXT(WebKit::WGC3Dsizei m, - const WebKit::WGC3Denum* bufs) {} - - virtual void bindTexImage2DCHROMIUM(WebKit::WGC3Denum target, - WebKit::WGC3Dint image_id) {} - - // GL_CHROMIUM_gpu_memory_buffer - virtual WebKit::WGC3Duint createImageCHROMIUM( - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height, - WebKit::WGC3Denum internalformat); - virtual void destroyImageCHROMIUM(WebKit::WGC3Duint image_id) {} - virtual void getImageParameterivCHROMIUM( - WebKit::WGC3Duint image_id, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* params) {} - virtual void* mapImageCHROMIUM( - WebKit::WGC3Duint image_id, - WebKit::WGC3Denum access); - virtual void unmapImageCHROMIUM(WebKit::WGC3Duint image_id) {} - - private: - DISALLOW_COPY_AND_ASSIGN(FakeWebGraphicsContext3D); -}; - -} // namespace cc - -#endif // CC_DEBUG_FAKE_WEB_GRAPHICS_CONTEXT_3D_H_ diff --git a/chromium/cc/debug/layer_tree_debug_state.cc b/chromium/cc/debug/layer_tree_debug_state.cc index 72c3a9ff18c..95245e0f0b2 100644 --- a/chromium/cc/debug/layer_tree_debug_state.cc +++ b/chromium/cc/debug/layer_tree_debug_state.cc @@ -23,6 +23,7 @@ LayerTreeDebugState::LayerTreeDebugState() show_touch_event_handler_rects(false), show_wheel_event_handler_rects(false), show_non_fast_scrollable_rects(false), + show_layer_animation_bounds_rects(false), slow_down_raster_scale_factor(0), rasterize_only_visible_content(false), show_picture_borders(false), @@ -48,7 +49,8 @@ bool LayerTreeDebugState::ShowHudRects() const { show_surface_damage_rects || show_screen_space_rects || show_replica_screen_space_rects || show_occluding_rects || show_non_occluding_rects || show_touch_event_handler_rects || - show_wheel_event_handler_rects || show_non_fast_scrollable_rects; + show_wheel_event_handler_rects || show_non_fast_scrollable_rects || + show_layer_animation_bounds_rects; } bool LayerTreeDebugState::ShowMemoryStats() const { @@ -74,6 +76,8 @@ bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a, b.show_wheel_event_handler_rects && a.show_non_fast_scrollable_rects == b.show_non_fast_scrollable_rects && + a.show_layer_animation_bounds_rects == + b.show_layer_animation_bounds_rects && a.slow_down_raster_scale_factor == b.slow_down_raster_scale_factor && a.rasterize_only_visible_content == b.rasterize_only_visible_content && @@ -99,6 +103,7 @@ LayerTreeDebugState LayerTreeDebugState::Unite(const LayerTreeDebugState& a, r.show_touch_event_handler_rects |= b.show_touch_event_handler_rects; r.show_wheel_event_handler_rects |= b.show_wheel_event_handler_rects; r.show_non_fast_scrollable_rects |= b.show_non_fast_scrollable_rects; + r.show_layer_animation_bounds_rects |= b.show_layer_animation_bounds_rects; if (b.slow_down_raster_scale_factor) r.slow_down_raster_scale_factor = b.slow_down_raster_scale_factor; diff --git a/chromium/cc/debug/layer_tree_debug_state.h b/chromium/cc/debug/layer_tree_debug_state.h index 1233a4e36f0..24196de13d6 100644 --- a/chromium/cc/debug/layer_tree_debug_state.h +++ b/chromium/cc/debug/layer_tree_debug_state.h @@ -29,6 +29,7 @@ class CC_EXPORT LayerTreeDebugState { bool show_touch_event_handler_rects; bool show_wheel_event_handler_rects; bool show_non_fast_scrollable_rects; + bool show_layer_animation_bounds_rects; int slow_down_raster_scale_factor; bool rasterize_only_visible_content; diff --git a/chromium/cc/debug/micro_benchmark.cc b/chromium/cc/debug/micro_benchmark.cc new file mode 100644 index 00000000000..464d0cb625d --- /dev/null +++ b/chromium/cc/debug/micro_benchmark.cc @@ -0,0 +1,54 @@ +// Copyright 2013 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 "cc/debug/micro_benchmark.h" + +#include "base/callback.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/values.h" +#include "cc/debug/micro_benchmark_impl.h" + +namespace cc { + +MicroBenchmark::MicroBenchmark(const DoneCallback& callback) + : callback_(callback), + is_done_(false), + processed_for_benchmark_impl_(false) {} + +MicroBenchmark::~MicroBenchmark() {} + +bool MicroBenchmark::IsDone() const { + return is_done_; +} + +void MicroBenchmark::DidUpdateLayers(LayerTreeHost* host) {} + +void MicroBenchmark::NotifyDone(scoped_ptr<base::Value> result) { + callback_.Run(result.Pass()); + is_done_ = true; +} + +void MicroBenchmark::RunOnLayer(Layer* layer) {} + +void MicroBenchmark::RunOnLayer(PictureLayer* layer) {} + +bool MicroBenchmark::ProcessedForBenchmarkImpl() const { + return processed_for_benchmark_impl_; +} + +scoped_ptr<MicroBenchmarkImpl> MicroBenchmark::GetBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop) { + DCHECK(!processed_for_benchmark_impl_); + processed_for_benchmark_impl_ = true; + return CreateBenchmarkImpl(origin_loop); +} + +scoped_ptr<MicroBenchmarkImpl> MicroBenchmark::CreateBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop) { + return make_scoped_ptr<MicroBenchmarkImpl>(NULL); +} + +} // namespace cc diff --git a/chromium/cc/debug/micro_benchmark.h b/chromium/cc/debug/micro_benchmark.h new file mode 100644 index 00000000000..f179fb9544d --- /dev/null +++ b/chromium/cc/debug/micro_benchmark.h @@ -0,0 +1,54 @@ +// Copyright 2013 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 CC_DEBUG_MICRO_BENCHMARK_H_ +#define CC_DEBUG_MICRO_BENCHMARK_H_ + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" + +namespace base { +class Value; +class MessageLoopProxy; +} // namespace base + +namespace cc { + +class LayerTreeHost; +class Layer; +class PictureLayer; +class MicroBenchmarkImpl; +class CC_EXPORT MicroBenchmark { + public: + typedef base::Callback<void(scoped_ptr<base::Value>)> DoneCallback; + + explicit MicroBenchmark(const DoneCallback& callback); + virtual ~MicroBenchmark(); + + bool IsDone() const; + virtual void DidUpdateLayers(LayerTreeHost* host); + + virtual void RunOnLayer(Layer* layer); + virtual void RunOnLayer(PictureLayer* layer); + + bool ProcessedForBenchmarkImpl() const; + scoped_ptr<MicroBenchmarkImpl> GetBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop); + + protected: + void NotifyDone(scoped_ptr<base::Value> result); + + virtual scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop); + + private: + DoneCallback callback_; + bool is_done_; + bool processed_for_benchmark_impl_; +}; + +} // namespace cc + +#endif // CC_DEBUG_MICRO_BENCHMARK_H_ diff --git a/chromium/cc/debug/micro_benchmark_controller.cc b/chromium/cc/debug/micro_benchmark_controller.cc new file mode 100644 index 00000000000..7d9025c1c42 --- /dev/null +++ b/chromium/cc/debug/micro_benchmark_controller.cc @@ -0,0 +1,106 @@ +// Copyright 2013 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 "cc/debug/micro_benchmark_controller.h" + +#include <string> + +#include "base/callback.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/values.h" +#include "cc/debug/picture_record_benchmark.h" +#include "cc/debug/rasterize_and_record_benchmark.h" +#include "cc/debug/unittest_only_benchmark.h" +#include "cc/trees/layer_tree_host.h" +#include "cc/trees/layer_tree_host_impl.h" + +namespace cc { + +namespace { + +scoped_ptr<MicroBenchmark> CreateBenchmark( + const std::string& name, + scoped_ptr<base::Value> value, + const MicroBenchmark::DoneCallback& callback) { + if (name == "picture_record_benchmark") { + return scoped_ptr<MicroBenchmark>( + new PictureRecordBenchmark(value.Pass(), callback)); + } else if (name == "rasterize_and_record_benchmark") { + return scoped_ptr<MicroBenchmark>( + new RasterizeAndRecordBenchmark(value.Pass(), callback)); + } else if (name == "unittest_only_benchmark") { + return scoped_ptr<MicroBenchmark>( + new UnittestOnlyBenchmark(value.Pass(), callback)); + } + return scoped_ptr<MicroBenchmark>(); +} + +class IsDonePredicate { + public: + typedef const MicroBenchmark* argument_type; + typedef bool result_type; + + result_type operator()(argument_type benchmark) const { + return benchmark->IsDone(); + } +}; + +} // namespace + +MicroBenchmarkController::MicroBenchmarkController(LayerTreeHost* host) + : host_(host), + main_controller_message_loop_(base::MessageLoopProxy::current().get()) { + DCHECK(host_); +} + +MicroBenchmarkController::~MicroBenchmarkController() {} + +bool MicroBenchmarkController::ScheduleRun( + const std::string& micro_benchmark_name, + scoped_ptr<base::Value> value, + const MicroBenchmark::DoneCallback& callback) { + scoped_ptr<MicroBenchmark> benchmark = + CreateBenchmark(micro_benchmark_name, value.Pass(), callback); + if (benchmark.get()) { + benchmarks_.push_back(benchmark.Pass()); + host_->SetNeedsCommit(); + return true; + } + return false; +} + +void MicroBenchmarkController::ScheduleImplBenchmarks( + LayerTreeHostImpl* host_impl) { + for (ScopedPtrVector<MicroBenchmark>::iterator it = benchmarks_.begin(); + it != benchmarks_.end(); + ++it) { + scoped_ptr<MicroBenchmarkImpl> benchmark_impl; + if (!(*it)->ProcessedForBenchmarkImpl()) { + benchmark_impl = + (*it)->GetBenchmarkImpl(main_controller_message_loop_); + } + + if (benchmark_impl.get()) + host_impl->ScheduleMicroBenchmark(benchmark_impl.Pass()); + } +} + +void MicroBenchmarkController::DidUpdateLayers() { + for (ScopedPtrVector<MicroBenchmark>::iterator it = benchmarks_.begin(); + it != benchmarks_.end(); + ++it) { + if (!(*it)->IsDone()) + (*it)->DidUpdateLayers(host_); + } + + CleanUpFinishedBenchmarks(); +} + +void MicroBenchmarkController::CleanUpFinishedBenchmarks() { + benchmarks_.erase( + benchmarks_.partition(std::not1(IsDonePredicate())), + benchmarks_.end()); +} + +} // namespace cc diff --git a/chromium/cc/debug/micro_benchmark_controller.h b/chromium/cc/debug/micro_benchmark_controller.h new file mode 100644 index 00000000000..7220dc1778f --- /dev/null +++ b/chromium/cc/debug/micro_benchmark_controller.h @@ -0,0 +1,49 @@ +// Copyright 2013 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 CC_DEBUG_MICRO_BENCHMARK_CONTROLLER_H_ +#define CC_DEBUG_MICRO_BENCHMARK_CONTROLLER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "cc/base/scoped_ptr_vector.h" +#include "cc/debug/micro_benchmark.h" + +namespace base { +class Value; +class MessageLoopProxy; +} // namespace base + +namespace cc { + +class LayerTreeHost; +class LayerTreeHostImpl; +class CC_EXPORT MicroBenchmarkController { + public: + explicit MicroBenchmarkController(LayerTreeHost* host); + ~MicroBenchmarkController(); + + void DidUpdateLayers(); + + bool ScheduleRun(const std::string& micro_benchmark_name, + scoped_ptr<base::Value> value, + const MicroBenchmark::DoneCallback& callback); + + void ScheduleImplBenchmarks(LayerTreeHostImpl* host_impl); + + private: + void CleanUpFinishedBenchmarks(); + + LayerTreeHost* host_; + ScopedPtrVector<MicroBenchmark> benchmarks_; + scoped_refptr<base::MessageLoopProxy> main_controller_message_loop_; + + DISALLOW_COPY_AND_ASSIGN(MicroBenchmarkController); +}; + +} // namespace cc + +#endif // CC_DEBUG_MICRO_BENCHMARK_CONTROLLER_H_ diff --git a/chromium/cc/debug/micro_benchmark_controller_impl.cc b/chromium/cc/debug/micro_benchmark_controller_impl.cc new file mode 100644 index 00000000000..821ba5f8d44 --- /dev/null +++ b/chromium/cc/debug/micro_benchmark_controller_impl.cc @@ -0,0 +1,59 @@ +// Copyright 2013 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 "cc/debug/micro_benchmark_controller_impl.h" + +#include <string> + +#include "base/callback.h" +#include "base/values.h" +#include "cc/trees/layer_tree_host_impl.h" + +namespace cc { + +namespace { + +class IsDonePredicate { + public: + typedef const MicroBenchmarkImpl* argument_type; + typedef bool result_type; + + result_type operator()(argument_type benchmark) const { + return benchmark->IsDone(); + } +}; + +} // namespace + +MicroBenchmarkControllerImpl::MicroBenchmarkControllerImpl( + LayerTreeHostImpl* host) + : host_(host) { + DCHECK(host_); +} + +MicroBenchmarkControllerImpl::~MicroBenchmarkControllerImpl() {} + +void MicroBenchmarkControllerImpl::ScheduleRun( + scoped_ptr<MicroBenchmarkImpl> benchmark) { + benchmarks_.push_back(benchmark.Pass()); +} + +void MicroBenchmarkControllerImpl::DidCompleteCommit() { + for (ScopedPtrVector<MicroBenchmarkImpl>::iterator it = benchmarks_.begin(); + it != benchmarks_.end(); + ++it) { + DCHECK(!(*it)->IsDone()); + (*it)->DidCompleteCommit(host_); + } + + CleanUpFinishedBenchmarks(); +} + +void MicroBenchmarkControllerImpl::CleanUpFinishedBenchmarks() { + benchmarks_.erase( + benchmarks_.partition(std::not1(IsDonePredicate())), + benchmarks_.end()); +} + +} // namespace cc diff --git a/chromium/cc/debug/micro_benchmark_controller_impl.h b/chromium/cc/debug/micro_benchmark_controller_impl.h new file mode 100644 index 00000000000..734bf63ce6b --- /dev/null +++ b/chromium/cc/debug/micro_benchmark_controller_impl.h @@ -0,0 +1,37 @@ +// Copyright 2013 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 CC_DEBUG_MICRO_BENCHMARK_CONTROLLER_IMPL_H_ +#define CC_DEBUG_MICRO_BENCHMARK_CONTROLLER_IMPL_H_ + +#include <string> + +#include "base/basictypes.h" +#include "cc/base/scoped_ptr_vector.h" +#include "cc/debug/micro_benchmark_impl.h" + +namespace cc { + +class LayerTreeHostImpl; +class CC_EXPORT MicroBenchmarkControllerImpl { + public: + explicit MicroBenchmarkControllerImpl(LayerTreeHostImpl* host); + ~MicroBenchmarkControllerImpl(); + + void DidCompleteCommit(); + + void ScheduleRun(scoped_ptr<MicroBenchmarkImpl> benchmark); + + private: + void CleanUpFinishedBenchmarks(); + + LayerTreeHostImpl* host_; + ScopedPtrVector<MicroBenchmarkImpl> benchmarks_; + + DISALLOW_COPY_AND_ASSIGN(MicroBenchmarkControllerImpl); +}; + +} // namespace cc + +#endif // CC_DEBUG_MICRO_BENCHMARK_CONTROLLER_IMPL_H_ diff --git a/chromium/cc/debug/micro_benchmark_controller_unittest.cc b/chromium/cc/debug/micro_benchmark_controller_unittest.cc new file mode 100644 index 00000000000..4894947a6da --- /dev/null +++ b/chromium/cc/debug/micro_benchmark_controller_unittest.cc @@ -0,0 +1,141 @@ +// Copyright 2013 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 "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "cc/debug/micro_benchmark.h" +#include "cc/debug/micro_benchmark_controller.h" +#include "cc/layers/layer.h" +#include "cc/resources/resource_update_queue.h" +#include "cc/test/fake_layer_tree_host.h" +#include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/fake_proxy.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +class MicroBenchmarkControllerTest : public testing::Test { + public: + virtual void SetUp() OVERRIDE { + impl_proxy_ = make_scoped_ptr(new FakeImplProxy); + layer_tree_host_impl_ = + make_scoped_ptr(new FakeLayerTreeHostImpl(impl_proxy_.get())); + + layer_tree_host_ = FakeLayerTreeHost::Create(); + layer_tree_host_->SetRootLayer(Layer::Create()); + layer_tree_host_->InitializeForTesting(scoped_ptr<Proxy>(new FakeProxy)); + } + + virtual void TearDown() OVERRIDE { + layer_tree_host_impl_.reset(); + layer_tree_host_.reset(); + impl_proxy_.reset(); + } + + scoped_ptr<FakeLayerTreeHost> layer_tree_host_; + scoped_ptr<FakeLayerTreeHostImpl> layer_tree_host_impl_; + scoped_ptr<FakeImplProxy> impl_proxy_; +}; + +void Noop(scoped_ptr<base::Value> value) { +} + +void IncrementCallCount(int* count, scoped_ptr<base::Value> value) { + ++(*count); +} + +TEST_F(MicroBenchmarkControllerTest, ScheduleFail) { + bool result = layer_tree_host_->ScheduleMicroBenchmark( + "non_existant_benchmark", scoped_ptr<base::Value>(), base::Bind(&Noop)); + EXPECT_FALSE(result); +} + +TEST_F(MicroBenchmarkControllerTest, CommitScheduled) { + EXPECT_FALSE(layer_tree_host_->needs_commit()); + bool result = layer_tree_host_->ScheduleMicroBenchmark( + "unittest_only_benchmark", scoped_ptr<base::Value>(), base::Bind(&Noop)); + EXPECT_TRUE(result); + EXPECT_TRUE(layer_tree_host_->needs_commit()); +} + +TEST_F(MicroBenchmarkControllerTest, BenchmarkRan) { + int run_count = 0; + bool result = layer_tree_host_->ScheduleMicroBenchmark( + "unittest_only_benchmark", + scoped_ptr<base::Value>(), + base::Bind(&IncrementCallCount, base::Unretained(&run_count))); + EXPECT_TRUE(result); + + scoped_ptr<ResourceUpdateQueue> queue(new ResourceUpdateQueue); + layer_tree_host_->SetOutputSurfaceLostForTesting(false); + layer_tree_host_->UpdateLayers(queue.get()); + + EXPECT_EQ(1, run_count); +} + +TEST_F(MicroBenchmarkControllerTest, MultipleBenchmarkRan) { + int run_count = 0; + bool result = layer_tree_host_->ScheduleMicroBenchmark( + "unittest_only_benchmark", + scoped_ptr<base::Value>(), + base::Bind(&IncrementCallCount, base::Unretained(&run_count))); + EXPECT_TRUE(result); + result = layer_tree_host_->ScheduleMicroBenchmark( + "unittest_only_benchmark", + scoped_ptr<base::Value>(), + base::Bind(&IncrementCallCount, base::Unretained(&run_count))); + EXPECT_TRUE(result); + + scoped_ptr<ResourceUpdateQueue> queue(new ResourceUpdateQueue); + layer_tree_host_->SetOutputSurfaceLostForTesting(false); + layer_tree_host_->UpdateLayers(queue.get()); + + EXPECT_EQ(2, run_count); + + result = layer_tree_host_->ScheduleMicroBenchmark( + "unittest_only_benchmark", + scoped_ptr<base::Value>(), + base::Bind(&IncrementCallCount, base::Unretained(&run_count))); + EXPECT_TRUE(result); + result = layer_tree_host_->ScheduleMicroBenchmark( + "unittest_only_benchmark", + scoped_ptr<base::Value>(), + base::Bind(&IncrementCallCount, base::Unretained(&run_count))); + EXPECT_TRUE(result); + + layer_tree_host_->UpdateLayers(queue.get()); + EXPECT_EQ(4, run_count); + + layer_tree_host_->UpdateLayers(queue.get()); + EXPECT_EQ(4, run_count); +} + +TEST_F(MicroBenchmarkControllerTest, BenchmarkImplRan) { + int run_count = 0; + scoped_ptr<base::DictionaryValue> settings(new base::DictionaryValue); + settings->SetBoolean("run_benchmark_impl", true); + + // Schedule a main thread benchmark. + bool result = layer_tree_host_->ScheduleMicroBenchmark( + "unittest_only_benchmark", + settings.PassAs<base::Value>(), + base::Bind(&IncrementCallCount, base::Unretained(&run_count))); + EXPECT_TRUE(result); + + // Schedule impl benchmarks. In production code, this is run in commit. + layer_tree_host_->GetMicroBenchmarkController()->ScheduleImplBenchmarks( + layer_tree_host_impl_.get()); + + // Now complete the commit (as if on the impl thread). + layer_tree_host_impl_->CommitComplete(); + + // Make sure all posted messages run. + base::MessageLoop::current()->RunUntilIdle(); + + EXPECT_EQ(1, run_count); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/debug/micro_benchmark_impl.cc b/chromium/cc/debug/micro_benchmark_impl.cc new file mode 100644 index 00000000000..7ec58c8de0b --- /dev/null +++ b/chromium/cc/debug/micro_benchmark_impl.cc @@ -0,0 +1,48 @@ +// Copyright 2013 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 "cc/debug/micro_benchmark_impl.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/values.h" + +namespace cc { + +namespace { + +void RunCallback(const MicroBenchmarkImpl::DoneCallback& callback, + scoped_ptr<base::Value> result) { + callback.Run(result.Pass()); +} + +} + +MicroBenchmarkImpl::MicroBenchmarkImpl( + const DoneCallback& callback, + scoped_refptr<base::MessageLoopProxy> origin_loop) + : callback_(callback), is_done_(false), origin_loop_(origin_loop) {} + +MicroBenchmarkImpl::~MicroBenchmarkImpl() {} + +bool MicroBenchmarkImpl::IsDone() const { + return is_done_; +} + +void MicroBenchmarkImpl::DidCompleteCommit(LayerTreeHostImpl* host) {} + +void MicroBenchmarkImpl::NotifyDone(scoped_ptr<base::Value> result) { + origin_loop_->PostTask( + FROM_HERE, + base::Bind(RunCallback, callback_, base::Passed(&result))); + is_done_ = true; +} + +void MicroBenchmarkImpl::RunOnLayer(LayerImpl* layer) {} + +void MicroBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) {} + +} // namespace cc diff --git a/chromium/cc/debug/micro_benchmark_impl.h b/chromium/cc/debug/micro_benchmark_impl.h new file mode 100644 index 00000000000..4f3f74f6516 --- /dev/null +++ b/chromium/cc/debug/micro_benchmark_impl.h @@ -0,0 +1,48 @@ +// Copyright 2013 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 CC_DEBUG_MICRO_BENCHMARK_IMPL_H_ +#define CC_DEBUG_MICRO_BENCHMARK_IMPL_H_ + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" + +namespace base { +class Value; +class MessageLoopProxy; +} // namespace base + +namespace cc { + +class LayerTreeHostImpl; +class LayerImpl; +class PictureLayerImpl; +class CC_EXPORT MicroBenchmarkImpl { + public: + typedef base::Callback<void(scoped_ptr<base::Value>)> DoneCallback; + + explicit MicroBenchmarkImpl( + const DoneCallback& callback, + scoped_refptr<base::MessageLoopProxy> origin_loop); + virtual ~MicroBenchmarkImpl(); + + bool IsDone() const; + virtual void DidCompleteCommit(LayerTreeHostImpl* host); + + virtual void RunOnLayer(LayerImpl* layer); + virtual void RunOnLayer(PictureLayerImpl* layer); + + protected: + void NotifyDone(scoped_ptr<base::Value> result); + + private: + DoneCallback callback_; + bool is_done_; + scoped_refptr<base::MessageLoopProxy> origin_loop_; +}; + +} // namespace cc + +#endif // CC_DEBUG_MICRO_BENCHMARK_IMPL_H_ diff --git a/chromium/cc/debug/picture_record_benchmark.cc b/chromium/cc/debug/picture_record_benchmark.cc new file mode 100644 index 00000000000..430d1d0bcd9 --- /dev/null +++ b/chromium/cc/debug/picture_record_benchmark.cc @@ -0,0 +1,126 @@ +// Copyright 2013 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 "cc/debug/picture_record_benchmark.h" + +#include <algorithm> + +#include "base/basictypes.h" +#include "base/values.h" +#include "cc/layers/layer.h" +#include "cc/layers/picture_layer.h" +#include "cc/trees/layer_tree_host.h" +#include "cc/trees/layer_tree_host_common.h" +#include "ui/gfx/rect.h" + +namespace cc { + +namespace { + +const int kPositionIncrement = 100; +const int kTileGridSize = 512; +const int kTileGridBorder = 1; + +} // namespace + +PictureRecordBenchmark::PictureRecordBenchmark( + scoped_ptr<base::Value> value, + const MicroBenchmark::DoneCallback& callback) + : MicroBenchmark(callback) { + if (!value) + return; + + base::ListValue* list = NULL; + value->GetAsList(&list); + if (!list) + return; + + for (base::ListValue::iterator it = list->begin(); it != list->end(); ++it) { + base::DictionaryValue* dictionary = NULL; + (*it)->GetAsDictionary(&dictionary); + if (!dictionary || + !dictionary->HasKey("width") || + !dictionary->HasKey("height")) + continue; + + int width, height; + dictionary->GetInteger("width", &width); + dictionary->GetInteger("height", &height); + + dimensions_.push_back(std::make_pair(width, height)); + } +} + +PictureRecordBenchmark::~PictureRecordBenchmark() {} + +void PictureRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) { + LayerTreeHostCommon::CallFunctionForSubtree( + host->root_layer(), + base::Bind(&PictureRecordBenchmark::Run, base::Unretained(this))); + + scoped_ptr<base::ListValue> results(new base::ListValue()); + for (std::map<std::pair<int, int>, TotalTime>::iterator it = times_.begin(); + it != times_.end(); + ++it) { + std::pair<int, int> dimensions = it->first; + base::TimeDelta total_time = it->second.first; + unsigned total_count = it->second.second; + + double average_time = 0.0; + if (total_count > 0) + average_time = total_time.InMillisecondsF() / total_count; + + scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); + result->SetInteger("width", dimensions.first); + result->SetInteger("height", dimensions.second); + result->SetInteger("samples_count", total_count); + result->SetDouble("time_ms", average_time); + + results->Append(result.release()); + } + + NotifyDone(results.PassAs<base::Value>()); +} + +void PictureRecordBenchmark::Run(Layer* layer) { + layer->RunMicroBenchmark(this); +} + +void PictureRecordBenchmark::RunOnLayer(PictureLayer* layer) { + ContentLayerClient* painter = layer->client(); + gfx::Size content_bounds = layer->content_bounds(); + + SkTileGridPicture::TileGridInfo tile_grid_info; + tile_grid_info.fTileInterval.set(kTileGridSize - 2 * kTileGridBorder, + kTileGridSize - 2 * kTileGridBorder); + tile_grid_info.fMargin.set(kTileGridBorder, kTileGridBorder); + tile_grid_info.fOffset.set(-kTileGridBorder, -kTileGridBorder); + + for (size_t i = 0; i < dimensions_.size(); ++i) { + std::pair<int, int> dimensions = dimensions_[i]; + int width = dimensions.first; + int height = dimensions.second; + + int y_limit = std::max(1, content_bounds.height() - height); + int x_limit = std::max(1, content_bounds.width() - width); + for (int y = 0; y < y_limit; y += kPositionIncrement) { + for (int x = 0; x < x_limit; x += kPositionIncrement) { + gfx::Rect rect = gfx::Rect(x, y, width, height); + + base::TimeTicks start = base::TimeTicks::HighResNow(); + + scoped_refptr<Picture> picture = Picture::Create(rect); + picture->Record(painter, tile_grid_info); + + base::TimeTicks end = base::TimeTicks::HighResNow(); + base::TimeDelta duration = end - start; + TotalTime& total_time = times_[dimensions]; + total_time.first += duration; + total_time.second++; + } + } + } +} + +} // namespace cc diff --git a/chromium/cc/debug/picture_record_benchmark.h b/chromium/cc/debug/picture_record_benchmark.h new file mode 100644 index 00000000000..89f2bc0781e --- /dev/null +++ b/chromium/cc/debug/picture_record_benchmark.h @@ -0,0 +1,39 @@ +// Copyright 2013 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 CC_DEBUG_PICTURE_RECORD_BENCHMARK_H_ +#define CC_DEBUG_PICTURE_RECORD_BENCHMARK_H_ + +#include <map> +#include <utility> +#include <vector> + +#include "base/time/time.h" +#include "cc/debug/micro_benchmark_controller.h" + +namespace cc { + +class LayerTreeHost; +class Layer; +class CC_EXPORT PictureRecordBenchmark : public MicroBenchmark { + public: + explicit PictureRecordBenchmark(scoped_ptr<base::Value> value, + const MicroBenchmark::DoneCallback& callback); + virtual ~PictureRecordBenchmark(); + + // Implements MicroBenchmark interface. + virtual void DidUpdateLayers(LayerTreeHost* host) OVERRIDE; + virtual void RunOnLayer(PictureLayer* layer) OVERRIDE; + + private: + void Run(Layer* layer); + + typedef std::pair<base::TimeDelta, unsigned> TotalTime; + std::map<std::pair<int, int>, TotalTime> times_; + std::vector<std::pair<int, int> > dimensions_; +}; + +} // namespace cc + +#endif // CC_DEBUG_PICTURE_RECORD_BENCHMARK_H_ diff --git a/chromium/cc/debug/rasterize_and_record_benchmark.cc b/chromium/cc/debug/rasterize_and_record_benchmark.cc new file mode 100644 index 00000000000..4646afd6bce --- /dev/null +++ b/chromium/cc/debug/rasterize_and_record_benchmark.cc @@ -0,0 +1,142 @@ +// Copyright 2013 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 "cc/debug/rasterize_and_record_benchmark.h" + +#include <algorithm> +#include <limits> + +#include "base/basictypes.h" +#include "base/values.h" +#include "cc/debug/rasterize_and_record_benchmark_impl.h" +#include "cc/layers/layer.h" +#include "cc/layers/picture_layer.h" +#include "cc/trees/layer_tree_host.h" +#include "cc/trees/layer_tree_host_common.h" +#include "ui/gfx/rect.h" + +namespace cc { + +namespace { + +const int kDefaultRecordRepeatCount = 100; + +base::TimeTicks Now() { + return base::TimeTicks::IsThreadNowSupported() + ? base::TimeTicks::ThreadNow() + : base::TimeTicks::HighResNow(); +} + +} // namespace + +RasterizeAndRecordBenchmark::RasterizeAndRecordBenchmark( + scoped_ptr<base::Value> value, + const MicroBenchmark::DoneCallback& callback) + : MicroBenchmark(callback), + record_repeat_count_(kDefaultRecordRepeatCount), + settings_(value.Pass()), + main_thread_benchmark_done_(false), + host_(NULL), + weak_ptr_factory_(this) { + base::DictionaryValue* settings = NULL; + settings_->GetAsDictionary(&settings); + if (!settings) + return; + + if (settings->HasKey("record_repeat_count")) + settings->GetInteger("record_repeat_count", &record_repeat_count_); +} + +RasterizeAndRecordBenchmark::~RasterizeAndRecordBenchmark() { + weak_ptr_factory_.InvalidateWeakPtrs(); +} + +void RasterizeAndRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) { + host_ = host; + LayerTreeHostCommon::CallFunctionForSubtree( + host->root_layer(), + base::Bind(&RasterizeAndRecordBenchmark::Run, base::Unretained(this))); + + DCHECK(!results_.get()); + results_ = make_scoped_ptr(new base::DictionaryValue); + results_->SetInteger("pixels_recorded", record_results_.pixels_recorded); + results_->SetDouble("record_time_ms", + record_results_.total_best_time.InMillisecondsF()); + main_thread_benchmark_done_ = true; +} + +void RasterizeAndRecordBenchmark::RecordRasterResults( + scoped_ptr<base::Value> results_value) { + DCHECK(main_thread_benchmark_done_); + + base::DictionaryValue* results = NULL; + results_value->GetAsDictionary(&results); + + DCHECK(results); + DCHECK(results->HasKey("pixels_rasterized")); + DCHECK(results->HasKey("rasterize_time_ms")); + + int pixels_rasterized; + results->GetInteger("pixels_rasterized", &pixels_rasterized); + double rasterize_time_ms; + results->GetDouble("rasterize_time_ms", &rasterize_time_ms); + + results_->SetInteger("pixels_rasterized", pixels_rasterized); + results_->SetDouble("rasterize_time_ms", rasterize_time_ms); + + NotifyDone(results_.PassAs<base::Value>()); +} + +scoped_ptr<MicroBenchmarkImpl> RasterizeAndRecordBenchmark::CreateBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop) { + return scoped_ptr<MicroBenchmarkImpl>(new RasterizeAndRecordBenchmarkImpl( + origin_loop, + settings_.get(), + base::Bind(&RasterizeAndRecordBenchmark::RecordRasterResults, + weak_ptr_factory_.GetWeakPtr()))); +} + +void RasterizeAndRecordBenchmark::Run(Layer* layer) { + layer->RunMicroBenchmark(this); +} + +void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) { + ContentLayerClient* painter = layer->client(); + gfx::Size content_bounds = layer->content_bounds(); + + DCHECK(host_); + gfx::Size tile_grid_size = host_->settings().default_tile_size; + + SkTileGridPicture::TileGridInfo tile_grid_info; + PicturePileBase::ComputeTileGridInfo(tile_grid_size, &tile_grid_info); + + gfx::Rect visible_content_rect = gfx::ScaleToEnclosingRect( + layer->visible_content_rect(), 1.f / layer->contents_scale_x()); + if (visible_content_rect.IsEmpty()) + return; + + scoped_refptr<Picture> picture = Picture::Create(visible_content_rect); + + base::TimeDelta min_time = + base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max()); + for (int i = 0; i < record_repeat_count_; ++i) { + base::TimeTicks start = Now(); + picture->Record(painter, tile_grid_info); + base::TimeTicks end = Now(); + base::TimeDelta duration = end - start; + if (duration < min_time) + min_time = duration; + } + + record_results_.pixels_recorded += + visible_content_rect.width() * visible_content_rect.height(); + record_results_.total_best_time += min_time; +} + +RasterizeAndRecordBenchmark::RecordResults::RecordResults() + : pixels_recorded(0) {} + +RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {} + +} // namespace cc diff --git a/chromium/cc/debug/rasterize_and_record_benchmark.h b/chromium/cc/debug/rasterize_and_record_benchmark.h new file mode 100644 index 00000000000..2cea16a2f4e --- /dev/null +++ b/chromium/cc/debug/rasterize_and_record_benchmark.h @@ -0,0 +1,66 @@ +// Copyright 2013 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 CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_H_ +#define CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_H_ + +#include <map> +#include <utility> +#include <vector> + +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "cc/debug/micro_benchmark_controller.h" + +namespace base { +class DictionaryValue; +} + +namespace cc { + +class LayerTreeHost; +class Layer; +class RasterizeAndRecordBenchmark : public MicroBenchmark { + public: + explicit RasterizeAndRecordBenchmark( + scoped_ptr<base::Value> value, + const MicroBenchmark::DoneCallback& callback); + virtual ~RasterizeAndRecordBenchmark(); + + // Implements MicroBenchmark interface. + virtual void DidUpdateLayers(LayerTreeHost* host) OVERRIDE; + virtual void RunOnLayer(PictureLayer* layer) OVERRIDE; + + virtual scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop) OVERRIDE; + + private: + void Run(Layer* layer); + + void RecordRasterResults(scoped_ptr<base::Value> results); + + struct RecordResults { + RecordResults(); + ~RecordResults(); + + int pixels_recorded; + base::TimeDelta total_best_time; + }; + + RecordResults record_results_; + int record_repeat_count_; + scoped_ptr<base::Value> settings_; + scoped_ptr<base::DictionaryValue> results_; + + // The following is used in DCHECKs. + bool main_thread_benchmark_done_; + + LayerTreeHost* host_; + + base::WeakPtrFactory<RasterizeAndRecordBenchmark> weak_ptr_factory_; +}; + +} // namespace cc + +#endif // CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_H_ diff --git a/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc b/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc new file mode 100644 index 00000000000..f2904a3bebf --- /dev/null +++ b/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc @@ -0,0 +1,120 @@ +// Copyright 2013 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 "cc/debug/rasterize_and_record_benchmark_impl.h" + +#include <algorithm> +#include <limits> + +#include "base/basictypes.h" +#include "base/values.h" +#include "cc/layers/layer_impl.h" +#include "cc/layers/picture_layer_impl.h" +#include "cc/trees/layer_tree_host_common.h" +#include "cc/trees/layer_tree_host_impl.h" +#include "ui/gfx/rect.h" + +namespace cc { + +namespace { + +const int kDefaultRasterizeRepeatCount = 100; + +base::TimeTicks Now() { + return base::TimeTicks::IsThreadNowSupported() + ? base::TimeTicks::ThreadNow() + : base::TimeTicks::HighResNow(); +} + +} // namespace + +RasterizeAndRecordBenchmarkImpl::RasterizeAndRecordBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop, + base::Value* value, + const MicroBenchmarkImpl::DoneCallback& callback) + : MicroBenchmarkImpl(callback, origin_loop), + rasterize_repeat_count_(kDefaultRasterizeRepeatCount) { + base::DictionaryValue* settings = NULL; + value->GetAsDictionary(&settings); + if (!settings) + return; + + if (settings->HasKey("rasterize_repeat_count")) + settings->GetInteger("rasterize_repeat_count", &rasterize_repeat_count_); +} + +RasterizeAndRecordBenchmarkImpl::~RasterizeAndRecordBenchmarkImpl() {} + +void RasterizeAndRecordBenchmarkImpl::DidCompleteCommit( + LayerTreeHostImpl* host) { + LayerTreeHostCommon::CallFunctionForSubtree( + host->RootLayer(), + base::Bind(&RasterizeAndRecordBenchmarkImpl::Run, + base::Unretained(this))); + + scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); + result->SetInteger("pixels_rasterized", rasterize_results_.pixels_rasterized); + result->SetDouble("rasterize_time_ms", + rasterize_results_.total_best_time.InMillisecondsF()); + + NotifyDone(result.PassAs<base::Value>()); +} + +void RasterizeAndRecordBenchmarkImpl::Run(LayerImpl* layer) { + layer->RunMicroBenchmark(this); +} + +void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) { + if (layer->visible_content_rect().IsEmpty()) + return; + + PictureLayerTilingSet tiling_set(layer, layer->content_bounds()); + + PictureLayerTiling* tiling = tiling_set.AddTiling(layer->contents_scale_x()); + tiling->CreateAllTilesForTesting(); + for (PictureLayerTiling::CoverageIterator it( + tiling, layer->contents_scale_x(), layer->visible_content_rect()); + it; + ++it) { + DCHECK(*it); + + PicturePileImpl* picture_pile = (*it)->picture_pile(); + gfx::Rect content_rect = (*it)->content_rect(); + float contents_scale = (*it)->contents_scale(); + + base::TimeDelta min_time = + base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max()); + for (int i = 0; i < rasterize_repeat_count_; ++i) { + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, + content_rect.width(), + content_rect.height()); + bitmap.allocPixels(); + + SkBitmapDevice device(bitmap); + SkCanvas canvas(&device); + PicturePileImpl::Analysis analysis; + + base::TimeTicks start = Now(); + picture_pile->AnalyzeInRect( + content_rect, contents_scale, &analysis, NULL); + picture_pile->RasterToBitmap(&canvas, content_rect, contents_scale, NULL); + base::TimeTicks end = Now(); + base::TimeDelta duration = end - start; + if (duration < min_time) + min_time = duration; + } + + rasterize_results_.pixels_rasterized += + content_rect.width() * content_rect.height(); + rasterize_results_.total_best_time += min_time; + } +} + +RasterizeAndRecordBenchmarkImpl::RasterizeResults::RasterizeResults() + : pixels_rasterized(0) {} + +RasterizeAndRecordBenchmarkImpl::RasterizeResults::~RasterizeResults() {} + +} // namespace cc diff --git a/chromium/cc/debug/rasterize_and_record_benchmark_impl.h b/chromium/cc/debug/rasterize_and_record_benchmark_impl.h new file mode 100644 index 00000000000..0f9de9ba4f4 --- /dev/null +++ b/chromium/cc/debug/rasterize_and_record_benchmark_impl.h @@ -0,0 +1,49 @@ +// Copyright 2013 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 CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_IMPL_H_ +#define CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_IMPL_H_ + +#include <map> +#include <utility> +#include <vector> + +#include "base/time/time.h" +#include "cc/debug/micro_benchmark_impl.h" + +namespace cc { + +class LayerTreeHostImpl; +class PictureLayerImpl; +class LayerImpl; +class RasterizeAndRecordBenchmarkImpl : public MicroBenchmarkImpl { + public: + explicit RasterizeAndRecordBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop, + base::Value* value, + const MicroBenchmarkImpl::DoneCallback& callback); + virtual ~RasterizeAndRecordBenchmarkImpl(); + + // Implements MicroBenchmark interface. + virtual void DidCompleteCommit(LayerTreeHostImpl* host) OVERRIDE; + virtual void RunOnLayer(PictureLayerImpl* layer) OVERRIDE; + + private: + void Run(LayerImpl* layer); + + struct RasterizeResults { + RasterizeResults(); + ~RasterizeResults(); + + int pixels_rasterized; + base::TimeDelta total_best_time; + }; + + RasterizeResults rasterize_results_; + int rasterize_repeat_count_; +}; + +} // namespace cc + +#endif // CC_DEBUG_RASTERIZE_AND_RECORD_BENCHMARK_IMPL_H_ diff --git a/chromium/cc/debug/rendering_stats.cc b/chromium/cc/debug/rendering_stats.cc index 64cf69e0fe3..abce5ae562b 100644 --- a/chromium/cc/debug/rendering_stats.cc +++ b/chromium/cc/debug/rendering_stats.cc @@ -8,184 +8,67 @@ namespace cc { MainThreadRenderingStats::MainThreadRenderingStats() - : animation_frame_count(0), - screen_frame_count(0), - commit_count(0), - painted_pixel_count(0), - recorded_pixel_count(0), - image_gathering_count(0) {} + : frame_count(0), + painted_pixel_count(0), + recorded_pixel_count(0) {} -ImplThreadRenderingStats::ImplThreadRenderingStats() - : screen_frame_count(0), - dropped_frame_count(0), - rasterized_pixel_count(0), - impl_thread_scroll_count(0), - main_thread_scroll_count(0), - drawn_layer_count(0), - missing_tile_count(0), - deferred_image_decode_count(0), - deferred_image_cache_hit_count(0), - tile_analysis_count(0), - solid_color_tile_analysis_count(0) {} - -void RenderingStats::EnumerateFields(Enumerator* enumerator) const { - enumerator->AddInt64("numAnimationFrames", - main_stats.animation_frame_count); - enumerator->AddInt64("numFramesSentToScreen", main_stats.screen_frame_count + - impl_stats.screen_frame_count); - enumerator->AddDouble("totalPaintTimeInSeconds", - main_stats.paint_time.InSecondsF()); - enumerator->AddDouble("totalRecordTimeInSeconds", - main_stats.record_time.InSecondsF()); - enumerator->AddDouble("totalCommitTimeInSeconds", - main_stats.commit_time.InSecondsF()); - enumerator->AddInt64("totalCommitCount", main_stats.commit_count); - enumerator->AddInt64("totalPixelsPainted", main_stats.painted_pixel_count); - enumerator->AddInt64("totalPixelsRecorded", main_stats.recorded_pixel_count); - enumerator->AddInt64("totalImageGatheringCount", - main_stats.image_gathering_count); - enumerator->AddDouble("totalImageGatheringTimeInSeconds", - main_stats.image_gathering_time.InSecondsF()); - enumerator->AddInt64("droppedFrameCount", impl_stats.dropped_frame_count); - enumerator->AddDouble("totalRasterizeTimeInSeconds", - impl_stats.rasterize_time.InSecondsF()); - enumerator->AddDouble( - "totalRasterizeTimeForNowBinsOnPendingTree", - impl_stats.rasterize_time_for_now_bins_on_pending_tree.InSecondsF()); - enumerator->AddDouble("bestRasterizeTimeInSeconds", - impl_stats.best_rasterize_time.InSecondsF()); - enumerator->AddInt64("totalPixelsRasterized", - impl_stats.rasterized_pixel_count); - enumerator->AddInt64("numImplThreadScrolls", - impl_stats.impl_thread_scroll_count); - enumerator->AddInt64("numMainThreadScrolls", - impl_stats.main_thread_scroll_count); - enumerator->AddInt64("numLayersDrawn", impl_stats.drawn_layer_count); - enumerator->AddInt64("numMissingTiles", impl_stats.missing_tile_count); - enumerator->AddInt64("totalDeferredImageDecodeCount", - impl_stats.deferred_image_decode_count); - enumerator->AddInt64("totalTilesAnalyzed", impl_stats.tile_analysis_count); - enumerator->AddInt64("solidColorTilesAnalyzed", - impl_stats.solid_color_tile_analysis_count); - enumerator->AddInt64("totalDeferredImageCacheHitCount", - impl_stats.deferred_image_cache_hit_count); - enumerator->AddDouble("totalDeferredImageDecodeTimeInSeconds", - impl_stats.deferred_image_decode_time.InSecondsF()); - enumerator->AddDouble("totalTileAnalysisTimeInSeconds", - impl_stats.tile_analysis_time.InSecondsF()); -} - -void MainThreadRenderingStats::IssueTraceEvent() const { - TRACE_EVENT_INSTANT1("benchmark", - "MainThreadRenderingStats::IssueTraceEvent", - TRACE_EVENT_SCOPE_THREAD, - "data", AsTraceableData()); -} - -scoped_ptr<base::debug::ConvertableToTraceFormat> +scoped_refptr<base::debug::ConvertableToTraceFormat> MainThreadRenderingStats::AsTraceableData() const { scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue()); - record_data->SetInteger("animation_frame_count", - animation_frame_count); - record_data->SetInteger("screen_frame_count", - screen_frame_count); - record_data->SetDouble("paint_time", - paint_time.InSecondsF()); - record_data->SetDouble("record_time", - record_time.InSecondsF()); - record_data->SetDouble("commit_time", - commit_time.InSecondsF()); - record_data->SetInteger("commit_count", - commit_count); - record_data->SetInteger("painted_pixel_count", - painted_pixel_count); - record_data->SetInteger("recorded_pixel_count", - recorded_pixel_count); - record_data->SetInteger("image_gathering_count", - image_gathering_count); - record_data->SetDouble("image_gathering_time", - image_gathering_time.InSecondsF()); + record_data->SetInteger("frame_count", frame_count); + record_data->SetDouble("paint_time", paint_time.InSecondsF()); + record_data->SetInteger("painted_pixel_count", painted_pixel_count); + record_data->SetDouble("record_time", record_time.InSecondsF()); + record_data->SetInteger("recorded_pixel_count", recorded_pixel_count); return TracedValue::FromValue(record_data.release()); } -void ImplThreadRenderingStats::IssueTraceEvent() const { - TRACE_EVENT_INSTANT1("benchmark", - "ImplThreadRenderingStats::IssueTraceEvent", - TRACE_EVENT_SCOPE_THREAD, - "data", AsTraceableData()); +void MainThreadRenderingStats::Add(const MainThreadRenderingStats& other) { + frame_count += other.frame_count; + paint_time += other.paint_time; + painted_pixel_count += other.painted_pixel_count; + record_time += other.record_time; + recorded_pixel_count += other.recorded_pixel_count; } -scoped_ptr<base::debug::ConvertableToTraceFormat> +ImplThreadRenderingStats::ImplThreadRenderingStats() + : frame_count(0), + rasterized_pixel_count(0) {} + +scoped_refptr<base::debug::ConvertableToTraceFormat> ImplThreadRenderingStats::AsTraceableData() const { scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue()); - record_data->SetInteger("screen_frame_count", - screen_frame_count); - record_data->SetInteger("dropped_frame_count", - dropped_frame_count); - record_data->SetDouble("rasterize_time", - rasterize_time.InSecondsF()); - record_data->SetDouble( - "rasterize_time_for_now_bins_on_pending_tree", - rasterize_time_for_now_bins_on_pending_tree.InSecondsF()); - record_data->SetDouble("best_rasterize_time", - best_rasterize_time.InSecondsF()); - record_data->SetInteger("rasterized_pixel_count", - rasterized_pixel_count); - record_data->SetInteger("impl_thread_scroll_count", - impl_thread_scroll_count); - record_data->SetInteger("main_thread_scroll_count", - main_thread_scroll_count); - record_data->SetInteger("drawn_layer_count", - drawn_layer_count); - record_data->SetInteger("missing_tile_count", - missing_tile_count); - record_data->SetInteger("deferred_image_decode_count", - deferred_image_decode_count); - record_data->SetInteger("deferred_image_cache_hit_count", - deferred_image_cache_hit_count); - record_data->SetInteger("tile_analysis_count", - tile_analysis_count); - record_data->SetInteger("solid_color_tile_analysis_count", - solid_color_tile_analysis_count); - record_data->SetDouble("deferred_image_decode_time", - deferred_image_decode_time.InSecondsF()); - record_data->SetDouble("tile_analysis_time", - tile_analysis_time.InSecondsF()); + record_data->SetInteger("frame_count", frame_count); + record_data->SetDouble("rasterize_time", rasterize_time.InSecondsF()); + record_data->SetInteger("rasterized_pixel_count", rasterized_pixel_count); return TracedValue::FromValue(record_data.release()); } - -void MainThreadRenderingStats::Add(const MainThreadRenderingStats& other) { - animation_frame_count += other.animation_frame_count; - screen_frame_count += other.screen_frame_count; - paint_time += other.paint_time; - record_time += other.record_time; - commit_time += other.commit_time; - commit_count += other.commit_count; - painted_pixel_count += other.painted_pixel_count; - recorded_pixel_count += other.recorded_pixel_count; - image_gathering_count += other.image_gathering_count; - image_gathering_time += other.image_gathering_time; -} - void ImplThreadRenderingStats::Add(const ImplThreadRenderingStats& other) { - screen_frame_count += other.screen_frame_count; - dropped_frame_count += other.dropped_frame_count; + frame_count += other.frame_count; rasterize_time += other.rasterize_time; - rasterize_time_for_now_bins_on_pending_tree += - other.rasterize_time_for_now_bins_on_pending_tree; - best_rasterize_time += other.best_rasterize_time; + analysis_time += other.analysis_time; rasterized_pixel_count += other.rasterized_pixel_count; - impl_thread_scroll_count += other.impl_thread_scroll_count; - main_thread_scroll_count += other.main_thread_scroll_count; - drawn_layer_count += other.drawn_layer_count; - missing_tile_count += other.missing_tile_count; - deferred_image_decode_count += other.deferred_image_decode_count; - deferred_image_cache_hit_count += other.deferred_image_cache_hit_count; - deferred_image_decode_time += other.deferred_image_decode_time; - tile_analysis_count += other.tile_analysis_count; - solid_color_tile_analysis_count += other.solid_color_tile_analysis_count; - tile_analysis_time += other.tile_analysis_time; +} + +void RenderingStats::EnumerateFields(Enumerator* enumerator) const { + enumerator->AddInt64("frameCount", + main_stats.frame_count + impl_stats.frame_count); + enumerator->AddDouble("paintTime", + main_stats.paint_time.InSecondsF()); + enumerator->AddInt64("paintedPixelCount", + main_stats.painted_pixel_count); + enumerator->AddDouble("recordTime", + main_stats.record_time.InSecondsF()); + enumerator->AddInt64("recordedPixelCount", + main_stats.recorded_pixel_count); + // Combine rasterization and analysis time as a precursor to combining + // them in the same step internally. + enumerator->AddDouble("rasterizeTime", + impl_stats.rasterize_time.InSecondsF() + + impl_stats.analysis_time.InSecondsF()); + enumerator->AddInt64("rasterizedPixelCount", + impl_stats.rasterized_pixel_count); } void RenderingStats::Add(const RenderingStats& other) { diff --git a/chromium/cc/debug/rendering_stats.h b/chromium/cc/debug/rendering_stats.h index ee13706034a..d28f1107157 100644 --- a/chromium/cc/debug/rendering_stats.h +++ b/chromium/cc/debug/rendering_stats.h @@ -32,20 +32,14 @@ struct CC_EXPORT MainThreadRenderingStats { // Note: when adding new members, please remember to update EnumerateFields // and Add in rendering_stats.cc. - int64 animation_frame_count; - int64 screen_frame_count; + int64 frame_count; base::TimeDelta paint_time; - base::TimeDelta record_time; - base::TimeDelta commit_time; - int64 commit_count; int64 painted_pixel_count; + base::TimeDelta record_time; int64 recorded_pixel_count; - int64 image_gathering_count; - base::TimeDelta image_gathering_time; MainThreadRenderingStats(); - void IssueTraceEvent() const; - scoped_ptr<base::debug::ConvertableToTraceFormat> AsTraceableData() const; + scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData() const; void Add(const MainThreadRenderingStats& other); }; @@ -53,26 +47,13 @@ struct CC_EXPORT ImplThreadRenderingStats { // Note: when adding new members, please remember to update EnumerateFields // and Add in rendering_stats.cc. - int64 screen_frame_count; - int64 dropped_frame_count; + int64 frame_count; base::TimeDelta rasterize_time; - base::TimeDelta rasterize_time_for_now_bins_on_pending_tree; - base::TimeDelta best_rasterize_time; + base::TimeDelta analysis_time; int64 rasterized_pixel_count; - int64 impl_thread_scroll_count; - int64 main_thread_scroll_count; - int64 drawn_layer_count; - int64 missing_tile_count; - int64 deferred_image_decode_count; - int64 deferred_image_cache_hit_count; - int64 tile_analysis_count; - int64 solid_color_tile_analysis_count; - base::TimeDelta deferred_image_decode_time; - base::TimeDelta tile_analysis_time; ImplThreadRenderingStats(); - void IssueTraceEvent() const; - scoped_ptr<base::debug::ConvertableToTraceFormat> AsTraceableData() const; + scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData() const; void Add(const ImplThreadRenderingStats& other); }; diff --git a/chromium/cc/debug/rendering_stats_instrumentation.cc b/chromium/cc/debug/rendering_stats_instrumentation.cc index 3c2c96b8b00..63840a35f74 100644 --- a/chromium/cc/debug/rendering_stats_instrumentation.cc +++ b/chromium/cc/debug/rendering_stats_instrumentation.cc @@ -57,41 +57,16 @@ base::TimeDelta RenderingStatsInstrumentation::EndRecording( return base::TimeDelta(); } -void RenderingStatsInstrumentation::IncrementAnimationFrameCount() { - if (!record_rendering_stats_) - return; - - base::AutoLock scoped_lock(lock_); - main_stats_.animation_frame_count++; -} - -void RenderingStatsInstrumentation::IncrementScreenFrameCount( - int64 count, bool main_thread) { +void RenderingStatsInstrumentation::IncrementFrameCount(int64 count, + bool main_thread) { if (!record_rendering_stats_) return; base::AutoLock scoped_lock(lock_); if (main_thread) - main_stats_.screen_frame_count += count; + main_stats_.frame_count += count; else - impl_stats_.screen_frame_count += count; -} - -void RenderingStatsInstrumentation::IncrementDroppedFrameCount(int64 count) { - if (!record_rendering_stats_) - return; - - base::AutoLock scoped_lock(lock_); - impl_stats_.dropped_frame_count += count; -} - -void RenderingStatsInstrumentation::AddCommit(base::TimeDelta duration) { - if (!record_rendering_stats_) - return; - - base::AutoLock scoped_lock(lock_); - main_stats_.commit_time += duration; - main_stats_.commit_count++; + impl_stats_.frame_count += count; } void RenderingStatsInstrumentation::AddPaint(base::TimeDelta duration, @@ -114,95 +89,23 @@ void RenderingStatsInstrumentation::AddRecord(base::TimeDelta duration, main_stats_.recorded_pixel_count += pixels; } -void RenderingStatsInstrumentation::AddRaster(base::TimeDelta total_duration, - base::TimeDelta best_duration, - int64 pixels, - bool is_in_pending_tree_now_bin) { +void RenderingStatsInstrumentation::AddRaster(base::TimeDelta duration, + int64 pixels) { if (!record_rendering_stats_) return; base::AutoLock scoped_lock(lock_); - impl_stats_.rasterize_time += total_duration; - impl_stats_.best_rasterize_time += best_duration; + impl_stats_.rasterize_time += duration; impl_stats_.rasterized_pixel_count += pixels; - - if (is_in_pending_tree_now_bin) { - impl_stats_.rasterize_time_for_now_bins_on_pending_tree += - total_duration; - } -} - -void RenderingStatsInstrumentation::IncrementImplThreadScrolls() { - if (!record_rendering_stats_) - return; - - base::AutoLock scoped_lock(lock_); - impl_stats_.impl_thread_scroll_count++; -} - -void RenderingStatsInstrumentation::IncrementMainThreadScrolls() { - if (!record_rendering_stats_) - return; - - base::AutoLock scoped_lock(lock_); - impl_stats_.main_thread_scroll_count++; -} - -void RenderingStatsInstrumentation::AddLayersDrawn(int64 amount) { - if (!record_rendering_stats_) - return; - - base::AutoLock scoped_lock(lock_); - impl_stats_.drawn_layer_count += amount; -} - -void RenderingStatsInstrumentation::AddMissingTiles(int64 amount) { - if (!record_rendering_stats_) - return; - - base::AutoLock scoped_lock(lock_); - impl_stats_.missing_tile_count += amount; -} - -void RenderingStatsInstrumentation::AddDeferredImageDecode( - base::TimeDelta duration) { - if (!record_rendering_stats_) - return; - - base::AutoLock scoped_lock(lock_); - impl_stats_.deferred_image_decode_time += duration; - impl_stats_.deferred_image_decode_count++; -} - -void RenderingStatsInstrumentation::AddImageGathering( - base::TimeDelta duration) { - if (!record_rendering_stats_) - return; - - base::AutoLock scoped_lock(lock_); - main_stats_.image_gathering_time += duration; - main_stats_.image_gathering_count++; -} - -void RenderingStatsInstrumentation::IncrementDeferredImageCacheHitCount() { - if (!record_rendering_stats_) - return; - - base::AutoLock scoped_lock(lock_); - impl_stats_.deferred_image_cache_hit_count++; } -void RenderingStatsInstrumentation::AddAnalysisResult( - base::TimeDelta duration, - bool is_solid_color) { +void RenderingStatsInstrumentation::AddAnalysis(base::TimeDelta duration, + int64 pixels) { if (!record_rendering_stats_) return; base::AutoLock scoped_lock(lock_); - impl_stats_.tile_analysis_count++; - impl_stats_.tile_analysis_time += duration; - if (is_solid_color) - impl_stats_.solid_color_tile_analysis_count++; + impl_stats_.analysis_time += duration; } } // namespace cc diff --git a/chromium/cc/debug/rendering_stats_instrumentation.h b/chromium/cc/debug/rendering_stats_instrumentation.h index 5f74f9e6132..68117557e7d 100644 --- a/chromium/cc/debug/rendering_stats_instrumentation.h +++ b/chromium/cc/debug/rendering_stats_instrumentation.h @@ -19,11 +19,11 @@ class CC_EXPORT RenderingStatsInstrumentation { virtual ~RenderingStatsInstrumentation(); // Return current main thread rendering stats. - MainThreadRenderingStats GetMainThreadRenderingStats() { + const MainThreadRenderingStats& main_thread_rendering_stats() { return main_stats_; } // Return current impl thread rendering stats. - ImplThreadRenderingStats GetImplThreadRenderingStats() { + const ImplThreadRenderingStats& impl_thread_rendering_stats() { return impl_stats_; } // Return the accumulated, combined rendering stats. @@ -36,15 +36,6 @@ class CC_EXPORT RenderingStatsInstrumentation { // clear current stats. void AccumulateAndClearImplThreadStats(); - // Issue trace event for current main thread rendering stats. - void IssueTraceEventForMainThreadStats() { - main_stats_.IssueTraceEvent(); - } - // Issue trace event for current impl thread rendering stats. - void IssueTraceEventForImplThreadStats() { - impl_stats_.IssueTraceEvent(); - } - // Read and write access to the record_rendering_stats_ flag is not locked to // improve performance. The flag is commonly turned off and hardly changes // it's value during runtime. @@ -57,35 +48,17 @@ class CC_EXPORT RenderingStatsInstrumentation { base::TimeTicks StartRecording() const; base::TimeDelta EndRecording(base::TimeTicks start_time) const; - void IncrementAnimationFrameCount(); - void IncrementScreenFrameCount(int64 count, bool main_thread); - void IncrementDroppedFrameCount(int64 count); - - void AddCommit(base::TimeDelta duration); + void IncrementFrameCount(int64 count, bool main_thread); void AddPaint(base::TimeDelta duration, int64 pixels); void AddRecord(base::TimeDelta duration, int64 pixels); - void AddRaster(base::TimeDelta total_duraction, - base::TimeDelta best_duration, - int64 pixels, - bool is_in_pending_tree_now_bin); - - void IncrementImplThreadScrolls(); - void IncrementMainThreadScrolls(); - - void AddLayersDrawn(int64 amount); - void AddMissingTiles(int64 amount); - - void AddDeferredImageDecode(base::TimeDelta duration); - void AddImageGathering(base::TimeDelta duration); - - void IncrementDeferredImageCacheHitCount(); - - void AddAnalysisResult(base::TimeDelta duration, bool is_solid_color); + void AddRaster(base::TimeDelta duration, int64 pixels); + void AddAnalysis(base::TimeDelta duration, int64 pixels); protected: RenderingStatsInstrumentation(); private: + // TODO(ernstm): rename to *_thread_rendering_stats_* MainThreadRenderingStats main_stats_; MainThreadRenderingStats main_stats_accu_; ImplThreadRenderingStats impl_stats_; diff --git a/chromium/cc/debug/test_context_provider.cc b/chromium/cc/debug/test_context_provider.cc deleted file mode 100644 index d09ecd86ed9..00000000000 --- a/chromium/cc/debug/test_context_provider.cc +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright 2013 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 "cc/debug/test_context_provider.h" - -#include <set> -#include <vector> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/logging.h" -#include "base/strings/string_split.h" -#include "cc/debug/test_web_graphics_context_3d.h" - -namespace cc { - -class TestContextProvider::LostContextCallbackProxy - : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback { - public: - explicit LostContextCallbackProxy(TestContextProvider* provider) - : provider_(provider) { - provider_->context3d_->setContextLostCallback(this); - } - - virtual ~LostContextCallbackProxy() { - provider_->context3d_->setContextLostCallback(NULL); - } - - virtual void onContextLost() { - provider_->OnLostContext(); - } - - private: - TestContextProvider* provider_; -}; - -class TestContextProvider::SwapBuffersCompleteCallbackProxy - : public WebKit::WebGraphicsContext3D:: - WebGraphicsSwapBuffersCompleteCallbackCHROMIUM { - public: - explicit SwapBuffersCompleteCallbackProxy(TestContextProvider* provider) - : provider_(provider) { - provider_->context3d_->setSwapBuffersCompleteCallbackCHROMIUM(this); - } - - virtual ~SwapBuffersCompleteCallbackProxy() { - provider_->context3d_->setSwapBuffersCompleteCallbackCHROMIUM(NULL); - } - - virtual void onSwapBuffersComplete() { - provider_->OnSwapBuffersComplete(); - } - - private: - TestContextProvider* provider_; -}; - -// static -scoped_refptr<TestContextProvider> TestContextProvider::Create() { - return Create(TestWebGraphicsContext3D::Create().Pass()); -} - -// static -scoped_refptr<TestContextProvider> TestContextProvider::Create( - const CreateCallback& create_callback) { - scoped_refptr<TestContextProvider> provider = new TestContextProvider; - if (!provider->InitializeOnMainThread(create_callback)) - return NULL; - return provider; -} - -scoped_ptr<TestWebGraphicsContext3D> ReturnScopedContext( - scoped_ptr<TestWebGraphicsContext3D> context) { - return context.Pass(); -} - -// static -scoped_refptr<TestContextProvider> TestContextProvider::Create( - scoped_ptr<TestWebGraphicsContext3D> context) { - return Create(base::Bind(&ReturnScopedContext, base::Passed(&context))); -} - -TestContextProvider::TestContextProvider() - : bound_(false), - destroyed_(false) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - context_thread_checker_.DetachFromThread(); -} - -TestContextProvider::~TestContextProvider() { - DCHECK(main_thread_checker_.CalledOnValidThread() || - context_thread_checker_.CalledOnValidThread()); -} - -bool TestContextProvider::InitializeOnMainThread( - const CreateCallback& create_callback) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - - DCHECK(!context3d_); - DCHECK(!create_callback.is_null()); - context3d_ = create_callback.Run(); - return context3d_; -} - -bool TestContextProvider::BindToCurrentThread() { - DCHECK(context3d_); - - // This is called on the thread the context will be used. - DCHECK(context_thread_checker_.CalledOnValidThread()); - - if (bound_) - return true; - - bound_ = true; - if (!context3d_->makeContextCurrent()) { - base::AutoLock lock(destroyed_lock_); - destroyed_ = true; - return false; - } - - lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this)); - swap_buffers_complete_callback_proxy_.reset( - new SwapBuffersCompleteCallbackProxy(this)); - - return true; -} - -ContextProvider::Capabilities TestContextProvider::ContextCapabilities() { - DCHECK(context3d_); - DCHECK(bound_); - DCHECK(context_thread_checker_.CalledOnValidThread()); - - return context3d_->test_capabilities(); -} - -WebKit::WebGraphicsContext3D* TestContextProvider::Context3d() { - DCHECK(context3d_); - DCHECK(bound_); - DCHECK(context_thread_checker_.CalledOnValidThread()); - - return context3d_.get(); -} - -class GrContext* TestContextProvider::GrContext() { - DCHECK(context3d_); - DCHECK(bound_); - DCHECK(context_thread_checker_.CalledOnValidThread()); - - // TODO(danakj): Make a test GrContext that works with a test Context3d. - return NULL; -} - -void TestContextProvider::VerifyContexts() { - DCHECK(context3d_); - DCHECK(bound_); - DCHECK(context_thread_checker_.CalledOnValidThread()); - - if (context3d_->isContextLost()) { - base::AutoLock lock(destroyed_lock_); - destroyed_ = true; - } -} - -bool TestContextProvider::DestroyedOnMainThread() { - DCHECK(main_thread_checker_.CalledOnValidThread()); - - base::AutoLock lock(destroyed_lock_); - return destroyed_; -} - -void TestContextProvider::OnLostContext() { - DCHECK(context_thread_checker_.CalledOnValidThread()); - { - base::AutoLock lock(destroyed_lock_); - if (destroyed_) - return; - destroyed_ = true; - } - if (!lost_context_callback_.is_null()) - base::ResetAndReturn(&lost_context_callback_).Run(); -} - -void TestContextProvider::OnSwapBuffersComplete() { - DCHECK(context_thread_checker_.CalledOnValidThread()); - if (!swap_buffers_complete_callback_.is_null()) - swap_buffers_complete_callback_.Run(); -} - -TestWebGraphicsContext3D* TestContextProvider::TestContext3d() { - DCHECK(context3d_); - DCHECK(bound_); - DCHECK(context_thread_checker_.CalledOnValidThread()); - - return context3d_.get(); -} - -TestWebGraphicsContext3D* TestContextProvider::UnboundTestContext3d() { - DCHECK(context3d_); - DCHECK(context_thread_checker_.CalledOnValidThread()); - - return context3d_.get(); -} - -void TestContextProvider::SetMemoryAllocation( - const ManagedMemoryPolicy& policy, - bool discard_backbuffer_when_not_visible) { - if (memory_policy_changed_callback_.is_null()) - return; - memory_policy_changed_callback_.Run( - policy, discard_backbuffer_when_not_visible); -} - -void TestContextProvider::SetLostContextCallback( - const LostContextCallback& cb) { - DCHECK(context_thread_checker_.CalledOnValidThread()); - DCHECK(lost_context_callback_.is_null() || cb.is_null()); - lost_context_callback_ = cb; -} - -void TestContextProvider::SetSwapBuffersCompleteCallback( - const SwapBuffersCompleteCallback& cb) { - DCHECK(context_thread_checker_.CalledOnValidThread()); - DCHECK(swap_buffers_complete_callback_.is_null() || cb.is_null()); - swap_buffers_complete_callback_ = cb; -} - -void TestContextProvider::SetMemoryPolicyChangedCallback( - const MemoryPolicyChangedCallback& cb) { - DCHECK(context_thread_checker_.CalledOnValidThread()); - DCHECK(memory_policy_changed_callback_.is_null() || cb.is_null()); - memory_policy_changed_callback_ = cb; -} - -void TestContextProvider::SetMaxTransferBufferUsageBytes( - size_t max_transfer_buffer_usage_bytes) { - context3d_->SetMaxTransferBufferUsageBytes(max_transfer_buffer_usage_bytes); -} - -} // namespace cc diff --git a/chromium/cc/debug/test_context_provider.h b/chromium/cc/debug/test_context_provider.h deleted file mode 100644 index 0401fcf1ba8..00000000000 --- a/chromium/cc/debug/test_context_provider.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2013 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 CC_DEBUG_TEST_CONTEXT_PROVIDER_H_ -#define CC_DEBUG_TEST_CONTEXT_PROVIDER_H_ - -#include "base/callback.h" -#include "base/memory/scoped_ptr.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread_checker.h" -#include "cc/base/cc_export.h" -#include "cc/output/context_provider.h" - -namespace WebKit { class WebGraphicsContext3D; } - -namespace cc { -class TestWebGraphicsContext3D; - -class CC_EXPORT TestContextProvider - : public NON_EXPORTED_BASE(cc::ContextProvider) { - public: - typedef base::Callback<scoped_ptr<TestWebGraphicsContext3D>(void)> - CreateCallback; - - static scoped_refptr<TestContextProvider> Create(); - static scoped_refptr<TestContextProvider> Create( - const CreateCallback& create_callback); - static scoped_refptr<TestContextProvider> Create( - scoped_ptr<TestWebGraphicsContext3D> context); - - virtual bool BindToCurrentThread() OVERRIDE; - virtual Capabilities ContextCapabilities() OVERRIDE; - virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE; - virtual class GrContext* GrContext() OVERRIDE; - virtual void VerifyContexts() OVERRIDE; - virtual bool DestroyedOnMainThread() OVERRIDE; - virtual void SetLostContextCallback(const LostContextCallback& cb) OVERRIDE; - virtual void SetSwapBuffersCompleteCallback( - const SwapBuffersCompleteCallback& cb) OVERRIDE; - virtual void SetMemoryPolicyChangedCallback( - const MemoryPolicyChangedCallback& cb) OVERRIDE; - - TestWebGraphicsContext3D* TestContext3d(); - - // This returns the TestWebGraphicsContext3D but is valid to call - // before the context is bound to a thread. This is needed to set up - // state on the test context before binding. Don't call - // makeContextCurrent on the context returned from this method. - TestWebGraphicsContext3D* UnboundTestContext3d(); - - void SetMemoryAllocation(const ManagedMemoryPolicy& policy, - bool discard_backbuffer_when_not_visible); - - void SetMaxTransferBufferUsageBytes(size_t max_transfer_buffer_usage_bytes); - - protected: - TestContextProvider(); - virtual ~TestContextProvider(); - - bool InitializeOnMainThread(const CreateCallback& create_callback); - - void OnLostContext(); - void OnSwapBuffersComplete(); - - scoped_ptr<TestWebGraphicsContext3D> context3d_; - bool bound_; - - base::ThreadChecker main_thread_checker_; - base::ThreadChecker context_thread_checker_; - - base::Lock destroyed_lock_; - bool destroyed_; - - LostContextCallback lost_context_callback_; - SwapBuffersCompleteCallback swap_buffers_complete_callback_; - MemoryPolicyChangedCallback memory_policy_changed_callback_; - - class LostContextCallbackProxy; - scoped_ptr<LostContextCallbackProxy> lost_context_callback_proxy_; - - class SwapBuffersCompleteCallbackProxy; - scoped_ptr<SwapBuffersCompleteCallbackProxy> - swap_buffers_complete_callback_proxy_; -}; - -} // namespace cc - -#endif // CC_DEBUG_TEST_CONTEXT_PROVIDER_H_ - diff --git a/chromium/cc/debug/test_web_graphics_context_3d.cc b/chromium/cc/debug/test_web_graphics_context_3d.cc deleted file mode 100644 index 634778fc4e6..00000000000 --- a/chromium/cc/debug/test_web_graphics_context_3d.cc +++ /dev/null @@ -1,632 +0,0 @@ -// Copyright 2013 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 "cc/debug/test_web_graphics_context_3d.h" - -#include <algorithm> -#include <string> - -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "gpu/GLES2/gl2extchromium.h" -#include "third_party/khronos/GLES2/gl2ext.h" - -using WebKit::WGC3Dboolean; -using WebKit::WGC3Dchar; -using WebKit::WGC3Denum; -using WebKit::WGC3Dint; -using WebKit::WGC3Dsizei; -using WebKit::WGC3Dsizeiptr; -using WebKit::WGC3Duint; -using WebKit::WebGLId; -using WebKit::WebGraphicsContext3D; - -namespace cc { - -static const WebGLId kFramebufferId = 1; -static const WebGLId kProgramId = 2; -static const WebGLId kRenderbufferId = 3; -static const WebGLId kShaderId = 4; - -static unsigned s_context_id = 1; - -const WebGLId TestWebGraphicsContext3D::kExternalTextureId = 1337; - -static base::LazyInstance<base::Lock>::Leaky - g_shared_namespace_lock = LAZY_INSTANCE_INITIALIZER; - -TestWebGraphicsContext3D::Namespace* - TestWebGraphicsContext3D::shared_namespace_ = NULL; - -TestWebGraphicsContext3D::Namespace::Namespace() - : next_buffer_id(1), - next_image_id(1), - next_texture_id(1) { -} - -TestWebGraphicsContext3D::Namespace::~Namespace() { - g_shared_namespace_lock.Get().AssertAcquired(); - if (shared_namespace_ == this) - shared_namespace_ = NULL; -} - -// static -scoped_ptr<TestWebGraphicsContext3D> TestWebGraphicsContext3D::Create() { - return make_scoped_ptr(new TestWebGraphicsContext3D()); -} - -TestWebGraphicsContext3D::TestWebGraphicsContext3D() - : FakeWebGraphicsContext3D(), - context_id_(s_context_id++), - times_make_current_succeeds_(-1), - times_bind_texture_succeeds_(-1), - times_end_query_succeeds_(-1), - times_gen_mailbox_succeeds_(-1), - context_lost_(false), - times_map_image_chromium_succeeds_(-1), - times_map_buffer_chromium_succeeds_(-1), - context_lost_callback_(NULL), - swap_buffers_callback_(NULL), - max_texture_size_(2048), - width_(0), - height_(0), - bound_buffer_(0), - weak_ptr_factory_(this) { - CreateNamespace(); - test_capabilities_.swapbuffers_complete_callback = true; -} - -TestWebGraphicsContext3D::TestWebGraphicsContext3D( - const WebGraphicsContext3D::Attributes& attributes) - : FakeWebGraphicsContext3D(), - context_id_(s_context_id++), - attributes_(attributes), - times_make_current_succeeds_(-1), - times_bind_texture_succeeds_(-1), - times_end_query_succeeds_(-1), - times_gen_mailbox_succeeds_(-1), - context_lost_(false), - times_map_image_chromium_succeeds_(-1), - times_map_buffer_chromium_succeeds_(-1), - context_lost_callback_(NULL), - swap_buffers_callback_(NULL), - max_texture_size_(2048), - width_(0), - height_(0), - bound_buffer_(0), - weak_ptr_factory_(this) { - CreateNamespace(); - test_capabilities_.swapbuffers_complete_callback = true; -} - -void TestWebGraphicsContext3D::CreateNamespace() { - if (attributes_.shareResources) { - base::AutoLock lock(g_shared_namespace_lock.Get()); - if (shared_namespace_) { - namespace_ = shared_namespace_; - } else { - namespace_ = new Namespace; - shared_namespace_ = namespace_.get(); - } - } else { - namespace_ = new Namespace; - } -} - -TestWebGraphicsContext3D::~TestWebGraphicsContext3D() { - for (size_t i = 0; i < sync_point_callbacks_.size(); ++i) { - if (sync_point_callbacks_[i] != NULL) - delete sync_point_callbacks_[i]; - } - base::AutoLock lock(g_shared_namespace_lock.Get()); - namespace_ = NULL; -} - -bool TestWebGraphicsContext3D::makeContextCurrent() { - if (times_make_current_succeeds_ >= 0) { - if (!times_make_current_succeeds_) { - loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, - GL_INNOCENT_CONTEXT_RESET_ARB); - } - --times_make_current_succeeds_; - } - return !context_lost_; -} - -int TestWebGraphicsContext3D::width() { - return width_; -} - -int TestWebGraphicsContext3D::height() { - return height_; -} - -void TestWebGraphicsContext3D::reshapeWithScaleFactor( - int width, int height, float scale_factor) { - width_ = width; - height_ = height; -} - -bool TestWebGraphicsContext3D::isContextLost() { - return context_lost_; -} - -WGC3Denum TestWebGraphicsContext3D::getGraphicsResetStatusARB() { - return context_lost_ ? GL_UNKNOWN_CONTEXT_RESET_ARB : GL_NO_ERROR; -} - -WGC3Denum TestWebGraphicsContext3D::checkFramebufferStatus( - WGC3Denum target) { - if (context_lost_) - return GL_FRAMEBUFFER_UNDEFINED_OES; - return GL_FRAMEBUFFER_COMPLETE; -} - -WebGraphicsContext3D::Attributes - TestWebGraphicsContext3D::getContextAttributes() { - return attributes_; -} - -WebKit::WebString TestWebGraphicsContext3D::getString(WGC3Denum name) { - return WebKit::WebString(); -} - -WGC3Dint TestWebGraphicsContext3D::getUniformLocation( - WebGLId program, - const WGC3Dchar* name) { - return 0; -} - -WGC3Dsizeiptr TestWebGraphicsContext3D::getVertexAttribOffset( - WGC3Duint index, - WGC3Denum pname) { - return 0; -} - -WGC3Dboolean TestWebGraphicsContext3D::isBuffer( - WebGLId buffer) { - return false; -} - -WGC3Dboolean TestWebGraphicsContext3D::isEnabled( - WGC3Denum cap) { - return false; -} - -WGC3Dboolean TestWebGraphicsContext3D::isFramebuffer( - WebGLId framebuffer) { - return false; -} - -WGC3Dboolean TestWebGraphicsContext3D::isProgram( - WebGLId program) { - return false; -} - -WGC3Dboolean TestWebGraphicsContext3D::isRenderbuffer( - WebGLId renderbuffer) { - return false; -} - -WGC3Dboolean TestWebGraphicsContext3D::isShader( - WebGLId shader) { - return false; -} - -WGC3Dboolean TestWebGraphicsContext3D::isTexture( - WebGLId texture) { - return false; -} - -WebGLId TestWebGraphicsContext3D::createBuffer() { - return NextBufferId(); -} - -void TestWebGraphicsContext3D::deleteBuffer(WebGLId id) { - base::AutoLock lock(namespace_->lock); - unsigned context_id = id >> 17; - unsigned buffer_id = id & 0x1ffff; - DCHECK(buffer_id && buffer_id < namespace_->next_buffer_id); - DCHECK_EQ(context_id, context_id_); -} - -WebGLId TestWebGraphicsContext3D::createFramebuffer() { - return kFramebufferId | context_id_ << 16; -} - -void TestWebGraphicsContext3D::deleteFramebuffer(WebGLId id) { - DCHECK_EQ(kFramebufferId | context_id_ << 16, id); -} - -WebGLId TestWebGraphicsContext3D::createProgram() { - return kProgramId | context_id_ << 16; -} - -void TestWebGraphicsContext3D::deleteProgram(WebGLId id) { - DCHECK_EQ(kProgramId | context_id_ << 16, id); -} - -WebGLId TestWebGraphicsContext3D::createRenderbuffer() { - return kRenderbufferId | context_id_ << 16; -} - -void TestWebGraphicsContext3D::deleteRenderbuffer(WebGLId id) { - DCHECK_EQ(kRenderbufferId | context_id_ << 16, id); -} - -WebGLId TestWebGraphicsContext3D::createShader(WGC3Denum) { - return kShaderId | context_id_ << 16; -} - -void TestWebGraphicsContext3D::deleteShader(WebGLId id) { - DCHECK_EQ(kShaderId | context_id_ << 16, id); -} - -WebGLId TestWebGraphicsContext3D::createTexture() { - WebGLId texture_id = NextTextureId(); - DCHECK_NE(texture_id, kExternalTextureId); - base::AutoLock lock(namespace_->lock); - namespace_->textures.push_back(texture_id); - return texture_id; -} - -void TestWebGraphicsContext3D::deleteTexture(WebGLId texture_id) { - base::AutoLock lock(namespace_->lock); - std::vector<WebKit::WebGLId>& textures = namespace_->textures; - DCHECK(std::find(textures.begin(), textures.end(), texture_id) != - textures.end()); - textures.erase(std::find(textures.begin(), textures.end(), texture_id)); -} - -void TestWebGraphicsContext3D::attachShader(WebGLId program, WebGLId shader) { - DCHECK_EQ(kProgramId | context_id_ << 16, program); - DCHECK_EQ(kShaderId | context_id_ << 16, shader); -} - -void TestWebGraphicsContext3D::useProgram(WebGLId program) { - if (!program) - return; - DCHECK_EQ(kProgramId | context_id_ << 16, program); -} - -void TestWebGraphicsContext3D::bindFramebuffer( - WGC3Denum target, WebGLId framebuffer) { - if (!framebuffer) - return; - DCHECK_EQ(kFramebufferId | context_id_ << 16, framebuffer); -} - -void TestWebGraphicsContext3D::bindRenderbuffer( - WGC3Denum target, WebGLId renderbuffer) { - if (!renderbuffer) - return; - DCHECK_EQ(kRenderbufferId | context_id_ << 16, renderbuffer); -} - -void TestWebGraphicsContext3D::bindTexture( - WGC3Denum target, WebGLId texture_id) { - if (times_bind_texture_succeeds_ >= 0) { - if (!times_bind_texture_succeeds_) { - loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, - GL_INNOCENT_CONTEXT_RESET_ARB); - } - --times_bind_texture_succeeds_; - } - - if (!texture_id) - return; - if (texture_id == kExternalTextureId) - return; - base::AutoLock lock(namespace_->lock); - std::vector<WebKit::WebGLId>& textures = namespace_->textures; - DCHECK(std::find(textures.begin(), textures.end(), texture_id) != - textures.end()); - used_textures_.insert(texture_id); -} - -void TestWebGraphicsContext3D::endQueryEXT(WGC3Denum target) { - if (times_end_query_succeeds_ >= 0) { - if (!times_end_query_succeeds_) { - loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, - GL_INNOCENT_CONTEXT_RESET_ARB); - } - --times_end_query_succeeds_; - } -} - -void TestWebGraphicsContext3D::getQueryObjectuivEXT( - WebGLId query, - WGC3Denum pname, - WGC3Duint* params) { - // If the context is lost, behave as if result is available. - if (pname == GL_QUERY_RESULT_AVAILABLE_EXT) - *params = 1; -} - -void TestWebGraphicsContext3D::getIntegerv( - WGC3Denum pname, - WebKit::WGC3Dint* value) { - if (pname == GL_MAX_TEXTURE_SIZE) - *value = max_texture_size_; - else if (pname == GL_ACTIVE_TEXTURE) - *value = GL_TEXTURE0; -} - -void TestWebGraphicsContext3D::genMailboxCHROMIUM(WebKit::WGC3Dbyte* mailbox) { - if (times_gen_mailbox_succeeds_ >= 0) { - if (!times_gen_mailbox_succeeds_) { - loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, - GL_INNOCENT_CONTEXT_RESET_ARB); - } - --times_gen_mailbox_succeeds_; - } - if (context_lost_) { - memset(mailbox, 0, 64); - return; - } - - static char mailbox_name1 = '1'; - static char mailbox_name2 = '1'; - mailbox[0] = mailbox_name1; - mailbox[1] = mailbox_name2; - mailbox[2] = '\0'; - if (++mailbox_name1 == 0) { - mailbox_name1 = '1'; - ++mailbox_name2; - } -} - -void TestWebGraphicsContext3D::setContextLostCallback( - WebGraphicsContextLostCallback* callback) { - context_lost_callback_ = callback; -} - -void TestWebGraphicsContext3D::loseContextCHROMIUM(WGC3Denum current, - WGC3Denum other) { - if (context_lost_) - return; - context_lost_ = true; - if (context_lost_callback_) - context_lost_callback_->onContextLost(); - - for (size_t i = 0; i < shared_contexts_.size(); ++i) - shared_contexts_[i]->loseContextCHROMIUM(current, other); - shared_contexts_.clear(); -} - -void TestWebGraphicsContext3D::signalSyncPoint( - unsigned sync_point, - WebGraphicsSyncPointCallback* callback) { - sync_point_callbacks_.push_back(callback); -} - -void TestWebGraphicsContext3D::signalQuery( - WebKit::WebGLId query, - WebGraphicsSyncPointCallback* callback) { - sync_point_callbacks_.push_back(callback); -} - -void TestWebGraphicsContext3D::setSwapBuffersCompleteCallbackCHROMIUM( - WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback) { - if (test_capabilities_.swapbuffers_complete_callback) - swap_buffers_callback_ = callback; -} - -void TestWebGraphicsContext3D::prepareTexture() { - if (swap_buffers_callback_) { - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&TestWebGraphicsContext3D::SwapBuffersComplete, - weak_ptr_factory_.GetWeakPtr())); - } - CallAllSyncPointCallbacks(); -} - -void TestWebGraphicsContext3D::finish() { - CallAllSyncPointCallbacks(); -} - -void TestWebGraphicsContext3D::flush() { - CallAllSyncPointCallbacks(); -} - -static void CallAndDestroy( - WebKit::WebGraphicsContext3D::WebGraphicsSyncPointCallback* callback) { - if (!callback) - return; - callback->onSyncPointReached(); - delete callback; -} - -void TestWebGraphicsContext3D::CallAllSyncPointCallbacks() { - for (size_t i = 0; i < sync_point_callbacks_.size(); ++i) { - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&CallAndDestroy, - sync_point_callbacks_[i])); - } - sync_point_callbacks_.clear(); -} - -void TestWebGraphicsContext3D::SwapBuffersComplete() { - if (swap_buffers_callback_) - swap_buffers_callback_->onSwapBuffersComplete(); -} - -void TestWebGraphicsContext3D::bindBuffer(WebKit::WGC3Denum target, - WebKit::WebGLId buffer) { - bound_buffer_ = buffer; - if (!bound_buffer_) - return; - unsigned context_id = buffer >> 17; - unsigned buffer_id = buffer & 0x1ffff; - base::AutoLock lock(namespace_->lock); - DCHECK(buffer_id && buffer_id < namespace_->next_buffer_id); - DCHECK_EQ(context_id, context_id_); - - base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers; - if (buffers.count(bound_buffer_) == 0) - buffers.set(bound_buffer_, make_scoped_ptr(new Buffer).Pass()); - - buffers.get(bound_buffer_)->target = target; -} - -void TestWebGraphicsContext3D::bufferData(WebKit::WGC3Denum target, - WebKit::WGC3Dsizeiptr size, - const void* data, - WebKit::WGC3Denum usage) { - base::AutoLock lock(namespace_->lock); - base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers; - DCHECK_GT(buffers.count(bound_buffer_), 0u); - DCHECK_EQ(target, buffers.get(bound_buffer_)->target); - Buffer* buffer = buffers.get(bound_buffer_); - if (context_lost_) { - buffer->pixels.reset(); - return; - } - - buffer->pixels.reset(new uint8[size]); - buffer->size = size; - if (data != NULL) - memcpy(buffer->pixels.get(), data, size); -} - -void* TestWebGraphicsContext3D::mapBufferCHROMIUM(WebKit::WGC3Denum target, - WebKit::WGC3Denum access) { - base::AutoLock lock(namespace_->lock); - base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers; - DCHECK_GT(buffers.count(bound_buffer_), 0u); - DCHECK_EQ(target, buffers.get(bound_buffer_)->target); - if (times_map_buffer_chromium_succeeds_ >= 0) { - if (!times_map_buffer_chromium_succeeds_) { - return NULL; - } - --times_map_buffer_chromium_succeeds_; - } - return buffers.get(bound_buffer_)->pixels.get(); -} - -WebKit::WGC3Dboolean TestWebGraphicsContext3D::unmapBufferCHROMIUM( - WebKit::WGC3Denum target) { - base::AutoLock lock(namespace_->lock); - base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers; - DCHECK_GT(buffers.count(bound_buffer_), 0u); - DCHECK_EQ(target, buffers.get(bound_buffer_)->target); - buffers.get(bound_buffer_)->pixels.reset(); - return true; -} - -WebKit::WGC3Duint TestWebGraphicsContext3D::createImageCHROMIUM( - WebKit::WGC3Dsizei width, WebKit::WGC3Dsizei height, - WebKit::WGC3Denum internalformat) { - DCHECK_EQ(GL_RGBA8_OES, static_cast<int>(internalformat)); - WebKit::WGC3Duint image_id = NextImageId(); - base::AutoLock lock(namespace_->lock); - base::ScopedPtrHashMap<unsigned, Image>& images = namespace_->images; - images.set(image_id, make_scoped_ptr(new Image).Pass()); - images.get(image_id)->pixels.reset(new uint8[width * height * 4]); - return image_id; -} - -void TestWebGraphicsContext3D::destroyImageCHROMIUM( - WebKit::WGC3Duint id) { - base::AutoLock lock(namespace_->lock); - unsigned context_id = id >> 17; - unsigned image_id = id & 0x1ffff; - DCHECK(image_id && image_id < namespace_->next_image_id); - DCHECK_EQ(context_id, context_id_); -} - -void TestWebGraphicsContext3D::getImageParameterivCHROMIUM( - WebKit::WGC3Duint image_id, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* params) { - base::AutoLock lock(namespace_->lock); - DCHECK_GT(namespace_->images.count(image_id), 0u); - DCHECK_EQ(GL_IMAGE_ROWBYTES_CHROMIUM, static_cast<int>(pname)); - *params = 0; -} - -void* TestWebGraphicsContext3D::mapImageCHROMIUM(WebKit::WGC3Duint image_id, - WebKit::WGC3Denum access) { - base::AutoLock lock(namespace_->lock); - base::ScopedPtrHashMap<unsigned, Image>& images = namespace_->images; - DCHECK_GT(images.count(image_id), 0u); - if (times_map_image_chromium_succeeds_ >= 0) { - if (!times_map_image_chromium_succeeds_) { - return NULL; - } - --times_map_image_chromium_succeeds_; - } - return images.get(image_id)->pixels.get(); -} - -void TestWebGraphicsContext3D::unmapImageCHROMIUM( - WebKit::WGC3Duint image_id) { - base::AutoLock lock(namespace_->lock); - DCHECK_GT(namespace_->images.count(image_id), 0u); -} - -size_t TestWebGraphicsContext3D::NumTextures() const { - base::AutoLock lock(namespace_->lock); - return namespace_->textures.size(); -} - -WebKit::WebGLId TestWebGraphicsContext3D::TextureAt(int i) const { - base::AutoLock lock(namespace_->lock); - return namespace_->textures[i]; -} - -WebGLId TestWebGraphicsContext3D::NextTextureId() { - base::AutoLock lock(namespace_->lock); - WebGLId texture_id = namespace_->next_texture_id++; - DCHECK(texture_id < (1 << 16)); - texture_id |= context_id_ << 16; - return texture_id; -} - -WebGLId TestWebGraphicsContext3D::NextBufferId() { - base::AutoLock lock(namespace_->lock); - WebGLId buffer_id = namespace_->next_buffer_id++; - DCHECK(buffer_id < (1 << 17)); - buffer_id |= context_id_ << 17; - return buffer_id; -} - -WebKit::WGC3Duint TestWebGraphicsContext3D::NextImageId() { - base::AutoLock lock(namespace_->lock); - WGC3Duint image_id = namespace_->next_image_id++; - DCHECK(image_id < (1 << 17)); - image_id |= context_id_ << 17; - return image_id; -} - -size_t TestWebGraphicsContext3D::GetTransferBufferMemoryUsedBytes() const { - size_t total_bytes = 0; - base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers; - base::ScopedPtrHashMap<unsigned, Buffer>::iterator it = buffers.begin(); - for (; it != buffers.end(); ++it) { - Buffer* buffer = it->second; - if (buffer->target == GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM) - total_bytes += buffer->size; - } - return total_bytes; -} - -void TestWebGraphicsContext3D::SetMaxTransferBufferUsageBytes( - size_t max_transfer_buffer_usage_bytes) { - test_capabilities_.max_transfer_buffer_usage_bytes = - max_transfer_buffer_usage_bytes; -} - -TestWebGraphicsContext3D::Buffer::Buffer() : target(0), size(0) {} - -TestWebGraphicsContext3D::Buffer::~Buffer() {} - -TestWebGraphicsContext3D::Image::Image() {} - -TestWebGraphicsContext3D::Image::~Image() {} - -} // namespace cc diff --git a/chromium/cc/debug/test_web_graphics_context_3d.h b/chromium/cc/debug/test_web_graphics_context_3d.h deleted file mode 100644 index 4db270c4dd6..00000000000 --- a/chromium/cc/debug/test_web_graphics_context_3d.h +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2013 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 CC_DEBUG_TEST_WEB_GRAPHICS_CONTEXT_3D_H_ -#define CC_DEBUG_TEST_WEB_GRAPHICS_CONTEXT_3D_H_ - -#include <vector> - -#include "base/compiler_specific.h" -#include "base/containers/hash_tables.h" -#include "base/containers/scoped_ptr_hash_map.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/stl_util.h" -#include "base/synchronization/lock.h" -#include "cc/base/cc_export.h" -#include "cc/debug/fake_web_graphics_context_3d.h" -#include "cc/output/context_provider.h" -#include "third_party/khronos/GLES2/gl2.h" - -namespace cc { - -class CC_EXPORT TestWebGraphicsContext3D : public FakeWebGraphicsContext3D { - public: - static scoped_ptr<TestWebGraphicsContext3D> Create(); - - virtual ~TestWebGraphicsContext3D(); - - virtual bool makeContextCurrent(); - - virtual int width(); - virtual int height(); - - virtual void reshapeWithScaleFactor( - int width, int height, float scale_factor); - - virtual bool isContextLost(); - virtual WebKit::WGC3Denum getGraphicsResetStatusARB(); - - virtual void attachShader(WebKit::WebGLId program, WebKit::WebGLId shader); - virtual void bindFramebuffer( - WebKit::WGC3Denum target, WebKit::WebGLId framebuffer); - virtual void bindRenderbuffer( - WebKit::WGC3Denum target, WebKit::WebGLId renderbuffer); - virtual void bindTexture( - WebKit::WGC3Denum target, - WebKit::WebGLId texture_id); - - virtual WebKit::WGC3Denum checkFramebufferStatus(WebKit::WGC3Denum target); - - virtual Attributes getContextAttributes(); - - virtual WebKit::WebString getString(WebKit::WGC3Denum name); - virtual WebKit::WGC3Dint getUniformLocation( - WebKit::WebGLId program, - const WebKit::WGC3Dchar* name); - virtual WebKit::WGC3Dsizeiptr getVertexAttribOffset( - WebKit::WGC3Duint index, - WebKit::WGC3Denum pname); - - virtual WebKit::WGC3Dboolean isBuffer(WebKit::WebGLId buffer); - virtual WebKit::WGC3Dboolean isEnabled(WebKit::WGC3Denum cap); - virtual WebKit::WGC3Dboolean isFramebuffer(WebKit::WebGLId framebuffer); - virtual WebKit::WGC3Dboolean isProgram(WebKit::WebGLId program); - virtual WebKit::WGC3Dboolean isRenderbuffer(WebKit::WebGLId renderbuffer); - virtual WebKit::WGC3Dboolean isShader(WebKit::WebGLId shader); - virtual WebKit::WGC3Dboolean isTexture(WebKit::WebGLId texture); - - virtual void useProgram(WebKit::WebGLId program); - - virtual WebKit::WebGLId createBuffer(); - virtual WebKit::WebGLId createFramebuffer(); - virtual WebKit::WebGLId createProgram(); - virtual WebKit::WebGLId createRenderbuffer(); - virtual WebKit::WebGLId createShader(WebKit::WGC3Denum); - virtual WebKit::WebGLId createTexture(); - - virtual void deleteBuffer(WebKit::WebGLId id); - virtual void deleteFramebuffer(WebKit::WebGLId id); - virtual void deleteProgram(WebKit::WebGLId id); - virtual void deleteRenderbuffer(WebKit::WebGLId id); - virtual void deleteShader(WebKit::WebGLId id); - virtual void deleteTexture(WebKit::WebGLId texture_id); - - virtual void endQueryEXT(WebKit::WGC3Denum target); - virtual void getQueryObjectuivEXT( - WebKit::WebGLId query, - WebKit::WGC3Denum pname, - WebKit::WGC3Duint* params); - - virtual void getIntegerv( - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* value); - - virtual void genMailboxCHROMIUM(WebKit::WGC3Dbyte* mailbox); - virtual void produceTextureCHROMIUM(WebKit::WGC3Denum target, - const WebKit::WGC3Dbyte* mailbox) { } - virtual void consumeTextureCHROMIUM(WebKit::WGC3Denum target, - const WebKit::WGC3Dbyte* mailbox) { } - - virtual void setContextLostCallback( - WebGraphicsContextLostCallback* callback); - - virtual void loseContextCHROMIUM(WebKit::WGC3Denum current, - WebKit::WGC3Denum other); - - // Takes ownership of the |callback|. - virtual void signalSyncPoint(unsigned sync_point, - WebGraphicsSyncPointCallback* callback); - virtual void signalQuery(WebKit::WebGLId query, - WebGraphicsSyncPointCallback* callback); - - virtual void setSwapBuffersCompleteCallbackCHROMIUM( - WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback); - - virtual void prepareTexture(); - virtual void finish(); - virtual void flush(); - - virtual void bindBuffer(WebKit::WGC3Denum target, WebKit::WebGLId buffer); - virtual void bufferData(WebKit::WGC3Denum target, - WebKit::WGC3Dsizeiptr size, - const void* data, - WebKit::WGC3Denum usage); - virtual void* mapBufferCHROMIUM(WebKit::WGC3Denum target, - WebKit::WGC3Denum access); - virtual WebKit::WGC3Dboolean unmapBufferCHROMIUM(WebKit::WGC3Denum target); - - virtual WebKit::WGC3Duint createImageCHROMIUM( - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height, - WebKit::WGC3Denum internalformat); - virtual void destroyImageCHROMIUM(WebKit::WGC3Duint image_id); - virtual void getImageParameterivCHROMIUM( - WebKit::WGC3Duint image_id, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint* params); - virtual void* mapImageCHROMIUM( - WebKit::WGC3Duint image_id, - WebKit::WGC3Denum access); - virtual void unmapImageCHROMIUM(WebKit::WGC3Duint image_id); - - const ContextProvider::Capabilities& test_capabilities() const { - return test_capabilities_; - } - - // When set, MakeCurrent() will fail after this many times. - void set_times_make_current_succeeds(int times) { - times_make_current_succeeds_ = times; - } - void set_times_bind_texture_succeeds(int times) { - times_bind_texture_succeeds_ = times; - } - void set_times_end_query_succeeds(int times) { - times_end_query_succeeds_ = times; - } - void set_times_gen_mailbox_succeeds(int times) { - times_gen_mailbox_succeeds_ = times; - } - - // When set, mapImageCHROMIUM and mapBufferCHROMIUM will return NULL after - // this many times. - void set_times_map_image_chromium_succeeds(int times) { - times_map_image_chromium_succeeds_ = times; - } - void set_times_map_buffer_chromium_succeeds(int times) { - times_map_buffer_chromium_succeeds_ = times; - } - - size_t NumTextures() const; - WebKit::WebGLId TextureAt(int i) const; - - size_t NumUsedTextures() const { return used_textures_.size(); } - bool UsedTexture(int texture) const { - return ContainsKey(used_textures_, texture); - } - void ResetUsedTextures() { used_textures_.clear(); } - - void set_support_swapbuffers_complete_callback(bool support) { - test_capabilities_.swapbuffers_complete_callback = support; - } - void set_have_extension_io_surface(bool have) { - test_capabilities_.iosurface = have; - } - void set_have_extension_egl_image(bool have) { - test_capabilities_.egl_image_external = have; - } - void set_have_post_sub_buffer(bool have) { - test_capabilities_.post_sub_buffer = have; - } - void set_have_discard_framebuffer(bool have) { - test_capabilities_.discard_framebuffer = have; - } - - // When this context is lost, all contexts in its share group are also lost. - void add_share_group_context(WebKit::WebGraphicsContext3D* context3d) { - shared_contexts_.push_back(context3d); - } - - void set_max_texture_size(int size) { max_texture_size_ = size; } - - static const WebKit::WebGLId kExternalTextureId; - virtual WebKit::WebGLId NextTextureId(); - - virtual WebKit::WebGLId NextBufferId(); - - virtual WebKit::WebGLId NextImageId(); - - size_t GetTransferBufferMemoryUsedBytes() const; - void SetMaxTransferBufferUsageBytes(size_t max_transfer_buffer_usage_bytes); - - protected: - struct Buffer { - Buffer(); - ~Buffer(); - - WebKit::WGC3Denum target; - scoped_ptr<uint8[]> pixels; - size_t size; - - private: - DISALLOW_COPY_AND_ASSIGN(Buffer); - }; - - struct Image { - Image(); - ~Image(); - - scoped_ptr<uint8[]> pixels; - - private: - DISALLOW_COPY_AND_ASSIGN(Image); - }; - - struct Namespace : public base::RefCountedThreadSafe<Namespace> { - Namespace(); - - // Protects all fields. - base::Lock lock; - unsigned next_buffer_id; - unsigned next_image_id; - unsigned next_texture_id; - std::vector<WebKit::WebGLId> textures; - base::ScopedPtrHashMap<unsigned, Buffer> buffers; - base::ScopedPtrHashMap<unsigned, Image> images; - - private: - friend class base::RefCountedThreadSafe<Namespace>; - ~Namespace(); - DISALLOW_COPY_AND_ASSIGN(Namespace); - }; - - TestWebGraphicsContext3D(); - TestWebGraphicsContext3D( - const WebKit::WebGraphicsContext3D::Attributes& attributes); - - void CallAllSyncPointCallbacks(); - void SwapBuffersComplete(); - void CreateNamespace(); - - unsigned context_id_; - Attributes attributes_; - ContextProvider::Capabilities test_capabilities_; - int times_make_current_succeeds_; - int times_bind_texture_succeeds_; - int times_end_query_succeeds_; - int times_gen_mailbox_succeeds_; - bool context_lost_; - int times_map_image_chromium_succeeds_; - int times_map_buffer_chromium_succeeds_; - WebGraphicsContextLostCallback* context_lost_callback_; - WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* swap_buffers_callback_; - std::vector<WebGraphicsSyncPointCallback*> sync_point_callbacks_; - base::hash_set<WebKit::WebGLId> used_textures_; - std::vector<WebKit::WebGraphicsContext3D*> shared_contexts_; - int max_texture_size_; - int width_; - int height_; - - unsigned bound_buffer_; - - scoped_refptr<Namespace> namespace_; - static Namespace* shared_namespace_; - - base::WeakPtrFactory<TestWebGraphicsContext3D> weak_ptr_factory_; -}; - -} // namespace cc - -#endif // CC_DEBUG_TEST_WEB_GRAPHICS_CONTEXT_3D_H_ diff --git a/chromium/cc/debug/traced_picture.cc b/chromium/cc/debug/traced_picture.cc index 0cc2148f5f0..143f0b87adb 100644 --- a/chromium/cc/debug/traced_picture.cc +++ b/chromium/cc/debug/traced_picture.cc @@ -19,19 +19,17 @@ TracedPicture::TracedPicture(scoped_refptr<Picture> picture) TracedPicture::~TracedPicture() { } -scoped_ptr<base::debug::ConvertableToTraceFormat> +scoped_refptr<base::debug::ConvertableToTraceFormat> TracedPicture::AsTraceablePicture(Picture* picture) { - TracedPicture* ptr = new TracedPicture(picture); - scoped_ptr<TracedPicture> result(ptr); - return result.PassAs<base::debug::ConvertableToTraceFormat>(); + return scoped_refptr<base::debug::ConvertableToTraceFormat>( + new TracedPicture(picture)); } -scoped_ptr<base::debug::ConvertableToTraceFormat> +scoped_refptr<base::debug::ConvertableToTraceFormat> TracedPicture::AsTraceablePictureAlias(Picture* original) { - TracedPicture* ptr = new TracedPicture(original); + scoped_refptr<TracedPicture> ptr = new TracedPicture(original); ptr->is_alias_ = true; - scoped_ptr<TracedPicture> result(ptr); - return result.PassAs<base::debug::ConvertableToTraceFormat>(); + return scoped_refptr<base::debug::ConvertableToTraceFormat>(ptr); } void TracedPicture::AppendAsTraceFormat(std::string* out) const { diff --git a/chromium/cc/debug/traced_picture.h b/chromium/cc/debug/traced_picture.h index 50511f2034a..cc212ceed82 100644 --- a/chromium/cc/debug/traced_picture.h +++ b/chromium/cc/debug/traced_picture.h @@ -17,17 +17,17 @@ class TracedPicture : public base::debug::ConvertableToTraceFormat { public: explicit TracedPicture(scoped_refptr<Picture>); - virtual ~TracedPicture(); - - static scoped_ptr<base::debug::ConvertableToTraceFormat> + static scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceablePicture(Picture* picture); - static scoped_ptr<base::debug::ConvertableToTraceFormat> + static scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceablePictureAlias(Picture* original); virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE; private: + virtual ~TracedPicture(); + void AppendPicture(std::string* out) const; void AppendPictureAlias(std::string* out) const; diff --git a/chromium/cc/debug/traced_value.cc b/chromium/cc/debug/traced_value.cc index fbca5c60c80..5a324148725 100644 --- a/chromium/cc/debug/traced_value.cc +++ b/chromium/cc/debug/traced_value.cc @@ -30,11 +30,10 @@ void TracedValue::MakeDictIntoImplicitSnapshotWithCategory( MakeDictIntoImplicitSnapshot(dict, object_name, id); } -scoped_ptr<base::debug::ConvertableToTraceFormat> TracedValue::FromValue( +scoped_refptr<base::debug::ConvertableToTraceFormat> TracedValue::FromValue( base::Value* value) { - TracedValue* ptr = new TracedValue(value); - scoped_ptr<TracedValue> result(ptr); - return result.PassAs<base::debug::ConvertableToTraceFormat>(); + return scoped_refptr<base::debug::ConvertableToTraceFormat>( + new TracedValue(value)); } TracedValue::TracedValue(base::Value* value) diff --git a/chromium/cc/debug/traced_value.h b/chromium/cc/debug/traced_value.h index 148aca8ebb6..fe17695a45c 100644 --- a/chromium/cc/debug/traced_value.h +++ b/chromium/cc/debug/traced_value.h @@ -26,15 +26,14 @@ class TracedValue : public base::debug::ConvertableToTraceFormat { base::DictionaryValue* dict, const char* object_name, const void* id); - static scoped_ptr<ConvertableToTraceFormat> FromValue( + static scoped_refptr<base::debug::ConvertableToTraceFormat> FromValue( base::Value* value); - virtual ~TracedValue(); - virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE; private: explicit TracedValue(base::Value* value); + virtual ~TracedValue(); scoped_ptr<base::Value> value_; diff --git a/chromium/cc/debug/unittest_only_benchmark.cc b/chromium/cc/debug/unittest_only_benchmark.cc new file mode 100644 index 00000000000..9c6b17699e3 --- /dev/null +++ b/chromium/cc/debug/unittest_only_benchmark.cc @@ -0,0 +1,55 @@ +// Copyright 2013 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 "cc/debug/unittest_only_benchmark.h" + +#include "base/bind.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/values.h" +#include "cc/debug/unittest_only_benchmark_impl.h" + +namespace cc { + +UnittestOnlyBenchmark::UnittestOnlyBenchmark(scoped_ptr<base::Value> value, + const DoneCallback& callback) + : MicroBenchmark(callback), + create_impl_benchmark_(false), + weak_ptr_factory_(this) { + if (!value) + return; + + base::DictionaryValue* settings = NULL; + value->GetAsDictionary(&settings); + if (!settings) + return; + + if (settings->HasKey("run_benchmark_impl")) + settings->GetBoolean("run_benchmark_impl", &create_impl_benchmark_); +} + +UnittestOnlyBenchmark::~UnittestOnlyBenchmark() { + weak_ptr_factory_.InvalidateWeakPtrs(); +} + +void UnittestOnlyBenchmark::DidUpdateLayers(LayerTreeHost* host) { + NotifyDone(scoped_ptr<base::Value>()); +} + +void UnittestOnlyBenchmark::RecordImplResults(scoped_ptr<base::Value> results) { + NotifyDone(results.Pass()); +} + +scoped_ptr<MicroBenchmarkImpl> UnittestOnlyBenchmark::CreateBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop) { + if (!create_impl_benchmark_) + return make_scoped_ptr<MicroBenchmarkImpl>(NULL); + + return scoped_ptr<MicroBenchmarkImpl>(new UnittestOnlyBenchmarkImpl( + origin_loop, + NULL, + base::Bind(&UnittestOnlyBenchmark::RecordImplResults, + weak_ptr_factory_.GetWeakPtr()))); +} + +} // namespace cc diff --git a/chromium/cc/debug/unittest_only_benchmark.h b/chromium/cc/debug/unittest_only_benchmark.h new file mode 100644 index 00000000000..83312859644 --- /dev/null +++ b/chromium/cc/debug/unittest_only_benchmark.h @@ -0,0 +1,35 @@ +// Copyright 2013 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 CC_DEBUG_UNITTEST_ONLY_BENCHMARK_H_ +#define CC_DEBUG_UNITTEST_ONLY_BENCHMARK_H_ + +#include "base/memory/weak_ptr.h" +#include "cc/debug/micro_benchmark.h" + +namespace cc { + +class CC_EXPORT UnittestOnlyBenchmark : public MicroBenchmark { + public: + UnittestOnlyBenchmark(scoped_ptr<base::Value> value, + const DoneCallback& callback); + virtual ~UnittestOnlyBenchmark(); + + virtual void DidUpdateLayers(LayerTreeHost* host) OVERRIDE; + + protected: + virtual scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop) OVERRIDE; + + private: + void RecordImplResults(scoped_ptr<base::Value> results); + + bool create_impl_benchmark_; + base::WeakPtrFactory<UnittestOnlyBenchmark> weak_ptr_factory_; +}; + +} // namespace cc + +#endif // CC_DEBUG_UNITTEST_ONLY_BENCHMARK_H_ + diff --git a/chromium/cc/debug/unittest_only_benchmark_impl.cc b/chromium/cc/debug/unittest_only_benchmark_impl.cc new file mode 100644 index 00000000000..b249ce34476 --- /dev/null +++ b/chromium/cc/debug/unittest_only_benchmark_impl.cc @@ -0,0 +1,24 @@ +// Copyright 2013 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 "cc/debug/unittest_only_benchmark_impl.h" + +#include "base/message_loop/message_loop_proxy.h" +#include "base/values.h" + +namespace cc { + +UnittestOnlyBenchmarkImpl::UnittestOnlyBenchmarkImpl( + scoped_refptr<base::MessageLoopProxy> origin_loop, + base::Value* settings, + const DoneCallback& callback) + : MicroBenchmarkImpl(callback, origin_loop) {} + +UnittestOnlyBenchmarkImpl::~UnittestOnlyBenchmarkImpl() {} + +void UnittestOnlyBenchmarkImpl::DidCompleteCommit(LayerTreeHostImpl* host) { + NotifyDone(scoped_ptr<base::Value>()); +} + +} // namespace cc diff --git a/chromium/cc/debug/unittest_only_benchmark_impl.h b/chromium/cc/debug/unittest_only_benchmark_impl.h new file mode 100644 index 00000000000..b9e9bc9e95b --- /dev/null +++ b/chromium/cc/debug/unittest_only_benchmark_impl.h @@ -0,0 +1,31 @@ +// Copyright 2013 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 CC_DEBUG_UNITTEST_ONLY_BENCHMARK_IMPL_H_ +#define CC_DEBUG_UNITTEST_ONLY_BENCHMARK_IMPL_H_ + +#include "base/memory/weak_ptr.h" +#include "cc/debug/micro_benchmark_impl.h" + +namespace base { +class Value; +class MessageLoopProxy; +} + +namespace cc { + +class LayerTreeHostImpl; +class CC_EXPORT UnittestOnlyBenchmarkImpl : public MicroBenchmarkImpl { + public: + UnittestOnlyBenchmarkImpl(scoped_refptr<base::MessageLoopProxy> origin_loop, + base::Value* settings, + const DoneCallback& callback); + virtual ~UnittestOnlyBenchmarkImpl(); + + virtual void DidCompleteCommit(LayerTreeHostImpl* host) OVERRIDE; +}; + +} // namespace cc + +#endif // CC_DEBUG_UNITTEST_ONLY_BENCHMARK_IMPL_H_ diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h index d28935f0a39..fde89d265d6 100644 --- a/chromium/cc/input/input_handler.h +++ b/chromium/cc/input/input_handler.h @@ -8,6 +8,7 @@ #include "base/basictypes.h" #include "base/time/time.h" #include "cc/base/cc_export.h" +#include "cc/base/swap_promise_monitor.h" #include "cc/input/scrollbar.h" namespace gfx { @@ -96,6 +97,8 @@ class CC_EXPORT InputHandler { virtual void NotifyCurrentFlingVelocity(gfx::Vector2dF velocity) = 0; + virtual void MouseMoveAt(gfx::Point mouse_position) = 0; + // Stop scrolling the selected layer. Should only be called if ScrollBegin() // returned ScrollStarted. virtual void ScrollEnd() = 0; @@ -124,8 +127,13 @@ class CC_EXPORT InputHandler { virtual bool HaveTouchEventHandlersAt(gfx::Point viewport_point) = 0; - virtual void SetLatencyInfoForInputEvent( - const ui::LatencyInfo& latency_info) = 0; + // Calling CreateLatencyInfoSwapPromiseMonitor() to get a scoped + // LatencyInfoSwapPromiseMonitor. During the life time of the + // LatencyInfoSwapPromiseMonitor, if SetNeedsRedraw() or SetNeedsRedrawRect() + // is called on LayerTreeHostImpl, the original latency info will be turned + // into a LatencyInfoSwapPromise. + virtual scoped_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor( + ui::LatencyInfo* latency) = 0; protected: InputHandler() {} diff --git a/chromium/cc/input/layer_scroll_offset_delegate.h b/chromium/cc/input/layer_scroll_offset_delegate.h index 895d36d7490..54a11c9e2bd 100644 --- a/chromium/cc/input/layer_scroll_offset_delegate.h +++ b/chromium/cc/input/layer_scroll_offset_delegate.h @@ -6,6 +6,7 @@ #define CC_INPUT_LAYER_SCROLL_OFFSET_DELEGATE_H_ #include "base/basictypes.h" +#include "ui/gfx/size_f.h" #include "ui/gfx/vector2d_f.h" namespace cc { @@ -16,6 +17,10 @@ namespace cc { // The LayerScrollOffsetDelegate is only used on the impl thread. class LayerScrollOffsetDelegate { public: + // This is called by the compositor to notify the delegate what is the upper + // total scroll offset bound. + virtual void SetMaxScrollOffset(gfx::Vector2dF max_scroll_offset) = 0; + // This is called by the compositor when the scroll offset of the layer would // have otherwise changed. virtual void SetTotalScrollOffset(gfx::Vector2dF new_value) = 0; @@ -25,9 +30,22 @@ class LayerScrollOffsetDelegate { // There is no requirement that the return values of this method are // stable in time (two subsequent calls may yield different results). // The return value is not required to be related to the values passed in to - // the SetTotalScrollOffset method in any way. + // the SetTotalScrollOffset method in any way however it is required to be no + // more than the value passed to the most recent SetMaxScrollOffset call. virtual gfx::Vector2dF GetTotalScrollOffset() = 0; + // This is called by the compositor to check whether a delegate-managed fling + // is active or not. + virtual bool IsExternalFlingActive() const = 0; + + // This is called by the compositor to notify the delegate what is the current + // page scale factor is. + virtual void SetTotalPageScaleFactor(float page_scale_factor) = 0; + + // This is called by the compositor to notify the delegate what is the layer's + // scrollable size is. + virtual void SetScrollableSize(gfx::SizeF scrollable_size) = 0; + protected: LayerScrollOffsetDelegate() {} virtual ~LayerScrollOffsetDelegate() {} diff --git a/chromium/cc/input/top_controls_manager.cc b/chromium/cc/input/top_controls_manager.cc index 925830cf40e..871d9e6f69c 100644 --- a/chromium/cc/input/top_controls_manager.cc +++ b/chromium/cc/input/top_controls_manager.cc @@ -7,11 +7,12 @@ #include <algorithm> #include "base/logging.h" -#include "base/time/time.h" #include "cc/animation/keyframed_animation_curve.h" #include "cc/animation/timing_function.h" #include "cc/input/top_controls_manager_client.h" +#include "cc/output/begin_frame_args.h" #include "cc/trees/layer_tree_impl.h" +#include "ui/gfx/frame_time.h" #include "ui/gfx/transform.h" #include "ui/gfx/vector2d_f.h" @@ -48,7 +49,8 @@ TopControlsManager::TopControlsManager(TopControlsManagerClient* client, top_controls_show_height_( top_controls_height * top_controls_hide_threshold), top_controls_hide_height_( - top_controls_height * (1.f - top_controls_show_threshold)) { + top_controls_height * (1.f - top_controls_show_threshold)), + pinch_gesture_active_(false) { CHECK(client_); } @@ -89,6 +91,7 @@ void TopControlsManager::UpdateTopControlsState(TopControlsState constraints, } void TopControlsManager::ScrollBegin() { + DCHECK(!pinch_gesture_active_); ResetAnimations(); current_scroll_delta_ = 0.f; controls_scroll_begin_offset_ = controls_top_offset_; @@ -96,6 +99,9 @@ void TopControlsManager::ScrollBegin() { gfx::Vector2dF TopControlsManager::ScrollBy( const gfx::Vector2dF pending_delta) { + if (pinch_gesture_active_) + return pending_delta; + if (permitted_state_ == SHOWN && pending_delta.y() > 0) return pending_delta; else if (permitted_state_ == HIDDEN && pending_delta.y() < 0) @@ -120,9 +126,24 @@ gfx::Vector2dF TopControlsManager::ScrollBy( } void TopControlsManager::ScrollEnd() { + DCHECK(!pinch_gesture_active_); StartAnimationIfNecessary(); } +void TopControlsManager::PinchBegin() { + DCHECK(!pinch_gesture_active_); + pinch_gesture_active_ = true; + StartAnimationIfNecessary(); +} + +void TopControlsManager::PinchEnd() { + DCHECK(pinch_gesture_active_); + // Pinch{Begin,End} will always occur within the scope of Scroll{Begin,End}, + // so return to a state expected by the remaining scroll sequence. + pinch_gesture_active_ = false; + ScrollBegin(); +} + void TopControlsManager::SetControlsTopOffset(float controls_top_offset) { controls_top_offset = std::max(controls_top_offset, -top_controls_height_); controls_top_offset = std::min(controls_top_offset, 0.f); @@ -174,7 +195,7 @@ void TopControlsManager::SetupAnimation(AnimationDirection direction) { top_controls_animation_ = KeyframedFloatAnimationCurve::Create(); double start_time = - (base::TimeTicks::Now() - base::TimeTicks()).InMillisecondsF(); + (gfx::FrameTime::Now() - base::TimeTicks()).InMillisecondsF(); top_controls_animation_->AddKeyframe( FloatKeyframe::Create(start_time, controls_top_offset_, scoped_ptr<TimingFunction>())); diff --git a/chromium/cc/input/top_controls_manager.h b/chromium/cc/input/top_controls_manager.h index 9bc3040d31a..246efba5b9a 100644 --- a/chromium/cc/input/top_controls_manager.h +++ b/chromium/cc/input/top_controls_manager.h @@ -56,6 +56,11 @@ class CC_EXPORT TopControlsManager gfx::Vector2dF ScrollBy(const gfx::Vector2dF pending_delta); void ScrollEnd(); + // The caller should ensure that |Pinch{Begin,End}| are called within + // the scope of |Scroll{Begin,End}|. + void PinchBegin(); + void PinchEnd(); + gfx::Vector2dF Animate(base::TimeTicks monotonic_time); protected: @@ -91,6 +96,8 @@ class CC_EXPORT TopControlsManager // the user stops the scroll. float top_controls_hide_height_; + bool pinch_gesture_active_; + DISALLOW_COPY_AND_ASSIGN(TopControlsManager); }; diff --git a/chromium/cc/input/top_controls_manager_unittest.cc b/chromium/cc/input/top_controls_manager_unittest.cc index da7475f576c..74687adfac0 100644 --- a/chromium/cc/input/top_controls_manager_unittest.cc +++ b/chromium/cc/input/top_controls_manager_unittest.cc @@ -12,6 +12,7 @@ #include "cc/test/fake_layer_tree_host_impl.h" #include "cc/trees/layer_tree_impl.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/frame_time.h" #include "ui/gfx/vector2d_f.h" namespace cc { @@ -131,7 +132,7 @@ TEST(TopControlsManagerTest, PartialShownHideAnimation) { EXPECT_TRUE(manager->animation()); - base::TimeTicks time = base::TimeTicks::Now(); + base::TimeTicks time = gfx::FrameTime::Now(); float previous_offset = manager->controls_top_offset(); while (manager->animation()) { time = base::TimeDelta::FromMicroseconds(100) + time; @@ -161,7 +162,7 @@ TEST(TopControlsManagerTest, PartialShownShowAnimation) { EXPECT_TRUE(manager->animation()); - base::TimeTicks time = base::TimeTicks::Now(); + base::TimeTicks time = gfx::FrameTime::Now(); float previous_offset = manager->controls_top_offset(); while (manager->animation()) { time = base::TimeDelta::FromMicroseconds(100) + time; @@ -187,7 +188,7 @@ TEST(TopControlsManagerTest, PartialHiddenWithAmbiguousThresholdShows) { manager->ScrollEnd(); EXPECT_TRUE(manager->animation()); - base::TimeTicks time = base::TimeTicks::Now(); + base::TimeTicks time = gfx::FrameTime::Now(); float previous_offset = manager->controls_top_offset(); while (manager->animation()) { time = base::TimeDelta::FromMicroseconds(100) + time; @@ -213,7 +214,7 @@ TEST(TopControlsManagerTest, PartialHiddenWithAmbiguousThresholdHides) { manager->ScrollEnd(); EXPECT_TRUE(manager->animation()); - base::TimeTicks time = base::TimeTicks::Now(); + base::TimeTicks time = gfx::FrameTime::Now(); float previous_offset = manager->controls_top_offset(); while (manager->animation()) { time = base::TimeDelta::FromMicroseconds(100) + time; @@ -243,7 +244,7 @@ TEST(TopControlsManagerTest, PartialShownWithAmbiguousThresholdHides) { manager->ScrollEnd(); EXPECT_TRUE(manager->animation()); - base::TimeTicks time = base::TimeTicks::Now(); + base::TimeTicks time = gfx::FrameTime::Now(); float previous_offset = manager->controls_top_offset(); while (manager->animation()) { time = base::TimeDelta::FromMicroseconds(100) + time; @@ -273,7 +274,7 @@ TEST(TopControlsManagerTest, PartialShownWithAmbiguousThresholdShows) { manager->ScrollEnd(); EXPECT_TRUE(manager->animation()); - base::TimeTicks time = base::TimeTicks::Now(); + base::TimeTicks time = gfx::FrameTime::Now(); float previous_offset = manager->controls_top_offset(); while (manager->animation()) { time = base::TimeDelta::FromMicroseconds(100) + time; @@ -286,5 +287,88 @@ TEST(TopControlsManagerTest, PartialShownWithAmbiguousThresholdShows) { EXPECT_EQ(100.f, manager->content_top_offset()); } +TEST(TopControlsManagerTest, PinchIgnoresScroll) { + MockTopControlsManagerClient client(0.5f, 0.5f); + TopControlsManager* manager = client.manager(); + + // Hide the controls. + manager->ScrollBegin(); + EXPECT_EQ(0.f, manager->controls_top_offset()); + + manager->ScrollBy(gfx::Vector2dF(0.f, 300.f)); + EXPECT_EQ(-100.f, manager->controls_top_offset()); + + manager->PinchBegin(); + EXPECT_EQ(-100.f, manager->controls_top_offset()); + + // Scrolls are ignored during pinch. + manager->ScrollBy(gfx::Vector2dF(0.f, -15.f)); + EXPECT_EQ(-100.f, manager->controls_top_offset()); + manager->PinchEnd(); + EXPECT_EQ(-100.f, manager->controls_top_offset()); + + // Scrolls should no long be ignored. + manager->ScrollBy(gfx::Vector2dF(0.f, -15.f)); + EXPECT_EQ(-85.f, manager->controls_top_offset()); + EXPECT_EQ(15.f, manager->content_top_offset()); + manager->ScrollEnd(); + + EXPECT_TRUE(manager->animation()); +} + +TEST(TopControlsManagerTest, PinchBeginStartsAnimationIfNecessary) { + MockTopControlsManagerClient client(0.5f, 0.5f); + TopControlsManager* manager = client.manager(); + + manager->ScrollBegin(); + manager->ScrollBy(gfx::Vector2dF(0.f, 300.f)); + EXPECT_EQ(-100.f, manager->controls_top_offset()); + + manager->PinchBegin(); + EXPECT_FALSE(manager->animation()); + + manager->PinchEnd(); + EXPECT_FALSE(manager->animation()); + + manager->ScrollBy(gfx::Vector2dF(0.f, -15.f)); + EXPECT_EQ(-85.f, manager->controls_top_offset()); + EXPECT_EQ(15.f, manager->content_top_offset()); + + manager->PinchBegin(); + EXPECT_TRUE(manager->animation()); + + base::TimeTicks time = base::TimeTicks::Now(); + float previous_offset = manager->controls_top_offset(); + while (manager->animation()) { + time = base::TimeDelta::FromMicroseconds(100) + time; + manager->Animate(time); + EXPECT_LT(manager->controls_top_offset(), previous_offset); + previous_offset = manager->controls_top_offset(); + } + EXPECT_FALSE(manager->animation()); + + manager->PinchEnd(); + EXPECT_FALSE(manager->animation()); + + manager->ScrollBy(gfx::Vector2dF(0.f, -55.f)); + EXPECT_EQ(-45.f, manager->controls_top_offset()); + EXPECT_EQ(55.f, manager->content_top_offset()); + EXPECT_FALSE(manager->animation()); + + manager->ScrollEnd(); + EXPECT_TRUE(manager->animation()); + + time = base::TimeTicks::Now(); + previous_offset = manager->controls_top_offset(); + while (manager->animation()) { + time = base::TimeDelta::FromMicroseconds(100) + time; + manager->Animate(time); + EXPECT_GT(manager->controls_top_offset(), previous_offset); + previous_offset = manager->controls_top_offset(); + } + EXPECT_FALSE(manager->animation()); + EXPECT_EQ(0.f, manager->controls_top_offset()); +} + } // namespace } // namespace cc diff --git a/chromium/cc/layers/append_quads_data.h b/chromium/cc/layers/append_quads_data.h index 1ec8184a17a..5e19731fd28 100644 --- a/chromium/cc/layers/append_quads_data.h +++ b/chromium/cc/layers/append_quads_data.h @@ -12,19 +12,15 @@ namespace cc { struct AppendQuadsData { AppendQuadsData() - : had_occlusion_from_outside_target_surface(false), - had_incomplete_tile(false), + : had_incomplete_tile(false), num_missing_tiles(0), render_pass_id(0, 0) {} explicit AppendQuadsData(RenderPass::Id render_pass_id) - : had_occlusion_from_outside_target_surface(false), - had_incomplete_tile(false), + : had_incomplete_tile(false), num_missing_tiles(0), render_pass_id(render_pass_id) {} - // Set by the QuadCuller. - bool had_occlusion_from_outside_target_surface; // Set by the layer appending quads. bool had_incomplete_tile; // Set by the layer appending quads. diff --git a/chromium/cc/layers/compositing_reasons.h b/chromium/cc/layers/compositing_reasons.h index 02354a03283..6331a906ada 100644 --- a/chromium/cc/layers/compositing_reasons.h +++ b/chromium/cc/layers/compositing_reasons.h @@ -53,6 +53,8 @@ const uint64 kCompositingReasonLayerForBackground = GG_UINT64_C(1) << 30; const uint64 kCompositingReasonLayerForMask = GG_UINT64_C(1) << 31; const uint64 kCompositingReasonOverflowScrollingParent = GG_UINT64_C(1) << 32; const uint64 kCompositingReasonOutOfFlowClipping = GG_UINT64_C(1) << 33; +const uint64 kCompositingReasonIsolateCompositedDescendants = + GG_UINT64_C(1) << 35; typedef uint64 CompositingReasons; diff --git a/chromium/cc/layers/content_layer.cc b/chromium/cc/layers/content_layer.cc index 3d611eeef28..24cb8b36361 100644 --- a/chromium/cc/layers/content_layer.cc +++ b/chromium/cc/layers/content_layer.cc @@ -165,4 +165,10 @@ skia::RefPtr<SkPicture> ContentLayer::GetPicture() const { return picture; } +void ContentLayer::OnOutputSurfaceCreated() { + SetTextureFormat( + layer_tree_host()->GetRendererCapabilities().best_texture_format); + TiledLayer::OnOutputSurfaceCreated(); +} + } // namespace cc diff --git a/chromium/cc/layers/content_layer.h b/chromium/cc/layers/content_layer.h index a076c31dcac..45de86cde71 100644 --- a/chromium/cc/layers/content_layer.h +++ b/chromium/cc/layers/content_layer.h @@ -54,13 +54,17 @@ class CC_EXPORT ContentLayer : public TiledLayer { virtual skia::RefPtr<SkPicture> GetPicture() const OVERRIDE; + virtual void OnOutputSurfaceCreated() OVERRIDE; + protected: explicit ContentLayer(ContentLayerClient* client); virtual ~ContentLayer(); - private: // TiledLayer implementation. virtual LayerUpdater* Updater() const OVERRIDE; + + private: + // TiledLayer implementation. virtual void CreateUpdaterIfNeeded() OVERRIDE; void UpdateCanUseLCDText(); diff --git a/chromium/cc/layers/delegated_frame_provider.cc b/chromium/cc/layers/delegated_frame_provider.cc new file mode 100644 index 00000000000..c97f23171f5 --- /dev/null +++ b/chromium/cc/layers/delegated_frame_provider.cc @@ -0,0 +1,110 @@ +// Copyright 2013 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 "cc/layers/delegated_frame_provider.h" + +#include "cc/layers/delegated_frame_resource_collection.h" +#include "cc/layers/delegated_renderer_layer.h" +#include "cc/output/delegated_frame_data.h" +#include "cc/quads/render_pass_draw_quad.h" + +namespace cc { + +DelegatedFrameProvider::DelegatedFrameProvider( + const scoped_refptr<DelegatedFrameResourceCollection>& resource_collection, + scoped_ptr<DelegatedFrameData> frame) + : resource_collection_(resource_collection) { + RenderPass* root_pass = frame->render_pass_list.back(); + frame_size_ = root_pass->output_rect.size(); + DCHECK(!frame_size_.IsEmpty()); + SetFrameData(frame.Pass()); +} + +DelegatedFrameProvider::~DelegatedFrameProvider() { + ReturnedResourceArray returned; + TransferableResource::ReturnResources(frame_->resource_list, &returned); + resource_collection_->UnrefResources(returned); +} + +void DelegatedFrameProvider::AddObserver(DelegatedRendererLayer* layer) { + if (DCHECK_IS_ON()) { + for (size_t i = 0; i < observers_.size(); ++i) + DCHECK(observers_[i].layer != layer); + } + + observers_.push_back(Observer(layer, gfx::RectF(frame_size_))); + + DCHECK(frame_) << "Must have a frame when given to a DelegatedRendererLayer."; +} + +void DelegatedFrameProvider::RemoveObserver(DelegatedRendererLayer* layer) { + bool found_observer = false; + for (size_t i = 0; i < observers_.size(); ++i) { + if (observers_[i].layer != layer) + continue; + observers_.erase(observers_.begin() + i); + found_observer = true; + break; + } + DCHECK(found_observer); +} + +void DelegatedFrameProvider::SetFrameData( + scoped_ptr<DelegatedFrameData> frame) { + DCHECK(frame); + DCHECK_NE(0u, frame->render_pass_list.size()); + + if (frame_) { + ReturnedResourceArray returned; + TransferableResource::ReturnResources(frame_->resource_list, &returned); + resource_collection_->UnrefResources(returned); + } + + frame_ = frame.Pass(); + + resource_collection_->ReceivedResources(frame_->resource_list); + resource_collection_->RefResources(frame_->resource_list); + + RenderPass* root_pass = frame_->render_pass_list.back(); + DCHECK_EQ(frame_size_.ToString(), root_pass->output_rect.size().ToString()) + << "All frames in a single DelegatedFrameProvider must have the same " + << "size. Use a new frame provider for frames of a different size."; + + for (size_t i = 0; i < observers_.size(); ++i) { + observers_[i].damage = + gfx::UnionRects(observers_[i].damage, root_pass->damage_rect); + observers_[i].layer->ProviderHasNewFrame(); + } +} + +DelegatedFrameData* DelegatedFrameProvider::GetFrameDataAndRefResources( + DelegatedRendererLayer* observer, + gfx::RectF* damage) { + + bool found_observer = false; + for (size_t i = 0; i < observers_.size(); ++i) { + if (observers_[i].layer != observer) + continue; + *damage = observers_[i].damage; + // The observer is now responsible for the damage. + observers_[i].damage = gfx::RectF(); + found_observer = true; + } + DCHECK(found_observer); + + resource_collection_->RefResources(frame_->resource_list); + return frame_.get(); +} + +ReturnCallback +DelegatedFrameProvider::GetReturnResourcesCallbackForImplThread() { + return resource_collection_->GetReturnResourcesCallbackForImplThread(); +} + +void DelegatedFrameProvider::UnrefResourcesOnMainThread( + const ReturnedResourceArray& returned) { + resource_collection_->UnrefResources(returned); +} + +} // namespace cc diff --git a/chromium/cc/layers/delegated_frame_provider.h b/chromium/cc/layers/delegated_frame_provider.h new file mode 100644 index 00000000000..b71c74881b2 --- /dev/null +++ b/chromium/cc/layers/delegated_frame_provider.h @@ -0,0 +1,75 @@ +// Copyright 2013 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 CC_LAYERS_DELEGATED_FRAME_PROVIDER_H_ +#define CC_LAYERS_DELEGATED_FRAME_PROVIDER_H_ + +#include <vector> + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "cc/resources/return_callback.h" +#include "cc/resources/returned_resource.h" +#include "ui/gfx/rect_f.h" +#include "ui/gfx/size.h" + +namespace cc { +class DelegatedFrameData; +class DelegatedFrameResourceCollection; +class DelegatedRendererLayer; + +// Only one observing layer has ownership of the DelegatedFrameProvider. Only +// the active observer should call GetFrameDataAndRefResources(). All frames +// provided by a single DelegatedFrameProvider must have the same size. A new +// provider must be used for frames of a different size. +class CC_EXPORT DelegatedFrameProvider + : public base::RefCounted<DelegatedFrameProvider> { + public: + explicit DelegatedFrameProvider( + const scoped_refptr<DelegatedFrameResourceCollection>& + resource_collection, + scoped_ptr<DelegatedFrameData> frame); + + void AddObserver(DelegatedRendererLayer* layer); + void RemoveObserver(DelegatedRendererLayer* layer); + + void SetFrameData(scoped_ptr<DelegatedFrameData> frame); + + // The DelegatedFrameData returned here must be displayed in order to not + // lose track of damage. + DelegatedFrameData* GetFrameDataAndRefResources( + DelegatedRendererLayer* observer, + gfx::RectF* damage); + + ReturnCallback GetReturnResourcesCallbackForImplThread(); + void UnrefResourcesOnMainThread(const ReturnedResourceArray& unused); + + gfx::Size frame_size() const { return frame_size_; } + + private: + friend class base::RefCounted<DelegatedFrameProvider>; + ~DelegatedFrameProvider(); + + scoped_refptr<DelegatedFrameResourceCollection> resource_collection_; + + scoped_ptr<DelegatedFrameData> frame_; + + struct Observer { + DelegatedRendererLayer* layer; + gfx::RectF damage; + + Observer(DelegatedRendererLayer* layer, const gfx::RectF& damage) + : layer(layer), damage(damage) {} + }; + std::vector<Observer> observers_; + + gfx::Size frame_size_; + + DISALLOW_COPY_AND_ASSIGN(DelegatedFrameProvider); +}; + +} // namespace cc + +#endif // CC_LAYERS_DELEGATED_FRAME_PROVIDER_H_ diff --git a/chromium/cc/layers/delegated_frame_provider_unittest.cc b/chromium/cc/layers/delegated_frame_provider_unittest.cc new file mode 100644 index 00000000000..20b355c6192 --- /dev/null +++ b/chromium/cc/layers/delegated_frame_provider_unittest.cc @@ -0,0 +1,395 @@ +// Copyright 2013 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 "cc/layers/delegated_frame_provider.h" +#include "cc/layers/delegated_frame_resource_collection.h" +#include "cc/layers/delegated_renderer_layer.h" +#include "cc/output/delegated_frame_data.h" +#include "cc/quads/texture_draw_quad.h" +#include "cc/resources/returned_resource.h" +#include "cc/resources/transferable_resource.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +class DelegatedFrameProviderTest + : public testing::Test, + public DelegatedFrameResourceCollectionClient { + protected: + DelegatedFrameProviderTest() : resources_available_(false) {} + + scoped_ptr<DelegatedFrameData> CreateFrameData(gfx::Rect root_output_rect, + gfx::Rect root_damage_rect) { + scoped_ptr<DelegatedFrameData> frame(new DelegatedFrameData); + + scoped_ptr<RenderPass> root_pass(RenderPass::Create()); + root_pass->SetNew(RenderPass::Id(1, 1), + root_output_rect, + root_damage_rect, + gfx::Transform()); + frame->render_pass_list.push_back(root_pass.Pass()); + return frame.Pass(); + } + + void AddTransferableResource(DelegatedFrameData* frame, + ResourceProvider::ResourceId resource_id) { + TransferableResource resource; + resource.id = resource_id; + resource.target = GL_TEXTURE_2D; + frame->resource_list.push_back(resource); + } + + void AddTextureQuad(DelegatedFrameData* frame, + ResourceProvider::ResourceId resource_id) { + scoped_ptr<SharedQuadState> sqs = SharedQuadState::Create(); + scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create(); + float vertex_opacity[4] = {1.f, 1.f, 1.f, 1.f}; + quad->SetNew(sqs.get(), + gfx::Rect(0, 0, 10, 10), + gfx::Rect(0, 0, 10, 10), + resource_id, + false, + gfx::PointF(0.f, 0.f), + gfx::PointF(1.f, 1.f), + SK_ColorTRANSPARENT, + vertex_opacity, + false); + frame->render_pass_list[0]->shared_quad_state_list.push_back(sqs.Pass()); + frame->render_pass_list[0]->quad_list.push_back(quad.PassAs<DrawQuad>()); + } + + virtual void SetUp() OVERRIDE { + resource_collection_ = new DelegatedFrameResourceCollection; + resource_collection_->SetClient(this); + } + + virtual void TearDown() OVERRIDE { resource_collection_->SetClient(NULL); } + + virtual void UnusedResourcesAreAvailable() OVERRIDE { + resources_available_ = true; + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources_); + } + + bool ReturnAndResetResourcesAvailable() { + bool r = resources_available_; + resources_available_ = false; + return r; + } + + void SetFrameProvider(scoped_ptr<DelegatedFrameData> frame_data) { + frame_provider_ = + new DelegatedFrameProvider(resource_collection_, frame_data.Pass()); + } + + scoped_refptr<DelegatedFrameResourceCollection> resource_collection_; + scoped_refptr<DelegatedFrameProvider> frame_provider_; + bool resources_available_; + ReturnedResourceArray resources_; +}; + +TEST_F(DelegatedFrameProviderTest, SameResources) { + scoped_ptr<DelegatedFrameData> frame = + CreateFrameData(gfx::Rect(1, 1), gfx::Rect(1, 1)); + AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); + SetFrameProvider(frame.Pass()); + + frame = CreateFrameData(gfx::Rect(1, 1), gfx::Rect(1, 1)); + AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); + SetFrameProvider(frame.Pass()); + + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(0u, resources_.size()); + + frame_provider_ = NULL; + + EXPECT_TRUE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(1u, resources_.size()); + EXPECT_EQ(444u, resources_[0].id); +} + +TEST_F(DelegatedFrameProviderTest, ReplaceResources) { + scoped_ptr<DelegatedFrameData> frame = + CreateFrameData(gfx::Rect(1, 1), gfx::Rect(1, 1)); + AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); + SetFrameProvider(frame.Pass()); + + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + + frame = CreateFrameData(gfx::Rect(1, 1), gfx::Rect(1, 1)); + AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); + SetFrameProvider(frame.Pass()); + + EXPECT_TRUE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(1u, resources_.size()); + EXPECT_EQ(444u, resources_[0].id); + resources_.clear(); + + frame_provider_ = NULL; + + EXPECT_TRUE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(1u, resources_.size()); + EXPECT_EQ(555u, resources_[0].id); +} + +TEST_F(DelegatedFrameProviderTest, RefResources) { + scoped_ptr<DelegatedFrameData> frame = + CreateFrameData(gfx::Rect(5, 5), gfx::Rect(2, 2)); + AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); + + TransferableResourceArray reffed = frame->resource_list; + ReturnedResourceArray returned; + TransferableResource::ReturnResources(reffed, &returned); + + SetFrameProvider(frame.Pass()); + + scoped_refptr<DelegatedRendererLayer> observer1 = + DelegatedRendererLayer::Create(frame_provider_); + scoped_refptr<DelegatedRendererLayer> observer2 = + DelegatedRendererLayer::Create(frame_provider_); + + gfx::RectF damage; + + // Both observers get a full frame of damage on the first request. + frame_provider_->GetFrameDataAndRefResources(observer1, &damage); + EXPECT_EQ(gfx::RectF(5.f, 5.f).ToString(), damage.ToString()); + frame_provider_->GetFrameDataAndRefResources(observer2, &damage); + EXPECT_EQ(gfx::RectF(5.f, 5.f).ToString(), damage.ToString()); + + // And both get no damage on the 2nd request. This adds a second ref to the + // resources. + frame_provider_->GetFrameDataAndRefResources(observer1, &damage); + EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + frame_provider_->GetFrameDataAndRefResources(observer2, &damage); + EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + + frame = CreateFrameData(gfx::Rect(5, 5), gfx::Rect(2, 2)); + AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); + frame_provider_->SetFrameData(frame.Pass()); + + // The resources from the first frame are still reffed by the observers. + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + + // There are 4 refs taken. + frame_provider_->UnrefResourcesOnMainThread(returned); + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + frame_provider_->UnrefResourcesOnMainThread(returned); + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + frame_provider_->UnrefResourcesOnMainThread(returned); + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + + // The 4th unref will release them. + frame_provider_->UnrefResourcesOnMainThread(returned); + + EXPECT_TRUE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(1u, resources_.size()); + EXPECT_EQ(444u, resources_[0].id); +} + +TEST_F(DelegatedFrameProviderTest, RefResourcesInFrameProvider) { + scoped_ptr<DelegatedFrameData> frame = + CreateFrameData(gfx::Rect(5, 5), gfx::Rect(2, 2)); + AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); + + TransferableResourceArray reffed = frame->resource_list; + ReturnedResourceArray returned; + TransferableResource::ReturnResources(reffed, &returned); + + SetFrameProvider(frame.Pass()); + + scoped_refptr<DelegatedRendererLayer> observer1 = + DelegatedRendererLayer::Create(frame_provider_); + scoped_refptr<DelegatedRendererLayer> observer2 = + DelegatedRendererLayer::Create(frame_provider_); + + gfx::RectF damage; + + // Take a ref on each observer. + frame_provider_->GetFrameDataAndRefResources(observer1, &damage); + frame_provider_->GetFrameDataAndRefResources(observer2, &damage); + + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + + // Release both refs. But there's still a ref held in the frame + // provider itself. + frame_provider_->UnrefResourcesOnMainThread(returned); + frame_provider_->UnrefResourcesOnMainThread(returned); + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + + // Setting a new frame will release it. + frame = CreateFrameData(gfx::Rect(5, 5), gfx::Rect(2, 2)); + AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); + frame_provider_->SetFrameData(frame.Pass()); + + EXPECT_TRUE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(1u, resources_.size()); + EXPECT_EQ(444u, resources_[0].id); +} + +TEST_F(DelegatedFrameProviderTest, RefResourcesInFrameProviderUntilDestroy) { + scoped_ptr<DelegatedFrameData> frame = + CreateFrameData(gfx::Rect(5, 5), gfx::Rect(2, 2)); + AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); + + TransferableResourceArray reffed = frame->resource_list; + ReturnedResourceArray returned; + TransferableResource::ReturnResources(reffed, &returned); + + SetFrameProvider(frame.Pass()); + + scoped_refptr<DelegatedRendererLayer> observer1 = + DelegatedRendererLayer::Create(frame_provider_); + scoped_refptr<DelegatedRendererLayer> observer2 = + DelegatedRendererLayer::Create(frame_provider_); + + gfx::RectF damage; + + // Take a ref on each observer. + frame_provider_->GetFrameDataAndRefResources(observer1, &damage); + frame_provider_->GetFrameDataAndRefResources(observer2, &damage); + + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + + // Release both refs. But there's still a ref held in the frame + // provider itself. + frame_provider_->UnrefResourcesOnMainThread(returned); + frame_provider_->UnrefResourcesOnMainThread(returned); + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + + // Releasing all references to the frame provider will release + // the frame. + observer1 = NULL; + observer2 = NULL; + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + + frame_provider_ = NULL; + + EXPECT_TRUE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(1u, resources_.size()); + EXPECT_EQ(444u, resources_[0].id); +} + +TEST_F(DelegatedFrameProviderTest, Damage) { + scoped_ptr<DelegatedFrameData> frame = + CreateFrameData(gfx::Rect(5, 5), gfx::Rect(2, 2)); + AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); + + TransferableResourceArray reffed = frame->resource_list; + ReturnedResourceArray returned; + TransferableResource::ReturnResources(reffed, &returned); + + SetFrameProvider(frame.Pass()); + + scoped_refptr<DelegatedRendererLayer> observer1 = + DelegatedRendererLayer::Create(frame_provider_); + scoped_refptr<DelegatedRendererLayer> observer2 = + DelegatedRendererLayer::Create(frame_provider_); + + gfx::RectF damage; + + // Both observers get a full frame of damage on the first request. + frame_provider_->GetFrameDataAndRefResources(observer1, &damage); + EXPECT_EQ(gfx::RectF(5.f, 5.f).ToString(), damage.ToString()); + frame_provider_->GetFrameDataAndRefResources(observer2, &damage); + EXPECT_EQ(gfx::RectF(5.f, 5.f).ToString(), damage.ToString()); + + // And both get no damage on the 2nd request. + frame_provider_->GetFrameDataAndRefResources(observer1, &damage); + EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + frame_provider_->GetFrameDataAndRefResources(observer2, &damage); + EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + + frame = CreateFrameData(gfx::Rect(5, 5), gfx::Rect(2, 2)); + AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); + frame_provider_->SetFrameData(frame.Pass()); + + // Both observers get the damage for the new frame. + frame_provider_->GetFrameDataAndRefResources(observer1, &damage); + EXPECT_EQ(gfx::RectF(2.f, 2.f).ToString(), damage.ToString()); + frame_provider_->GetFrameDataAndRefResources(observer2, &damage); + EXPECT_EQ(gfx::RectF(2.f, 2.f).ToString(), damage.ToString()); + + // And both get no damage on the 2nd request. + frame_provider_->GetFrameDataAndRefResources(observer1, &damage); + EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + frame_provider_->GetFrameDataAndRefResources(observer2, &damage); + EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); +} + +TEST_F(DelegatedFrameProviderTest, LostNothing) { + scoped_ptr<DelegatedFrameData> frame = + CreateFrameData(gfx::Rect(5, 5), gfx::Rect(5, 5)); + + TransferableResourceArray reffed = frame->resource_list; + + SetFrameProvider(frame.Pass()); + + // There is nothing to lose. + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + EXPECT_FALSE(resource_collection_->LoseAllResources()); + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(0u, resources_.size()); +} + +TEST_F(DelegatedFrameProviderTest, LostSomething) { + scoped_ptr<DelegatedFrameData> frame = + CreateFrameData(gfx::Rect(5, 5), gfx::Rect(5, 5)); + AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); + + SetFrameProvider(frame.Pass()); + + // Add a second reference on the resource. + frame = CreateFrameData(gfx::Rect(5, 5), gfx::Rect(5, 5)); + AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); + + SetFrameProvider(frame.Pass()); + + // There is something to lose. + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + EXPECT_TRUE(resource_collection_->LoseAllResources()); + EXPECT_TRUE(ReturnAndResetResourcesAvailable()); + + EXPECT_EQ(1u, resources_.size()); + EXPECT_EQ(444u, resources_[0].id); + EXPECT_EQ(2, resources_[0].count); +} + +TEST_F(DelegatedFrameProviderTest, NothingReturnedAfterLoss) { + scoped_ptr<DelegatedFrameData> frame = + CreateFrameData(gfx::Rect(1, 1), gfx::Rect(1, 1)); + AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); + SetFrameProvider(frame.Pass()); + + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + + // Lose all the resources. + EXPECT_TRUE(resource_collection_->LoseAllResources()); + EXPECT_TRUE(ReturnAndResetResourcesAvailable()); + resources_.clear(); + + frame_provider_ = NULL; + + // Nothing is returned twice. + EXPECT_FALSE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(0u, resources_.size()); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/layers/delegated_frame_resource_collection.cc b/chromium/cc/layers/delegated_frame_resource_collection.cc new file mode 100644 index 00000000000..5ca4eda57d7 --- /dev/null +++ b/chromium/cc/layers/delegated_frame_resource_collection.cc @@ -0,0 +1,133 @@ +// Copyright 2013 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 "cc/layers/delegated_frame_resource_collection.h" + +#include "base/bind.h" +#include "cc/trees/blocking_task_runner.h" + +namespace cc { + +DelegatedFrameResourceCollection::DelegatedFrameResourceCollection() + : client_(NULL), + main_thread_runner_(BlockingTaskRunner::current()), + lost_all_resources_(false), + weak_ptr_factory_(this) { + DCHECK(main_thread_checker_.CalledOnValidThread()); +} + +DelegatedFrameResourceCollection::~DelegatedFrameResourceCollection() { + DCHECK(main_thread_checker_.CalledOnValidThread()); +} + +void DelegatedFrameResourceCollection::SetClient( + DelegatedFrameResourceCollectionClient* client) { + client_ = client; +} + +void DelegatedFrameResourceCollection::TakeUnusedResourcesForChildCompositor( + ReturnedResourceArray* array) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK(array->empty()); + array->swap(returned_resources_for_child_compositor_); +} + +bool DelegatedFrameResourceCollection::LoseAllResources() { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK(!lost_all_resources_); + lost_all_resources_ = true; + + if (resource_id_ref_count_map_.empty()) + return false; + + ReturnedResourceArray to_return; + + for (ResourceIdRefCountMap::iterator it = resource_id_ref_count_map_.begin(); + it != resource_id_ref_count_map_.end(); + ++it) { + DCHECK_GE(it->second.refs_to_wait_for, 1); + + ReturnedResource returned; + returned.id = it->first; + returned.count = it->second.refs_to_return; + returned.lost = true; + to_return.push_back(returned); + } + + returned_resources_for_child_compositor_.insert( + returned_resources_for_child_compositor_.end(), + to_return.begin(), + to_return.end()); + if (client_) + client_->UnusedResourcesAreAvailable(); + return true; +} + +void DelegatedFrameResourceCollection::ReceivedResources( + const TransferableResourceArray& resources) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK(!lost_all_resources_); + + for (size_t i = 0; i < resources.size(); ++i) + resource_id_ref_count_map_[resources[i].id].refs_to_return++; +} + +void DelegatedFrameResourceCollection::UnrefResources( + const ReturnedResourceArray& returned) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + + if (lost_all_resources_) + return; + + ReturnedResourceArray to_return; + + for (size_t i = 0; i < returned.size(); ++i) { + ResourceIdRefCountMap::iterator it = + resource_id_ref_count_map_.find(returned[i].id); + DCHECK(it != resource_id_ref_count_map_.end()); + DCHECK_GE(it->second.refs_to_wait_for, returned[i].count); + it->second.refs_to_wait_for -= returned[i].count; + if (it->second.refs_to_wait_for == 0) { + to_return.push_back(returned[i]); + to_return.back().count = it->second.refs_to_return; + resource_id_ref_count_map_.erase(it); + } + } + + if (to_return.empty()) + return; + + returned_resources_for_child_compositor_.insert( + returned_resources_for_child_compositor_.end(), + to_return.begin(), + to_return.end()); + if (client_) + client_->UnusedResourcesAreAvailable(); +} + +void DelegatedFrameResourceCollection::RefResources( + const TransferableResourceArray& resources) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + for (size_t i = 0; i < resources.size(); ++i) + resource_id_ref_count_map_[resources[i].id].refs_to_wait_for++; +} + +static void UnrefResourcesOnImplThread( + base::WeakPtr<DelegatedFrameResourceCollection> self, + scoped_refptr<BlockingTaskRunner> main_thread_runner, + const ReturnedResourceArray& returned) { + main_thread_runner->PostTask( + FROM_HERE, + base::Bind( + &DelegatedFrameResourceCollection::UnrefResources, self, returned)); +} + +ReturnCallback +DelegatedFrameResourceCollection::GetReturnResourcesCallbackForImplThread() { + return base::Bind(&UnrefResourcesOnImplThread, + weak_ptr_factory_.GetWeakPtr(), + main_thread_runner_); +} + +} // namespace cc diff --git a/chromium/cc/layers/delegated_frame_resource_collection.h b/chromium/cc/layers/delegated_frame_resource_collection.h new file mode 100644 index 00000000000..9a5d336749b --- /dev/null +++ b/chromium/cc/layers/delegated_frame_resource_collection.h @@ -0,0 +1,71 @@ +// Copyright 2013 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 CC_LAYERS_DELEGATED_FRAME_RESOURCE_COLLECTION_H_ +#define CC_LAYERS_DELEGATED_FRAME_RESOURCE_COLLECTION_H_ + +#include "base/containers/hash_tables.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/threading/thread_checker.h" +#include "cc/base/cc_export.h" +#include "cc/resources/return_callback.h" +#include "cc/resources/returned_resource.h" +#include "cc/resources/transferable_resource.h" + +namespace cc { +class BlockingTaskRunner; + +class CC_EXPORT DelegatedFrameResourceCollectionClient { + public: + // Called to inform the client that returned resources can be + // grabbed off the DelegatedFrameResourceCollection. + virtual void UnusedResourcesAreAvailable() = 0; +}; + +class CC_EXPORT DelegatedFrameResourceCollection + : public base::RefCounted<DelegatedFrameResourceCollection> { + public: + DelegatedFrameResourceCollection(); + + void SetClient(DelegatedFrameResourceCollectionClient* client); + + void TakeUnusedResourcesForChildCompositor(ReturnedResourceArray* array); + + // Considers all resources as lost, and returns true if it held any resource + // to lose. + bool LoseAllResources(); + + // Methods for DelegatedFrameProvider. + void RefResources(const TransferableResourceArray& resources); + void UnrefResources(const ReturnedResourceArray& returned); + void ReceivedResources(const TransferableResourceArray& resources); + ReturnCallback GetReturnResourcesCallbackForImplThread(); + + private: + friend class base::RefCounted<DelegatedFrameResourceCollection>; + ~DelegatedFrameResourceCollection(); + + DelegatedFrameResourceCollectionClient* client_; + scoped_refptr<BlockingTaskRunner> main_thread_runner_; + + ReturnedResourceArray returned_resources_for_child_compositor_; + bool lost_all_resources_; + + struct RefCount { + int refs_to_return; + int refs_to_wait_for; + }; + typedef base::hash_map<unsigned, RefCount> ResourceIdRefCountMap; + ResourceIdRefCountMap resource_id_ref_count_map_; + + base::ThreadChecker main_thread_checker_; + base::WeakPtrFactory<DelegatedFrameResourceCollection> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(DelegatedFrameResourceCollection); +}; + +} // namespace cc + +#endif // CC_LAYERS_DELEGATED_FRAME_RESOURCE_COLLECTION_H_ diff --git a/chromium/cc/layers/delegated_frame_resource_collection_unittest.cc b/chromium/cc/layers/delegated_frame_resource_collection_unittest.cc new file mode 100644 index 00000000000..29f0eb54a5a --- /dev/null +++ b/chromium/cc/layers/delegated_frame_resource_collection_unittest.cc @@ -0,0 +1,160 @@ +// Copyright 2013 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 "base/bind.h" +#include "base/run_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" +#include "cc/layers/delegated_frame_resource_collection.h" +#include "cc/resources/returned_resource.h" +#include "cc/resources/transferable_resource.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +class DelegatedFrameResourceCollectionTest + : public testing::Test, + public DelegatedFrameResourceCollectionClient { + protected: + DelegatedFrameResourceCollectionTest() : resources_available_(false) {} + + virtual void SetUp() OVERRIDE { CreateResourceCollection(); } + + virtual void TearDown() OVERRIDE { DestroyResourceCollection(); } + + void CreateResourceCollection() { + DCHECK(!resource_collection_); + resource_collection_ = new DelegatedFrameResourceCollection; + resource_collection_->SetClient(this); + } + + void DestroyResourceCollection() { + if (resource_collection_) { + resource_collection_->SetClient(NULL); + resource_collection_ = NULL; + } + } + + TransferableResourceArray CreateResourceArray() { + TransferableResourceArray resources; + TransferableResource resource; + resource.id = 444; + resources.push_back(resource); + return resources; + } + + virtual void UnusedResourcesAreAvailable() OVERRIDE { + resources_available_ = true; + resource_collection_->TakeUnusedResourcesForChildCompositor( + &returned_resources_); + if (!resources_available_closure_.is_null()) + resources_available_closure_.Run(); + } + + bool ReturnAndResetResourcesAvailable() { + bool r = resources_available_; + resources_available_ = false; + return r; + } + + scoped_refptr<DelegatedFrameResourceCollection> resource_collection_; + bool resources_available_; + ReturnedResourceArray returned_resources_; + base::Closure resources_available_closure_; +}; + +// This checks that taking the return callback doesn't take extra refcounts, +// since it's sent to other threads. +TEST_F(DelegatedFrameResourceCollectionTest, NoRef) { + // Start with one ref. + EXPECT_TRUE(resource_collection_->HasOneRef()); + + ReturnCallback return_callback = + resource_collection_->GetReturnResourcesCallbackForImplThread(); + + // Callback shouldn't take a ref since it's sent to other threads. + EXPECT_TRUE(resource_collection_->HasOneRef()); +} + +void ReturnResourcesOnThread(ReturnCallback callback, + const ReturnedResourceArray& resources, + base::WaitableEvent* event) { + callback.Run(resources); + if (event) + event->Wait(); +} + +// Tests that the ReturnCallback can run safely on threads even after the +// last references to the collection were dropped. +// Flaky: crbug.com/313441 +TEST_F(DelegatedFrameResourceCollectionTest, Thread) { + base::Thread thread("test thread"); + thread.Start(); + + TransferableResourceArray resources = CreateResourceArray(); + resource_collection_->ReceivedResources(resources); + resource_collection_->RefResources(resources); + + ReturnedResourceArray returned_resources; + TransferableResource::ReturnResources(resources, &returned_resources); + + base::WaitableEvent event(false, false); + + { + base::RunLoop run_loop; + resources_available_closure_ = run_loop.QuitClosure(); + + thread.message_loop()->PostTask( + FROM_HERE, + base::Bind( + &ReturnResourcesOnThread, + resource_collection_->GetReturnResourcesCallbackForImplThread(), + returned_resources, + &event)); + + run_loop.Run(); + } + EXPECT_TRUE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(1u, returned_resources_.size()); + EXPECT_EQ(444u, returned_resources_[0].id); + EXPECT_EQ(1, returned_resources_[0].count); + returned_resources_.clear(); + + // The event prevents the return resources callback from being deleted. + // Destroy the last reference from this thread to the collection before + // signaling the event, to ensure any reference taken by the callback, if any, + // would be the last one. + DestroyResourceCollection(); + event.Signal(); + + CreateResourceCollection(); + resource_collection_->ReceivedResources(resources); + resource_collection_->RefResources(resources); + + // Destroy the collection before we have a chance to run the return callback. + ReturnCallback return_callback = + resource_collection_->GetReturnResourcesCallbackForImplThread(); + resource_collection_->LoseAllResources(); + DestroyResourceCollection(); + + EXPECT_TRUE(ReturnAndResetResourcesAvailable()); + EXPECT_EQ(1u, returned_resources_.size()); + EXPECT_EQ(444u, returned_resources_[0].id); + EXPECT_EQ(1, returned_resources_[0].count); + EXPECT_TRUE(returned_resources_[0].lost); + returned_resources_.clear(); + + base::WaitableEvent* null_event = NULL; + thread.message_loop()->PostTask(FROM_HERE, + base::Bind(&ReturnResourcesOnThread, + return_callback, + returned_resources, + null_event)); + + thread.Stop(); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/layers/delegated_renderer_layer.cc b/chromium/cc/layers/delegated_renderer_layer.cc index cc49c753e25..6616b9b345a 100644 --- a/chromium/cc/layers/delegated_renderer_layer.cc +++ b/chromium/cc/layers/delegated_renderer_layer.cc @@ -4,7 +4,6 @@ #include "cc/layers/delegated_renderer_layer.h" -#include "cc/layers/delegated_renderer_layer_client.h" #include "cc/layers/delegated_renderer_layer_impl.h" #include "cc/output/delegated_frame_data.h" #include "cc/quads/render_pass_draw_quad.h" @@ -14,20 +13,25 @@ namespace cc { scoped_refptr<DelegatedRendererLayer> DelegatedRendererLayer::Create( - DelegatedRendererLayerClient* client) { + const scoped_refptr<DelegatedFrameProvider>& frame_provider) { return scoped_refptr<DelegatedRendererLayer>( - new DelegatedRendererLayer(client)); + new DelegatedRendererLayer(frame_provider)); } DelegatedRendererLayer::DelegatedRendererLayer( - DelegatedRendererLayerClient* client) + const scoped_refptr<DelegatedFrameProvider>& frame_provider) : Layer(), - client_(client), - needs_filter_context_(false), + frame_provider_(frame_provider), + should_collect_new_frame_(true), + frame_data_(NULL), main_thread_runner_(BlockingTaskRunner::current()), - weak_ptrs_(this) {} + weak_ptrs_(this) { + frame_provider_->AddObserver(this); +} -DelegatedRendererLayer::~DelegatedRendererLayer() {} +DelegatedRendererLayer::~DelegatedRendererLayer() { + frame_provider_->RemoveObserver(this); +} scoped_ptr<LayerImpl> DelegatedRendererLayer::CreateLayerImpl( LayerTreeImpl* tree_impl) { @@ -48,17 +52,15 @@ void DelegatedRendererLayer::SetLayerTreeHost(LayerTreeHost* host) { // or we never commited a frame with resources. SetNextCommitWaitsForActivation(); } else { - if (needs_filter_context_) - host->set_needs_filter_context(); + // There is no active frame in the new layer tree host to wait for so no + // need to call SetNextCommitWaitsForActivation(). + should_collect_new_frame_ = true; + SetNeedsUpdate(); } Layer::SetLayerTreeHost(host); } -bool DelegatedRendererLayer::DrawsContent() const { - return Layer::DrawsContent() && !frame_size_.IsEmpty(); -} - void DelegatedRendererLayer::PushPropertiesTo(LayerImpl* impl) { Layer::PushPropertiesTo(impl); @@ -68,24 +70,20 @@ void DelegatedRendererLayer::PushPropertiesTo(LayerImpl* impl) { delegated_impl->SetDisplaySize(display_size_); delegated_impl->CreateChildIdIfNeeded( - base::Bind(&DelegatedRendererLayer::ReceiveUnusedResourcesOnImplThread, - main_thread_runner_, - weak_ptrs_.GetWeakPtr())); + frame_provider_->GetReturnResourcesCallbackForImplThread()); if (frame_data_) - delegated_impl->SetFrameData(frame_data_.Pass(), damage_in_frame_); - frame_data_.reset(); - damage_in_frame_ = gfx::RectF(); - - // The ResourceProvider will have the new frame as soon as we push it to the - // pending tree. So unused resources will be returned as well. - if (client_) - client_->DidCommitFrameData(); - - // TODO(danakj): The DidCommitFrameData() notification requires a push - // properties to happen in order to notify about unused resources returned - // from the parent compositor. crbug.com/259090 - needs_push_properties_ = true; + delegated_impl->SetFrameData(frame_data_, frame_damage_); + frame_data_ = NULL; + frame_damage_ = gfx::RectF(); +} + +void DelegatedRendererLayer::ProviderHasNewFrame() { + should_collect_new_frame_ = true; + SetNeedsUpdate(); + // The active frame needs to be replaced and resources returned before the + // commit is called complete. + SetNextCommitWaitsForActivation(); } void DelegatedRendererLayer::SetDisplaySize(gfx::Size size) { @@ -95,76 +93,42 @@ void DelegatedRendererLayer::SetDisplaySize(gfx::Size size) { SetNeedsCommit(); } -void DelegatedRendererLayer::SetFrameData( - scoped_ptr<DelegatedFrameData> new_frame_data) { - DCHECK(new_frame_data); - - if (frame_data_) { - // Copy the resources from the last provided frame into the unused resources - // list, as the new frame will provide its own resources. - TransferableResource::ReturnResources( - frame_data_->resource_list, - &unused_resources_for_child_compositor_); - } - frame_data_ = new_frame_data.Pass(); - if (!frame_data_->render_pass_list.empty()) { - RenderPass* root_pass = frame_data_->render_pass_list.back(); - damage_in_frame_.Union(root_pass->damage_rect); - frame_size_ = root_pass->output_rect.size(); - } else { - frame_size_ = gfx::Size(); - } - - // If any RenderPassDrawQuad has a filter operation, then we need a filter - // context to draw this layer's content. - for (size_t i = 0; - !needs_filter_context_ && i < frame_data_->render_pass_list.size(); - ++i) { - const QuadList& quad_list = frame_data_->render_pass_list[i]->quad_list; - for (size_t j = 0; !needs_filter_context_ && j < quad_list.size(); ++j) { +static bool FrameDataRequiresFilterContext(const DelegatedFrameData* frame) { + for (size_t i = 0; i < frame->render_pass_list.size(); ++i) { + const QuadList& quad_list = frame->render_pass_list[i]->quad_list; + for (size_t j = 0; j < quad_list.size(); ++j) { + if (quad_list[j]->shared_quad_state->blend_mode != + SkXfermode::kSrcOver_Mode) + return true; if (quad_list[j]->material != DrawQuad::RENDER_PASS) continue; const RenderPassDrawQuad* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad_list[j]); if (!render_pass_quad->filters.IsEmpty() || !render_pass_quad->background_filters.IsEmpty()) - needs_filter_context_ = true; + return true; } } - if (needs_filter_context_ && layer_tree_host()) - layer_tree_host()->set_needs_filter_context(); - - SetNeedsCommit(); - // The active frame needs to be replaced and resources returned before the - // commit is called complete. - SetNextCommitWaitsForActivation(); + return false; } -void DelegatedRendererLayer::TakeUnusedResourcesForChildCompositor( - ReturnedResourceArray* array) { - DCHECK(array->empty()); - array->clear(); +bool DelegatedRendererLayer::Update(ResourceUpdateQueue* queue, + const OcclusionTracker* occlusion) { + bool updated = Layer::Update(queue, occlusion); + if (!should_collect_new_frame_) + return updated; - array->swap(unused_resources_for_child_compositor_); -} + frame_data_ = + frame_provider_->GetFrameDataAndRefResources(this, &frame_damage_); + should_collect_new_frame_ = false; -void DelegatedRendererLayer::ReceiveUnusedResources( - const ReturnedResourceArray& unused) { - unused_resources_for_child_compositor_.insert( - unused_resources_for_child_compositor_.end(), - unused.begin(), - unused.end()); -} + // If any quad has a filter operation or a blend mode other than normal, + // then we need an offscreen context to draw this layer's content. + if (FrameDataRequiresFilterContext(frame_data_)) + layer_tree_host()->set_needs_filter_context(); -// static -void DelegatedRendererLayer::ReceiveUnusedResourcesOnImplThread( - scoped_refptr<BlockingTaskRunner> task_runner, - base::WeakPtr<DelegatedRendererLayer> self, - const ReturnedResourceArray& unused) { - task_runner->PostTask( - FROM_HERE, - base::Bind( - &DelegatedRendererLayer::ReceiveUnusedResources, self, unused)); + SetNeedsPushProperties(); + return true; } } // namespace cc diff --git a/chromium/cc/layers/delegated_renderer_layer.h b/chromium/cc/layers/delegated_renderer_layer.h index 60e9c3c05d9..dc9dfee4705 100644 --- a/chromium/cc/layers/delegated_renderer_layer.h +++ b/chromium/cc/layers/delegated_renderer_layer.h @@ -5,28 +5,29 @@ #ifndef CC_LAYERS_DELEGATED_RENDERER_LAYER_H_ #define CC_LAYERS_DELEGATED_RENDERER_LAYER_H_ +#include "base/containers/hash_tables.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/synchronization/lock.h" #include "cc/base/cc_export.h" +#include "cc/layers/delegated_frame_provider.h" #include "cc/layers/layer.h" #include "cc/resources/returned_resource.h" namespace cc { class BlockingTaskRunner; -class DelegatedFrameData; -class DelegatedRendererLayerClient; class CC_EXPORT DelegatedRendererLayer : public Layer { public: static scoped_refptr<DelegatedRendererLayer> Create( - DelegatedRendererLayerClient* client); + const scoped_refptr<DelegatedFrameProvider>& frame_provider); virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) OVERRIDE; virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE; + virtual bool Update(ResourceUpdateQueue* queue, + const OcclusionTracker* occlusion) OVERRIDE; virtual void PushPropertiesTo(LayerImpl* impl) OVERRIDE; - virtual bool DrawsContent() const OVERRIDE; // Set the size at which the frame should be displayed, with the origin at the // layer's origin. This must always contain at least the layer's bounds. A @@ -34,32 +35,25 @@ class CC_EXPORT DelegatedRendererLayer : public Layer { // in the layer's bounds. void SetDisplaySize(gfx::Size size); - void SetFrameData(scoped_ptr<DelegatedFrameData> frame_data); - - // Passes ownership of any unused resources that had been given by the child - // compositor to the given array, so they can be given back to the child. - void TakeUnusedResourcesForChildCompositor(ReturnedResourceArray* array); + // Called by the DelegatedFrameProvider when a new frame is available to be + // picked up. + void ProviderHasNewFrame(); protected: - explicit DelegatedRendererLayer(DelegatedRendererLayerClient* client); + DelegatedRendererLayer( + const scoped_refptr<DelegatedFrameProvider>& frame_provider); virtual ~DelegatedRendererLayer(); private: - void ReceiveUnusedResources(const ReturnedResourceArray& unused); - static void ReceiveUnusedResourcesOnImplThread( - scoped_refptr<BlockingTaskRunner> task_runner, - base::WeakPtr<DelegatedRendererLayer> self, - const ReturnedResourceArray& unused); - - scoped_ptr<DelegatedFrameData> frame_data_; - gfx::RectF damage_in_frame_; - gfx::Size frame_size_; - gfx::Size display_size_; + scoped_refptr<DelegatedFrameProvider> frame_provider_; + + bool should_collect_new_frame_; - DelegatedRendererLayerClient* client_; - bool needs_filter_context_; + DelegatedFrameData* frame_data_; + gfx::RectF frame_damage_; + + gfx::Size display_size_; - ReturnedResourceArray unused_resources_for_child_compositor_; scoped_refptr<BlockingTaskRunner> main_thread_runner_; base::WeakPtrFactory<DelegatedRendererLayer> weak_ptrs_; diff --git a/chromium/cc/layers/delegated_renderer_layer_client.h b/chromium/cc/layers/delegated_renderer_layer_client.h deleted file mode 100644 index eb599358074..00000000000 --- a/chromium/cc/layers/delegated_renderer_layer_client.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013 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 CC_LAYERS_DELEGATED_RENDERER_LAYER_CLIENT_H_ -#define CC_LAYERS_DELEGATED_RENDERER_LAYER_CLIENT_H_ - -#include "cc/base/cc_export.h" - -namespace cc { - -class CC_EXPORT DelegatedRendererLayerClient { - public: - // Called after the object passed in SetFrameData was handed over - // to the DelegatedRendererLayerImpl. - virtual void DidCommitFrameData() = 0; - - protected: - virtual ~DelegatedRendererLayerClient() {} -}; - -} // namespace cc -#endif // CC_LAYERS_DELEGATED_RENDERER_LAYER_CLIENT_H_ diff --git a/chromium/cc/layers/delegated_renderer_layer_impl.cc b/chromium/cc/layers/delegated_renderer_layer_impl.cc index 34a1cd86755..07734585724 100644 --- a/chromium/cc/layers/delegated_renderer_layer_impl.cc +++ b/chromium/cc/layers/delegated_renderer_layer_impl.cc @@ -33,9 +33,7 @@ DelegatedRendererLayerImpl::~DelegatedRendererLayerImpl() { ClearChildId(); } -bool DelegatedRendererLayerImpl::HasDelegatedContent() const { - return !render_passes_in_draw_order_.empty(); -} +bool DelegatedRendererLayerImpl::HasDelegatedContent() const { return true; } bool DelegatedRendererLayerImpl::HasContributingDelegatedRenderPasses() const { // The root RenderPass for the layer is merged with its target @@ -101,14 +99,13 @@ void DelegatedRendererLayerImpl::CreateChildIdIfNeeded( } void DelegatedRendererLayerImpl::SetFrameData( - scoped_ptr<DelegatedFrameData> frame_data, + const DelegatedFrameData* frame_data, gfx::RectF damage_in_frame) { - DCHECK(frame_data); DCHECK(child_id_) << "CreateChildIdIfNeeded must be called first."; - + DCHECK(frame_data); + DCHECK(!frame_data->render_pass_list.empty()); // A frame with an empty root render pass is invalid. - DCHECK(frame_data->render_pass_list.empty() || - !frame_data->render_pass_list.back()->output_rect.IsEmpty()); + DCHECK(!frame_data->render_pass_list.back()->output_rect.IsEmpty()); ResourceProvider* resource_provider = layer_tree_impl()->resource_provider(); const ResourceProvider::ResourceIdMap& resource_map = @@ -116,6 +113,9 @@ void DelegatedRendererLayerImpl::SetFrameData( resource_provider->ReceiveFromChild(child_id_, frame_data->resource_list); + ScopedPtrVector<RenderPass> render_pass_list; + RenderPass::CopyAll(frame_data->render_pass_list, &render_pass_list); + bool invalid_frame = false; ResourceProvider::ResourceIdArray resources_in_frame; DrawQuad::ResourceIteratorCallback remap_resources_to_parent_callback = @@ -123,8 +123,8 @@ void DelegatedRendererLayerImpl::SetFrameData( &invalid_frame, resource_map, &resources_in_frame); - for (size_t i = 0; i < frame_data->render_pass_list.size(); ++i) { - RenderPass* pass = frame_data->render_pass_list[i]; + for (size_t i = 0; i < render_pass_list.size(); ++i) { + RenderPass* pass = render_pass_list[i]; for (size_t j = 0; j < pass->quad_list.size(); ++j) { DrawQuad* quad = pass->quad_list[j]; quad->IterateResources(remap_resources_to_parent_callback); @@ -142,19 +142,16 @@ void DelegatedRendererLayerImpl::SetFrameData( resource_provider->DeclareUsedResourcesFromChild(child_id_, resources_); // Display size is already set so we can compute what the damage rect - // will be in layer space. - if (!frame_data->render_pass_list.empty()) { - RenderPass* new_root_pass = frame_data->render_pass_list.back(); - gfx::RectF damage_in_layer = MathUtil::MapClippedRect( - DelegatedFrameToLayerSpaceTransform( - new_root_pass->output_rect.size()), - damage_in_frame); - set_update_rect(gfx::UnionRects(update_rect(), damage_in_layer)); - } - - // Save the remapped quads on the layer. This steals the quads and render - // passes from the frame_data. - SetRenderPasses(&frame_data->render_pass_list); + // will be in layer space. The damage may exceed the visible portion of + // the frame, so intersect the damage to the layer's bounds. + RenderPass* new_root_pass = render_pass_list.back(); + gfx::Size frame_size = new_root_pass->output_rect.size(); + gfx::RectF damage_in_layer = MathUtil::MapClippedRect( + DelegatedFrameToLayerSpaceTransform(frame_size), damage_in_frame); + set_update_rect(gfx::IntersectRects( + gfx::UnionRects(update_rect(), damage_in_layer), gfx::Rect(bounds()))); + + SetRenderPasses(&render_pass_list); have_render_passes_to_push_ = true; } @@ -184,7 +181,6 @@ void DelegatedRendererLayerImpl::SetRenderPasses( } void DelegatedRendererLayerImpl::ClearRenderPasses() { - // TODO(danakj): Release the resources back to the nested compositor. render_passes_index_by_id_.clear(); render_passes_in_draw_order_.clear(); } @@ -243,6 +239,13 @@ void DelegatedRendererLayerImpl::AppendContributingRenderPasses( RenderPassSink* render_pass_sink) { DCHECK(HasContributingDelegatedRenderPasses()); + const RenderPass* root_delegated_render_pass = + render_passes_in_draw_order_.back(); + gfx::Size frame_size = root_delegated_render_pass->output_rect.size(); + gfx::Transform delegated_frame_to_root_transform = + screen_space_transform() * + DelegatedFrameToLayerSpaceTransform(frame_size); + for (size_t i = 0; i < render_passes_in_draw_order_.size() - 1; ++i) { RenderPass::Id output_render_pass_id(-1, -1); bool present = @@ -254,8 +257,11 @@ void DelegatedRendererLayerImpl::AppendContributingRenderPasses( << render_passes_in_draw_order_[i]->id.index; DCHECK_GT(output_render_pass_id.index, 0); - render_pass_sink->AppendRenderPass( - render_passes_in_draw_order_[i]->Copy(output_render_pass_id)); + scoped_ptr<RenderPass> copy_pass = + render_passes_in_draw_order_[i]->Copy(output_render_pass_id); + copy_pass->transform_to_root_target.ConcatTransform( + delegated_frame_to_root_transform); + render_pass_sink->AppendRenderPass(copy_pass.Pass()); } } @@ -271,6 +277,7 @@ void DelegatedRendererLayerImpl::AppendQuads( AppendQuadsData* append_quads_data) { AppendRainbowDebugBorder(quad_sink, append_quads_data); + // This list will be empty after a lost context until a new frame arrives. if (render_passes_in_draw_order_.empty()) return; diff --git a/chromium/cc/layers/delegated_renderer_layer_impl.h b/chromium/cc/layers/delegated_renderer_layer_impl.h index 7d774f1c357..358b7b9acf4 100644 --- a/chromium/cc/layers/delegated_renderer_layer_impl.h +++ b/chromium/cc/layers/delegated_renderer_layer_impl.h @@ -45,7 +45,7 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl { // inform when resources are no longer in use. void CreateChildIdIfNeeded(const ReturnCallback& return_callback); - void SetFrameData(scoped_ptr<DelegatedFrameData> frame_data, + void SetFrameData(const DelegatedFrameData* frame_data, gfx::RectF damage_in_frame); void SetDisplaySize(gfx::Size size); diff --git a/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc b/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc index a641e00eaf0..8cb0f3e376c 100644 --- a/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc +++ b/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc @@ -5,7 +5,6 @@ #include "cc/layers/delegated_renderer_layer_impl.h" #include "cc/base/scoped_ptr_vector.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/layers/append_quads_data.h" #include "cc/layers/quad_sink.h" #include "cc/layers/solid_color_layer_impl.h" @@ -21,10 +20,12 @@ #include "cc/test/mock_quad_culler.h" #include "cc/test/render_pass_test_common.h" #include "cc/test/render_pass_test_utils.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/layer_tree_impl.h" #include "cc/trees/single_thread_proxy.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/frame_time.h" #include "ui/gfx/transform.h" namespace cc { @@ -88,24 +89,21 @@ class DelegatedRendererLayerImplTestSimple delegated_renderer_layer->SetTransform(transform); ScopedPtrVector<RenderPass> delegated_render_passes; - TestRenderPass* pass1 = AddRenderPass( - &delegated_render_passes, - RenderPass::Id(9, 6), - gfx::Rect(6, 6, 6, 6), - gfx::Transform()); + TestRenderPass* pass1 = AddRenderPass(&delegated_render_passes, + RenderPass::Id(9, 6), + gfx::Rect(6, 6, 6, 6), + gfx::Transform(1, 0, 0, 1, 5, 6)); AddQuad(pass1, gfx::Rect(0, 0, 6, 6), 33u); - TestRenderPass* pass2 = AddRenderPass( - &delegated_render_passes, - RenderPass::Id(9, 7), - gfx::Rect(7, 7, 7, 7), - gfx::Transform()); + TestRenderPass* pass2 = AddRenderPass(&delegated_render_passes, + RenderPass::Id(9, 7), + gfx::Rect(7, 7, 7, 7), + gfx::Transform(1, 0, 0, 1, 7, 8)); AddQuad(pass2, gfx::Rect(0, 0, 7, 7), 22u); AddRenderPassQuad(pass2, pass1); - TestRenderPass* pass3 = AddRenderPass( - &delegated_render_passes, - RenderPass::Id(9, 8), - gfx::Rect(0, 0, 8, 8), - gfx::Transform()); + TestRenderPass* pass3 = AddRenderPass(&delegated_render_passes, + RenderPass::Id(9, 8), + gfx::Rect(0, 0, 8, 8), + gfx::Transform(1, 0, 0, 1, 9, 10)); AddRenderPassQuad(pass3, pass2); delegated_renderer_layer->SetFrameDataForRenderPasses( &delegated_render_passes); @@ -165,7 +163,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, AddsContributingRenderPasses) { EXPECT_EQ(gfx::Rect(7, 7, 7, 7).ToString(), frame.render_passes[2]->output_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -201,7 +199,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, EXPECT_EQ(gfx::Rect(0, 0, 6, 6).ToString(), frame.render_passes[1]->quad_list[0]->rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -228,7 +226,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, AddsQuadsToTargetRenderPass) { EXPECT_EQ(gfx::Rect(0, 0, 15, 15).ToString(), frame.render_passes[3]->quad_list[1]->rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -262,6 +260,42 @@ TEST_F(DelegatedRendererLayerImplTestSimple, EXPECT_TRANSFORMATION_MATRIX_EQ( gfx::Transform(), frame.render_passes[1]->quad_list[0]->quadTransform()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); + host_impl_->DidDrawAllLayers(frame); +} + +TEST_F(DelegatedRendererLayerImplTestSimple, RenderPassTransformIsModified) { + LayerTreeHostImpl::FrameData frame; + EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); + + // The delegated layer has a surface between it and the root. + EXPECT_TRUE(delegated_renderer_layer_->render_target()->parent()); + + // Each non-DelegatedRendererLayer added one RenderPass. The + // DelegatedRendererLayer added two contributing passes. + ASSERT_EQ(5u, frame.render_passes.size()); + + // The DelegatedRendererLayer is at position 9,9 compared to the root, so all + // render pass' transforms to the root should be shifted by this amount. + // The DelegatedRendererLayer has a size of 10x10, but the root delegated + // RenderPass has a size of 8x8, so any render passes should be scaled by + // 10/8. + gfx::Transform transform; + transform.Translate(9.0, 9.0); + transform.Scale(10.0 / 8.0, 10.0 / 8.0); + + // The first contributing surface has a translation of 5, 6. + gfx::Transform five_six(1, 0, 0, 1, 5, 6); + + // The second contributing surface has a translation of 7, 8. + gfx::Transform seven_eight(1, 0, 0, 1, 7, 8); + + EXPECT_TRANSFORMATION_MATRIX_EQ( + transform * five_six, frame.render_passes[1]->transform_to_root_target); + EXPECT_TRANSFORMATION_MATRIX_EQ( + transform * seven_eight, + frame.render_passes[2]->transform_to_root_target); + host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -274,7 +308,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, DoesNotOwnARenderSurface) { // has no need to be a RenderSurface for the quads it carries. EXPECT_FALSE(delegated_renderer_layer_->render_surface()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -289,7 +323,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, DoesOwnARenderSurfaceForOpacity) { // render surface. EXPECT_TRUE(delegated_renderer_layer_->render_surface()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -307,7 +341,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, // render surface. EXPECT_TRUE(delegated_renderer_layer_->render_surface()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -354,7 +388,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface, AddsRenderPasses) { EXPECT_EQ(gfx::Rect(7, 7, 7, 7).ToString(), frame.render_passes[2]->output_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -391,7 +425,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface, EXPECT_EQ(gfx::Rect(0, 0, 6, 6).ToString(), frame.render_passes[1]->quad_list[0]->rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -416,7 +450,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface, AddsQuadsToTargetRenderPass) { EXPECT_EQ(gfx::Rect(7, 7, 7, 7).ToString(), frame.render_passes[3]->quad_list[0]->rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -448,7 +482,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface, EXPECT_TRANSFORMATION_MATRIX_EQ( gfx::Transform(), frame.render_passes[1]->quad_list[0]->quadTransform()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -480,7 +514,7 @@ class DelegatedRendererLayerImplTestTransform gfx::Size child_pass_content_bounds(7, 7); gfx::Rect child_pass_rect(20, 20, 7, 7); gfx::Transform child_pass_transform; - child_pass_transform.Scale(0.8, 0.8); + child_pass_transform.Scale(0.8f, 0.8f); child_pass_transform.Translate(9.0, 9.0); gfx::Rect child_pass_clip_rect(21, 21, 3, 3); bool child_pass_clipped = false; @@ -495,13 +529,13 @@ class DelegatedRendererLayerImplTestTransform AppendQuadsData data(pass->id); SharedQuadState* shared_quad_state = quad_sink.UseSharedQuadState( SharedQuadState::Create()); - shared_quad_state->SetAll( - child_pass_transform, - child_pass_content_bounds, - child_pass_rect, - child_pass_clip_rect, - child_pass_clipped, - 1.f); + shared_quad_state->SetAll(child_pass_transform, + child_pass_content_bounds, + child_pass_rect, + child_pass_clip_rect, + child_pass_clipped, + 1.f, + SkXfermode::kSrcOver_Mode); scoped_ptr<SolidColorDrawQuad> color_quad; color_quad = SolidColorDrawQuad::Create(); @@ -530,13 +564,13 @@ class DelegatedRendererLayerImplTestTransform AppendQuadsData data(pass->id); SharedQuadState* shared_quad_state = quad_sink.UseSharedQuadState(SharedQuadState::Create()); - shared_quad_state->SetAll( - root_pass_transform, - root_pass_content_bounds, - root_pass_rect, - root_pass_clip_rect, - root_pass_clipped, - 1.f); + shared_quad_state->SetAll(root_pass_transform, + root_pass_content_bounds, + root_pass_rect, + root_pass_clip_rect, + root_pass_clipped, + 1.f, + SkXfermode::kSrcOver_Mode); scoped_ptr<RenderPassDrawQuad> render_pass_quad = RenderPassDrawQuad::Create(); @@ -549,7 +583,6 @@ class DelegatedRendererLayerImplTestTransform child_pass_rect, // contents_changed_since_last_frame gfx::RectF(), // mask_uv_rect FilterOperations(), // filters - skia::RefPtr<SkImageFilter>(), // filter FilterOperations()); // background_filters quad_sink.Append(render_pass_quad.PassAs<DrawQuad>(), &data); @@ -677,13 +710,13 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_NoSurface) { contrib_delegated_shared_quad_state->clip_rect.ToString()); EXPECT_FALSE(contrib_delegated_shared_quad_state->is_clipped); expected.MakeIdentity(); - expected.Scale(0.8, 0.8); + expected.Scale(0.8f, 0.8f); expected.Translate(9.0, 9.0); EXPECT_TRANSFORMATION_MATRIX_EQ( expected, contrib_delegated_shared_quad_state->content_to_target_transform); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -740,13 +773,13 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_NoSurface) { contrib_delegated_shared_quad_state->clip_rect.ToString()); EXPECT_FALSE(contrib_delegated_shared_quad_state->is_clipped); expected.MakeIdentity(); - expected.Scale(0.8, 0.8); + expected.Scale(0.8f, 0.8f); expected.Translate(9.0, 9.0); EXPECT_TRANSFORMATION_MATRIX_EQ( expected, contrib_delegated_shared_quad_state->content_to_target_transform); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -796,13 +829,13 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_Surface) { contrib_delegated_shared_quad_state->clip_rect.ToString()); EXPECT_FALSE(contrib_delegated_shared_quad_state->is_clipped); expected.MakeIdentity(); - expected.Scale(0.8, 0.8); + expected.Scale(0.8f, 0.8f); expected.Translate(9.0, 9.0); EXPECT_TRANSFORMATION_MATRIX_EQ( expected, contrib_delegated_shared_quad_state->content_to_target_transform); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -851,13 +884,13 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_Surface) { contrib_delegated_shared_quad_state->clip_rect.ToString()); EXPECT_FALSE(contrib_delegated_shared_quad_state->is_clipped); expected.MakeIdentity(); - expected.Scale(0.8, 0.8); + expected.Scale(0.8f, 0.8f); expected.Translate(9.0, 9.0); EXPECT_TRANSFORMATION_MATRIX_EQ( expected, contrib_delegated_shared_quad_state->content_to_target_transform); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -900,13 +933,13 @@ class DelegatedRendererLayerImplTestClip AppendQuadsData data(pass->id); SharedQuadState* shared_quad_state = quad_sink.UseSharedQuadState(SharedQuadState::Create()); - shared_quad_state->SetAll( - child_pass_transform, - child_pass_content_bounds, - child_pass_rect, - child_pass_clip_rect, - child_pass_clipped, - 1.f); + shared_quad_state->SetAll(child_pass_transform, + child_pass_content_bounds, + child_pass_rect, + child_pass_clip_rect, + child_pass_clipped, + 1.f, + SkXfermode::kSrcOver_Mode); scoped_ptr<SolidColorDrawQuad> color_quad; color_quad = SolidColorDrawQuad::Create(); @@ -938,7 +971,8 @@ class DelegatedRendererLayerImplTestClip root_pass_rect, root_pass_clip_rect, root_pass_clipped, - 1.f); + 1.f, + SkXfermode::kSrcOver_Mode); scoped_ptr<RenderPassDrawQuad> render_pass_quad = RenderPassDrawQuad::Create(); @@ -951,7 +985,6 @@ class DelegatedRendererLayerImplTestClip child_pass_rect, // contents_changed_since_last_frame gfx::RectF(), // mask_uv_rect FilterOperations(), // filters - skia::RefPtr<SkImageFilter>(), // filter FilterOperations()); // background_filters quad_sink.Append(render_pass_quad.PassAs<DrawQuad>(), &data); @@ -1034,7 +1067,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, // Quads are clipped to the delegated renderer layer. EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -1063,7 +1096,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, // Quads came with a clip rect. EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -1093,7 +1126,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, // Quads are clipped to the delegated renderer layer. EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -1122,7 +1155,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, // Quads came with a clip rect. EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -1151,7 +1184,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, // clip rect is ignored, and they are not set as clipped. EXPECT_FALSE(root_delegated_shared_quad_state->is_clipped); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -1181,7 +1214,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, // Quads came with a clip rect. EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -1210,7 +1243,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, // clip rect is ignored, and they are not set as clipped. EXPECT_FALSE(root_delegated_shared_quad_state->is_clipped); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -1241,7 +1274,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, QuadsClipped_LayerClipped_Surface) { // Quads came with a clip rect. EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -1294,7 +1327,7 @@ TEST_F(DelegatedRendererLayerImplTest, InvalidRenderPassDrawQuad) { EXPECT_EQ(DrawQuad::SOLID_COLOR, frame.render_passes[0]->quad_list[0]->material); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } diff --git a/chromium/cc/layers/draw_properties.h b/chromium/cc/layers/draw_properties.h index 181d900f267..5fd42a49e94 100644 --- a/chromium/cc/layers/draw_properties.h +++ b/chromium/cc/layers/draw_properties.h @@ -13,7 +13,7 @@ namespace cc { // Container for properties that layers need to compute before they can be // drawn. -template <typename LayerType, typename RenderSurfaceType> +template <typename LayerType> struct CC_EXPORT DrawProperties { DrawProperties() : opacity(0.f), @@ -28,9 +28,13 @@ struct CC_EXPORT DrawProperties { contents_scale_y(1.f), num_descendants_that_draw_content(0), num_unclipped_descendants(0), - descendants_can_clip_selves(false), - can_draw_directly_to_backbuffer(false), - layer_or_descendant_has_copy_request(false) {} + layer_or_descendant_has_copy_request(false), + has_child_with_a_scroll_parent(false), + sorted_for_recursion(false), + index_of_first_descendants_addition(0), + num_descendants_added(0), + index_of_first_render_surface_layer_list_addition(0), + num_render_surfaces_added(0) {} // Transforms objects from content space to target surface space, where // this layer would be drawn. @@ -65,7 +69,7 @@ struct CC_EXPORT DrawProperties { LayerType* render_target; // The surface that this layer and its subtree would contribute to. - scoped_ptr<RenderSurfaceType> render_surface; + scoped_ptr<typename LayerType::RenderSurfaceType> render_surface; // This rect is in the layer's content space. gfx::Rect visible_content_rect; @@ -93,15 +97,27 @@ struct CC_EXPORT DrawProperties { // does not include our clip children because they are clipped by us. int num_unclipped_descendants; - // If true, every descendant in the sub-tree can clip itself without the - // need to use hardware sissoring or a new render target. - bool descendants_can_clip_selves; - - bool can_draw_directly_to_backbuffer; - // If true, the layer or some layer in its sub-tree has a CopyOutputRequest // present on it. bool layer_or_descendant_has_copy_request; + + // This is true if the layer has any direct child that has a scroll parent. + // This layer will not be the scroll parent in this case. This information + // lets us avoid work in CalculateDrawPropertiesInternal -- if none of our + // children have scroll parents, we will not need to recur out of order. + bool has_child_with_a_scroll_parent; + + // This is true if the order (wrt to its siblings in the tree) in which the + // layer will be visited while computing draw properties has been determined. + bool sorted_for_recursion; + + // If this layer is visited out of order, its contribution to the descendant + // and render surface layer lists will be put aside in a temporary list. + // These values will allow for an efficient reordering of these additions. + size_t index_of_first_descendants_addition; + size_t num_descendants_added; + size_t index_of_first_render_surface_layer_list_addition; + size_t num_render_surfaces_added; }; } // namespace cc diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc index c1fa9f37dbc..da4784074cf 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl.cc +++ b/chromium/cc/layers/heads_up_display_layer_impl.cc @@ -12,6 +12,7 @@ #include "cc/debug/debug_rect_history.h" #include "cc/debug/frame_rate_counter.h" #include "cc/debug/paint_time_counter.h" +#include "cc/debug/traced_value.h" #include "cc/layers/quad_sink.h" #include "cc/output/renderer.h" #include "cc/quads/texture_draw_quad.h" @@ -85,13 +86,15 @@ bool HeadsUpDisplayLayerImpl::WillDraw(DrawMode draw_mode, return false; if (!hud_resource_) - hud_resource_ = ScopedResource::create(resource_provider); + hud_resource_ = ScopedResource::Create(resource_provider); // TODO(danakj): The HUD could swap between two textures instead of creating a // texture every frame in ubercompositor. if (hud_resource_->size() != content_bounds() || - resource_provider->InUseByConsumer(hud_resource_->id())) + (hud_resource_->id() && + resource_provider->InUseByConsumer(hud_resource_->id()))) { hud_resource_->Free(); + } if (!hud_resource_->id()) { hud_resource_->Allocate(content_bounds(), @@ -132,8 +135,9 @@ void HeadsUpDisplayLayerImpl::AppendQuads(QuadSink* quad_sink, } void HeadsUpDisplayLayerImpl::UpdateHudTexture( + DrawMode draw_mode, ResourceProvider* resource_provider) { - if (!hud_resource_->id()) + if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE || !hud_resource_->id()) return; SkISize canvas_size; @@ -144,6 +148,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( if (canvas_size.width() != content_bounds().width() || canvas_size.width() != content_bounds().height() || !hud_canvas_) { + TRACE_EVENT0("cc", "ResizeHudCanvas"); bool opaque = false; hud_canvas_ = make_scoped_ptr(skia::CreateBitmapCanvas( content_bounds().width(), content_bounds().height(), opaque)); @@ -151,14 +156,18 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( UpdateHudContents(); - hud_canvas_->clear(SkColorSetARGB(0, 0, 0, 0)); - hud_canvas_->save(); - hud_canvas_->scale(contents_scale_x(), contents_scale_y()); + { + TRACE_EVENT0("cc", "DrawHudContents"); + hud_canvas_->clear(SkColorSetARGB(0, 0, 0, 0)); + hud_canvas_->save(); + hud_canvas_->scale(contents_scale_x(), contents_scale_y()); - DrawHudContents(hud_canvas_.get()); + DrawHudContents(hud_canvas_.get()); - hud_canvas_->restore(); + hud_canvas_->restore(); + } + TRACE_EVENT0("cc", "UploadHudTexture"); const SkBitmap* bitmap = &hud_canvas_->getDevice()->accessBitmap(false); SkAutoLockPixels locker(*bitmap); @@ -643,6 +652,12 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects( stroke_width = DebugColors::NonFastScrollableRectBorderWidth(); label_text = "repaints on scroll"; break; + case ANIMATION_BOUNDS_RECT_TYPE: + stroke_color = DebugColors::LayerAnimationBoundsBorderColor(); + fill_color = DebugColors::LayerAnimationBoundsFillColor(); + stroke_width = DebugColors::LayerAnimationBoundsBorderWidth(); + label_text = "animation bounds"; + break; } gfx::RectF debug_layer_rect = gfx::ScaleRect(debug_rects[i].rect, diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h index 32bf77e143d..fa38f15eafe 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl.h +++ b/chromium/cc/layers/heads_up_display_layer_impl.h @@ -40,7 +40,8 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl { ResourceProvider* resource_provider) OVERRIDE; virtual void AppendQuads(QuadSink* quad_sink, AppendQuadsData* append_quads_data) OVERRIDE; - void UpdateHudTexture(ResourceProvider* resource_provider); + void UpdateHudTexture(DrawMode draw_mode, + ResourceProvider* resource_provider); virtual void DidLoseOutputSurface() OVERRIDE; diff --git a/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc b/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc new file mode 100644 index 00000000000..5afc01956d8 --- /dev/null +++ b/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc @@ -0,0 +1,55 @@ +// Copyright 2013 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 "cc/layers/append_quads_data.h" +#include "cc/layers/heads_up_display_layer_impl.h" +#include "cc/test/fake_impl_proxy.h" +#include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/fake_output_surface.h" +#include "cc/test/mock_quad_culler.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +void CheckDrawLayer(HeadsUpDisplayLayerImpl* layer, + ResourceProvider* resource_provider, + DrawMode draw_mode) { + MockQuadCuller quad_culler; + AppendQuadsData data; + bool will_draw = layer->WillDraw(draw_mode, resource_provider); + if (will_draw) + layer->AppendQuads(&quad_culler, &data); + layer->UpdateHudTexture(draw_mode, resource_provider); + if (will_draw) + layer->DidDraw(resource_provider); + + size_t expected_quad_list_size = will_draw ? 1 : 0; + EXPECT_EQ(expected_quad_list_size, quad_culler.quad_list().size()); +} + +TEST(HeadsUpDisplayLayerImplTest, ResourcelessSoftwareDrawAfterResourceLoss) { + FakeImplProxy proxy; + FakeLayerTreeHostImpl host_impl(&proxy); + host_impl.CreatePendingTree(); + host_impl.InitializeRenderer(CreateFakeOutputSurface()); + scoped_ptr<HeadsUpDisplayLayerImpl> layer = + HeadsUpDisplayLayerImpl::Create(host_impl.pending_tree(), 1); + layer->SetContentBounds(gfx::Size(100, 100)); + + // Check regular hardware draw is ok. + CheckDrawLayer( + layer.get(), host_impl.resource_provider(), DRAW_MODE_HARDWARE); + + // Simulate a resource loss on transitioning to resourceless software mode. + layer->DidLoseOutputSurface(); + + // Should skip resourceless software draw and not crash in UpdateHudTexture. + CheckDrawLayer(layer.get(), + host_impl.resource_provider(), + DRAW_MODE_RESOURCELESS_SOFTWARE); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/layers/image_layer.cc b/chromium/cc/layers/image_layer.cc index bbf1aa82e34..2f90bfc50a8 100644 --- a/chromium/cc/layers/image_layer.cc +++ b/chromium/cc/layers/image_layer.cc @@ -80,6 +80,12 @@ bool ImageLayer::DrawsContent() const { return !bitmap_.isNull() && TiledLayer::DrawsContent(); } +void ImageLayer::OnOutputSurfaceCreated() { + SetTextureFormat( + layer_tree_host()->GetRendererCapabilities().best_texture_format); + TiledLayer::OnOutputSurfaceCreated(); +} + float ImageLayer::ImageContentsScaleX() const { if (bounds().IsEmpty() || bitmap_.width() == 0) return 1; diff --git a/chromium/cc/layers/image_layer.h b/chromium/cc/layers/image_layer.h index ae8383a22c3..6cd82755bfc 100644 --- a/chromium/cc/layers/image_layer.h +++ b/chromium/cc/layers/image_layer.h @@ -31,6 +31,7 @@ class CC_EXPORT ImageLayer : public TiledLayer { float* contents_scale_x, float* contents_scale_y, gfx::Size* content_bounds) OVERRIDE; + virtual void OnOutputSurfaceCreated() OVERRIDE; void SetBitmap(const SkBitmap& image); diff --git a/chromium/cc/layers/io_surface_layer_impl.cc b/chromium/cc/layers/io_surface_layer_impl.cc index e8c627be08b..a70006a69c9 100644 --- a/chromium/cc/layers/io_surface_layer_impl.cc +++ b/chromium/cc/layers/io_surface_layer_impl.cc @@ -11,7 +11,7 @@ #include "cc/quads/io_surface_draw_quad.h" #include "cc/trees/layer_tree_impl.h" #include "gpu/GLES2/gl2extchromium.h" -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" +#include "gpu/command_buffer/client/gles2_interface.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" @@ -21,7 +21,8 @@ IOSurfaceLayerImpl::IOSurfaceLayerImpl(LayerTreeImpl* tree_impl, int id) : LayerImpl(tree_impl, id), io_surface_id_(0), io_surface_changed_(false), - io_surface_texture_id_(0) {} + io_surface_texture_id_(0), + io_surface_resource_id_(0) {} IOSurfaceLayerImpl::~IOSurfaceLayerImpl() { if (!io_surface_texture_id_) @@ -43,7 +44,7 @@ void IOSurfaceLayerImpl::DestroyTexture() { layer_tree_impl()->output_surface()->context_provider().get(); // TODO(skaslev): Implement this path for software compositing. if (context_provider) - context_provider->Context3d()->deleteTexture(io_surface_texture_id_); + context_provider->ContextGL()->DeleteTextures(1, &io_surface_texture_id_); io_surface_texture_id_ = 0; } } @@ -74,25 +75,23 @@ bool IOSurfaceLayerImpl::WillDraw(DrawMode draw_mode, return false; } - WebKit::WebGraphicsContext3D* context3d = context_provider->Context3d(); + gpu::gles2::GLES2Interface* gl = context_provider->ContextGL(); // TODO(ernstm): Do this in a way that we can track memory usage. if (!io_surface_texture_id_) { - io_surface_texture_id_ = context3d->createTexture(); + gl->GenTextures(1, &io_surface_texture_id_); io_surface_resource_id_ = resource_provider->CreateResourceFromExternalTexture( GL_TEXTURE_RECTANGLE_ARB, io_surface_texture_id_); } - GLC(context3d, - context3d->bindTexture(GL_TEXTURE_RECTANGLE_ARB, - io_surface_texture_id_)); - context3d->texImageIOSurface2DCHROMIUM(GL_TEXTURE_RECTANGLE_ARB, - io_surface_size_.width(), - io_surface_size_.height(), - io_surface_id_, - 0); + GLC(gl, gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, io_surface_texture_id_)); + gl->TexImageIOSurface2DCHROMIUM(GL_TEXTURE_RECTANGLE_ARB, + io_surface_size_.width(), + io_surface_size_.height(), + io_surface_id_, + 0); // Do not check for error conditions. texImageIOSurface2DCHROMIUM() is // supposed to hold on to the last good IOSurface if the new one is already // closed. This is only a possibility during live resizing of plugins. diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc index 86887a6ad2c..f7682fd912f 100644 --- a/chromium/cc/layers/layer.cc +++ b/chromium/cc/layers/layer.cc @@ -12,6 +12,7 @@ #include "base/single_thread_task_runner.h" #include "cc/animation/animation.h" #include "cc/animation/animation_events.h" +#include "cc/animation/keyframed_animation_curve.h" #include "cc/animation/layer_animation_controller.h" #include "cc/layers/layer_client.h" #include "cc/layers/layer_impl.h" @@ -41,11 +42,9 @@ Layer::Layer() scrollable_(false), should_scroll_on_main_thread_(false), have_wheel_event_handlers_(false), - anchor_point_(0.5f, 0.5f), - background_color_(0), - compositing_reasons_(kCompositingReasonUnknown), - opacity_(1.f), - anchor_point_z_(0.f), + user_scrollable_horizontal_(true), + user_scrollable_vertical_(true), + is_root_for_isolated_group_(false), is_container_for_fixed_position_layers_(false), is_drawable_(false), hide_layer_and_subtree_(false), @@ -56,6 +55,12 @@ Layer::Layer() use_parent_backface_visibility_(false), draw_checkerboard_for_missing_tiles_(false), force_render_surface_(false), + anchor_point_(0.5f, 0.5f), + background_color_(0), + compositing_reasons_(kCompositingReasonUnknown), + opacity_(1.f), + blend_mode_(SkXfermode::kSrcOver_Mode), + anchor_point_z_(0.f), scroll_parent_(NULL), clip_parent_(NULL), replica_layer_(NULL), @@ -68,6 +73,7 @@ Layer::Layer() layer_animation_controller_ = LayerAnimationController::Create(layer_id_); layer_animation_controller_->AddValueObserver(this); + layer_animation_controller_->set_value_provider(this); } Layer::~Layer() { @@ -79,6 +85,7 @@ Layer::~Layer() { DCHECK(!layer_tree_host()); layer_animation_controller_->RemoveValueObserver(this); + layer_animation_controller_->remove_value_provider(this); // Remove the parent reference from all children and dependents. RemoveAllChildren(); @@ -123,9 +130,7 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) { if (host && layer_animation_controller_->has_any_animation()) host->SetNeedsCommit(); - if (host && - (!filters_.IsEmpty() || !background_filters_.IsEmpty() || filter_)) - layer_tree_host_->set_needs_filter_context(); + SetNeedsFilterContextIfNeeded(); } void Layer::SetNeedsUpdate() { @@ -159,6 +164,15 @@ void Layer::SetNextCommitWaitsForActivation() { layer_tree_host_->SetNextCommitWaitsForActivation(); } +void Layer::SetNeedsFilterContextIfNeeded() { + if (!layer_tree_host_) + return; + + if (!filters_.IsEmpty() || !background_filters_.IsEmpty() || + !uses_default_blend_mode()) + layer_tree_host_->set_needs_filter_context(); +} + void Layer::SetNeedsPushProperties() { if (needs_push_properties_) return; @@ -207,10 +221,6 @@ skia::RefPtr<SkPicture> Layer::GetPicture() const { return skia::RefPtr<SkPicture>(); } -bool Layer::CanClipSelf() const { - return false; -} - void Layer::SetParent(Layer* layer) { DCHECK(!layer || !layer->HasAncestor(this)); @@ -472,22 +482,13 @@ void Layer::SetFilters(const FilterOperations& filters) { DCHECK(IsPropertyChangeAllowed()); if (filters_ == filters) return; - DCHECK(!filter_); filters_ = filters; SetNeedsCommit(); - if (!filters.IsEmpty() && layer_tree_host_) - layer_tree_host_->set_needs_filter_context(); + SetNeedsFilterContextIfNeeded(); } -void Layer::SetFilter(const skia::RefPtr<SkImageFilter>& filter) { - DCHECK(IsPropertyChangeAllowed()); - if (filter_.get() == filter.get()) - return; - DCHECK(filters_.IsEmpty()); - filter_ = filter; - SetNeedsCommit(); - if (filter && layer_tree_host_) - layer_tree_host_->set_needs_filter_context(); +bool Layer::FilterIsAnimating() const { + return layer_animation_controller_->IsAnimatingProperty(Animation::Filter); } void Layer::SetBackgroundFilters(const FilterOperations& filters) { @@ -496,8 +497,7 @@ void Layer::SetBackgroundFilters(const FilterOperations& filters) { return; background_filters_ = filters; SetNeedsCommit(); - if (!filters.IsEmpty() && layer_tree_host_) - layer_tree_host_->set_needs_filter_context(); + SetNeedsFilterContextIfNeeded(); } void Layer::SetOpacity(float opacity) { @@ -516,6 +516,64 @@ bool Layer::OpacityCanAnimateOnImplThread() const { return false; } +void Layer::SetBlendMode(SkXfermode::Mode blend_mode) { + DCHECK(IsPropertyChangeAllowed()); + if (blend_mode_ == blend_mode) + return; + + // Allowing only blend modes that are defined in the CSS Compositing standard: + // http://dev.w3.org/fxtf/compositing-1/#blending + switch (blend_mode) { + case SkXfermode::kSrcOver_Mode: + case SkXfermode::kScreen_Mode: + case SkXfermode::kOverlay_Mode: + case SkXfermode::kDarken_Mode: + case SkXfermode::kLighten_Mode: + case SkXfermode::kColorDodge_Mode: + case SkXfermode::kColorBurn_Mode: + case SkXfermode::kHardLight_Mode: + case SkXfermode::kSoftLight_Mode: + case SkXfermode::kDifference_Mode: + case SkXfermode::kExclusion_Mode: + case SkXfermode::kMultiply_Mode: + case SkXfermode::kHue_Mode: + case SkXfermode::kSaturation_Mode: + case SkXfermode::kColor_Mode: + case SkXfermode::kLuminosity_Mode: + // supported blend modes + break; + case SkXfermode::kClear_Mode: + case SkXfermode::kSrc_Mode: + case SkXfermode::kDst_Mode: + case SkXfermode::kDstOver_Mode: + case SkXfermode::kSrcIn_Mode: + case SkXfermode::kDstIn_Mode: + case SkXfermode::kSrcOut_Mode: + case SkXfermode::kDstOut_Mode: + case SkXfermode::kSrcATop_Mode: + case SkXfermode::kDstATop_Mode: + case SkXfermode::kXor_Mode: + case SkXfermode::kPlus_Mode: + case SkXfermode::kModulate_Mode: + // Porter Duff Compositing Operators are not yet supported + // http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators + NOTREACHED(); + return; + } + + blend_mode_ = blend_mode; + SetNeedsCommit(); + SetNeedsFilterContextIfNeeded(); +} + +void Layer::SetIsRootForIsolatedGroup(bool root) { + DCHECK(IsPropertyChangeAllowed()); + if (is_root_for_isolated_group_ == root) + return; + is_root_for_isolated_group_ = root; + SetNeedsCommit(); +} + void Layer::SetContentsOpaque(bool opaque) { DCHECK(IsPropertyChangeAllowed()); if (contents_opaque_ == opaque) @@ -630,7 +688,7 @@ void Layer::SetScrollOffset(gfx::Vector2d scroll_offset) { void Layer::SetScrollOffsetFromImplSide(gfx::Vector2d scroll_offset) { DCHECK(IsPropertyChangeAllowed()); - // This function only gets called during a begin frame, so there + // This function only gets called during a BeginMainFrame, so there // is no need to call SetNeedsUpdate here. DCHECK(layer_tree_host_ && layer_tree_host_->CommitRequested()); if (scroll_offset_ == scroll_offset) @@ -659,6 +717,16 @@ void Layer::SetScrollable(bool scrollable) { SetNeedsCommit(); } +void Layer::SetUserScrollable(bool horizontal, bool vertical) { + DCHECK(IsPropertyChangeAllowed()); + if (user_scrollable_horizontal_ == horizontal && + user_scrollable_vertical_ == vertical) + return; + user_scrollable_horizontal_ = horizontal; + user_scrollable_vertical_ = vertical; + SetNeedsCommit(); +} + void Layer::SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) { DCHECK(IsPropertyChangeAllowed()); if (should_scroll_on_main_thread_ == should_scroll_on_main_thread) @@ -808,10 +876,12 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { bool is_tracing; TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("cc.debug"), &is_tracing); - if (is_tracing) - layer->SetDebugName(DebugName()); - else - layer->SetDebugName(std::string()); + if (is_tracing) { + layer->SetDebugName(DebugName()); + layer->SetDebugInfo(TakeDebugInfo()); + } else { + layer->SetDebugName(std::string()); + } layer->SetCompositingReasons(compositing_reasons_); layer->SetDoubleSided(double_sided_); @@ -820,8 +890,9 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { layer->SetForceRenderSurface(force_render_surface_); layer->SetDrawsContent(DrawsContent()); layer->SetHideLayerAndSubtree(hide_layer_and_subtree_); - layer->SetFilters(filters()); - layer->SetFilter(filter()); + if (!layer->FilterIsAnimatingOnImplOnly() && !FilterIsAnimating()) + layer->SetFilters(filters_); + DCHECK(!(FilterIsAnimating() && layer->FilterIsAnimatingOnImplOnly())); layer->SetBackgroundFilters(background_filters()); layer->SetMasksToBounds(masks_to_bounds_); layer->SetShouldScrollOnMainThread(should_scroll_on_main_thread_); @@ -832,6 +903,8 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { if (!layer->OpacityIsAnimatingOnImplOnly() && !OpacityIsAnimating()) layer->SetOpacity(opacity_); DCHECK(!(OpacityIsAnimating() && layer->OpacityIsAnimatingOnImplOnly())); + layer->SetBlendMode(blend_mode_); + layer->SetIsRootForIsolatedGroup(is_root_for_isolated_group_); layer->SetPosition(position_); layer->SetIsContainerForFixedPositionLayers( IsContainerForFixedPositionLayers()); @@ -845,6 +918,8 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { DCHECK(!(TransformIsAnimating() && layer->TransformIsAnimatingOnImplOnly())); layer->SetScrollable(scrollable_); + layer->set_user_scrollable_horizontal(user_scrollable_horizontal_); + layer->set_user_scrollable_vertical(user_scrollable_vertical_); layer->SetMaxScrollOffset(max_scroll_offset_); LayerImpl* scroll_parent = NULL; @@ -879,8 +954,8 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { } // Adjust the scroll delta to be just the scrolls that have happened since - // the begin frame was sent. This happens for impl-side painting - // in LayerImpl::ApplyScrollDeltasSinceBeginFrame in a separate tree walk. + // the BeginMainFrame was sent. This happens for impl-side painting + // in LayerImpl::ApplyScrollDeltasSinceBeginMainFrame in a separate tree walk. if (layer->layer_tree_impl()->settings().impl_side_painting) { layer->SetScrollOffset(scroll_offset_); } else { @@ -925,9 +1000,7 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { stacking_order_changed_ = false; update_rect_ = gfx::RectF(); - // Animating layers require further push properties to clean up the animation. - // crbug.com/259088 - needs_push_properties_ = layer_animation_controller_->has_any_animation(); + needs_push_properties_ = false; num_dependents_need_push_properties_ = 0; } @@ -966,6 +1039,14 @@ std::string Layer::DebugName() { return client_ ? client_->DebugName() : std::string(); } +scoped_refptr<base::debug::ConvertableToTraceFormat> Layer::TakeDebugInfo() { + if (client_) + return client_->TakeDebugInfo(); + else + return NULL; +} + + void Layer::SetCompositingReasons(CompositingReasons reasons) { compositing_reasons_ = reasons; } @@ -980,22 +1061,37 @@ void Layer::ClearRenderSurface() { draw_properties_.render_surface.reset(); } +gfx::Vector2dF Layer::ScrollOffsetForAnimation() const { + return TotalScrollOffset(); +} + +// On<Property>Animated is called due to an ongoing accelerated animation. +// Since this animation is also being run on the compositor thread, there +// is no need to request a commit to push this value over, so the value is +// set directly rather than by calling Set<Property>. +void Layer::OnFilterAnimated(const FilterOperations& filters) { + filters_ = filters; +} + void Layer::OnOpacityAnimated(float opacity) { - // This is called due to an ongoing accelerated animation. Since this - // animation is also being run on the impl thread, there is no need to request - // a commit to push this value over, so set the value directly rather than - // calling SetOpacity. opacity_ = opacity; } void Layer::OnTransformAnimated(const gfx::Transform& transform) { - // This is called due to an ongoing accelerated animation. Since this - // animation is also being run on the impl thread, there is no need to request - // a commit to push this value over, so set this value directly rather than - // calling SetTransform. transform_ = transform; } +void Layer::OnScrollOffsetAnimated(gfx::Vector2dF scroll_offset) { + // Do nothing. Scroll deltas will be sent from the compositor thread back + // to the main thread in the same manner as during non-animated + // compositor-driven scrolling. +} + +void Layer::OnAnimationWaitingForDeletion() { + // Animations are only deleted during PushProperties. + SetNeedsPushProperties(); +} + bool Layer::IsActive() const { return true; } @@ -1021,21 +1117,10 @@ void Layer::RemoveAnimation(int animation_id) { SetNeedsCommit(); } -void Layer::SuspendAnimations(double monotonic_time) { - layer_animation_controller_->SuspendAnimations(monotonic_time); - SetNeedsCommit(); -} - -void Layer::ResumeAnimations(double monotonic_time) { - layer_animation_controller_->ResumeAnimations(monotonic_time); - SetNeedsCommit(); -} - void Layer::SetLayerAnimationControllerForTest( scoped_refptr<LayerAnimationController> controller) { layer_animation_controller_->RemoveValueObserver(this); layer_animation_controller_ = controller; - layer_animation_controller_->set_force_sync(); layer_animation_controller_->AddValueObserver(this); SetNeedsCommit(); } @@ -1098,4 +1183,8 @@ void Layer::RemoveFromClipTree() { clip_parent_ = NULL; } +void Layer::RunMicroBenchmark(MicroBenchmark* benchmark) { + benchmark->RunOnLayer(this); +} + } // namespace cc diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h index 737e83df067..f0bca17f47c 100644 --- a/chromium/cc/layers/layer.h +++ b/chromium/cc/layers/layer.h @@ -13,9 +13,11 @@ #include "base/observer_list.h" #include "cc/animation/layer_animation_controller.h" #include "cc/animation/layer_animation_value_observer.h" +#include "cc/animation/layer_animation_value_provider.h" #include "cc/base/cc_export.h" #include "cc/base/region.h" #include "cc/base/scoped_ptr_vector.h" +#include "cc/debug/micro_benchmark.h" #include "cc/layers/compositing_reasons.h" #include "cc/layers/draw_properties.h" #include "cc/layers/layer_lists.h" @@ -28,6 +30,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkPicture.h" +#include "third_party/skia/include/core/SkXfermode.h" #include "ui/gfx/rect.h" #include "ui/gfx/rect_f.h" #include "ui/gfx/transform.h" @@ -36,6 +39,12 @@ namespace gfx { class BoxF; } +namespace base { +namespace debug { +class ConvertableToTraceFormat; +} +} + namespace cc { class Animation; @@ -57,8 +66,13 @@ struct AnimationEvent; // Base class for composited layers. Special layer types are derived from // this class. class CC_EXPORT Layer : public base::RefCounted<Layer>, - public LayerAnimationValueObserver { + public LayerAnimationValueObserver, + public LayerAnimationValueProvider { public: + typedef RenderSurfaceLayerList RenderSurfaceListType; + typedef LayerList LayerListType; + typedef RenderSurface RenderSurfaceType; + enum LayerIdLabels { INVALID_ID = -1, }; @@ -121,11 +135,25 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, bool OpacityIsAnimating() const; virtual bool OpacityCanAnimateOnImplThread() const; + void SetBlendMode(SkXfermode::Mode blend_mode); + SkXfermode::Mode blend_mode() const { return blend_mode_; } + + bool uses_default_blend_mode() const { + return blend_mode_ == SkXfermode::kSrcOver_Mode; + } + + // A layer is root for an isolated group when it and all its descendants are + // drawn over a black and fully transparent background, creating an isolated + // group. It should be used along with SetBlendMode(), in order to restrict + // layers within the group to blend with layers outside this group. + void SetIsRootForIsolatedGroup(bool root); + bool is_root_for_isolated_group() const { + return is_root_for_isolated_group_; + } + void SetFilters(const FilterOperations& filters); const FilterOperations& filters() const { return filters_; } - - void SetFilter(const skia::RefPtr<SkImageFilter>& filter); - skia::RefPtr<SkImageFilter> filter() const { return filter_; } + bool FilterIsAnimating() const; // Background filters are filters applied to what is behind this layer, when // they are viewed through non-opaque regions in this layer. They are used @@ -186,10 +214,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, return clip_children_.get(); } - DrawProperties<Layer, RenderSurface>& draw_properties() { - return draw_properties_; - } - const DrawProperties<Layer, RenderSurface>& draw_properties() const { + DrawProperties<Layer>& draw_properties() { return draw_properties_; } + const DrawProperties<Layer>& draw_properties() const { return draw_properties_; } @@ -250,6 +276,12 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, void SetScrollable(bool scrollable); bool scrollable() const { return scrollable_; } + void SetUserScrollable(bool horizontal, bool vertical); + bool user_scrollable_horizontal() const { + return user_scrollable_horizontal_; + } + bool user_scrollable_vertical() const { return user_scrollable_vertical_; } + void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread); bool should_scroll_on_main_thread() const { return should_scroll_on_main_thread_; @@ -329,8 +361,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, virtual bool NeedMoreUpdates(); virtual void SetIsMask(bool is_mask) {} virtual void ReduceMemoryUsage() {} + virtual void OnOutputSurfaceCreated() {} virtual std::string DebugName(); + virtual scoped_refptr<base::debug::ConvertableToTraceFormat> TakeDebugInfo(); void SetLayerClient(LayerClient* client) { client_ = client; } @@ -367,9 +401,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, void PauseAnimation(int animation_id, double time_offset); void RemoveAnimation(int animation_id); - void SuspendAnimations(double monotonic_time); - void ResumeAnimations(double monotonic_time); - bool AnimatedBoundsForBox(const gfx::BoxF& box, gfx::BoxF* bounds) { return layer_animation_controller_->AnimatedBoundsForBox(box, bounds); } @@ -399,8 +430,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, virtual skia::RefPtr<SkPicture> GetPicture() const; - virtual bool CanClipSelf() const; - // Constructs a LayerImpl of the correct runtime type for this Layer type. virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl); @@ -428,6 +457,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, return num_dependents_need_push_properties_ > 0; } + virtual void RunMicroBenchmark(MicroBenchmark* benchmark); + protected: friend class LayerImpl; friend class TreeSynchronizer; @@ -454,6 +485,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, // unused resources on the impl thread are returned before commit completes. void SetNextCommitWaitsForActivation(); + // Called when the blend mode or filters have been changed. + void SetNeedsFilterContextIfNeeded(); + void SetNeedsPushProperties(); void AddDependentNeedsPushProperties(); void RemoveDependentNeedsPushProperties(); @@ -513,9 +547,15 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, // This should only be called from RemoveFromParent(). void RemoveChildOrDependent(Layer* child); + // LayerAnimationValueProvider implementation. + virtual gfx::Vector2dF ScrollOffsetForAnimation() const OVERRIDE; + // LayerAnimationValueObserver implementation. + virtual void OnFilterAnimated(const FilterOperations& filters) OVERRIDE; virtual void OnOpacityAnimated(float opacity) OVERRIDE; virtual void OnTransformAnimated(const gfx::Transform& transform) OVERRIDE; + virtual void OnScrollOffsetAnimated(gfx::Vector2dF scroll_offset) OVERRIDE; + virtual void OnAnimationWaitingForDeletion() OVERRIDE; virtual bool IsActive() const OVERRIDE; LayerList children_; @@ -533,9 +573,22 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, gfx::Vector2d scroll_offset_; gfx::Vector2d max_scroll_offset_; - bool scrollable_; - bool should_scroll_on_main_thread_; - bool have_wheel_event_handlers_; + bool scrollable_ : 1; + bool should_scroll_on_main_thread_ : 1; + bool have_wheel_event_handlers_ : 1; + bool user_scrollable_horizontal_ : 1; + bool user_scrollable_vertical_ : 1; + bool is_root_for_isolated_group_ : 1; + bool is_container_for_fixed_position_layers_ : 1; + bool is_drawable_ : 1; + bool hide_layer_and_subtree_ : 1; + bool masks_to_bounds_ : 1; + bool contents_opaque_ : 1; + bool double_sided_ : 1; + bool preserves_3d_ : 1; + bool use_parent_backface_visibility_ : 1; + bool draw_checkerboard_for_missing_tiles_ : 1; + bool force_render_surface_ : 1; Region non_fast_scrollable_region_; Region touch_event_handler_region_; gfx::PointF position_; @@ -543,21 +596,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, SkColor background_color_; CompositingReasons compositing_reasons_; float opacity_; - skia::RefPtr<SkImageFilter> filter_; + SkXfermode::Mode blend_mode_; FilterOperations filters_; FilterOperations background_filters_; float anchor_point_z_; - bool is_container_for_fixed_position_layers_; LayerPositionConstraint position_constraint_; - bool is_drawable_; - bool hide_layer_and_subtree_; - bool masks_to_bounds_; - bool contents_opaque_; - bool double_sided_; - bool preserves_3d_; - bool use_parent_backface_visibility_; - bool draw_checkerboard_for_missing_tiles_; - bool force_render_surface_; Layer* scroll_parent_; scoped_ptr<std::set<Layer*> > scroll_children_; @@ -579,7 +622,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, base::Closure did_scroll_callback_; - DrawProperties<Layer, RenderSurface> draw_properties_; + DrawProperties<Layer> draw_properties_; PaintProperties paint_properties_; diff --git a/chromium/cc/layers/layer_client.h b/chromium/cc/layers/layer_client.h index 73c0fd2514b..6ef6efe1c1b 100644 --- a/chromium/cc/layers/layer_client.h +++ b/chromium/cc/layers/layer_client.h @@ -7,14 +7,27 @@ #include <string> +#include "base/memory/ref_counted.h" #include "cc/base/cc_export.h" +namespace base { +namespace debug { +class ConvertableToTraceFormat; +} +} + namespace cc { class CC_EXPORT LayerClient { public: virtual std::string DebugName() = 0; + // Returns a pointer to a debug info object, if one has been computed. + // If not, returns NULL. If the returned pointer is non-NULL, the caller takes + // ownership of the pointer. + virtual scoped_refptr<base::debug::ConvertableToTraceFormat> + TakeDebugInfo() = 0; + protected: virtual ~LayerClient() {} }; diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc index b0c5399d32e..74b69b5572a 100644 --- a/chromium/cc/layers/layer_impl.cc +++ b/chromium/cc/layers/layer_impl.cc @@ -1,10 +1,11 @@ -// Copyright 2011 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "cc/layers/layer_impl.h" #include "base/debug/trace_event.h" +#include "base/json/json_reader.h" #include "base/strings/stringprintf.h" #include "cc/animation/animation_registrar.h" #include "cc/animation/scrollbar_animation_controller.h" @@ -13,6 +14,7 @@ #include "cc/base/math_util.h" #include "cc/debug/debug_colors.h" #include "cc/debug/layer_tree_debug_state.h" +#include "cc/debug/micro_benchmark_impl.h" #include "cc/debug/traced_value.h" #include "cc/input/layer_scroll_offset_delegate.h" #include "cc/layers/painted_scrollbar_layer_impl.h" @@ -22,12 +24,12 @@ #include "cc/trees/layer_tree_impl.h" #include "cc/trees/layer_tree_settings.h" #include "cc/trees/proxy.h" +#include "ui/gfx/box_f.h" #include "ui/gfx/point_conversions.h" #include "ui/gfx/quad_f.h" #include "ui/gfx/rect_conversions.h" namespace cc { - LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id) : parent_(NULL), scroll_parent_(NULL), @@ -42,14 +44,14 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id) scrollable_(false), should_scroll_on_main_thread_(false), have_wheel_event_handlers_(false), - background_color_(0), + user_scrollable_horizontal_(true), + user_scrollable_vertical_(true), stacking_order_changed_(false), double_sided_(true), layer_property_changed_(false), - layer_surface_property_changed_(false), masks_to_bounds_(false), contents_opaque_(false), - opacity_(1.0), + is_root_for_isolated_group_(false), preserves_3d_(false), use_parent_backface_visibility_(false), draw_checkerboard_for_missing_tiles_(false), @@ -57,6 +59,9 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id) hide_layer_and_subtree_(false), force_render_surface_(false), is_container_for_fixed_position_layers_(false), + background_color_(0), + opacity_(1.0), + blend_mode_(SkXfermode::kSrcOver_Mode), draw_depth_(0.f), compositing_reasons_(kCompositingReasonUnknown), current_draw_mode_(DRAW_MODE_NONE), @@ -69,13 +74,19 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id) layer_animation_controller_ = registrar->GetAnimationControllerForId(layer_id_); layer_animation_controller_->AddValueObserver(this); + if (IsActive()) + layer_animation_controller_->set_value_provider(this); } LayerImpl::~LayerImpl() { DCHECK_EQ(DRAW_MODE_NONE, current_draw_mode_); - layer_tree_impl_->UnregisterLayer(this); layer_animation_controller_->RemoveValueObserver(this); + layer_animation_controller_->remove_value_provider(this); + + if (!copy_requests_.empty() && layer_tree_impl_->IsActiveTree()) + layer_tree_impl()->RemoveLayerWithCopyOutputRequest(this); + layer_tree_impl_->UnregisterLayer(this); if (scroll_children_) { for (std::set<LayerImpl*>::iterator it = scroll_children_->begin(); @@ -150,6 +161,11 @@ void LayerImpl::SetScrollParent(LayerImpl* parent) { scroll_parent_ = parent; } +void LayerImpl::SetDebugInfo( + scoped_refptr<base::debug::ConvertableToTraceFormat> other) { + debug_info_ = other; +} + void LayerImpl::SetScrollChildren(std::set<LayerImpl*>* children) { if (scroll_children_.get() == children) return; @@ -243,7 +259,8 @@ scoped_ptr<SharedQuadState> LayerImpl::CreateSharedQuadState() const { draw_properties_.visible_content_rect, draw_properties_.clip_rect, draw_properties_.is_clipped, - draw_properties_.opacity); + draw_properties_.opacity, + blend_mode_); return state.Pass(); } @@ -342,14 +359,14 @@ void LayerImpl::SetSentScrollDelta(gfx::Vector2d sent_scroll_delta) { gfx::Vector2dF LayerImpl::ScrollBy(gfx::Vector2dF scroll) { DCHECK(scrollable()); - gfx::Vector2dF min_delta = -scroll_offset_; gfx::Vector2dF max_delta = max_scroll_offset_ - scroll_offset_; // Clamp new_delta so that position + delta stays within scroll bounds. gfx::Vector2dF new_delta = (ScrollDelta() + scroll); new_delta.SetToMax(min_delta); new_delta.SetToMin(max_delta); - gfx::Vector2dF unscrolled = ScrollDelta() + scroll - new_delta; + gfx::Vector2dF unscrolled = + ScrollDelta() + scroll - new_delta; SetScrollDelta(new_delta); return unscrolled; } @@ -374,7 +391,7 @@ void LayerImpl::ApplySentScrollDeltasFromAbortedCommit() { sent_scroll_delta_ = gfx::Vector2d(); } -void LayerImpl::ApplyScrollDeltasSinceBeginFrame() { +void LayerImpl::ApplyScrollDeltasSinceBeginMainFrame() { // Only the pending tree can have missing scrolls. DCHECK(layer_tree_impl()->IsPendingTree()); if (!scrollable()) @@ -472,10 +489,6 @@ skia::RefPtr<SkPicture> LayerImpl::GetPicture() { return skia::RefPtr<SkPicture>(); } -bool LayerImpl::CanClipSelf() const { - return false; -} - bool LayerImpl::AreVisibleResourcesReady() const { return true; } @@ -500,7 +513,6 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->SetDrawsContent(DrawsContent()); layer->SetHideLayerAndSubtree(hide_layer_and_subtree_); layer->SetFilters(filters()); - layer->SetFilter(filter()); layer->SetBackgroundFilters(background_filters()); layer->SetMasksToBounds(masks_to_bounds_); layer->SetShouldScrollOnMainThread(should_scroll_on_main_thread_); @@ -509,6 +521,8 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->SetTouchEventHandlerRegion(touch_event_handler_region_); layer->SetContentsOpaque(contents_opaque_); layer->SetOpacity(opacity_); + layer->SetBlendMode(blend_mode_); + layer->SetIsRootForIsolatedGroup(is_root_for_isolated_group_); layer->SetPosition(position_); layer->SetIsContainerForFixedPositionLayers( is_container_for_fixed_position_layers_); @@ -520,6 +534,8 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->SetTransform(transform_); layer->SetScrollable(scrollable_); + layer->set_user_scrollable_horizontal(user_scrollable_horizontal_); + layer->set_user_scrollable_vertical(user_scrollable_vertical_); layer->SetScrollOffsetAndDelta( scroll_offset_, layer->ScrollDelta() - layer->sent_scroll_delta()); layer->SetSentScrollDelta(gfx::Vector2d()); @@ -568,6 +584,8 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { // Reset any state that should be cleared for the next update. stacking_order_changed_ = false; update_rect_ = gfx::RectF(); + + layer->SetDebugInfo(debug_info_); } base::DictionaryValue* LayerImpl::LayerTreeAsJson() const { @@ -599,6 +617,13 @@ base::DictionaryValue* LayerImpl::LayerTreeAsJson() const { if (scrollable_) result->SetBoolean("Scrollable", scrollable_); + if (have_wheel_event_handlers_) + result->SetBoolean("WheelHandler", have_wheel_event_handlers_); + if (!touch_event_handler_region_.IsEmpty()) { + scoped_ptr<base::Value> region = touch_event_handler_region_.AsValue(); + result->Set("TouchRegion", region.release()); + } + list = new base::ListValue; for (size_t i = 0; i < children_.size(); ++i) list->Append(children_[i]->LayerTreeAsJson()); @@ -614,30 +639,6 @@ void LayerImpl::SetStackingOrderChanged(bool stacking_order_changed) { } } -bool LayerImpl::LayerSurfacePropertyChanged() const { - if (layer_surface_property_changed_) - return true; - - // If this layer's surface property hasn't changed, we want to see if - // some layer above us has changed this property. This is done for the - // case when such parent layer does not draw content, and therefore will - // not be traversed by the damage tracker. We need to make sure that - // property change on such layer will be caught by its descendants. - LayerImpl* current = this->parent_; - while (current && !current->draw_properties_.render_surface) { - if (current->layer_surface_property_changed_) - return true; - current = current->parent_; - } - - return false; -} - -void LayerImpl::NoteLayerSurfacePropertyChanged() { - layer_surface_property_changed_ = true; - layer_tree_impl()->set_needs_update_draw_properties(); -} - void LayerImpl::NoteLayerPropertyChanged() { layer_property_changed_ = true; layer_tree_impl()->set_needs_update_draw_properties(); @@ -660,7 +661,6 @@ const char* LayerImpl::LayerTypeAsString() const { void LayerImpl::ResetAllChangeTrackingForSubtree() { layer_property_changed_ = false; - layer_surface_property_changed_ = false; update_rect_ = gfx::RectF(); @@ -683,6 +683,14 @@ bool LayerImpl::LayerIsAlwaysDamaged() const { return false; } +gfx::Vector2dF LayerImpl::ScrollOffsetForAnimation() const { + return TotalScrollOffset(); +} + +void LayerImpl::OnFilterAnimated(const FilterOperations& filters) { + SetFilters(filters); +} + void LayerImpl::OnOpacityAnimated(float opacity) { SetOpacity(opacity); } @@ -691,6 +699,20 @@ void LayerImpl::OnTransformAnimated(const gfx::Transform& transform) { SetTransform(transform); } +void LayerImpl::OnScrollOffsetAnimated(gfx::Vector2dF scroll_offset) { + // Only layers in the active tree should need to do anything here, since + // layers in the pending tree will find out about these changes as a + // result of the call to SetScrollDelta. + if (!IsActive()) + return; + + SetScrollDelta(scroll_offset - scroll_offset_); + + layer_tree_impl_->DidAnimateScrollOffset(); +} + +void LayerImpl::OnAnimationWaitingForDeletion() {} + bool LayerImpl::IsActive() const { return layer_tree_impl_->IsActiveTree(); } @@ -818,11 +840,20 @@ void LayerImpl::SetFilters(const FilterOperations& filters) { if (filters_ == filters) return; - DCHECK(!filter_); filters_ = filters; NoteLayerPropertyChangedForSubtree(); } +bool LayerImpl::FilterIsAnimating() const { + return layer_animation_controller_->IsAnimatingProperty(Animation::Filter); +} + +bool LayerImpl::FilterIsAnimatingOnImplOnly() const { + Animation* filter_animation = + layer_animation_controller_->GetAnimation(Animation::Filter); + return filter_animation && filter_animation->is_impl_only(); +} + void LayerImpl::SetBackgroundFilters( const FilterOperations& filters) { if (background_filters_ == filters) @@ -832,15 +863,6 @@ void LayerImpl::SetBackgroundFilters( NoteLayerPropertyChanged(); } -void LayerImpl::SetFilter(const skia::RefPtr<SkImageFilter>& filter) { - if (filter_.get() == filter.get()) - return; - - DCHECK(filters_.IsEmpty()); - filter_ = filter; - NoteLayerPropertyChangedForSubtree(); -} - void LayerImpl::SetMasksToBounds(bool masks_to_bounds) { if (masks_to_bounds_ == masks_to_bounds) return; @@ -862,7 +884,7 @@ void LayerImpl::SetOpacity(float opacity) { return; opacity_ = opacity; - NoteLayerSurfacePropertyChanged(); + NoteLayerPropertyChangedForSubtree(); } bool LayerImpl::OpacityIsAnimating() const { @@ -875,6 +897,21 @@ bool LayerImpl::OpacityIsAnimatingOnImplOnly() const { return opacity_animation && opacity_animation->is_impl_only(); } +void LayerImpl::SetBlendMode(SkXfermode::Mode blend_mode) { + if (blend_mode_ == blend_mode) + return; + + blend_mode_ = blend_mode; + NoteLayerPropertyChangedForSubtree(); +} + +void LayerImpl::SetIsRootForIsolatedGroup(bool root) { + if (is_root_for_isolated_group_ == root) + return; + + is_root_for_isolated_group_ = root; +} + void LayerImpl::SetPosition(gfx::PointF position) { if (position_ == position) return; @@ -906,7 +943,7 @@ void LayerImpl::SetTransform(const gfx::Transform& transform) { return; transform_ = transform; - NoteLayerSurfacePropertyChanged(); + NoteLayerPropertyChangedForSubtree(); } bool LayerImpl::TransformIsAnimating() const { @@ -1001,8 +1038,15 @@ void LayerImpl::SetScrollOffsetDelegate( } gfx::Vector2dF total_offset = TotalScrollOffset(); scroll_offset_delegate_ = scroll_offset_delegate; - if (scroll_offset_delegate_) + if (scroll_offset_delegate_) { + scroll_offset_delegate_->SetMaxScrollOffset(max_scroll_offset_); scroll_offset_delegate_->SetTotalScrollOffset(total_offset); + } +} + +bool LayerImpl::IsExternalFlingActive() const { + return scroll_offset_delegate_ && + scroll_offset_delegate_->IsExternalFlingActive(); } void LayerImpl::SetScrollOffset(gfx::Vector2d scroll_offset) { @@ -1088,6 +1132,9 @@ void LayerImpl::SetMaxScrollOffset(gfx::Vector2d max_scroll_offset) { return; max_scroll_offset_ = max_scroll_offset; + if (scroll_offset_delegate_) + scroll_offset_delegate_->SetMaxScrollOffset(max_scroll_offset_); + layer_tree_impl()->set_needs_update_draw_properties(); UpdateScrollbarPositions(); } @@ -1266,6 +1313,9 @@ CompositingReasonsAsValue(CompositingReasons reasons) { if (reasons & kCompositingReasonOutOfFlowClipping) reason_list->AppendString("Has clipping ancestor"); + if (reasons & kCompositingReasonIsolateCompositedDescendants) + reason_list->AppendString("Should isolate composited descendants"); + return reason_list.PassAs<base::Value>(); } @@ -1315,6 +1365,30 @@ void LayerImpl::AsValueInto(base::DictionaryValue* state) const { if (clip_parent_) state->SetInteger("clip_parent", clip_parent_->id()); + + state->SetBoolean("can_use_lcd_text", can_use_lcd_text()); + state->SetBoolean("contents_opaque", contents_opaque()); + + if (layer_animation_controller_->IsAnimatingProperty(Animation::Transform) || + layer_animation_controller_->IsAnimatingProperty(Animation::Filter)) { + gfx::BoxF box(bounds().width(), bounds().height(), 0.f); + gfx::BoxF inflated; + if (layer_animation_controller_->AnimatedBoundsForBox(box, &inflated)) + state->Set("animated_bounds", MathUtil::AsValue(inflated).release()); + } + + if (debug_info_.get()) { + std::string str; + debug_info_->AppendAsTraceFormat(&str); + base::JSONReader json_reader; + // Parsing the JSON and re-encoding it is not very efficient, + // but it's the simplest way to achieve the desired effect, which + // is to output: + // {..., layout_rects: [{geometry_rect: ...}, ...], ...} + // rather than: + // {layout_rects: "[{geometry_rect: ...}, ...]", ...} + state->Set("layout_rects", json_reader.ReadToValue(str)); + } } size_t LayerImpl::GPUMemoryUsageInBytes() const { return 0; } @@ -1325,4 +1399,8 @@ scoped_ptr<base::Value> LayerImpl::AsValue() const { return state.PassAs<base::Value>(); } +void LayerImpl::RunMicroBenchmark(MicroBenchmarkImpl* benchmark) { + benchmark->RunOnLayer(this); +} + } // namespace cc diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h index ba0ff7b8216..cfbd353bf54 100644 --- a/chromium/cc/layers/layer_impl.h +++ b/chromium/cc/layers/layer_impl.h @@ -13,6 +13,7 @@ #include "base/values.h" #include "cc/animation/layer_animation_controller.h" #include "cc/animation/layer_animation_value_observer.h" +#include "cc/animation/layer_animation_value_provider.h" #include "cc/base/cc_export.h" #include "cc/base/region.h" #include "cc/base/scoped_ptr_vector.h" @@ -35,6 +36,10 @@ #include "ui/gfx/transform.h" namespace base { +namespace debug { +class ConvertableToTraceFormat; +} + class DictionaryValue; } @@ -42,11 +47,11 @@ namespace cc { class LayerTreeHostImpl; class LayerTreeImpl; +class MicroBenchmarkImpl; class QuadSink; class Renderer; class ScrollbarAnimationController; class ScrollbarLayerImplBase; -class Layer; struct AppendQuadsData; @@ -57,8 +62,13 @@ enum DrawMode { DRAW_MODE_RESOURCELESS_SOFTWARE }; -class CC_EXPORT LayerImpl : LayerAnimationValueObserver { +class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, + public LayerAnimationValueProvider { public: + typedef LayerImplList RenderSurfaceListType; + typedef LayerImplList LayerListType; + typedef RenderSurfaceImpl RenderSurfaceType; + static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) { return make_scoped_ptr(new LayerImpl(tree_impl, id)); } @@ -67,9 +77,15 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { int id() const { return layer_id_; } + // LayerAnimationValueProvider implementation. + virtual gfx::Vector2dF ScrollOffsetForAnimation() const OVERRIDE; + // LayerAnimationValueObserver implementation. + virtual void OnFilterAnimated(const FilterOperations& filters) OVERRIDE; virtual void OnOpacityAnimated(float opacity) OVERRIDE; virtual void OnTransformAnimated(const gfx::Transform& transform) OVERRIDE; + virtual void OnScrollOffsetAnimated(gfx::Vector2dF scroll_offset) OVERRIDE; + virtual void OnAnimationWaitingForDeletion() OVERRIDE; virtual bool IsActive() const OVERRIDE; // Tree structure. @@ -187,15 +203,14 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { void SetFilters(const FilterOperations& filters); const FilterOperations& filters() const { return filters_; } + bool FilterIsAnimating() const; + bool FilterIsAnimatingOnImplOnly() const; void SetBackgroundFilters(const FilterOperations& filters); const FilterOperations& background_filters() const { return background_filters_; } - void SetFilter(const skia::RefPtr<SkImageFilter>& filter); - skia::RefPtr<SkImageFilter> filter() const { return filter_; } - void SetMasksToBounds(bool masks_to_bounds); bool masks_to_bounds() const { return masks_to_bounds_; } @@ -207,6 +222,17 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { bool OpacityIsAnimating() const; bool OpacityIsAnimatingOnImplOnly() const; + void SetBlendMode(SkXfermode::Mode); + SkXfermode::Mode blend_mode() const { return blend_mode_; } + bool uses_default_blend_mode() const { + return blend_mode_ == SkXfermode::kSrcOver_Mode; + } + + void SetIsRootForIsolatedGroup(bool root); + bool is_root_for_isolated_group() const { + return is_root_for_isolated_group_; + } + void SetPosition(gfx::PointF position); gfx::PointF position() const { return position_; } @@ -267,10 +293,10 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { void CreateRenderSurface(); void ClearRenderSurface(); - DrawProperties<LayerImpl, RenderSurfaceImpl>& draw_properties() { + DrawProperties<LayerImpl>& draw_properties() { return draw_properties_; } - const DrawProperties<LayerImpl, RenderSurfaceImpl>& draw_properties() const { + const DrawProperties<LayerImpl>& draw_properties() const { return draw_properties_; } @@ -335,6 +361,12 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { float contents_scale_y() const { return draw_properties_.contents_scale_y; } void SetContentsScale(float contents_scale_x, float contents_scale_y); + // Computes a box in screen space that should entirely contain the layer's + // bounds through the entirety of the layer's current animation. Returns true + // and sets |out| to the inflation if there are animations that can inflate + // bounds in the path to the root layer. Returns false otherwise. + bool GetAnimationBounds(gfx::BoxF* out) const { return false; } + virtual void CalculateContentsScale(float ideal_contents_scale, float device_scale_factor, float page_scale_factor, @@ -345,6 +377,8 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { void SetScrollOffsetDelegate( LayerScrollOffsetDelegate* scroll_offset_delegate); + bool IsExternalFlingActive() const; + void SetScrollOffset(gfx::Vector2d scroll_offset); void SetScrollOffsetAndDelta(gfx::Vector2d scroll_offset, gfx::Vector2dF scroll_delta); @@ -368,8 +402,15 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { void SetScrollable(bool scrollable) { scrollable_ = scrollable; } bool scrollable() const { return scrollable_; } + void set_user_scrollable_horizontal(bool scrollable) { + user_scrollable_horizontal_ = scrollable; + } + void set_user_scrollable_vertical(bool scrollable) { + user_scrollable_vertical_ = scrollable; + } + void ApplySentScrollDeltasFromAbortedCommit(); - void ApplyScrollDeltasSinceBeginFrame(); + void ApplyScrollDeltasSinceBeginMainFrame(); void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) { should_scroll_on_main_thread_ = should_scroll_on_main_thread; @@ -427,7 +468,6 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { bool LayerPropertyChanged() const { return layer_property_changed_ || LayerIsAlwaysDamaged(); } - bool LayerSurfacePropertyChanged() const; void ResetAllChangeTrackingForSubtree(); @@ -466,8 +506,6 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { virtual skia::RefPtr<SkPicture> GetPicture(); - virtual bool CanClipSelf() const; - virtual bool AreVisibleResourcesReady() const; virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl); @@ -480,6 +518,11 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { bool needs_push_properties() const { return true; } bool descendant_needs_push_properties() const { return true; } + virtual void RunMicroBenchmark(MicroBenchmarkImpl* benchmark); + + virtual void SetDebugInfo( + scoped_refptr<base::debug::ConvertableToTraceFormat> other); + protected: LayerImpl(LayerTreeImpl* layer_impl, int id); @@ -497,7 +540,6 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { virtual void AsValueInto(base::DictionaryValue* dict) const; - void NoteLayerSurfacePropertyChanged(); void NoteLayerPropertyChanged(); void NoteLayerPropertyChangedForSubtree(); @@ -539,43 +581,40 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { gfx::Size bounds_; gfx::Vector2d scroll_offset_; LayerScrollOffsetDelegate* scroll_offset_delegate_; - bool scrollable_; - bool should_scroll_on_main_thread_; - bool have_wheel_event_handlers_; - Region non_fast_scrollable_region_; - Region touch_event_handler_region_; - SkColor background_color_; - bool stacking_order_changed_; - + bool scrollable_ : 1; + bool should_scroll_on_main_thread_ : 1; + bool have_wheel_event_handlers_ : 1; + bool user_scrollable_horizontal_ : 1; + bool user_scrollable_vertical_ : 1; + bool stacking_order_changed_ : 1; // Whether the "back" of this layer should draw. - bool double_sided_; + bool double_sided_ : 1; // Tracks if drawing-related properties have changed since last redraw. - bool layer_property_changed_; + bool layer_property_changed_ : 1; + + bool masks_to_bounds_ : 1; + bool contents_opaque_ : 1; + bool is_root_for_isolated_group_ : 1; + bool preserves_3d_ : 1; + bool use_parent_backface_visibility_ : 1; + bool draw_checkerboard_for_missing_tiles_ : 1; + bool draws_content_ : 1; + bool hide_layer_and_subtree_ : 1; + bool force_render_surface_ : 1; - // Indicates that a property has changed on this layer that would not - // affect the pixels on its target surface, but would require redrawing - // the target_surface onto its ancestor target_surface. - // For layers that do not own a surface this flag acts as - // layer_property_changed_. - bool layer_surface_property_changed_; + // Set for the layer that other layers are fixed to. + bool is_container_for_fixed_position_layers_ : 1; + Region non_fast_scrollable_region_; + Region touch_event_handler_region_; + SkColor background_color_; - bool masks_to_bounds_; - bool contents_opaque_; float opacity_; + SkXfermode::Mode blend_mode_; gfx::PointF position_; - bool preserves_3d_; - bool use_parent_backface_visibility_; - bool draw_checkerboard_for_missing_tiles_; gfx::Transform sublayer_transform_; gfx::Transform transform_; - bool draws_content_; - bool hide_layer_and_subtree_; - bool force_render_surface_; - - // Set for the layer that other layers are fixed to. - bool is_container_for_fixed_position_layers_; // This property is effective when // is_container_for_fixed_position_layers_ == true, gfx::Vector2dF fixed_container_size_delta_; @@ -597,7 +636,6 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { FilterOperations filters_; FilterOperations background_filters_; - skia::RefPtr<SkImageFilter> filter_; protected: DrawMode current_draw_mode_; @@ -605,7 +643,7 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { private: // Rect indicating what was repainted/updated during update. // Note that plugin layers bypass this and leave it empty. - // Uses layer's content space. + // Uses layer (not content) space. gfx::RectF update_rect_; // Manages animations for this layer. @@ -623,7 +661,9 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { // Group of properties that need to be computed based on the layer tree // hierarchy before layers can be drawn. - DrawProperties<LayerImpl, RenderSurfaceImpl> draw_properties_; + DrawProperties<LayerImpl> draw_properties_; + + scoped_refptr<base::debug::ConvertableToTraceFormat> debug_info_; DISALLOW_COPY_AND_ASSIGN(LayerImpl); }; diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc index 1ab7a71b2ca..9d90c04928e 100644 --- a/chromium/cc/layers/layer_impl_unittest.cc +++ b/chromium/cc/layers/layer_impl_unittest.cc @@ -24,32 +24,28 @@ namespace { code_to_test; \ EXPECT_TRUE(root->LayerPropertyChanged()); \ EXPECT_TRUE(child->LayerPropertyChanged()); \ - EXPECT_TRUE(grand_child->LayerPropertyChanged()); \ - EXPECT_FALSE(root->LayerSurfacePropertyChanged()) + EXPECT_TRUE(grand_child->LayerPropertyChanged()); #define EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(code_to_test) \ root->ResetAllChangeTrackingForSubtree(); \ code_to_test; \ EXPECT_FALSE(root->LayerPropertyChanged()); \ EXPECT_FALSE(child->LayerPropertyChanged()); \ - EXPECT_FALSE(grand_child->LayerPropertyChanged()); \ - EXPECT_FALSE(root->LayerSurfacePropertyChanged()) + EXPECT_FALSE(grand_child->LayerPropertyChanged()); #define EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(code_to_test) \ root->ResetAllChangeTrackingForSubtree(); \ code_to_test; \ EXPECT_TRUE(root->LayerPropertyChanged()); \ EXPECT_FALSE(child->LayerPropertyChanged()); \ - EXPECT_FALSE(grand_child->LayerPropertyChanged()); \ - EXPECT_FALSE(root->LayerSurfacePropertyChanged()) + EXPECT_FALSE(grand_child->LayerPropertyChanged()); -#define EXECUTE_AND_VERIFY_ONLY_SURFACE_CHANGED(code_to_test) \ +#define EXECUTE_AND_VERIFY_ONLY_DESCENDANTS_CHANGED(code_to_test) \ root->ResetAllChangeTrackingForSubtree(); \ code_to_test; \ EXPECT_FALSE(root->LayerPropertyChanged()); \ - EXPECT_FALSE(child->LayerPropertyChanged()); \ - EXPECT_FALSE(grand_child->LayerPropertyChanged()); \ - EXPECT_TRUE(root->LayerSurfacePropertyChanged()) + EXPECT_TRUE(child->LayerPropertyChanged()); \ + EXPECT_TRUE(grand_child->LayerPropertyChanged()); #define VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(code_to_test) \ root->ResetAllChangeTrackingForSubtree(); \ @@ -99,11 +95,10 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { gfx::RectF(arbitrary_point_f, gfx::SizeF(1.234f, 5.678f)); SkColor arbitrary_color = SkColorSetRGB(10, 20, 30); gfx::Transform arbitrary_transform; - arbitrary_transform.Scale3d(0.1, 0.2, 0.3); + arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f); FilterOperations arbitrary_filters; arbitrary_filters.Append(FilterOperation::CreateOpacityFilter(0.5f)); - skia::RefPtr<SkImageFilter> arbitrary_filter = - skia::AdoptRef(new SkBlurImageFilter(SK_Scalar1, SK_Scalar1)); + SkXfermode::Mode arbitrary_blend_mode = SkXfermode::kMultiply_Mode; // These properties are internal, and should not be considered "change" when // they are used. @@ -117,7 +112,6 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetAnchorPointZ(arbitrary_number)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetFilters(arbitrary_filters)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetFilters(FilterOperations())); - EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetFilter(arbitrary_filter)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED( root->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 4))); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetMasksToBounds(true)); @@ -132,6 +126,9 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetScrollDelta(gfx::Vector2d())); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetScrollOffset(arbitrary_vector2d)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetHideLayerAndSubtree(true)); + EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetOpacity(arbitrary_number)); + EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetBlendMode(arbitrary_blend_mode)); + EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetTransform(arbitrary_transform)); // Changing these properties only affects the layer itself. EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->SetContentBounds(arbitrary_size)); @@ -143,18 +140,10 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED( root->SetBackgroundFilters(arbitrary_filters)); - // Changing these properties only affects how render surface is drawn - EXECUTE_AND_VERIFY_ONLY_SURFACE_CHANGED(root->SetOpacity(arbitrary_number)); - EXECUTE_AND_VERIFY_ONLY_SURFACE_CHANGED( - root->SetTransform(arbitrary_transform)); - - // Special case: check that sublayer transform changes all layer's - // descendants, but not the layer itself. - root->ResetAllChangeTrackingForSubtree(); - root->SetSublayerTransform(arbitrary_transform); - EXPECT_FALSE(root->LayerPropertyChanged()); - EXPECT_TRUE(child->LayerPropertyChanged()); - EXPECT_TRUE(grand_child->LayerPropertyChanged()); + // Changing these properties affects all layer's descendants, + // but not the layer itself. + EXECUTE_AND_VERIFY_ONLY_DESCENDANTS_CHANGED( + root->SetSublayerTransform(arbitrary_transform)); // Special case: check that SetBounds changes behavior depending on // masksToBounds. @@ -165,6 +154,9 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { // changed. EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetBounds(arbitrary_size)); + EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE( + root->SetIsRootForIsolatedGroup(true)); + // After setting all these properties already, setting to the exact same // values again should not cause any change. EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE( @@ -189,6 +181,10 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { root->SetContentsScale(arbitrary_number, arbitrary_number)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetContentsOpaque(true)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetOpacity(arbitrary_number)); + EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE( + root->SetBlendMode(arbitrary_blend_mode)); + EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE( + root->SetIsRootForIsolatedGroup(true)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetDrawsContent(true)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE( root->SetSublayerTransform(arbitrary_transform)); @@ -213,18 +209,16 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) { gfx::RectF(arbitrary_point_f, gfx::SizeF(1.234f, 5.678f)); SkColor arbitrary_color = SkColorSetRGB(10, 20, 30); gfx::Transform arbitrary_transform; - arbitrary_transform.Scale3d(0.1, 0.2, 0.3); + arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f); FilterOperations arbitrary_filters; arbitrary_filters.Append(FilterOperation::CreateOpacityFilter(0.5f)); - skia::RefPtr<SkImageFilter> arbitrary_filter = - skia::AdoptRef(new SkBlurImageFilter(SK_Scalar1, SK_Scalar1)); + SkXfermode::Mode arbitrary_blend_mode = SkXfermode::kMultiply_Mode; // Related filter functions. VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters)); VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters)); VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(FilterOperations())); - VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilter(arbitrary_filter)); - VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilter(arbitrary_filter)); + VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters)); // Related scrolling functions. VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetMaxScrollOffset(large_vector2d)); @@ -263,6 +257,7 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) { VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES( root->SetBackgroundFilters(arbitrary_filters)); VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetOpacity(arbitrary_number)); + VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetBlendMode(arbitrary_blend_mode)); VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetTransform(arbitrary_transform)); VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES( root->SetSublayerTransform(arbitrary_transform)); @@ -271,7 +266,8 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) { // Unrelated functions, set to the same values, no needs update. VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES( root->SetAnchorPointZ(arbitrary_number)); - VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilter(arbitrary_filter)); + VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetIsRootForIsolatedGroup(true)); + VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters)); VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetMasksToBounds(true)); VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetContentsOpaque(true)); VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetPosition(arbitrary_point_f)); @@ -289,6 +285,9 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) { root->SetBackgroundFilters(arbitrary_filters)); VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetOpacity(arbitrary_number)); VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES( + root->SetBlendMode(arbitrary_blend_mode)); + VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetIsRootForIsolatedGroup(true)); + VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES( root->SetTransform(arbitrary_transform)); VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES( root->SetSublayerTransform(arbitrary_transform)); @@ -391,15 +390,20 @@ TEST_F(LayerImplScrollTest, ScrollByWithNonZeroOffset) { class ScrollDelegateIgnore : public LayerScrollOffsetDelegate { public: + virtual void SetMaxScrollOffset(gfx::Vector2dF max_scroll_offset) OVERRIDE {} virtual void SetTotalScrollOffset(gfx::Vector2dF new_value) OVERRIDE {} virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE { return fixed_offset_; } + virtual bool IsExternalFlingActive() const OVERRIDE { return false; } void set_fixed_offset(gfx::Vector2dF fixed_offset) { fixed_offset_ = fixed_offset; } + virtual void SetTotalPageScaleFactor(float page_scale_factor) OVERRIDE {} + virtual void SetScrollableSize(gfx::SizeF scrollable_size) OVERRIDE {} + private: gfx::Vector2dF fixed_offset_; }; @@ -441,12 +445,16 @@ TEST_F(LayerImplScrollTest, ScrollByWithIgnoringDelegate) { class ScrollDelegateAccept : public LayerScrollOffsetDelegate { public: + virtual void SetMaxScrollOffset(gfx::Vector2dF max_scroll_offset) OVERRIDE {} virtual void SetTotalScrollOffset(gfx::Vector2dF new_value) OVERRIDE { current_offset_ = new_value; } virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE { return current_offset_; } + virtual bool IsExternalFlingActive() const OVERRIDE { return false; } + virtual void SetTotalPageScaleFactor(float page_scale_factor) OVERRIDE {} + virtual void SetScrollableSize(gfx::SizeF scrollable_size) OVERRIDE {} private: gfx::Vector2dF current_offset_; @@ -558,5 +566,21 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsWithAcceptingDelegate) { EXPECT_VECTOR_EQ(gfx::Vector2d(), layer()->sent_scroll_delta()); } +// The user-scrollability breaks for zoomed-in pages. So disable this. +// http://crbug.com/322223 +TEST_F(LayerImplScrollTest, DISABLED_ScrollUserUnscrollableLayer) { + gfx::Vector2d max_scroll_offset(50, 80); + gfx::Vector2d scroll_offset(10, 5); + gfx::Vector2dF scroll_delta(20.5f, 8.5f); + + layer()->set_user_scrollable_vertical(false); + layer()->SetMaxScrollOffset(max_scroll_offset); + layer()->SetScrollOffset(scroll_offset); + gfx::Vector2dF unscrolled = layer()->ScrollBy(scroll_delta); + + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 8.5f), unscrolled); + EXPECT_VECTOR_EQ(gfx::Vector2dF(30.5f, 5), layer()->TotalScrollOffset()); +} + } // namespace } // namespace cc diff --git a/chromium/cc/layers/layer_iterator.cc b/chromium/cc/layers/layer_iterator.cc index c33e7536ec0..a52c3f1f39a 100644 --- a/chromium/cc/layers/layer_iterator.cc +++ b/chromium/cc/layers/layer_iterator.cc @@ -17,81 +17,6 @@ template <typename LayerType, typename LayerList, typename RenderSurfaceType, typename ActionType> -void LayerIteratorActions::BackToFront::Begin( - LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it) { - it->target_render_surface_layer_index_ = 0; - it->current_layer_index_ = - LayerIteratorValue::kLayerIndexRepresentingTargetRenderSurface; - - highest_target_render_surface_layer_ = 0; -} - -template <typename LayerType, - typename LayerList, - typename RenderSurfaceType, - typename ActionType> -void LayerIteratorActions::BackToFront::End( - LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it) { - it->target_render_surface_layer_index_ = - LayerIteratorValue::kInvalidTargetRenderSurfaceLayerIndex; - it->current_layer_index_ = 0; -} - -template <typename LayerType, - typename LayerList, - typename RenderSurfaceType, - typename ActionType> -void LayerIteratorActions::BackToFront::Next( - LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it) { - // If the current layer has a RS, move to its layer list. Otherwise, - // visit the next layer in the current RS layer list. - if (it->current_layer_represents_contributing_render_surface()) { - // Save our position in the child_layers list for the RenderSurface, - // then jump to the next RenderSurface. Save where we - // came from in the next RenderSurface so we can get back to it. - it->target_render_surface()->current_layer_index_history_ = - it->current_layer_index_; - int previous_target_render_surface_layer = - it->target_render_surface_layer_index_; - - it->target_render_surface_layer_index_ = - ++highest_target_render_surface_layer_; - it->current_layer_index_ = - LayerIteratorValue::kLayerIndexRepresentingTargetRenderSurface; - - it->target_render_surface()->target_render_surface_layer_index_history_ = - previous_target_render_surface_layer; - } else { - ++it->current_layer_index_; - - int target_render_surface_num_children = - it->target_render_surface_children().size(); - while (it->current_layer_index_ == target_render_surface_num_children) { - // Jump back to the previous RenderSurface, - // and get back the position where we were in that list, - // and move to the next position there. - if (!it->target_render_surface_layer_index_) { - // End of the list - it->target_render_surface_layer_index_ = - LayerIteratorValue::kInvalidTargetRenderSurfaceLayerIndex; - it->current_layer_index_ = 0; - return; - } - it->target_render_surface_layer_index_ = it->target_render_surface() - ->target_render_surface_layer_index_history_; - it->current_layer_index_ = - it->target_render_surface()->current_layer_index_history_ + 1; - - target_render_surface_num_children = - it->target_render_surface_children().size(); - } - } -} - -template <typename LayerType, - typename LayerList, - typename RenderSurfaceType, - typename ActionType> void LayerIteratorActions::FrontToBack::Begin( LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it) { it->target_render_surface_layer_index_ = 0; @@ -176,26 +101,6 @@ void LayerIteratorActions::FrontToBack::GoToHighestInSubtree( // Declare each of the above functions for Layer and LayerImpl classes // so that they are linked. -template CC_EXPORT void LayerIteratorActions::BackToFront::Begin( - LayerIterator<Layer, RenderSurfaceLayerList, RenderSurface, BackToFront>* - it); -template CC_EXPORT void LayerIteratorActions::BackToFront::End( - LayerIterator<Layer, RenderSurfaceLayerList, RenderSurface, BackToFront>* - it); -template CC_EXPORT void LayerIteratorActions::BackToFront::Next( - LayerIterator<Layer, RenderSurfaceLayerList, RenderSurface, BackToFront>* - it); - -template CC_EXPORT void LayerIteratorActions::BackToFront::Begin( - LayerIterator<LayerImpl, LayerImplList, RenderSurfaceImpl, BackToFront>* - it); -template CC_EXPORT void LayerIteratorActions::BackToFront::End( - LayerIterator<LayerImpl, LayerImplList, RenderSurfaceImpl, BackToFront>* - it); -template CC_EXPORT void LayerIteratorActions::BackToFront::Next( - LayerIterator<LayerImpl, LayerImplList, RenderSurfaceImpl, BackToFront>* - it); - template CC_EXPORT void LayerIteratorActions::FrontToBack::Next( LayerIterator<Layer, RenderSurfaceLayerList, RenderSurface, FrontToBack>* it); diff --git a/chromium/cc/layers/layer_iterator.h b/chromium/cc/layers/layer_iterator.h index b8a02c34e22..5b132732545 100644 --- a/chromium/cc/layers/layer_iterator.h +++ b/chromium/cc/layers/layer_iterator.h @@ -69,11 +69,8 @@ namespace cc { // refers to the layer itself, as a child of the // current target RenderSurface. // -// The BackToFront iterator will return a layer representing the target surface -// before returning layers representing themselves as children of the current -// target surface. Whereas the FrontToBack ordering will iterate over children -// layers of a surface before the layer representing the surface -// as a target surface. +// The FrontToBack iterator will iterate over children layers of a surface +// before the layer representing the surface as a target surface. // // To use the iterators: // @@ -237,34 +234,6 @@ class LayerIterator { // Orderings for iterating over the RenderSurface-Layer tree. struct CC_EXPORT LayerIteratorActions { - // Walks layers sorted by z-order from back to front. - class CC_EXPORT BackToFront { - public: - template <typename LayerType, - typename LayerList, - typename RenderSurfaceType, - typename ActionType> - void Begin( - LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it); - - template <typename LayerType, - typename LayerList, - typename RenderSurfaceType, - typename ActionType> - void End( - LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it); - - template <typename LayerType, - typename LayerList, - typename RenderSurfaceType, - typename ActionType> - void Next( - LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it); - - private: - int highest_target_render_surface_layer_; - }; - // Walks layers sorted by z-order from front to back class CC_EXPORT FrontToBack { public: diff --git a/chromium/cc/layers/layer_iterator_unittest.cc b/chromium/cc/layers/layer_iterator_unittest.cc index c2ab71b3f92..c781d28b13f 100644 --- a/chromium/cc/layers/layer_iterator_unittest.cc +++ b/chromium/cc/layers/layer_iterator_unittest.cc @@ -54,10 +54,6 @@ typedef LayerIterator<Layer, RenderSurfaceLayerList, RenderSurface, LayerIteratorActions::FrontToBack> FrontToBack; -typedef LayerIterator<Layer, - RenderSurfaceLayerList, - RenderSurface, - LayerIteratorActions::BackToFront> BackToFront; void ResetCounts(RenderSurfaceLayerList* render_surface_layer_list) { for (unsigned surface_index = 0; @@ -101,27 +97,9 @@ void IterateFrontToBack( } } -void IterateBackToFront( - RenderSurfaceLayerList* render_surface_layer_list) { - ResetCounts(render_surface_layer_list); - int count = 0; - for (BackToFront it = BackToFront::Begin(render_surface_layer_list); - it != BackToFront::End(render_surface_layer_list); - ++it, ++count) { - TestLayer* layer = static_cast<TestLayer*>(*it); - if (it.represents_target_render_surface()) - layer->count_representing_target_surface_ = count; - if (it.represents_contributing_render_surface()) - layer->count_representing_contributing_surface_ = count; - if (it.represents_itself()) - layer->count_representing_itself_ = count; - } -} - TEST(LayerIteratorTest, EmptyTree) { RenderSurfaceLayerList render_surface_layer_list; - IterateBackToFront(&render_surface_layer_list); IterateFrontToBack(&render_surface_layer_list); } @@ -145,13 +123,6 @@ TEST(LayerIteratorTest, SimpleTree) { root_layer.get(), root_layer->bounds(), &render_surface_layer_list); LayerTreeHostCommon::CalculateDrawProperties(&inputs); - IterateBackToFront(&render_surface_layer_list); - EXPECT_COUNT(root_layer, 0, -1, 1); - EXPECT_COUNT(first, -1, -1, 2); - EXPECT_COUNT(second, -1, -1, 3); - EXPECT_COUNT(third, -1, -1, 4); - EXPECT_COUNT(fourth, -1, -1, 5); - IterateFrontToBack(&render_surface_layer_list); EXPECT_COUNT(root_layer, 5, -1, 4); EXPECT_COUNT(first, -1, -1, 3); @@ -188,17 +159,6 @@ TEST(LayerIteratorTest, ComplexTree) { root_layer.get(), root_layer->bounds(), &render_surface_layer_list); LayerTreeHostCommon::CalculateDrawProperties(&inputs); - IterateBackToFront(&render_surface_layer_list); - EXPECT_COUNT(root_layer, 0, -1, 1); - EXPECT_COUNT(root1, -1, -1, 2); - EXPECT_COUNT(root2, -1, -1, 3); - EXPECT_COUNT(root21, -1, -1, 4); - EXPECT_COUNT(root22, -1, -1, 5); - EXPECT_COUNT(root221, -1, -1, 6); - EXPECT_COUNT(root23, -1, -1, 7); - EXPECT_COUNT(root231, -1, -1, 8); - EXPECT_COUNT(root3, -1, -1, 9); - IterateFrontToBack(&render_surface_layer_list); EXPECT_COUNT(root_layer, 9, -1, 8); EXPECT_COUNT(root1, -1, -1, 7); @@ -244,17 +204,6 @@ TEST(LayerIteratorTest, ComplexTreeMultiSurface) { root_layer.get(), root_layer->bounds(), &render_surface_layer_list); LayerTreeHostCommon::CalculateDrawProperties(&inputs); - IterateBackToFront(&render_surface_layer_list); - EXPECT_COUNT(root_layer, 0, -1, 1); - EXPECT_COUNT(root1, -1, -1, 2); - EXPECT_COUNT(root2, 4, 3, -1); - EXPECT_COUNT(root21, -1, -1, 5); - EXPECT_COUNT(root22, 7, 6, 8); - EXPECT_COUNT(root221, -1, -1, 9); - EXPECT_COUNT(root23, 11, 10, 12); - EXPECT_COUNT(root231, -1, -1, 13); - EXPECT_COUNT(root3, -1, -1, 14); - IterateFrontToBack(&render_surface_layer_list); EXPECT_COUNT(root_layer, 14, -1, 13); EXPECT_COUNT(root1, -1, -1, 12); diff --git a/chromium/cc/layers/layer_lists.cc b/chromium/cc/layers/layer_lists.cc index 89cd4985701..fda1a1cf9f8 100644 --- a/chromium/cc/layers/layer_lists.cc +++ b/chromium/cc/layers/layer_lists.cc @@ -35,6 +35,13 @@ size_t RenderSurfaceLayerList::size() const { return list_.size(); } +scoped_refptr<Layer>& RenderSurfaceLayerList::operator[](size_t i) { + return list_[i]; +} +const scoped_refptr<Layer>& RenderSurfaceLayerList::operator[](size_t i) const { + return list_[i]; +} + LayerList::iterator RenderSurfaceLayerList::begin() { return list_.begin(); } diff --git a/chromium/cc/layers/layer_lists.h b/chromium/cc/layers/layer_lists.h index 24a9c3c14d6..01a7966888f 100644 --- a/chromium/cc/layers/layer_lists.h +++ b/chromium/cc/layers/layer_lists.h @@ -31,6 +31,8 @@ class CC_EXPORT RenderSurfaceLayerList { Layer* back(); size_t size() const; bool empty() const { return size() == 0u; } + scoped_refptr<Layer>& operator[](size_t i); + const scoped_refptr<Layer>& operator[](size_t i) const; LayerList::iterator begin(); LayerList::iterator end(); LayerList::const_iterator begin() const; diff --git a/chromium/cc/layers/layer_perftest.cc b/chromium/cc/layers/layer_perftest.cc new file mode 100644 index 00000000000..5a2de60d203 --- /dev/null +++ b/chromium/cc/layers/layer_perftest.cc @@ -0,0 +1,120 @@ +// Copyright 2013 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 "cc/layers/layer.h" + +#include "cc/resources/layer_painter.h" +#include "cc/test/fake_impl_proxy.h" +#include "cc/test/fake_layer_tree_host.h" +#include "cc/test/fake_layer_tree_host_client.h" +#include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/lap_timer.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/perf/perf_test.h" + +namespace cc { +namespace { + +static const int kTimeLimitMillis = 3000; +static const int kWarmupRuns = 5; +static const int kTimeCheckInterval = 10; + +class MockLayerPainter : public LayerPainter { + public: + virtual void Paint(SkCanvas* canvas, + gfx::Rect content_rect, + gfx::RectF* opaque) OVERRIDE {} +}; + + +class LayerPerfTest : public testing::Test { + public: + LayerPerfTest() + : host_impl_(&proxy_), + fake_client_(FakeLayerTreeHostClient::DIRECT_3D), + timer_(kWarmupRuns, + base::TimeDelta::FromMilliseconds(kTimeLimitMillis), + kTimeCheckInterval) {} + + protected: + virtual void SetUp() OVERRIDE { + layer_tree_host_ = FakeLayerTreeHost::Create(); + layer_tree_host_->InitializeSingleThreaded(&fake_client_); + } + + virtual void TearDown() OVERRIDE { + layer_tree_host_->SetRootLayer(NULL); + layer_tree_host_.reset(); + } + + FakeImplProxy proxy_; + FakeLayerTreeHostImpl host_impl_; + + FakeLayerTreeHostClient fake_client_; + scoped_ptr<FakeLayerTreeHost> layer_tree_host_; + LapTimer timer_; +}; + +TEST_F(LayerPerfTest, PushPropertiesTo) { + scoped_refptr<Layer> test_layer = Layer::Create(); + scoped_ptr<LayerImpl> impl_layer = + LayerImpl::Create(host_impl_.active_tree(), 1); + + layer_tree_host_->SetRootLayer(test_layer); + + float anchor_point_z = 0; + bool scrollable = true; + bool contents_opaque = true; + bool double_sided = true; + bool hide_layer_and_subtree = true; + bool masks_to_bounds = true; + + // Properties changed. + timer_.Reset(); + do { + test_layer->SetNeedsDisplayRect(gfx::RectF(0.f, 0.f, 5.f, 5.f)); + test_layer->SetAnchorPointZ(anchor_point_z); + test_layer->SetContentsOpaque(contents_opaque); + test_layer->SetDoubleSided(double_sided); + test_layer->SetHideLayerAndSubtree(hide_layer_and_subtree); + test_layer->SetMasksToBounds(masks_to_bounds); + test_layer->SetScrollable(scrollable); + test_layer->PushPropertiesTo(impl_layer.get()); + + anchor_point_z += 0.01f; + scrollable = !scrollable; + contents_opaque = !contents_opaque; + double_sided = !double_sided; + hide_layer_and_subtree = !hide_layer_and_subtree; + masks_to_bounds = !masks_to_bounds; + + timer_.NextLap(); + } while (!timer_.HasTimeLimitExpired()); + + perf_test::PrintResult("push_properties_to", + "", + "props_changed", + timer_.LapsPerSecond(), + "runs/s", + true); + + // Properties didn't change. + timer_.Reset(); + do { + test_layer->PushPropertiesTo(impl_layer.get()); + timer_.NextLap(); + } while (!timer_.HasTimeLimitExpired()); + + perf_test::PrintResult("push_properties_to", + "", + "props_didnt_change", + timer_.LapsPerSecond(), + "runs/s", + true); +} + + +} // namespace +} // namespace cc diff --git a/chromium/cc/layers/layer_position_constraint_unittest.cc b/chromium/cc/layers/layer_position_constraint_unittest.cc index 6384ba45327..8f6dcb11798 100644 --- a/chromium/cc/layers/layer_position_constraint_unittest.cc +++ b/chromium/cc/layers/layer_position_constraint_unittest.cc @@ -1094,5 +1094,120 @@ TEST_F(LayerPositionConstraintTest, grand_child->draw_transform()); } +TEST_F(LayerPositionConstraintTest, + ScrollCompensationForFixedWithinFixedWithSameContainer) { + // This test checks scroll compensation for a fixed-position layer that is + // inside of another fixed-position layer and both share the same container. + // In this situation, the parent fixed-position layer will receive + // the scroll compensation, and the child fixed-position layer does not + // need to compensate further. + + LayerImpl* child = root_->children()[0]; + LayerImpl* grand_child = child->children()[0]; + LayerImpl* great_grand_child = grand_child->children()[0]; + + child->SetIsContainerForFixedPositionLayers(true); + grand_child->SetPositionConstraint(fixed_to_top_left_); + + // Note carefully - great_grand_child is fixed to bottom right, to test + // sizeDelta being applied correctly; the compensation skips the grand_child + // because it is fixed to top left. + great_grand_child->SetPositionConstraint(fixed_to_bottom_right_); + + // Case 1: scrollDelta + child->SetScrollDelta(gfx::Vector2d(10, 10)); + ExecuteCalculateDrawProperties(root_.get()); + + // Here the child is affected by scroll delta, but the fixed position + // grand_child should not be affected. + gfx::Transform expected_child_transform; + expected_child_transform.Translate(-10.0, -10.0); + + gfx::Transform expected_grand_child_transform; + gfx::Transform expected_great_grand_child_transform; + + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform, + child->draw_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform, + grand_child->draw_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_transform, + great_grand_child->draw_transform()); + + // Case 2: sizeDelta + child->SetScrollDelta(gfx::Vector2d(0, 0)); + child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20)); + ExecuteCalculateDrawProperties(root_.get()); + + expected_child_transform.MakeIdentity(); + + expected_grand_child_transform.MakeIdentity(); + + // Fixed to bottom-right, size-delta compensation is applied. + expected_great_grand_child_transform.MakeIdentity(); + expected_great_grand_child_transform.Translate(20.0, 20.0); + + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform, + child->draw_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform, + grand_child->draw_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_transform, + great_grand_child->draw_transform()); +} + +TEST_F(LayerPositionConstraintTest, + ScrollCompensationForFixedWithinFixedWithInterveningContainer) { + // This test checks scroll compensation for a fixed-position layer that is + // inside of another fixed-position layer, but they have different fixed + // position containers. In this situation, the child fixed-position element + // would still have to compensate with respect to its container. + + LayerImpl* container1 = root_->children()[0]; + LayerImpl* fixed_to_container1 = container1->children()[0]; + LayerImpl* container2 = fixed_to_container1->children()[0]; + + { + // Add one more layer to the hierarchy for this test. + scoped_ptr<LayerImpl> fixed_to_container2_ptr = + LayerImpl::Create(host_impl_.active_tree(), 5); + container2->AddChild(fixed_to_container2_ptr.Pass()); + } + + LayerImpl* fixed_to_container2 = container2->children()[0]; + + container1->SetIsContainerForFixedPositionLayers(true); + fixed_to_container1->SetPositionConstraint(fixed_to_top_left_); + container2->SetIsContainerForFixedPositionLayers(true); + fixed_to_container2->SetPositionConstraint(fixed_to_top_left_); + + container1->SetScrollDelta(gfx::Vector2d(0, 15)); + container2->SetScrollDelta(gfx::Vector2d(30, 0)); + ExecuteCalculateDrawProperties(root_.get()); + + gfx::Transform expected_container1_transform; + expected_container1_transform.Translate(0.0, -15.0); + + gfx::Transform expected_fixed_to_container1_transform; + + // Since the container is a descendant of the fixed layer above, + // the expected draw transform for container2 would not + // include the scrollDelta that was applied to container1. + gfx::Transform expected_container2_transform; + expected_container2_transform.Translate(-30.0, 0.0); + + gfx::Transform expected_fixed_to_container2_transform; + + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_container1_transform, + container1->draw_transform()); + + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_fixed_to_container1_transform, + fixed_to_container1->draw_transform()); + + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_container2_transform, + container2->draw_transform()); + + EXPECT_TRANSFORMATION_MATRIX_EQ(expected_fixed_to_container2_transform, + fixed_to_container2->draw_transform()); +} + } // namespace } // namespace cc diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc index c5c5286d2aa..a77a5fb8819 100644 --- a/chromium/cc/layers/layer_unittest.cc +++ b/chromium/cc/layers/layer_unittest.cc @@ -38,9 +38,9 @@ namespace { class MockLayerTreeHost : public LayerTreeHost { public: - explicit MockLayerTreeHost(LayerTreeHostClient* client) - : LayerTreeHost(client, LayerTreeSettings()) { - Initialize(NULL); + explicit MockLayerTreeHost(FakeLayerTreeHostClient* client) + : LayerTreeHost(client, NULL, LayerTreeSettings()) { + InitializeSingleThreaded(client); } MOCK_METHOD0(SetNeedsCommit, void()); @@ -545,11 +545,14 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) { EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBackgroundColor(SK_ColorLTGRAY)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetMasksToBounds(true)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f)); + EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendMode(SkXfermode::kHue_Mode)); + EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsRootForIsolatedGroup(true)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetContentsOpaque(true)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetPosition(gfx::PointF(4.f, 9.f))); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetSublayerTransform( gfx::Transform(0.0, 0.0, 0.0, 0.0, 0.0, 0.0))); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollable(true)); + EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUserScrollable(true, false)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollOffset( gfx::Vector2d(10, 10))); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetShouldScrollOnMainThread(true)); @@ -607,7 +610,7 @@ TEST_F(LayerTest, PushPropertiesAccumulatesUpdateRect) { impl_layer->update_rect()); } -TEST_F(LayerTest, PushPropertiesCausesSurfacePropertyChangedForTransform) { +TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForTransform) { scoped_refptr<Layer> test_layer = Layer::Create(); scoped_ptr<LayerImpl> impl_layer = LayerImpl::Create(host_impl_.active_tree(), 1); @@ -619,14 +622,14 @@ TEST_F(LayerTest, PushPropertiesCausesSurfacePropertyChangedForTransform) { transform.Rotate(45.0); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(transform)); - EXPECT_FALSE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); test_layer->PushPropertiesTo(impl_layer.get()); - EXPECT_TRUE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_TRUE(impl_layer->LayerPropertyChanged()); } -TEST_F(LayerTest, PushPropertiesCausesSurfacePropertyChangedForOpacity) { +TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForOpacity) { scoped_refptr<Layer> test_layer = Layer::Create(); scoped_ptr<LayerImpl> impl_layer = LayerImpl::Create(host_impl_.active_tree(), 1); @@ -636,15 +639,15 @@ TEST_F(LayerTest, PushPropertiesCausesSurfacePropertyChangedForOpacity) { EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f)); - EXPECT_FALSE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); test_layer->PushPropertiesTo(impl_layer.get()); - EXPECT_TRUE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_TRUE(impl_layer->LayerPropertyChanged()); } TEST_F(LayerTest, - PushPropsDoesntCauseSurfacePropertyChangedDuringImplOnlyTransformAnim) { + PushPropsDoesntCauseLayerPropertyChangedDuringImplOnlyTransformAnim) { scoped_refptr<Layer> test_layer = Layer::Create(); scoped_ptr<LayerImpl> impl_layer = LayerImpl::Create(host_impl_.active_tree(), 1); @@ -665,9 +668,9 @@ TEST_F(LayerTest, transform.Rotate(45.0); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(transform)); - EXPECT_FALSE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); test_layer->PushPropertiesTo(impl_layer.get()); - EXPECT_TRUE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_TRUE(impl_layer->LayerPropertyChanged()); impl_layer->ResetAllChangeTrackingForSubtree(); AddAnimatedTransformToController(impl_layer->layer_animation_controller(), @@ -679,13 +682,13 @@ TEST_F(LayerTest, transform.Rotate(45.0); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(transform)); - EXPECT_FALSE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); test_layer->PushPropertiesTo(impl_layer.get()); - EXPECT_FALSE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); } TEST_F(LayerTest, - PushPropsDoesntCauseSurfacePropertyChangedDuringImplOnlyOpacityAnim) { + PushPropsDoesntCauseLayerPropertyChangedDuringImplOnlyOpacityAnim) { scoped_refptr<Layer> test_layer = Layer::Create(); scoped_ptr<LayerImpl> impl_layer = LayerImpl::Create(host_impl_.active_tree(), 1); @@ -705,9 +708,9 @@ TEST_F(LayerTest, EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f)); - EXPECT_FALSE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); test_layer->PushPropertiesTo(impl_layer.get()); - EXPECT_TRUE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_TRUE(impl_layer->LayerPropertyChanged()); impl_layer->ResetAllChangeTrackingForSubtree(); AddOpacityTransitionToController(impl_layer->layer_animation_controller(), @@ -719,11 +722,47 @@ TEST_F(LayerTest, set_is_impl_only(true); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.75f)); - EXPECT_FALSE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); test_layer->PushPropertiesTo(impl_layer.get()); - EXPECT_FALSE(impl_layer->LayerSurfacePropertyChanged()); + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); } +TEST_F(LayerTest, + PushPropsDoesntCauseLayerPropertyChangedDuringImplOnlyFilterAnim) { + scoped_refptr<Layer> test_layer = Layer::Create(); + scoped_ptr<LayerImpl> impl_layer = + LayerImpl::Create(host_impl_.active_tree(), 1); + + EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, + layer_tree_host_->SetRootLayer(test_layer)); + + scoped_ptr<AnimationRegistrar> registrar = AnimationRegistrar::Create(); + impl_layer->layer_animation_controller()->SetAnimationRegistrar( + registrar.get()); + + AddAnimatedFilterToController( + impl_layer->layer_animation_controller(), 1.0, 1.f, 2.f); + + FilterOperations filters; + filters.Append(FilterOperation::CreateBlurFilter(2.f)); + EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetFilters(filters)); + + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); + test_layer->PushPropertiesTo(impl_layer.get()); + EXPECT_TRUE(impl_layer->LayerPropertyChanged()); + + impl_layer->ResetAllChangeTrackingForSubtree(); + AddAnimatedFilterToController( + impl_layer->layer_animation_controller(), 1.0, 1.f, 2.f); + impl_layer->layer_animation_controller()->GetAnimation(Animation::Filter)-> + set_is_impl_only(true); + filters.Append(FilterOperation::CreateSepiaFilter(0.5f)); + EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetFilters(filters)); + + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); + test_layer->PushPropertiesTo(impl_layer.get()); + EXPECT_FALSE(impl_layer->LayerPropertyChanged()); +} TEST_F(LayerTest, MaskAndReplicaHasParent) { scoped_refptr<Layer> parent = Layer::Create(); @@ -766,11 +805,17 @@ class LayerTreeHostFactory { : client_(FakeLayerTreeHostClient::DIRECT_3D) {} scoped_ptr<LayerTreeHost> Create() { - return LayerTreeHost::Create(&client_, LayerTreeSettings(), NULL).Pass(); + return LayerTreeHost::CreateSingleThreaded(&client_, + &client_, + NULL, + LayerTreeSettings()).Pass(); } scoped_ptr<LayerTreeHost> Create(LayerTreeSettings settings) { - return LayerTreeHost::Create(&client_, settings, NULL).Pass(); + return LayerTreeHost::CreateSingleThreaded(&client_, + &client_, + NULL, + settings).Pass(); } private: diff --git a/chromium/cc/layers/nine_patch_layer.cc b/chromium/cc/layers/nine_patch_layer.cc index 5e000072f28..f6761318cd8 100644 --- a/chromium/cc/layers/nine_patch_layer.cc +++ b/chromium/cc/layers/nine_patch_layer.cc @@ -14,44 +14,6 @@ namespace cc { - -namespace { - -class ScopedUIResourceHolder : public NinePatchLayer::UIResourceHolder { - public: - static scoped_ptr<ScopedUIResourceHolder> Create(LayerTreeHost* host, - const SkBitmap& skbitmap) { - return make_scoped_ptr(new ScopedUIResourceHolder(host, skbitmap)); - } - virtual UIResourceId id() OVERRIDE { return resource_->id(); } - - private: - ScopedUIResourceHolder(LayerTreeHost* host, const SkBitmap& skbitmap) { - resource_ = ScopedUIResource::Create(host, UIResourceBitmap(skbitmap)); - } - - scoped_ptr<ScopedUIResource> resource_; -}; - -class SharedUIResourceHolder : public NinePatchLayer::UIResourceHolder { - public: - static scoped_ptr<SharedUIResourceHolder> Create(UIResourceId id) { - return make_scoped_ptr(new SharedUIResourceHolder(id)); - } - - virtual UIResourceId id() OVERRIDE { return id_; } - - private: - explicit SharedUIResourceHolder(UIResourceId id) : id_(id) {} - - UIResourceId id_; -}; - -} // anonymous namespace - - -NinePatchLayer::UIResourceHolder::~UIResourceHolder() {} - scoped_refptr<NinePatchLayer> NinePatchLayer::Create() { return make_scoped_refptr(new NinePatchLayer()); } @@ -65,25 +27,6 @@ scoped_ptr<LayerImpl> NinePatchLayer::CreateLayerImpl( return NinePatchLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); } -void NinePatchLayer::SetLayerTreeHost(LayerTreeHost* host) { - if (host == layer_tree_host()) - return; - - Layer::SetLayerTreeHost(host); - - // Recreate the resource hold against the new LTH. - RecreateUIResourceHolder(); -} - -void NinePatchLayer::RecreateUIResourceHolder() { - ui_resource_holder_.reset(); - if (!layer_tree_host() || bitmap_.empty()) - return; - - ui_resource_holder_ = - ScopedUIResourceHolder::Create(layer_tree_host(), bitmap_); -} - void NinePatchLayer::SetBorder(gfx::Rect border) { if (border == border_) return; @@ -91,34 +34,11 @@ void NinePatchLayer::SetBorder(gfx::Rect border) { SetNeedsCommit(); } -void NinePatchLayer::SetBitmap(const SkBitmap& skbitmap, gfx::Rect aperture) { - image_aperture_ = aperture; - bitmap_ = skbitmap; - - // TODO(ccameron): Remove this. This provides the default border that was - // provided before borders were required to be explicitly provided. Once Blink - // fixes its callers to call SetBorder, this can be removed. - SetBorder(gfx::Rect(aperture.x(), - aperture.y(), - skbitmap.width() - aperture.width(), - skbitmap.height() - aperture.height())); - RecreateUIResourceHolder(); - SetNeedsCommit(); -} - -void NinePatchLayer::SetUIResourceId(UIResourceId resource_id, - gfx::Rect aperture) { - if (ui_resource_holder_ && ui_resource_holder_->id() == resource_id && - image_aperture_ == aperture) +void NinePatchLayer::SetAperture(gfx::Rect aperture) { + if (image_aperture_ == aperture) return; image_aperture_ = aperture; - if (resource_id) { - ui_resource_holder_ = SharedUIResourceHolder::Create(resource_id); - } else { - ui_resource_holder_.reset(); - } - SetNeedsCommit(); } @@ -130,13 +50,8 @@ void NinePatchLayer::SetFillCenter(bool fill_center) { SetNeedsCommit(); } -bool NinePatchLayer::DrawsContent() const { - return ui_resource_holder_ && ui_resource_holder_->id() && - Layer::DrawsContent(); -} - void NinePatchLayer::PushPropertiesTo(LayerImpl* layer) { - Layer::PushPropertiesTo(layer); + UIResourceLayer::PushPropertiesTo(layer); NinePatchLayerImpl* layer_impl = static_cast<NinePatchLayerImpl*>(layer); if (!ui_resource_holder_) { @@ -144,10 +59,7 @@ void NinePatchLayer::PushPropertiesTo(LayerImpl* layer) { } else { DCHECK(layer_tree_host()); - gfx::Size image_size = - layer_tree_host()->GetUIResourceSize(ui_resource_holder_->id()); - layer_impl->SetUIResourceId(ui_resource_holder_->id()); - layer_impl->SetLayout(image_size, image_aperture_, border_, fill_center_); + layer_impl->SetLayout(image_aperture_, border_, fill_center_); } } diff --git a/chromium/cc/layers/nine_patch_layer.h b/chromium/cc/layers/nine_patch_layer.h index 5880635389a..dc9f81f6e18 100644 --- a/chromium/cc/layers/nine_patch_layer.h +++ b/chromium/cc/layers/nine_patch_layer.h @@ -8,6 +8,7 @@ #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" #include "cc/layers/layer.h" +#include "cc/layers/ui_resource_layer.h" #include "cc/resources/ui_resource_client.h" #include "ui/gfx/rect.h" @@ -16,16 +17,12 @@ namespace cc { class LayerTreeHost; class ScopedUIResource; -class CC_EXPORT NinePatchLayer : public Layer { +class CC_EXPORT NinePatchLayer : public UIResourceLayer { public: static scoped_refptr<NinePatchLayer> Create(); - virtual bool DrawsContent() const OVERRIDE; - virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; - virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE; - // |border| is the space around the center rectangular region in layer space // (known as aperture in image space). |border.x()| and |border.y()| are the // size of the left and top boundary, respectively. @@ -39,29 +36,17 @@ class CC_EXPORT NinePatchLayer : public Layer { // on the edges of the layer. The corners are unscaled, the top and bottom // rects are x-stretched to fit, and the left and right rects are // y-stretched to fit. - void SetBitmap(const SkBitmap& skbitmap, gfx::Rect aperture); - - // An alternative way of setting the resource to allow for sharing. - void SetUIResourceId(UIResourceId resource_id, gfx::Rect aperture); + void SetAperture(gfx::Rect aperture); void SetFillCenter(bool fill_center); - class UIResourceHolder { - public: - virtual UIResourceId id() = 0; - virtual ~UIResourceHolder(); - }; - private: NinePatchLayer(); virtual ~NinePatchLayer(); virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) OVERRIDE; - void RecreateUIResourceHolder(); gfx::Rect border_; bool fill_center_; - scoped_ptr<UIResourceHolder> ui_resource_holder_; - SkBitmap bitmap_; // The transparent center region that shows the parent layer's contents in // image space. diff --git a/chromium/cc/layers/nine_patch_layer_impl.cc b/chromium/cc/layers/nine_patch_layer_impl.cc index f609c3d2fda..2987179ae2e 100644 --- a/chromium/cc/layers/nine_patch_layer_impl.cc +++ b/chromium/cc/layers/nine_patch_layer_impl.cc @@ -15,27 +15,21 @@ namespace cc { NinePatchLayerImpl::NinePatchLayerImpl(LayerTreeImpl* tree_impl, int id) - : LayerImpl(tree_impl, id), - fill_center_(false), - ui_resource_id_(0) {} + : UIResourceLayerImpl(tree_impl, id), + fill_center_(false) {} NinePatchLayerImpl::~NinePatchLayerImpl() {} -ResourceProvider::ResourceId NinePatchLayerImpl::ContentsResourceId() const { - return 0; -} - scoped_ptr<LayerImpl> NinePatchLayerImpl::CreateLayerImpl( LayerTreeImpl* tree_impl) { return NinePatchLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); } void NinePatchLayerImpl::PushPropertiesTo(LayerImpl* layer) { - LayerImpl::PushPropertiesTo(layer); + UIResourceLayerImpl::PushPropertiesTo(layer); NinePatchLayerImpl* layer_impl = static_cast<NinePatchLayerImpl*>(layer); - layer_impl->SetUIResourceId(ui_resource_id_); - layer_impl->SetLayout(image_bounds_, image_aperture_, border_, fill_center_); + layer_impl->SetLayout(image_aperture_, border_, fill_center_); } static gfx::RectF NormalizedRect(float x, @@ -50,70 +44,57 @@ static gfx::RectF NormalizedRect(float x, height / total_height); } -void NinePatchLayerImpl::SetUIResourceId(UIResourceId uid) { - if (uid == ui_resource_id_) - return; - ui_resource_id_ = uid; - NoteLayerPropertyChanged(); -} - -void NinePatchLayerImpl::SetLayout(gfx::Size image_bounds, - gfx::Rect aperture, +void NinePatchLayerImpl::SetLayout(gfx::Rect aperture, gfx::Rect border, bool fill_center) { // This check imposes an ordering on the call sequence. An UIResource must // exist before SetLayout can be called. DCHECK(ui_resource_id_); + if (image_aperture_ == aperture && + border_ == border && fill_center_ == fill_center) + return; + + image_aperture_ = aperture; + border_ = border; + fill_center_ = fill_center; + + NoteLayerPropertyChanged(); +} + +void NinePatchLayerImpl::CheckGeometryLimitations() { // TODO(ccameron): the following "greater than or equal to" (GE) checks should // be greater than (GT) to avoid degenerate nine-patches. The relaxed // condition "equal to" is a workaround for the overhang shadow use case and // should be investigated further. // |border| is in layer space. It cannot exceed the bounds of the layer. - DCHECK(!border.size().IsEmpty()); - DCHECK_GE(bounds().width(), border.width()); - DCHECK_GE(bounds().height(), border.height()); + DCHECK(!border_.size().IsEmpty()); + DCHECK_GE(bounds().width(), border_.width()); + DCHECK_GE(bounds().height(), border_.height()); // Sanity Check on |border| - DCHECK_LT(border.x(), border.width()); - DCHECK_LT(border.y(), border.height()); - DCHECK_GE(border.x(), 0); - DCHECK_GE(border.y(), 0); + DCHECK_LT(border_.x(), border_.width()); + DCHECK_LT(border_.y(), border_.height()); + DCHECK_GE(border_.x(), 0); + DCHECK_GE(border_.y(), 0); // |aperture| is in image space. It cannot exceed the bounds of the bitmap. - DCHECK(!aperture.size().IsEmpty()); - DCHECK(gfx::Rect(image_bounds.width(), image_bounds.height()) - .Contains(aperture)); + DCHECK(!image_aperture_.size().IsEmpty()); + DCHECK(gfx::Rect(image_bounds_.width(), image_bounds_.height()) + .Contains(image_aperture_)); // Avoid the degenerate cases where the aperture touches the edge of the // image. - DCHECK_LT(aperture.width(), image_bounds.width() - 1); - DCHECK_LT(aperture.height(), image_bounds.height() - 1); - DCHECK_GT(aperture.x(), 0); - DCHECK_GT(aperture.y(), 0); - - if (image_bounds_ == image_bounds && image_aperture_ == aperture && - border_ == border && fill_center_ == fill_center) - return; - - image_bounds_ = image_bounds; - image_aperture_ = aperture; - border_ = border; - fill_center_ = fill_center; - - NoteLayerPropertyChanged(); -} - -bool NinePatchLayerImpl::WillDraw(DrawMode draw_mode, - ResourceProvider* resource_provider) { - if (!ui_resource_id_ || draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) - return false; - return LayerImpl::WillDraw(draw_mode, resource_provider); + DCHECK_LT(image_aperture_.width(), image_bounds_.width() - 1); + DCHECK_LT(image_aperture_.height(), image_bounds_.height() - 1); + DCHECK_GT(image_aperture_.x(), 0); + DCHECK_GT(image_aperture_.y(), 0); } void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink, AppendQuadsData* append_quads_data) { + CheckGeometryLimitations(); SharedQuadState* shared_quad_state = quad_sink->UseSharedQuadState(CreateSharedQuadState()); AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data); @@ -373,7 +354,11 @@ base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const { list->AppendInteger(image_aperture_.size().height()); result->Set("ImageAperture", list); - result->Set("ImageBounds", MathUtil::AsValue(image_bounds_).release()); + list = new base::ListValue; + list->AppendInteger(image_bounds_.width()); + list->AppendInteger(image_bounds_.height()); + result->Set("ImageBounds", list); + result->Set("Border", MathUtil::AsValue(border_).release()); base::FundamentalValue* fill_center = diff --git a/chromium/cc/layers/nine_patch_layer_impl.h b/chromium/cc/layers/nine_patch_layer_impl.h index ba414aed391..d85e40f3049 100644 --- a/chromium/cc/layers/nine_patch_layer_impl.h +++ b/chromium/cc/layers/nine_patch_layer_impl.h @@ -9,6 +9,7 @@ #include "cc/base/cc_export.h" #include "cc/layers/layer_impl.h" +#include "cc/layers/ui_resource_layer_impl.h" #include "cc/resources/resource_provider.h" #include "cc/resources/ui_resource_client.h" #include "ui/gfx/rect.h" @@ -20,7 +21,7 @@ class DictionaryValue; namespace cc { -class CC_EXPORT NinePatchLayerImpl : public LayerImpl { +class CC_EXPORT NinePatchLayerImpl : public UIResourceLayerImpl { public: static scoped_ptr<NinePatchLayerImpl> Create(LayerTreeImpl* tree_impl, int id) { @@ -28,9 +29,6 @@ class CC_EXPORT NinePatchLayerImpl : public LayerImpl { } virtual ~NinePatchLayerImpl(); - - void SetUIResourceId(UIResourceId uid); - // The bitmap stretches out the bounds of the layer. The following picture // illustrates the parameters associated with the dimensions. // @@ -55,8 +53,7 @@ class CC_EXPORT NinePatchLayerImpl : public LayerImpl { // |image_aperture| = (X, Y, P, Q) // |border| = (A, C, A + B, C + D) // |fill_center| indicates whether to draw the center quad or not. - void SetLayout(gfx::Size image_bounds, - gfx::Rect image_aperture, + void SetLayout(gfx::Rect image_aperture, gfx::Rect border, bool fill_center); @@ -64,11 +61,8 @@ class CC_EXPORT NinePatchLayerImpl : public LayerImpl { OVERRIDE; virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; - virtual bool WillDraw(DrawMode draw_mode, - ResourceProvider* resource_provider) OVERRIDE; virtual void AppendQuads(QuadSink* quad_sink, AppendQuadsData* append_quads_data) OVERRIDE; - virtual ResourceProvider::ResourceId ContentsResourceId() const OVERRIDE; virtual base::DictionaryValue* LayerTreeAsJson() const OVERRIDE; @@ -78,8 +72,7 @@ class CC_EXPORT NinePatchLayerImpl : public LayerImpl { private: virtual const char* LayerTypeAsString() const OVERRIDE; - // The size of the NinePatch bitmap in pixels. - gfx::Size image_bounds_; + void CheckGeometryLimitations(); // The transparent center region that shows the parent layer's contents in // image space. @@ -90,8 +83,6 @@ class CC_EXPORT NinePatchLayerImpl : public LayerImpl { bool fill_center_; - UIResourceId ui_resource_id_; - DISALLOW_COPY_AND_ASSIGN(NinePatchLayerImpl); }; diff --git a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc index 0fbc645be1b..60201110a25 100644 --- a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc +++ b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc @@ -9,7 +9,7 @@ #include "cc/resources/ui_resource_bitmap.h" #include "cc/resources/ui_resource_client.h" #include "cc/test/fake_impl_proxy.h" -#include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/fake_ui_resource_layer_tree_host_impl.h" #include "cc/test/geometry_test_utils.h" #include "cc/test/layer_test_common.h" #include "cc/test/mock_quad_culler.h" @@ -23,40 +23,6 @@ namespace cc { namespace { -class FakeUIResourceLayerTreeHostImpl : public FakeLayerTreeHostImpl { - public: - explicit FakeUIResourceLayerTreeHostImpl(Proxy* proxy) - : FakeLayerTreeHostImpl(proxy), fake_next_resource_id_(1) {} - - virtual void CreateUIResource( - UIResourceId uid, - const UIResourceBitmap& bitmap) OVERRIDE { - if (ResourceIdForUIResource(uid)) - DeleteUIResource(uid); - fake_ui_resource_map_[uid] = fake_next_resource_id_; - } - - virtual void DeleteUIResource(UIResourceId uid) OVERRIDE { - ResourceProvider::ResourceId id = ResourceIdForUIResource(uid); - if (id) - fake_ui_resource_map_.erase(uid); - } - - virtual ResourceProvider::ResourceId ResourceIdForUIResource( - UIResourceId uid) const OVERRIDE { - UIResourceMap::const_iterator iter = fake_ui_resource_map_.find(uid); - if (iter != fake_ui_resource_map_.end()) - return iter->second; - return 0; - } - - private: - ResourceProvider::ResourceId fake_next_resource_id_; - typedef base::hash_map<UIResourceId, ResourceProvider::ResourceId> - UIResourceMap; - UIResourceMap fake_ui_resource_map_; -}; - gfx::Rect ToRoundedIntRect(gfx::RectF rect_f) { return gfx::Rect(gfx::ToRoundedInt(rect_f.x()), gfx::ToRoundedInt(rect_f.y()), @@ -97,8 +63,8 @@ void NinePatchLayerLayoutTest(gfx::Size bitmap_size, host_impl.CreateUIResource(uid, bitmap); layer->SetUIResourceId(uid); - - layer->SetLayout(bitmap_size, aperture_rect, border, fill_center); + layer->SetImageBounds(bitmap_size); + layer->SetLayout(aperture_rect, border, fill_center); AppendQuadsData data; layer->AppendQuads(&quad_culler, &data); diff --git a/chromium/cc/layers/nine_patch_layer_unittest.cc b/chromium/cc/layers/nine_patch_layer_unittest.cc index 101146c0077..41da351088e 100644 --- a/chromium/cc/layers/nine_patch_layer_unittest.cc +++ b/chromium/cc/layers/nine_patch_layer_unittest.cc @@ -10,6 +10,7 @@ #include "cc/resources/resource_update_queue.h" #include "cc/resources/scoped_ui_resource.h" #include "cc/scheduler/texture_uploader.h" +#include "cc/test/fake_layer_tree_host.h" #include "cc/test/fake_layer_tree_host_client.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" @@ -29,34 +30,24 @@ using ::testing::AnyNumber; namespace cc { namespace { -class MockLayerTreeHost : public LayerTreeHost { - public: - explicit MockLayerTreeHost(LayerTreeHostClient* client) - : LayerTreeHost(client, LayerTreeSettings()) { - Initialize(NULL); - } -}; - class NinePatchLayerTest : public testing::Test { public: NinePatchLayerTest() : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {} - cc::Proxy* Proxy() const { return layer_tree_host_->proxy(); } - protected: virtual void SetUp() { - layer_tree_host_.reset(new MockLayerTreeHost(&fake_client_)); + layer_tree_host_ = FakeLayerTreeHost::Create(); } virtual void TearDown() { Mock::VerifyAndClearExpectations(layer_tree_host_.get()); } - scoped_ptr<MockLayerTreeHost> layer_tree_host_; + scoped_ptr<FakeLayerTreeHost> layer_tree_host_; FakeLayerTreeHostClient fake_client_; }; -TEST_F(NinePatchLayerTest, SetBitmap) { +TEST_F(NinePatchLayerTest, SetLayerProperties) { scoped_refptr<NinePatchLayer> test_layer = NinePatchLayer::Create(); ASSERT_TRUE(test_layer.get()); test_layer->SetIsDrawable(true); @@ -66,41 +57,6 @@ TEST_F(NinePatchLayerTest, SetBitmap) { Mock::VerifyAndClearExpectations(layer_tree_host_.get()); EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get()); - layer_tree_host_->InitializeOutputSurfaceIfNeeded(); - - ResourceUpdateQueue queue; - OcclusionTracker occlusion_tracker(gfx::Rect(), false); - test_layer->SavePaintProperties(); - test_layer->Update(&queue, &occlusion_tracker); - - EXPECT_FALSE(test_layer->DrawsContent()); - - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10); - bitmap.allocPixels(); - bitmap.setImmutable(); - - gfx::Rect aperture(5, 5, 1, 1); - bool fill_center = false; - test_layer->SetBitmap(bitmap, aperture); - test_layer->SetFillCenter(fill_center); - test_layer->Update(&queue, &occlusion_tracker); - - EXPECT_TRUE(test_layer->DrawsContent()); -} - -TEST_F(NinePatchLayerTest, SetUIResourceId) { - scoped_refptr<NinePatchLayer> test_layer = NinePatchLayer::Create(); - ASSERT_TRUE(test_layer.get()); - test_layer->SetIsDrawable(true); - test_layer->SetBounds(gfx::Size(100, 100)); - - layer_tree_host_->SetRootLayer(test_layer); - Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get()); - - layer_tree_host_->InitializeOutputSurfaceIfNeeded(); - ResourceUpdateQueue queue; OcclusionTracker occlusion_tracker(gfx::Rect(), false); test_layer->SavePaintProperties(); @@ -117,7 +73,8 @@ TEST_F(NinePatchLayerTest, SetUIResourceId) { layer_tree_host_.get(), UIResourceBitmap(bitmap)); gfx::Rect aperture(5, 5, 1, 1); bool fill_center = true; - test_layer->SetUIResourceId(resource->id(), aperture); + test_layer->SetAperture(aperture); + test_layer->SetUIResourceId(resource->id()); test_layer->SetFillCenter(fill_center); test_layer->Update(&queue, &occlusion_tracker); diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc index 4272fe688cc..6bb76368c48 100644 --- a/chromium/cc/layers/painted_scrollbar_layer.cc +++ b/chromium/cc/layers/painted_scrollbar_layer.cc @@ -39,7 +39,9 @@ PaintedScrollbarLayer::PaintedScrollbarLayer( : scrollbar_(scrollbar.Pass()), scroll_layer_id_(scroll_layer_id), thumb_thickness_(scrollbar_->ThumbThickness()), - thumb_length_(scrollbar_->ThumbLength()) { + thumb_length_(scrollbar_->ThumbLength()), + is_overlay_(scrollbar_->IsOverlay()), + has_thumb_(scrollbar_->HasThumb()) { if (!scrollbar_->IsOverlay()) SetShouldScrollOnMainThread(true); } @@ -127,10 +129,7 @@ void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { if (thumb_resource_.get()) scrollbar_layer->set_thumb_ui_resource_id(thumb_resource_->id()); - scrollbar_layer->set_is_overlay_scrollbar(scrollbar_->IsOverlay()); - - // PaintedScrollbarLayer must push properties every frame. crbug.com/259095 - needs_push_properties_ = true; + scrollbar_layer->set_is_overlay_scrollbar(is_overlay_); } ScrollbarLayerInterface* PaintedScrollbarLayer::ToScrollbarLayer() { @@ -174,16 +173,18 @@ gfx::Rect PaintedScrollbarLayer::OriginThumbRect() const { } void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() { - track_rect_ = scrollbar_->TrackRect(); - location_ = scrollbar_->Location(); - if (scrollbar_->HasThumb()) { - thumb_thickness_ = scrollbar_->ThumbThickness(); - thumb_length_ = scrollbar_->ThumbLength(); + UpdateProperty(scrollbar_->TrackRect(), &track_rect_); + UpdateProperty(scrollbar_->Location(), &location_); + UpdateProperty(scrollbar_->IsOverlay(), &is_overlay_); + UpdateProperty(scrollbar_->HasThumb(), &has_thumb_); + if (has_thumb_) { + UpdateProperty(scrollbar_->ThumbThickness(), &thumb_thickness_); + UpdateProperty(scrollbar_->ThumbLength(), &thumb_length_); } } bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue, - const OcclusionTracker* occlusion) { + const OcclusionTracker* occlusion) { UpdateThumbAndTrackGeometry(); gfx::Rect scaled_track_rect = ScrollbarLayerRectToContentRect( @@ -198,15 +199,20 @@ bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue, ContentsScalingLayer::Update(queue, occlusion); } + if (update_rect_.IsEmpty() && track_resource_) + return false; + track_resource_ = ScopedUIResource::Create( layer_tree_host(), RasterizeScrollbarPart(scaled_track_rect, TRACK)); - gfx::Rect thumb_rect = OriginThumbRect(); - if (scrollbar_->HasThumb() && !thumb_rect.IsEmpty()) { + gfx::Rect thumb_rect = OriginThumbRect(); + if (has_thumb_ && !thumb_rect.IsEmpty()) { thumb_resource_ = ScopedUIResource::Create( layer_tree_host(), RasterizeScrollbarPart(thumb_rect, THUMB)); } + // UI resources changed so push properties is needed. + SetNeedsPushProperties(); return true; } diff --git a/chromium/cc/layers/painted_scrollbar_layer.h b/chromium/cc/layers/painted_scrollbar_layer.h index e84377d1e5a..606ad69b905 100644 --- a/chromium/cc/layers/painted_scrollbar_layer.h +++ b/chromium/cc/layers/painted_scrollbar_layer.h @@ -65,6 +65,13 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface, gfx::Rect ScrollbarLayerRectToContentRect(gfx::Rect layer_rect) const; gfx::Rect OriginThumbRect() const; + template<typename T> void UpdateProperty(T value, T* prop) { + if (*prop == value) + return; + *prop = value; + SetNeedsPushProperties(); + } + int MaxTextureSize(); float ClampScaleToMaxTextureSize(float scale); @@ -80,6 +87,8 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface, int thumb_length_; gfx::Point location_; gfx::Rect track_rect_; + bool is_overlay_; + bool has_thumb_; scoped_ptr<ScopedUIResource> track_resource_; scoped_ptr<ScopedUIResource> thumb_resource_; diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc index e38a1a640be..a7fdfa3081d 100644 --- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc +++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc @@ -125,11 +125,6 @@ void PaintedScrollbarLayerImpl::AppendQuads( } } -void PaintedScrollbarLayerImpl::DidLoseOutputSurface() { - track_ui_resource_id_ = 0; - thumb_ui_resource_id_ = 0; -} - void PaintedScrollbarLayerImpl::SetThumbThickness(int thumb_thickness) { if (thumb_thickness_ == thumb_thickness) return; diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.h b/chromium/cc/layers/painted_scrollbar_layer_impl.h index c9d1f3dc0fc..a094416261f 100644 --- a/chromium/cc/layers/painted_scrollbar_layer_impl.h +++ b/chromium/cc/layers/painted_scrollbar_layer_impl.h @@ -33,8 +33,6 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase { virtual void AppendQuads(QuadSink* quad_sink, AppendQuadsData* append_quads_data) OVERRIDE; - virtual void DidLoseOutputSurface() OVERRIDE; - void SetThumbThickness(int thumb_thickness); void SetThumbLength(int thumb_length); void SetTrackStart(int track_start); diff --git a/chromium/cc/layers/picture_image_layer_impl.cc b/chromium/cc/layers/picture_image_layer_impl.cc index 7ae9de41004..b9a57f2b7b0 100644 --- a/chromium/cc/layers/picture_image_layer_impl.cc +++ b/chromium/cc/layers/picture_image_layer_impl.cc @@ -27,6 +27,26 @@ scoped_ptr<LayerImpl> PictureImageLayerImpl::CreateLayerImpl( return PictureImageLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); } +void PictureImageLayerImpl::CalculateContentsScale( + float ideal_contents_scale, + float device_scale_factor, + float page_scale_factor, + bool animating_transform_to_screen, + float* contents_scale_x, + float* contents_scale_y, + gfx::Size* content_bounds) { + // CalculateRasterContentsScale always returns 1.f, so make that the ideal + // scale. + ideal_contents_scale = 1.f; + PictureLayerImpl::CalculateContentsScale(ideal_contents_scale, + device_scale_factor, + page_scale_factor, + animating_transform_to_screen, + contents_scale_x, + contents_scale_y, + content_bounds); +} + void PictureImageLayerImpl::GetDebugBorderProperties( SkColor* color, float* width) const { *color = DebugColors::ImageLayerBorderColor(); @@ -38,15 +58,16 @@ bool PictureImageLayerImpl::ShouldAdjustRasterScale( return false; } -void PictureImageLayerImpl::CalculateRasterContentsScale( - bool animating_transform_to_screen, - float* raster_contents_scale, - float* low_res_raster_contents_scale) const { +void PictureImageLayerImpl::RecalculateRasterScales( + bool animating_transform_to_screen) { + // Defaults from PictureLayerImpl. + PictureLayerImpl::RecalculateRasterScales(animating_transform_to_screen); + // Don't scale images during rastering to ensure image quality, save memory // and avoid frequent re-rastering on change of scale. - *raster_contents_scale = std::max(1.f, MinimumContentsScale()); + raster_contents_scale_ = std::max(1.f, MinimumContentsScale()); // We don't need low res tiles. - *low_res_raster_contents_scale = *raster_contents_scale; + low_res_raster_contents_scale_ = raster_contents_scale_; } } // namespace cc diff --git a/chromium/cc/layers/picture_image_layer_impl.h b/chromium/cc/layers/picture_image_layer_impl.h index 4a2db50f668..0b3b246259d 100644 --- a/chromium/cc/layers/picture_image_layer_impl.h +++ b/chromium/cc/layers/picture_image_layer_impl.h @@ -17,22 +17,29 @@ class CC_EXPORT PictureImageLayerImpl : public PictureLayerImpl { } virtual ~PictureImageLayerImpl(); + // LayerImpl overrides. virtual const char* LayerTypeAsString() const OVERRIDE; virtual scoped_ptr<LayerImpl> CreateLayerImpl( LayerTreeImpl* tree_impl) OVERRIDE; + virtual void CalculateContentsScale(float ideal_contents_scale, + float device_scale_factor, + float page_scale_factor, + bool animating_transform_to_screen, + float* contents_scale_x, + float* contents_scale_y, + gfx::Size* content_bounds) OVERRIDE; protected: PictureImageLayerImpl(LayerTreeImpl* tree_impl, int id); virtual bool ShouldAdjustRasterScale( bool animating_transform_to_screen) const OVERRIDE; - virtual void CalculateRasterContentsScale( - bool animating_transform_to_screen, - float* raster_contents_scale, - float* low_res_raster_contents_scale) const OVERRIDE; + virtual void RecalculateRasterScales( + bool animating_transform_to_screen) OVERRIDE; virtual void GetDebugBorderProperties( SkColor* color, float* width) const OVERRIDE; + private: DISALLOW_COPY_AND_ASSIGN(PictureImageLayerImpl); }; diff --git a/chromium/cc/layers/picture_image_layer_impl_unittest.cc b/chromium/cc/layers/picture_image_layer_impl_unittest.cc index 9aae4d6f7d2..2910da1d5e7 100644 --- a/chromium/cc/layers/picture_image_layer_impl_unittest.cc +++ b/chromium/cc/layers/picture_image_layer_impl_unittest.cc @@ -4,11 +4,14 @@ #include "cc/layers/picture_image_layer_impl.h" +#include "cc/layers/append_quads_data.h" +#include "cc/resources/tile_priority.h" #include "cc/test/fake_impl_proxy.h" #include "cc/test/fake_layer_tree_host_impl.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_picture_layer_tiling_client.h" #include "cc/test/impl_side_painting_settings.h" +#include "cc/test/mock_quad_culler.h" #include "cc/trees/layer_tree_impl.h" #include "testing/gtest/include/gtest/gtest.h" @@ -20,6 +23,9 @@ class TestablePictureImageLayerImpl : public PictureImageLayerImpl { TestablePictureImageLayerImpl(LayerTreeImpl* tree_impl, int id) : PictureImageLayerImpl(tree_impl, id) { } + + PictureLayerTilingSet* tilings() { return tilings_.get(); } + friend class PictureImageLayerImplTest; }; @@ -32,9 +38,22 @@ class PictureImageLayerImplTest : public testing::Test { host_impl_.InitializeRenderer(CreateFakeOutputSurface()); } - scoped_ptr<TestablePictureImageLayerImpl> CreateLayer(int id) { + scoped_ptr<TestablePictureImageLayerImpl> CreateLayer(int id, + WhichTree which_tree) { + LayerTreeImpl* tree = NULL; + switch (which_tree) { + case ACTIVE_TREE: + tree = host_impl_.active_tree(); + break; + case PENDING_TREE: + tree = host_impl_.pending_tree(); + break; + case NUM_TREES: + NOTREACHED(); + break; + } TestablePictureImageLayerImpl* layer = - new TestablePictureImageLayerImpl(host_impl_.pending_tree(), id); + new TestablePictureImageLayerImpl(tree, id); layer->SetBounds(gfx::Size(100, 200)); layer->tilings_.reset(new PictureLayerTilingSet(&tiling_client_, layer->bounds())); @@ -46,14 +65,14 @@ class PictureImageLayerImplTest : public testing::Test { host_impl_.pending_tree()->UpdateDrawProperties(); } - private: + protected: FakeImplProxy proxy_; FakeLayerTreeHostImpl host_impl_; FakePictureLayerTilingClient tiling_client_; }; TEST_F(PictureImageLayerImplTest, CalculateContentsScale) { - scoped_ptr<TestablePictureImageLayerImpl> layer(CreateLayer(1)); + scoped_ptr<TestablePictureImageLayerImpl> layer(CreateLayer(1, PENDING_TREE)); layer->SetDrawsContent(true); float contents_scale_x; @@ -68,7 +87,7 @@ TEST_F(PictureImageLayerImplTest, CalculateContentsScale) { } TEST_F(PictureImageLayerImplTest, AreVisibleResourcesReady) { - scoped_ptr<TestablePictureImageLayerImpl> layer(CreateLayer(1)); + scoped_ptr<TestablePictureImageLayerImpl> layer(CreateLayer(1, PENDING_TREE)); layer->SetBounds(gfx::Size(100, 200)); layer->SetDrawsContent(true); @@ -85,5 +104,61 @@ TEST_F(PictureImageLayerImplTest, AreVisibleResourcesReady) { EXPECT_TRUE(layer->AreVisibleResourcesReady()); } +TEST_F(PictureImageLayerImplTest, IgnoreIdealContentScale) { + scoped_ptr<TestablePictureImageLayerImpl> pending_layer( + CreateLayer(1, PENDING_TREE)); + pending_layer->SetDrawsContent(true); + + // Set PictureLayerImpl::ideal_contents_scale_ to 2.f which is not equal + // to the content scale used by PictureImageLayerImpl. + const float suggested_ideal_contents_scale = 2.f; + const float device_scale_factor = 3.f; + const float page_scale_factor = 4.f; + const bool animating_transform_to_screen = false; + float contents_scale_x; + float contents_scale_y; + gfx::Size content_bounds; + pending_layer->CalculateContentsScale(suggested_ideal_contents_scale, + device_scale_factor, + page_scale_factor, + animating_transform_to_screen, + &contents_scale_x, + &contents_scale_y, + &content_bounds); + + // Push to active layer. + host_impl_.ActivatePendingTree(); + scoped_ptr<TestablePictureImageLayerImpl> active_layer( + CreateLayer(1, ACTIVE_TREE)); + pending_layer->PushPropertiesTo(active_layer.get()); + active_layer->CalculateContentsScale(suggested_ideal_contents_scale, + device_scale_factor, + page_scale_factor, + animating_transform_to_screen, + &contents_scale_x, + &contents_scale_y, + &content_bounds); + + // Create tile and resource. + active_layer->tilings()->tiling_at(0)->CreateAllTilesForTesting(); + host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting( + active_layer->tilings()->tiling_at(0)->AllTilesForTesting(), + host_impl_.resource_provider()); + + // Draw. + active_layer->draw_properties().visible_content_rect = + gfx::Rect(active_layer->bounds()); + MockQuadCuller quad_culler; + AppendQuadsData data; + active_layer->WillDraw(DRAW_MODE_SOFTWARE, NULL); + active_layer->AppendQuads(&quad_culler, &data); + active_layer->DidDraw(NULL); + + EXPECT_EQ(DrawQuad::TILED_CONTENT, quad_culler.quad_list()[0]->material); + + // Tiles are ready at correct scale, so should not set had_incomplete_tile. + EXPECT_FALSE(data.had_incomplete_tile); +} + } // namespace } // namespace cc diff --git a/chromium/cc/layers/picture_layer.cc b/chromium/cc/layers/picture_layer.cc index 4226f1ba713..1415c8075c5 100644 --- a/chromium/cc/layers/picture_layer.cc +++ b/chromium/cc/layers/picture_layer.cc @@ -4,8 +4,6 @@ #include "cc/layers/picture_layer.h" -#include "cc/debug/benchmark_instrumentation.h" -#include "cc/debug/devtools_instrumentation.h" #include "cc/layers/content_layer_client.h" #include "cc/layers/picture_layer_impl.h" #include "cc/trees/layer_tree_impl.h" @@ -21,7 +19,8 @@ PictureLayer::PictureLayer(ContentLayerClient* client) : client_(client), pile_(make_scoped_refptr(new PicturePile())), instrumentation_object_tracker_(id()), - is_mask_(false) { + is_mask_(false), + update_source_frame_number_(-1) { } PictureLayer::~PictureLayer() { @@ -43,12 +42,12 @@ void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) { // Update may not get called for an empty layer, so resize here instead. // Using layer_impl because either bounds() or paint_properties().bounds // may disagree and either one could have been pushed to layer_impl. - pile_->Resize(layer_impl->bounds()); + pile_->Resize(gfx::Size()); pile_->UpdateRecordedRegion(); - } - - if (DrawsContent()) { - DCHECK(paint_properties().bounds == pile_->size()); + } else if (update_source_frame_number_ == + layer_tree_host()->source_frame_number()) { + // If update called, then pile size must match bounds pushed to impl layer. + DCHECK_EQ(layer_impl->bounds().ToString(), pile_->size().ToString()); } layer_impl->SetIsMask(is_mask_); @@ -84,15 +83,19 @@ void PictureLayer::SetNeedsDisplayRect(const gfx::RectF& layer_rect) { bool PictureLayer::Update(ResourceUpdateQueue* queue, const OcclusionTracker* occlusion) { - // Do not early-out of this function so that PicturePile::Update has a chance - // to record pictures due to changing visibility of this layer. + update_source_frame_number_ = layer_tree_host()->source_frame_number(); + bool updated = Layer::Update(queue, occlusion); - TRACE_EVENT1(benchmark_instrumentation::kCategory, - benchmark_instrumentation::kPictureLayerUpdate, - benchmark_instrumentation::kSourceFrameNumber, - layer_tree_host()->source_frame_number()); + if (last_updated_visible_content_rect_ == visible_content_rect() && + pile_->size() == paint_properties().bounds && + pending_invalidation_.IsEmpty()) { + // Only early out if the visible content rect of this layer hasn't changed. + return updated; + } - bool updated = Layer::Update(queue, occlusion); + TRACE_EVENT1("cc", "PictureLayer::Update", + "source_frame_number", + layer_tree_host()->source_frame_number()); pile_->Resize(paint_properties().bounds); @@ -108,14 +111,15 @@ bool PictureLayer::Update(ResourceUpdateQueue* queue, // the full page content must always be provided in the picture layer. visible_layer_rect = gfx::Rect(bounds()); } - devtools_instrumentation::ScopedLayerTask paint_layer( - devtools_instrumentation::kPaintLayer, id()); updated |= pile_->Update(client_, SafeOpaqueBackgroundColor(), contents_opaque(), pile_invalidation_, visible_layer_rect, + update_source_frame_number_, rendering_stats_instrumentation()); + last_updated_visible_content_rect_ = visible_content_rect(); + if (updated) { SetNeedsPushProperties(); } else { @@ -153,4 +157,8 @@ skia::RefPtr<SkPicture> PictureLayer::GetPicture() const { return picture; } +void PictureLayer::RunMicroBenchmark(MicroBenchmark* benchmark) { + benchmark->RunOnLayer(this); +} + } // namespace cc diff --git a/chromium/cc/layers/picture_layer.h b/chromium/cc/layers/picture_layer.h index d7943307ddc..d986a9bfbbc 100644 --- a/chromium/cc/layers/picture_layer.h +++ b/chromium/cc/layers/picture_layer.h @@ -7,6 +7,7 @@ #include "cc/base/invalidation_region.h" #include "cc/debug/devtools_instrumentation.h" +#include "cc/debug/micro_benchmark_controller.h" #include "cc/layers/layer.h" #include "cc/resources/picture_pile.h" #include "cc/trees/occlusion_tracker.h" @@ -36,6 +37,10 @@ class CC_EXPORT PictureLayer : public Layer { virtual bool SupportsLCDText() const OVERRIDE; virtual skia::RefPtr<SkPicture> GetPicture() const OVERRIDE; + virtual void RunMicroBenchmark(MicroBenchmark* benchmark) OVERRIDE; + + ContentLayerClient* client() { return client_; } + protected: explicit PictureLayer(ContentLayerClient* client); virtual ~PictureLayer(); @@ -49,8 +54,11 @@ class CC_EXPORT PictureLayer : public Layer { InvalidationRegion pending_invalidation_; // Invalidation from the last time update was called. Region pile_invalidation_; + gfx::Rect last_updated_visible_content_rect_; bool is_mask_; + int update_source_frame_number_; + DISALLOW_COPY_AND_ASSIGN(PictureLayer); }; diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc index 95a4a076520..2f5ca94ba15 100644 --- a/chromium/cc/layers/picture_layer_impl.cc +++ b/chromium/cc/layers/picture_layer_impl.cc @@ -5,11 +5,13 @@ #include "cc/layers/picture_layer_impl.h" #include <algorithm> +#include <limits> #include "base/time/time.h" #include "cc/base/math_util.h" #include "cc/base/util.h" #include "cc/debug/debug_colors.h" +#include "cc/debug/micro_benchmark_impl.h" #include "cc/debug/traced_value.h" #include "cc/layers/append_quads_data.h" #include "cc/layers/quad_sink.h" @@ -18,6 +20,7 @@ #include "cc/quads/picture_draw_quad.h" #include "cc/quads/solid_color_draw_quad.h" #include "cc/quads/tile_draw_quad.h" +#include "cc/resources/tile_manager.h" #include "cc/trees/layer_tree_impl.h" #include "ui/gfx/quad_f.h" #include "ui/gfx/rect_conversions.h" @@ -25,6 +28,10 @@ namespace { const float kMaxScaleRatioDuringPinch = 2.0f; + +// When creating a new tiling during pinch, snap to an existing +// tiling's scale if the desired scale is within this ratio. +const float kSnapToExistingTilingRatio = 0.2f; } namespace cc { @@ -64,10 +71,18 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) { // It's possible this layer was never drawn or updated (e.g. because it was // a descendant of an opacity 0 layer). DoPostCommitInitializationIfNeeded(); + PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer); - LayerImpl::PushPropertiesTo(base_layer); + // We have already synced the important bits from the the active layer, and + // we will soon swap out its tilings and use them for recycling. However, + // there are now tiles in this layer's tilings that were unref'd and replaced + // with new tiles (due to invalidation). This resets all active priorities on + // the to-be-recycled tiling to ensure replaced tiles don't linger and take + // memory (due to a stale 'active' priority). + if (layer_impl->tilings_) + layer_impl->tilings_->DidBecomeRecycled(); - PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer); + LayerImpl::PushPropertiesTo(base_layer); // When the pending tree pushes to the active tree, the pending twin // disappears. @@ -110,12 +125,7 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink, SharedQuadState* shared_quad_state = quad_sink->UseSharedQuadState(CreateSharedQuadState()); - bool draw_direct_to_backbuffer = - draw_properties().can_draw_directly_to_backbuffer && - layer_tree_impl()->settings().force_direct_layer_drawing; - - if (draw_direct_to_backbuffer || - current_draw_mode_ == DRAW_MODE_RESOURCELESS_SOFTWARE) { + if (current_draw_mode_ == DRAW_MODE_RESOURCELESS_SOFTWARE) { AppendDebugBorderQuad( quad_sink, shared_quad_state, @@ -139,7 +149,6 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink, RGBA_8888, quad_content_rect, contents_scale, - draw_direct_to_backbuffer, pile_); if (quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data)) append_quads_data->num_missing_tiles++; @@ -227,7 +236,7 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink, case ManagedTileState::TileVersion::RESOURCE_MODE: { gfx::RectF texture_rect = iter.texture_rect(); gfx::Rect opaque_rect = iter->opaque_rect(); - opaque_rect.Intersect(content_rect); + opaque_rect.Intersect(geometry_rect); if (iter->contents_scale() != ideal_contents_scale_) append_quads_data->had_incomplete_tile = true; @@ -246,7 +255,7 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink, case ManagedTileState::TileVersion::PICTURE_PILE_MODE: { gfx::RectF texture_rect = iter.texture_rect(); gfx::Rect opaque_rect = iter->opaque_rect(); - opaque_rect.Intersect(content_rect); + opaque_rect.Intersect(geometry_rect); ResourceProvider* resource_provider = layer_tree_impl()->resource_provider(); @@ -261,7 +270,6 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink, format, iter->content_rect(), iter->contents_scale(), - draw_direct_to_backbuffer, pile_); draw_quad = quad.PassAs<DrawQuad>(); break; @@ -373,7 +381,7 @@ void PictureLayerImpl::DidBeginTracing() { void PictureLayerImpl::DidLoseOutputSurface() { if (tilings_) - tilings_->RemoveAllTilings(); + RemoveAllTilings(); ResetRasterScale(); } @@ -448,13 +456,24 @@ skia::RefPtr<SkPicture> PictureLayerImpl::GetPicture() { return pile_->GetFlattenedPicture(); } +bool PictureLayerImpl::ShouldUseGPURasterization() const { + // TODO(skaslev): Add a proper heuristic for hybrid (software or GPU) + // tile rasterization. Currently, when --enable-gpu-rasterization is + // set all tiles get GPU rasterized. + return layer_tree_impl()->settings().gpu_rasterization; +} + scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling, gfx::Rect content_rect) { if (!pile_->CanRaster(tiling->contents_scale(), content_rect)) return scoped_refptr<Tile>(); - return make_scoped_refptr(new Tile( - layer_tree_impl()->tile_manager(), + int flags = 0; + if (is_using_lcd_text_) + flags |= Tile::USE_LCD_TEXT; + if (ShouldUseGPURasterization()) + flags |= Tile::USE_GPU_RASTERIZATION; + return layer_tree_impl()->tile_manager()->CreateTile( pile_.get(), content_rect.size(), content_rect, @@ -462,7 +481,7 @@ scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling, tiling->contents_scale(), id(), layer_tree_impl()->source_frame_number(), - is_using_lcd_text_)); + flags); } void PictureLayerImpl::UpdatePile(Tile* tile) { @@ -474,7 +493,7 @@ const Region* PictureLayerImpl::GetInvalidation() { } const PictureLayerTiling* PictureLayerImpl::GetTwinTiling( - const PictureLayerTiling* tiling) { + const PictureLayerTiling* tiling) const { if (!twin_layer_) return NULL; @@ -544,7 +563,7 @@ void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) { UpdateLCDTextStatus(other->is_using_lcd_text_); if (!DrawsContent()) { - ResetRasterScale(); + RemoveAllTilings(); return; } @@ -587,7 +606,7 @@ void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) { tiling_invalidation, MinimumContentsScale()); } else { - tilings_->RemoveAllTilings(); + RemoveAllTilings(); } SanityCheckTilingState(); @@ -645,6 +664,10 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const { DCHECK(ideal_contents_scale_); DCHECK_GT(tilings_->num_tilings(), 0u); + // The goal of this function is to find the minimum set of tiles that need to + // be ready to draw in order to activate without flashing content from a + // higher res on the active tree to a lower res on the pending tree. + gfx::Rect rect(visible_content_rect()); float min_acceptable_scale = @@ -661,17 +684,21 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const { } } - // Mark tiles for activation in two passes. Ready to draw tiles in acceptable - // but non-ideal tilings are marked as required for activation, but any - // non-ready tiles are not marked as required. From there, any missing holes - // will need to be filled in from the high res tiling. - PictureLayerTiling* high_res = NULL; + PictureLayerTiling* low_res = NULL; + + // First pass: ready to draw tiles in acceptable but non-ideal tilings are + // marked as required for activation so that their textures are not thrown + // away; any non-ready tiles are not marked as required. Region missing_region = rect; for (size_t i = 0; i < tilings_->num_tilings(); ++i) { PictureLayerTiling* tiling = tilings_->tiling_at(i); DCHECK(tiling->has_ever_been_updated()); + if (tiling->resolution() == LOW_RESOLUTION) { + DCHECK(!low_res) << "There can only be one low res tiling"; + low_res = tiling; + } if (tiling->contents_scale() < min_acceptable_scale) continue; if (tiling->resolution() == HIGH_RESOLUTION) { @@ -697,21 +724,73 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const { iter->MarkRequiredForActivation(); } } - DCHECK(high_res) << "There must be one high res tiling"; - for (PictureLayerTiling::CoverageIterator iter(high_res, - contents_scale_x(), + + // If these pointers are null (because no twin, no matching tiling, or the + // simpification just below), then high res tiles will be required to fill any + // holes left by the first pass above. If the pointers are valid, then this + // layer is allowed to skip any tiles that are not ready on its twin. + const PictureLayerTiling* twin_high_res = NULL; + const PictureLayerTiling* twin_low_res = NULL; + + // As a simplification, only allow activating to skip twin tiles that the + // active layer is also missing when both this layer and its twin have 2 + // tilings (high and low). This avoids having to iterate/track coverage of + // non-ideal tilings during the last draw call on the active layer. + if (high_res && low_res && tilings_->num_tilings() == 2 && + twin_layer_ && twin_layer_->tilings_->num_tilings() == 2) { + twin_low_res = GetTwinTiling(low_res); + if (twin_low_res) + twin_high_res = GetTwinTiling(high_res); + } + // If this layer and its twin have different transforms, then don't compare + // them and only allow activating to high res tiles, since tiles on each layer + // will be in different places on screen. + if (!twin_high_res || !twin_low_res || + draw_properties().screen_space_transform != + twin_layer_->draw_properties().screen_space_transform) { + twin_high_res = NULL; + twin_low_res = NULL; + } + + // TODO(enne): temporarily disable this optimization: http://crbug.com/335289 + twin_high_res = NULL; + twin_low_res = NULL; + + // As a second pass, mark as required any visible high res tiles not filled in + // by acceptable non-ideal tiles from the first pass. + if (MarkVisibleTilesAsRequired( + high_res, twin_high_res, contents_scale_x(), rect, missing_region)) { + // As an optional third pass, if a high res tile was skipped because its + // twin was also missing, then fall back to mark low res tiles as required + // in case the active twin is substituting those for missing high res + // content. + MarkVisibleTilesAsRequired( + low_res, twin_low_res, contents_scale_x(), rect, missing_region); + } +} + +bool PictureLayerImpl::MarkVisibleTilesAsRequired( + PictureLayerTiling* tiling, + const PictureLayerTiling* optional_twin_tiling, + float contents_scale, + gfx::Rect rect, + const Region& missing_region) const { + bool twin_had_missing_tile = false; + for (PictureLayerTiling::CoverageIterator iter(tiling, + contents_scale, rect); iter; ++iter) { + Tile* tile = *iter; // A null tile (i.e. missing recording) can just be skipped. - if (!*iter) + if (!tile) continue; // This iteration is over the visible content rect which is potentially // less conservative than projecting the viewport into the layer. // Ignore tiles that are know to be outside the viewport. - if (iter->priority(PENDING_TREE).distance_to_visible_in_pixels != 0) + if (tile->priority(PENDING_TREE).distance_to_visible_in_pixels != 0) continue; // If the missing region doesn't cover it, this tile is fully @@ -719,8 +798,20 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const { if (!missing_region.Intersects(iter.geometry_rect())) continue; - iter->MarkRequiredForActivation(); + // If the twin tile doesn't exist (i.e. missing recording or so far away + // that it is outside the visible tile rect) or this tile is shared between + // with the twin, then this tile isn't required to prevent flashing. + if (optional_twin_tiling) { + Tile* twin_tile = optional_twin_tiling->TileAt(iter.i(), iter.j()); + if (!twin_tile || twin_tile == tile) { + twin_had_missing_tile = true; + continue; + } + } + + tile->MarkRequiredForActivation(); } + return twin_had_missing_tile; } void PictureLayerImpl::DoPostCommitInitialization() { @@ -768,9 +859,17 @@ void PictureLayerImpl::RemoveTiling(float contents_scale) { break; } } + if (tilings_->num_tilings() == 0) + ResetRasterScale(); SanityCheckTilingState(); } +void PictureLayerImpl::RemoveAllTilings() { + tilings_->RemoveAllTilings(); + // If there are no tilings, then raster scales are no longer meaningful. + ResetRasterScale(); +} + namespace { inline float PositiveRatio(float float1, float float2) { @@ -779,16 +878,6 @@ inline float PositiveRatio(float float1, float float2) { return float1 > float2 ? float1 / float2 : float2 / float1; } -inline bool IsCloserToThan( - PictureLayerTiling* layer1, - PictureLayerTiling* layer2, - float contents_scale) { - // Absolute value for ratios. - float ratio1 = PositiveRatio(layer1->contents_scale(), contents_scale); - float ratio2 = PositiveRatio(layer2->contents_scale(), contents_scale); - return ratio1 < ratio2; -} - } // namespace void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) { @@ -807,6 +896,11 @@ void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) { low_res_raster_contents_scale_ == 0.f || ShouldAdjustRasterScale(animating_transform_to_screen); + if (tilings_->num_tilings() == 0) { + DCHECK(change_target_tiling) + << "A layer with no tilings shouldn't have valid raster scales"; + } + // Store the value for the next time ShouldAdjustRasterScale is called. raster_source_scale_was_animating_ = animating_transform_to_screen; @@ -816,13 +910,7 @@ void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) { if (!layer_tree_impl()->device_viewport_valid_for_tile_management()) return; - raster_page_scale_ = ideal_page_scale_; - raster_device_scale_ = ideal_device_scale_; - raster_source_scale_ = ideal_source_scale_; - - CalculateRasterContentsScale(animating_transform_to_screen, - &raster_contents_scale_, - &low_res_raster_contents_scale_); + RecalculateRasterScales(animating_transform_to_screen); PictureLayerTiling* high_res = NULL; PictureLayerTiling* low_res = NULL; @@ -855,11 +943,14 @@ void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) { low_res != high_res) low_res = AddTiling(low_res_raster_contents_scale_); - high_res->set_resolution(HIGH_RESOLUTION); + // Set low-res if we have one. + if (!low_res) + low_res = previous_low_res; if (low_res && low_res != high_res) low_res->set_resolution(LOW_RESOLUTION); - else if (!low_res && previous_low_res) - previous_low_res->set_resolution(LOW_RESOLUTION); + + // Make sure we always have one high-res (even if high == low). + high_res->set_resolution(HIGH_RESOLUTION); SanityCheckTilingState(); } @@ -876,10 +967,12 @@ bool PictureLayerImpl::ShouldAdjustRasterScale( bool is_pinching = layer_tree_impl()->PinchGestureActive(); if (is_pinching && raster_page_scale_) { - // If the page scale diverges too far during pinch, change raster target to - // the current page scale. - float ratio = PositiveRatio(ideal_page_scale_, raster_page_scale_); - if (ratio >= kMaxScaleRatioDuringPinch) + // We change our raster scale when it is: + // - Higher than ideal (need a lower-res tiling available) + // - Too far from ideal (need a higher-res tiling available) + float ratio = ideal_page_scale_ / raster_page_scale_; + if (raster_page_scale_ > ideal_page_scale_ || + ratio > kMaxScaleRatioDuringPinch) return true; } @@ -896,41 +989,77 @@ bool PictureLayerImpl::ShouldAdjustRasterScale( return false; } -void PictureLayerImpl::CalculateRasterContentsScale( - bool animating_transform_to_screen, - float* raster_contents_scale, - float* low_res_raster_contents_scale) const { - *raster_contents_scale = ideal_contents_scale_; +float PictureLayerImpl::SnappedContentsScale(float scale) { + // If a tiling exists within the max snapping ratio, snap to its scale. + float snapped_contents_scale = scale; + float snapped_ratio = kSnapToExistingTilingRatio; + for (size_t i = 0; i < tilings_->num_tilings(); ++i) { + float tiling_contents_scale = tilings_->tiling_at(i)->contents_scale(); + float ratio = PositiveRatio(tiling_contents_scale, scale); + if (ratio < snapped_ratio) { + snapped_contents_scale = tiling_contents_scale; + snapped_ratio = ratio; + } + } + return snapped_contents_scale; +} + +void PictureLayerImpl::RecalculateRasterScales( + bool animating_transform_to_screen) { + raster_device_scale_ = ideal_device_scale_; + raster_source_scale_ = ideal_source_scale_; + + bool is_pinching = layer_tree_impl()->PinchGestureActive(); + if (!is_pinching || raster_contents_scale_ == 0.f) { + // When not pinching or when we have no previous scale, we use ideal scale: + raster_page_scale_ = ideal_page_scale_; + raster_contents_scale_ = ideal_contents_scale_; + } else { + // See ShouldAdjustRasterScale: + // - When zooming out, preemptively create new tiling at lower resolution. + // - When zooming in, approximate ideal using multiple of kMaxScaleRatio. + bool zooming_out = raster_page_scale_ > ideal_page_scale_; + float desired_contents_scale = + zooming_out ? raster_contents_scale_ / kMaxScaleRatioDuringPinch + : raster_contents_scale_ * kMaxScaleRatioDuringPinch; + raster_contents_scale_ = SnappedContentsScale(desired_contents_scale); + raster_page_scale_ = raster_contents_scale_ / raster_device_scale_; + } + + raster_contents_scale_ = + std::max(raster_contents_scale_, MinimumContentsScale()); // Don't allow animating CSS scales to drop below 1. This is needed because // changes in raster source scale aren't handled. See the comment in // ShouldAdjustRasterScale. if (animating_transform_to_screen) { - *raster_contents_scale = std::max( - *raster_contents_scale, 1.f * ideal_page_scale_ * ideal_device_scale_); + raster_contents_scale_ = std::max( + raster_contents_scale_, 1.f * ideal_page_scale_ * ideal_device_scale_); } // If this layer would only create one tile at this content scale, // don't create a low res tiling. gfx::Size content_bounds = - gfx::ToCeiledSize(gfx::ScaleSize(bounds(), *raster_contents_scale)); + gfx::ToCeiledSize(gfx::ScaleSize(bounds(), raster_contents_scale_)); gfx::Size tile_size = CalculateTileSize(content_bounds); if (tile_size.width() >= content_bounds.width() && tile_size.height() >= content_bounds.height()) { - *low_res_raster_contents_scale = *raster_contents_scale; + low_res_raster_contents_scale_ = raster_contents_scale_; return; } float low_res_factor = layer_tree_impl()->settings().low_res_contents_scale_factor; - *low_res_raster_contents_scale = std::max( - *raster_contents_scale * low_res_factor, + low_res_raster_contents_scale_ = std::max( + raster_contents_scale_ * low_res_factor, MinimumContentsScale()); } void PictureLayerImpl::CleanUpTilingsOnActiveLayer( std::vector<PictureLayerTiling*> used_tilings) { DCHECK(layer_tree_impl()->IsActiveTree()); + if (tilings_->num_tilings() == 0) + return; float min_acceptable_high_res_scale = std::min( raster_contents_scale_, ideal_contents_scale_); @@ -970,10 +1099,14 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer( } for (size_t i = 0; i < to_remove.size(); ++i) { - if (twin) + const PictureLayerTiling* twin_tiling = GetTwinTiling(to_remove[i]); + // Only remove tilings from the twin layer if they have + // NON_IDEAL_RESOLUTION. + if (twin_tiling && twin_tiling->resolution() == NON_IDEAL_RESOLUTION) twin->RemoveTiling(to_remove[i]->contents_scale()); tilings_->Remove(to_remove[i]); } + DCHECK_GT(tilings_->num_tilings(), 0u); SanityCheckTilingState(); } @@ -1021,9 +1154,6 @@ bool PictureLayerImpl::CanHaveTilings() const { return false; if (pile_->recorded_region().IsEmpty()) return false; - if (draw_properties().can_draw_directly_to_backbuffer && - layer_tree_impl()->settings().force_direct_layer_drawing) - return false; return true; } @@ -1059,6 +1189,7 @@ void PictureLayerImpl::GetDebugBorderProperties( } void PictureLayerImpl::AsValueInto(base::DictionaryValue* state) const { + const_cast<PictureLayerImpl*>(this)->DoPostCommitInitializationIfNeeded(); LayerImpl::AsValueInto(state); state->SetDouble("ideal_contents_scale", ideal_contents_scale_); state->SetDouble("geometry_contents_scale", contents_scale_x()); @@ -1066,6 +1197,11 @@ void PictureLayerImpl::AsValueInto(base::DictionaryValue* state) const { state->Set("pictures", pile_->AsValue().release()); state->Set("invalidation", invalidation_.AsValue().release()); + Region unrecorded_region(gfx::Rect(pile_->size())); + unrecorded_region.Subtract(pile_->recorded_region()); + if (!unrecorded_region.IsEmpty()) + state->Set("unrecorded_region", unrecorded_region.AsValue().release()); + scoped_ptr<base::ListValue> coverage_tiles(new base::ListValue); for (PictureLayerTilingSet::CoverageIterator iter(tilings_.get(), contents_scale_x(), @@ -1082,10 +1218,16 @@ void PictureLayerImpl::AsValueInto(base::DictionaryValue* state) const { coverage_tiles->Append(tile_data.release()); } state->Set("coverage_tiles", coverage_tiles.release()); + state->SetBoolean("is_using_lcd_text", is_using_lcd_text_); } size_t PictureLayerImpl::GPUMemoryUsageInBytes() const { + const_cast<PictureLayerImpl*>(this)->DoPostCommitInitializationIfNeeded(); return tilings_->GPUMemoryUsageInBytes(); } +void PictureLayerImpl::RunMicroBenchmark(MicroBenchmarkImpl* benchmark) { + benchmark->RunOnLayer(this); +} + } // namespace cc diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h index fd5c0677a98..ab6aad7138b 100644 --- a/chromium/cc/layers/picture_layer_impl.h +++ b/chromium/cc/layers/picture_layer_impl.h @@ -21,6 +21,7 @@ namespace cc { struct AppendQuadsData; class QuadSink; +class MicroBenchmarkImpl; class CC_EXPORT PictureLayerImpl : public LayerImpl, @@ -59,7 +60,7 @@ class CC_EXPORT PictureLayerImpl gfx::Size content_bounds) const OVERRIDE; virtual const Region* GetInvalidation() OVERRIDE; virtual const PictureLayerTiling* GetTwinTiling( - const PictureLayerTiling* tiling) OVERRIDE; + const PictureLayerTiling* tiling) const OVERRIDE; // PushPropertiesTo active tree => pending tree. void SyncTiling(const PictureLayerTiling* tiling); @@ -70,24 +71,33 @@ class CC_EXPORT PictureLayerImpl virtual size_t GPUMemoryUsageInBytes() const OVERRIDE; + virtual void RunMicroBenchmark(MicroBenchmarkImpl* benchmark) OVERRIDE; + protected: PictureLayerImpl(LayerTreeImpl* tree_impl, int id); PictureLayerTiling* AddTiling(float contents_scale); void RemoveTiling(float contents_scale); + void RemoveAllTilings(); void SyncFromActiveLayer(const PictureLayerImpl* other); void ManageTilings(bool animating_transform_to_screen); virtual bool ShouldAdjustRasterScale( bool animating_transform_to_screen) const; - virtual void CalculateRasterContentsScale( - bool animating_transform_to_screen, - float* raster_contents_scale, - float* low_res_raster_contents_scale) const; + virtual void RecalculateRasterScales( + bool animating_transform_to_screen); void CleanUpTilingsOnActiveLayer( std::vector<PictureLayerTiling*> used_tilings); float MinimumContentsScale() const; + float SnappedContentsScale(float new_contents_scale); void UpdateLCDTextStatus(bool new_status); void ResetRasterScale(); void MarkVisibleResourcesAsRequired() const; + bool MarkVisibleTilesAsRequired( + PictureLayerTiling* tiling, + const PictureLayerTiling* optional_twin_tiling, + float contents_scale, + gfx::Rect rect, + const Region& missing_region) const; + void DoPostCommitInitializationIfNeeded() { if (needs_post_commit_initialization_) DoPostCommitInitialization(); @@ -97,6 +107,7 @@ class CC_EXPORT PictureLayerImpl bool CanHaveTilings() const; bool CanHaveTilingWithScale(float contents_scale) const; void SanityCheckTilingState() const; + bool ShouldUseGPURasterization() const; virtual void GetDebugBorderProperties( SkColor* color, float* width) const OVERRIDE; diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc index e1cd39ada41..eb3b0597194 100644 --- a/chromium/cc/layers/picture_layer_impl_unittest.cc +++ b/chromium/cc/layers/picture_layer_impl_unittest.cc @@ -6,7 +6,6 @@ #include <utility> -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/layers/append_quads_data.h" #include "cc/layers/picture_layer.h" #include "cc/test/fake_content_layer_client.h" @@ -18,6 +17,7 @@ #include "cc/test/geometry_test_utils.h" #include "cc/test/impl_side_painting_settings.h" #include "cc/test/mock_quad_culler.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "cc/trees/layer_tree_impl.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmapDevice.h" @@ -68,18 +68,37 @@ class PictureLayerImplTest : public testing::Test { SetupTrees(pending_pile, active_pile); } - void SetupTrees( - scoped_refptr<PicturePileImpl> pending_pile, - scoped_refptr<PicturePileImpl> active_pile) { - SetupPendingTree(active_pile); + void ActivateTree() { host_impl_.ActivatePendingTree(); - + CHECK(!host_impl_.pending_tree()); + pending_layer_ = NULL; active_layer_ = static_cast<FakePictureLayerImpl*>( host_impl_.active_tree()->LayerById(id_)); + } + void SetupDefaultTreesWithFixedTileSize(gfx::Size layer_bounds, + gfx::Size tile_size) { + SetupDefaultTrees(layer_bounds); + pending_layer_->set_fixed_tile_size(tile_size); + active_layer_->set_fixed_tile_size(tile_size); + } + + void SetupTrees( + scoped_refptr<PicturePileImpl> pending_pile, + scoped_refptr<PicturePileImpl> active_pile) { + SetupPendingTree(active_pile); + ActivateTree(); SetupPendingTree(pending_pile); } + void CreateHighLowResAndSetAllTilesVisible() { + // Active layer must get updated first so pending layer can share from it. + active_layer_->CreateDefaultTilingsAndTiles(); + active_layer_->SetAllTilesVisible(); + pending_layer_->CreateDefaultTilingsAndTiles(); + pending_layer_->SetAllTilesVisible(); + } + void AddDefaultTilingsWithInvalidation(const Region& invalidation) { active_layer_->AddTiling(2.3f); active_layer_->AddTiling(1.0f); @@ -149,6 +168,20 @@ class PictureLayerImplTest : public testing::Test { active_layer_->DidLoseOutputSurface(); } + void AssertAllTilesRequired(PictureLayerTiling* tiling) { + std::vector<Tile*> tiles = tiling->AllTilesForTesting(); + for (size_t i = 0; i < tiles.size(); ++i) + EXPECT_TRUE(tiles[i]->required_for_activation()) << "i: " << i; + EXPECT_GT(tiles.size(), 0u); + } + + void AssertNoTilesRequired(PictureLayerTiling* tiling) { + std::vector<Tile*> tiles = tiling->AllTilesForTesting(); + for (size_t i = 0; i < tiles.size(); ++i) + EXPECT_FALSE(tiles[i]->required_for_activation()) << "i: " << i; + EXPECT_GT(tiles.size(), 0u); + } + protected: void TestTileGridAlignmentCommon() { // Layer to span 4 raster tiles in x and in y @@ -591,6 +624,157 @@ TEST_F(PictureLayerImplTest, ManageTilingsCreatesTilings) { pending_layer_->tilings()->tiling_at(3)->contents_scale()); } +TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) { + // This test makes sure that if a layer can have tilings, then a commit makes + // it not able to have tilings (empty size), and then a future commit that + // makes it valid again should be able to create tilings. + gfx::Size tile_size(400, 400); + gfx::Size layer_bounds(1300, 1900); + + scoped_refptr<FakePicturePileImpl> empty_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 0)); + scoped_refptr<FakePicturePileImpl> valid_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; + EXPECT_LT(low_res_factor, 1.f); + + float high_res_scale = 1.3f; + float low_res_scale = high_res_scale * low_res_factor; + float device_scale = 1.7f; + float page_scale = 3.2f; + float result_scale_x, result_scale_y; + gfx::Size result_bounds; + + SetupPendingTree(valid_pile); + pending_layer_->CalculateContentsScale(high_res_scale, + device_scale, + page_scale, + false, + &result_scale_x, + &result_scale_y, + &result_bounds); + ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings()); + EXPECT_FLOAT_EQ(high_res_scale, + pending_layer_->HighResTiling()->contents_scale()); + EXPECT_FLOAT_EQ(low_res_scale, + pending_layer_->LowResTiling()->contents_scale()); + + ActivateTree(); + SetupPendingTree(empty_pile); + pending_layer_->CalculateContentsScale(high_res_scale, + device_scale, + page_scale, + false, + &result_scale_x, + &result_scale_y, + &result_bounds); + ASSERT_EQ(2u, active_layer_->tilings()->num_tilings()); + ASSERT_EQ(0u, pending_layer_->tilings()->num_tilings()); + + ActivateTree(); + active_layer_->CalculateContentsScale(high_res_scale, + device_scale, + page_scale, + false, + &result_scale_x, + &result_scale_y, + &result_bounds); + ASSERT_EQ(0u, active_layer_->tilings()->num_tilings()); + + SetupPendingTree(valid_pile); + pending_layer_->CalculateContentsScale(high_res_scale, + device_scale, + page_scale, + false, + &result_scale_x, + &result_scale_y, + &result_bounds); + ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings()); + ASSERT_EQ(0u, active_layer_->tilings()->num_tilings()); + EXPECT_FLOAT_EQ(high_res_scale, + pending_layer_->HighResTiling()->contents_scale()); + EXPECT_FLOAT_EQ(low_res_scale, + pending_layer_->LowResTiling()->contents_scale()); +} + +TEST_F(PictureLayerImplTest, ZoomOutCrash) { + gfx::Size tile_size(400, 400); + gfx::Size layer_bounds(1300, 1900); + + // Set up the high and low res tilings before pinch zoom. + scoped_refptr<FakePicturePileImpl> pending_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakePicturePileImpl> active_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + SetupTrees(pending_pile, active_pile); + EXPECT_EQ(0u, active_layer_->tilings()->num_tilings()); + SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f, false); + host_impl_.PinchGestureBegin(); + SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, false); + SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, false); + EXPECT_EQ(active_layer_->tilings()->NumHighResTilings(), 1); +} + +TEST_F(PictureLayerImplTest, PinchGestureTilings) { + gfx::Size tile_size(400, 400); + gfx::Size layer_bounds(1300, 1900); + + scoped_refptr<FakePicturePileImpl> pending_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakePicturePileImpl> active_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + // Set up the high and low res tilings before pinch zoom. + SetupTrees(pending_pile, active_pile); + EXPECT_EQ(0u, active_layer_->tilings()->num_tilings()); + SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, false); + float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; + EXPECT_EQ(2u, active_layer_->tilings()->num_tilings()); + EXPECT_FLOAT_EQ( + 1.0f, + active_layer_->tilings()->tiling_at(0)->contents_scale()); + EXPECT_FLOAT_EQ( + 1.0f * low_res_factor, + active_layer_->tilings()->tiling_at(1)->contents_scale()); + + // Start a pinch gesture. + host_impl_.PinchGestureBegin(); + + // Zoom out by a small amount. We should create a tiling at half + // the scale (1/kMaxScaleRatioDuringPinch). + SetContentsScaleOnBothLayers(0.90f, 1.0f, 0.9f, false); + EXPECT_EQ(3u, active_layer_->tilings()->num_tilings()); + EXPECT_FLOAT_EQ( + 1.0f, + active_layer_->tilings()->tiling_at(0)->contents_scale()); + EXPECT_FLOAT_EQ( + 0.5f, + active_layer_->tilings()->tiling_at(1)->contents_scale()); + EXPECT_FLOAT_EQ( + 1.0f * low_res_factor, + active_layer_->tilings()->tiling_at(2)->contents_scale()); + + // Zoom out further, close to our low-res scale factor. We should + // use that tiling as high-res, and not create a new tiling. + SetContentsScaleOnBothLayers(low_res_factor, 1.0f, low_res_factor, false); + EXPECT_EQ(3u, active_layer_->tilings()->num_tilings()); + + // Zoom in a lot now. Since we increase by increments of + // kMaxScaleRatioDuringPinch, this will first use 0.5, then 1.0 + // and then finally create a new tiling at 2.0. + SetContentsScaleOnBothLayers(2.1f, 1.0f, 2.1f, false); + EXPECT_EQ(3u, active_layer_->tilings()->num_tilings()); + SetContentsScaleOnBothLayers(2.1f, 1.0f, 2.1f, false); + EXPECT_EQ(3u, active_layer_->tilings()->num_tilings()); + SetContentsScaleOnBothLayers(2.1f, 1.0f, 2.1f, false); + EXPECT_EQ(4u, active_layer_->tilings()->num_tilings()); + EXPECT_FLOAT_EQ( + 2.0f, + active_layer_->tilings()->tiling_at(0)->contents_scale()); +} + TEST_F(PictureLayerImplTest, CleanUpTilings) { gfx::Size tile_size(400, 400); gfx::Size layer_bounds(1300, 1900); @@ -742,12 +926,12 @@ TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) { EXPECT_BOTH_EQ(num_tilings(), 2u); // Page scale animation, new high res, but not new low res because animating. - contents_scale = 4.f; - page_scale = 4.f; + contents_scale = 2.f; + page_scale = 2.f; animating_transform = true; SetContentsScaleOnBothLayers( contents_scale, device_scale, page_scale, animating_transform); - EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f); + EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f); EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), low_res_factor); EXPECT_BOTH_EQ(num_tilings(), 3u); @@ -755,8 +939,8 @@ TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) { animating_transform = false; SetContentsScaleOnBothLayers( contents_scale, device_scale, page_scale, animating_transform); - EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f); - EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), 4.f * low_res_factor); + EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f); + EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), 2.f * low_res_factor); EXPECT_BOTH_EQ(num_tilings(), 4u); } @@ -885,6 +1069,7 @@ TEST_F(PictureLayerImplTest, ClampTilesToToMaxTileSize) { scoped_ptr<TestWebGraphicsContext3D> context = TestWebGraphicsContext3D::Create(); context->set_max_texture_size(140); + host_impl_.DidLoseOutputSurface(); host_impl_.InitializeRenderer(FakeOutputSurface::Create3d( context.Pass()).PassAs<OutputSurface>()); @@ -936,6 +1121,7 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) { scoped_ptr<TestWebGraphicsContext3D> context = TestWebGraphicsContext3D::Create(); context->set_max_texture_size(140); + host_impl_.DidLoseOutputSurface(); host_impl_.InitializeRenderer(FakeOutputSurface::Create3d( context.Pass()).PassAs<OutputSurface>()); @@ -1071,6 +1257,101 @@ TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) { EXPECT_GT(num_offscreen, 0); } +TEST_F(PictureLayerImplTest, HighResRequiredWhenUnsharedActiveAllReady) { + gfx::Size layer_bounds(400, 400); + gfx::Size tile_size(100, 100); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size); + + // No tiles shared. + pending_layer_->set_invalidation(gfx::Rect(layer_bounds)); + + CreateHighLowResAndSetAllTilesVisible(); + + active_layer_->SetAllTilesReady(); + + // No shared tiles and all active tiles ready, so pending can only + // activate with all high res tiles. + pending_layer_->MarkVisibleResourcesAsRequired(); + AssertAllTilesRequired(pending_layer_->HighResTiling()); + AssertNoTilesRequired(pending_layer_->LowResTiling()); +} + +// TODO(enne): temporarily disabled: http://crbug.com/335289 +TEST_F(PictureLayerImplTest, DISABLED_NothingRequiredIfAllHighResTilesShared) { + gfx::Size layer_bounds(400, 400); + gfx::Size tile_size(100, 100); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size); + + CreateHighLowResAndSetAllTilesVisible(); + + Tile* some_active_tile = + active_layer_->HighResTiling()->AllTilesForTesting()[0]; + EXPECT_FALSE(some_active_tile->IsReadyToDraw()); + + // All tiles shared (no invalidation), so even though the active tree's + // tiles aren't ready, there is nothing required. + pending_layer_->MarkVisibleResourcesAsRequired(); + AssertNoTilesRequired(pending_layer_->HighResTiling()); + AssertNoTilesRequired(pending_layer_->LowResTiling()); +} + +// TODO(enne): temporarily disabled: http://crbug.com/335289 +TEST_F(PictureLayerImplTest, DISABLED_NothingRequiredIfActiveMissingTiles) { + gfx::Size layer_bounds(400, 400); + gfx::Size tile_size(100, 100); + scoped_refptr<FakePicturePileImpl> pending_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + // An arbitrary bogus outside the layer recording. Enough for the layer to + // think it can create tiles, but not in bounds so all tiles are null. + Region active_recorded_region; + active_recorded_region.Union(gfx::Rect(1000, 1000, 1, 1)); + scoped_refptr<FakePicturePileImpl> active_pile = + FakePicturePileImpl::CreatePileWithRecordedRegion( + tile_size, layer_bounds, active_recorded_region); + SetupTrees(pending_pile, active_pile); + pending_layer_->set_fixed_tile_size(tile_size); + active_layer_->set_fixed_tile_size(tile_size); + + CreateHighLowResAndSetAllTilesVisible(); + + // Active layer has tilings, but no tiles due to missing recordings. + EXPECT_TRUE(active_layer_->CanHaveTilings()); + EXPECT_EQ(active_layer_->tilings()->num_tilings(), 2u); + EXPECT_EQ(active_layer_->HighResTiling()->AllTilesForTesting().size(), 0u); + + // Since the active layer has no tiles at all, the pending layer doesn't + // need content in order to activate. This is attempting to simulate + // scrolling past the end of recorded content on the active layer. + pending_layer_->MarkVisibleResourcesAsRequired(); + AssertNoTilesRequired(pending_layer_->HighResTiling()); + AssertNoTilesRequired(pending_layer_->LowResTiling()); +} + +TEST_F(PictureLayerImplTest, HighResRequiredIfActiveCantHaveTiles) { + gfx::Size layer_bounds(400, 400); + gfx::Size tile_size(100, 100); + scoped_refptr<FakePicturePileImpl> pending_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakePicturePileImpl> active_pile = + FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds); + SetupTrees(pending_pile, active_pile); + pending_layer_->set_fixed_tile_size(tile_size); + active_layer_->set_fixed_tile_size(tile_size); + + CreateHighLowResAndSetAllTilesVisible(); + + // Active layer can't have tiles. + EXPECT_FALSE(active_layer_->CanHaveTilings()); + + // All high res tiles required. This should be considered identical + // to the case where there is no active layer, to avoid flashing content. + // This can happen if a layer exists for a while and switches from + // not being able to have content to having content. + pending_layer_->MarkVisibleResourcesAsRequired(); + AssertAllTilesRequired(pending_layer_->HighResTiling()); + AssertNoTilesRequired(pending_layer_->LowResTiling()); +} + TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) { gfx::Size tile_size(100, 100); gfx::Size layer_bounds(400, 400); @@ -1106,19 +1387,92 @@ TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) { EXPECT_FALSE(active_layer_->needs_post_commit_initialization()); } -// Solid color scrollbar setting is required for deferred initialization. -class ImplSidePaintingSolidColorScrollbarSettings - : public ImplSidePaintingSettings { - public: - ImplSidePaintingSolidColorScrollbarSettings() { - solid_color_scrollbars = true; - } -}; +TEST_F(PictureLayerImplTest, SyncTilingAfterReleaseResource) { + SetupDefaultTrees(gfx::Size(10, 10)); + host_impl_.active_tree()->UpdateDrawProperties(); + EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties()); + + // Contrived unit test of a real crash. A layer is transparent during a + // context loss, and later becomes opaque, causing active layer SyncTiling to + // be called. + const float tile_scale = 2.f; + active_layer_->DidLoseOutputSurface(); + EXPECT_FALSE(active_layer_->tilings()->TilingAtScale(tile_scale)); + pending_layer_->AddTiling(2.f); + EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(tile_scale)); +} + +TEST_F(PictureLayerImplTest, NoTilingIfDoesNotDrawContent) { + // Set up layers with tilings. + SetupDefaultTrees(gfx::Size(10, 10)); + SetContentsScaleOnBothLayers(1.f, 1.f, 1.f, false); + pending_layer_->PushPropertiesTo(active_layer_); + EXPECT_TRUE(pending_layer_->DrawsContent()); + EXPECT_TRUE(pending_layer_->CanHaveTilings()); + EXPECT_GE(pending_layer_->num_tilings(), 0u); + EXPECT_GE(active_layer_->num_tilings(), 0u); + + // Set content to false, which should make CanHaveTilings return false. + pending_layer_->SetDrawsContent(false); + EXPECT_FALSE(pending_layer_->DrawsContent()); + EXPECT_FALSE(pending_layer_->CanHaveTilings()); + + // No tilings should be pushed to active layer. + pending_layer_->PushPropertiesTo(active_layer_); + EXPECT_EQ(0u, active_layer_->num_tilings()); +} + +TEST_F(PictureLayerImplTest, FirstTilingDuringPinch) { + SetupDefaultTrees(gfx::Size(10, 10)); + host_impl_.PinchGestureBegin(); + float high_res_scale = 2.3f; + SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, false); + + ASSERT_GE(pending_layer_->num_tilings(), 0u); + EXPECT_FLOAT_EQ(high_res_scale, + pending_layer_->HighResTiling()->contents_scale()); +} + +TEST_F(PictureLayerImplTest, FirstTilingTooSmall) { + SetupDefaultTrees(gfx::Size(10, 10)); + host_impl_.PinchGestureBegin(); + float high_res_scale = 0.0001f; + EXPECT_GT(pending_layer_->MinimumContentsScale(), high_res_scale); + + SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, false); + + ASSERT_GE(pending_layer_->num_tilings(), 0u); + EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(), + pending_layer_->HighResTiling()->contents_scale()); +} + +TEST_F(PictureLayerImplTest, PinchingTooSmall) { + SetupDefaultTrees(gfx::Size(10, 10)); + + float contents_scale = 0.15f; + SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f, false); + + ASSERT_GE(pending_layer_->num_tilings(), 0u); + EXPECT_FLOAT_EQ(contents_scale, + pending_layer_->HighResTiling()->contents_scale()); + + host_impl_.PinchGestureBegin(); + + float page_scale = 0.0001f; + EXPECT_LT(page_scale * contents_scale, + pending_layer_->MinimumContentsScale()); + + + SetContentsScaleOnBothLayers(contents_scale, 1.f, page_scale, false); + ASSERT_GE(pending_layer_->num_tilings(), 0u); + EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(), + pending_layer_->HighResTiling()->contents_scale()); +} class DeferredInitPictureLayerImplTest : public PictureLayerImplTest { public: DeferredInitPictureLayerImplTest() - : PictureLayerImplTest(ImplSidePaintingSolidColorScrollbarSettings()) {} + : PictureLayerImplTest(ImplSidePaintingSettings()) {} virtual void InitializeRenderer() OVERRIDE { host_impl_.InitializeRenderer(FakeOutputSurface::CreateDeferredGL( diff --git a/chromium/cc/layers/render_surface.cc b/chromium/cc/layers/render_surface.cc index a17beab9ba7..0eab856a956 100644 --- a/chromium/cc/layers/render_surface.cc +++ b/chromium/cc/layers/render_surface.cc @@ -18,7 +18,7 @@ RenderSurface::RenderSurface(Layer* owning_layer) screen_space_transforms_are_animating_(false), is_clipped_(false), contributes_to_drawn_surface_(false), - nearest_ancestor_that_moves_pixels_(NULL) {} + nearest_occlusion_immune_ancestor_(NULL) {} RenderSurface::~RenderSurface() { for (size_t i = 0; i < layer_list_.size(); ++i) { diff --git a/chromium/cc/layers/render_surface.h b/chromium/cc/layers/render_surface.h index adce0a8a201..ef9ba229736 100644 --- a/chromium/cc/layers/render_surface.h +++ b/chromium/cc/layers/render_surface.h @@ -102,11 +102,11 @@ class CC_EXPORT RenderSurface { // RenderPasses so they can't contribute to a surface. void AddContributingDelegatedRenderPassLayer(Layer* layer) {} - void SetNearestAncestorThatMovesPixels(RenderSurface* surface) { - nearest_ancestor_that_moves_pixels_ = surface; + void SetNearestOcclusionImmuneAncestor(RenderSurface* surface) { + nearest_occlusion_immune_ancestor_ = surface; } - const RenderSurface* nearest_ancestor_that_moves_pixels() const { - return nearest_ancestor_that_moves_pixels_; + const RenderSurface* nearest_occlusion_immune_ancestor() const { + return nearest_occlusion_immune_ancestor_; } private: @@ -135,9 +135,8 @@ class CC_EXPORT RenderSurface { RenderSurfaceLayerList layer_list_; // The nearest ancestor target surface that will contain the contents of this - // surface, and that is going to move pixels within the surface (such as with - // a blur). This can point to itself. - RenderSurface* nearest_ancestor_that_moves_pixels_; + // surface, and that ignores outside occlusion. This can point to itself. + RenderSurface* nearest_occlusion_immune_ancestor_; // For LayerIteratorActions int target_render_surface_layer_index_history_; diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc index 3262e281bbd..a8336bcaf4f 100644 --- a/chromium/cc/layers/render_surface_impl.cc +++ b/chromium/cc/layers/render_surface_impl.cc @@ -28,13 +28,13 @@ namespace cc { RenderSurfaceImpl::RenderSurfaceImpl(LayerImpl* owning_layer) : owning_layer_(owning_layer), surface_property_changed_(false), - draw_opacity_(1), draw_opacity_is_animating_(false), target_surface_transforms_are_animating_(false), screen_space_transforms_are_animating_(false), is_clipped_(false), contributes_to_drawn_surface_(false), - nearest_ancestor_that_moves_pixels_(NULL), + draw_opacity_(1), + nearest_occlusion_immune_ancestor_(NULL), target_render_surface_layer_index_history_(0), current_layer_index_history_(0) { damage_tracker_ = DamageTracker::Create(); @@ -133,7 +133,7 @@ void RenderSurfaceImpl::AppendRenderPasses(RenderPassSink* pass_sink) { delegated_renderer_layer->AppendContributingRenderPasses(pass_sink); } - scoped_ptr<RenderPass> pass = RenderPass::Create(); + scoped_ptr<RenderPass> pass = RenderPass::Create(layer_list_.size()); pass->SetNew(RenderPassId(), content_rect_, damage_tracker_->current_damage_rect(), @@ -156,7 +156,8 @@ void RenderSurfaceImpl::AppendQuads(QuadSink* quad_sink, content_rect_, clip_rect_, is_clipped_, - draw_opacity_); + draw_opacity_, + owning_layer_->blend_mode()); if (owning_layer_->ShowDebugBorders()) { SkColor color = for_replica ? @@ -228,7 +229,6 @@ void RenderSurfaceImpl::AppendQuads(QuadSink* quad_sink, contents_changed_since_last_frame, mask_uv_rect, owning_layer_->filters(), - owning_layer_->filter(), owning_layer_->background_filters()); quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); } diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h index f887a659394..c02a3194098 100644 --- a/chromium/cc/layers/render_surface_impl.h +++ b/chromium/cc/layers/render_surface_impl.h @@ -46,11 +46,11 @@ class CC_EXPORT RenderSurfaceImpl { void SetDrawOpacity(float opacity) { draw_opacity_ = opacity; } float draw_opacity() const { return draw_opacity_; } - void SetNearestAncestorThatMovesPixels(RenderSurfaceImpl* surface) { - nearest_ancestor_that_moves_pixels_ = surface; + void SetNearestOcclusionImmuneAncestor(RenderSurfaceImpl* surface) { + nearest_occlusion_immune_ancestor_ = surface; } - const RenderSurfaceImpl* nearest_ancestor_that_moves_pixels() const { - return nearest_ancestor_that_moves_pixels_; + const RenderSurfaceImpl* nearest_occlusion_immune_ancestor() const { + return nearest_occlusion_immune_ancestor_; } void SetDrawOpacityIsAnimating(bool draw_opacity_is_animating) { @@ -145,19 +145,19 @@ class CC_EXPORT RenderSurfaceImpl { // Uses this surface's space. gfx::Rect content_rect_; - bool surface_property_changed_; + bool surface_property_changed_ : 1; + bool draw_opacity_is_animating_ : 1; + bool target_surface_transforms_are_animating_ : 1; + bool screen_space_transforms_are_animating_ : 1; + + bool is_clipped_ : 1; + bool contributes_to_drawn_surface_ : 1; float draw_opacity_; - bool draw_opacity_is_animating_; gfx::Transform draw_transform_; gfx::Transform screen_space_transform_; gfx::Transform replica_draw_transform_; gfx::Transform replica_screen_space_transform_; - bool target_surface_transforms_are_animating_; - bool screen_space_transforms_are_animating_; - - bool is_clipped_; - bool contributes_to_drawn_surface_; // Uses the space of the surface's target surface. gfx::Rect clip_rect_; @@ -167,9 +167,8 @@ class CC_EXPORT RenderSurfaceImpl { contributing_delegated_render_pass_layer_list_; // The nearest ancestor target surface that will contain the contents of this - // surface, and that is going to move pixels within the surface (such as with - // a blur). This can point to itself. - RenderSurfaceImpl* nearest_ancestor_that_moves_pixels_; + // surface, and that ignores outside occlusion. This can point to itself. + RenderSurfaceImpl* nearest_occlusion_immune_ancestor_; scoped_ptr<DamageTracker> damage_tracker_; diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.cc b/chromium/cc/layers/scrollbar_layer_impl_base.cc index c1e7126ff52..362465be3b0 100644 --- a/chromium/cc/layers/scrollbar_layer_impl_base.cc +++ b/chromium/cc/layers/scrollbar_layer_impl_base.cc @@ -72,6 +72,13 @@ void ScrollbarLayerImplBase::SetVisibleToTotalLengthRatio(float ratio) { NoteLayerPropertyChanged(); } +void ScrollbarLayerImplBase::SetThumbThicknessScaleFactor(float factor) { + if (thumb_thickness_scale_factor_ == factor) + return; + thumb_thickness_scale_factor_ = factor; + NoteLayerPropertyChanged(); +} + gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const { // Thumb extent is the length of the thumb in the scrolling direction, thumb // thickness is in the perpendicular direction. Here's an example of a diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.h b/chromium/cc/layers/scrollbar_layer_impl_base.h index 55ade6ab04f..360ef970895 100644 --- a/chromium/cc/layers/scrollbar_layer_impl_base.h +++ b/chromium/cc/layers/scrollbar_layer_impl_base.h @@ -44,9 +44,7 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl { float thumb_thickness_scale_factor() { return thumb_thickness_scale_factor_; } - void set_thumb_thickness_scale_factor(float thumb_thickness_scale_factor) { - thumb_thickness_scale_factor_ = thumb_thickness_scale_factor; - } + void SetThumbThicknessScaleFactor(float thumb_thickness_scale_factor); protected: ScrollbarLayerImplBase(LayerTreeImpl* tree_impl, diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc index 2e1b4b6f483..53a9fa87b68 100644 --- a/chromium/cc/layers/scrollbar_layer_unittest.cc +++ b/chromium/cc/layers/scrollbar_layer_unittest.cc @@ -4,7 +4,6 @@ #include "base/containers/hash_tables.h" #include "cc/animation/scrollbar_animation_controller.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/layers/append_quads_data.h" #include "cc/layers/painted_scrollbar_layer.h" #include "cc/layers/painted_scrollbar_layer_impl.h" @@ -22,6 +21,7 @@ #include "cc/test/geometry_test_utils.h" #include "cc/test/layer_tree_test.h" #include "cc/test/mock_quad_culler.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_impl.h" #include "cc/trees/single_thread_proxy.h" @@ -364,7 +364,6 @@ class ScrollbarLayerSolidColorThumbTest : public testing::Test { public: ScrollbarLayerSolidColorThumbTest() { LayerTreeSettings layer_tree_settings; - layer_tree_settings.solid_color_scrollbars = true; host_impl_.reset(new FakeLayerTreeHostImpl(layer_tree_settings, &proxy_)); const int kThumbThickness = 3; @@ -513,13 +512,13 @@ TEST_F(ScrollbarLayerTestMaxTextureSize, DelegatingRenderer) { class MockLayerTreeHost : public LayerTreeHost { public: - MockLayerTreeHost(LayerTreeHostClient* client, + MockLayerTreeHost(FakeLayerTreeHostClient* client, const LayerTreeSettings& settings) - : LayerTreeHost(client, settings), + : LayerTreeHost(client, NULL, settings), next_id_(1), total_ui_resource_created_(0), total_ui_resource_deleted_(0) { - Initialize(NULL); + InitializeSingleThreaded(client); } virtual UIResourceId CreateUIResource(UIResourceClient* content) OVERRIDE { diff --git a/chromium/cc/layers/texture_layer.cc b/chromium/cc/layers/texture_layer.cc index a845709448f..5c954c140c2 100644 --- a/chromium/cc/layers/texture_layer.cc +++ b/chromium/cc/layers/texture_layer.cc @@ -14,7 +14,7 @@ #include "cc/trees/blocking_task_runner.h" #include "cc/trees/layer_tree_host.h" #include "third_party/khronos/GLES2/gl2.h" -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" +#include "third_party/khronos/GLES2/gl2ext.h" namespace cc { @@ -51,7 +51,7 @@ TextureLayer::~TextureLayer() { void TextureLayer::ClearClient() { if (rate_limit_context_ && client_ && layer_tree_host()) - layer_tree_host()->StopRateLimiter(client_->Context3d()); + layer_tree_host()->StopRateLimiter(); client_ = NULL; if (uses_mailbox_) SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>()); @@ -115,7 +115,7 @@ void TextureLayer::SetBlendBackgroundColor(bool blend) { void TextureLayer::SetRateLimitContext(bool rate_limit) { if (!rate_limit && rate_limit_context_ && client_ && layer_tree_host()) - layer_tree_host()->StopRateLimiter(client_->Context3d()); + layer_tree_host()->StopRateLimiter(); rate_limit_context_ = rate_limit; } @@ -133,9 +133,10 @@ void TextureLayer::SetTextureId(unsigned id) { SetNextCommitWaitsForActivation(); } -void TextureLayer::SetTextureMailbox( +void TextureLayer::SetTextureMailboxInternal( const TextureMailbox& mailbox, - scoped_ptr<SingleReleaseCallback> release_callback) { + scoped_ptr<SingleReleaseCallback> release_callback, + bool requires_commit) { DCHECK(uses_mailbox_); DCHECK(!mailbox.IsValid() || !holder_ref_ || !mailbox.Equals(holder_ref_->holder()->mailbox())); @@ -147,12 +148,26 @@ void TextureLayer::SetTextureMailbox( else holder_ref_.reset(); needs_set_mailbox_ = true; - SetNeedsCommit(); + // If we are within a commit, no need to do it again immediately after. + if (requires_commit) + SetNeedsCommit(); + else + SetNeedsPushProperties(); + // The active frame needs to be replaced and the mailbox returned before the // commit is called complete. SetNextCommitWaitsForActivation(); } +void TextureLayer::SetTextureMailbox( + const TextureMailbox& mailbox, + scoped_ptr<SingleReleaseCallback> release_callback) { + SetTextureMailboxInternal( + mailbox, + release_callback.Pass(), + true /* requires_commit */); +} + void TextureLayer::WillModifyTexture() { if (!uses_mailbox_ && layer_tree_host() && (DrawsContent() || content_committed_)) { @@ -165,7 +180,7 @@ void TextureLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) { Layer::SetNeedsDisplayRect(dirty_rect); if (rate_limit_context_ && client_ && layer_tree_host() && DrawsContent()) - layer_tree_host()->StartRateLimiter(client_->Context3d()); + layer_tree_host()->StartRateLimiter(); } void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) { @@ -182,7 +197,7 @@ void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) { SetNextCommitWaitsForActivation(); } if (rate_limit_context_ && client_) - layer_tree_host()->StopRateLimiter(client_->Context3d()); + layer_tree_host()->StopRateLimiter(); } // If we're removed from the tree, the TextureLayerImpl will be destroyed, and // we will need to set the mailbox again on a new TextureLayerImpl the next @@ -211,15 +226,15 @@ bool TextureLayer::Update(ResourceUpdateQueue* queue, &mailbox, &release_callback, layer_tree_host()->UsingSharedMemoryResources())) { - SetTextureMailbox(mailbox, release_callback.Pass()); + // Already within a commit, no need to do another one immediately. + SetTextureMailboxInternal( + mailbox, + release_callback.Pass(), + false /* requires_commit */); updated = true; } } else { texture_id_ = client_->PrepareTexture(); - DCHECK_EQ(!!texture_id_, !!client_->Context3d()); - if (client_->Context3d() && - client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR) - texture_id_ = 0; updated = true; SetNeedsPushProperties(); // The texture id needs to be removed from the active tree before the @@ -270,10 +285,6 @@ Region TextureLayer::VisibleContentOpaqueRegion() const { return Region(); } -bool TextureLayer::CanClipSelf() const { - return true; -} - TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference( MailboxHolder* holder) : holder_(holder) { diff --git a/chromium/cc/layers/texture_layer.h b/chromium/cc/layers/texture_layer.h index 5fb214c2c13..5f137724b23 100644 --- a/chromium/cc/layers/texture_layer.h +++ b/chromium/cc/layers/texture_layer.h @@ -13,8 +13,6 @@ #include "cc/layers/layer.h" #include "cc/resources/texture_mailbox.h" -namespace WebKit { class WebGraphicsContext3D; } - namespace cc { class BlockingTaskRunner; class SingleReleaseCallback; @@ -143,13 +141,16 @@ class CC_EXPORT TextureLayer : public Layer { virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; virtual Region VisibleContentOpaqueRegion() const OVERRIDE; - virtual bool CanClipSelf() const OVERRIDE; - protected: TextureLayer(TextureLayerClient* client, bool uses_mailbox); virtual ~TextureLayer(); private: + void SetTextureMailboxInternal( + const TextureMailbox& mailbox, + scoped_ptr<SingleReleaseCallback> release_callback, + bool requires_commit); + TextureLayerClient* client_; bool uses_mailbox_; diff --git a/chromium/cc/layers/texture_layer_client.h b/chromium/cc/layers/texture_layer_client.h index 187b12f16c4..47d6ae0e174 100644 --- a/chromium/cc/layers/texture_layer_client.h +++ b/chromium/cc/layers/texture_layer_client.h @@ -7,8 +7,6 @@ #include "cc/resources/single_release_callback.h" -namespace WebKit { class WebGraphicsContext3D; } - namespace cc { class ResourceUpdateQueue; class TextureMailbox; @@ -19,10 +17,6 @@ class TextureLayerClient { // Returns the texture ID to be used for compositing. virtual unsigned PrepareTexture() = 0; - // Returns the context that is providing the texture. Used for rate limiting - // and detecting lost context. - virtual WebKit::WebGraphicsContext3D* Context3d() = 0; - // Returns true and provides a mailbox if a new frame is available. // Returns false if no new data is available // and the old mailbox is to be reused. diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc index e16fd3c3f18..96b44c75792 100644 --- a/chromium/cc/layers/texture_layer_impl.cc +++ b/chromium/cc/layers/texture_layer_impl.cc @@ -66,6 +66,7 @@ void TextureLayerImpl::PushPropertiesTo(LayerImpl* layer) { texture_layer->set_uv_bottom_right(uv_bottom_right_); texture_layer->set_vertex_opacity(vertex_opacity_); texture_layer->set_premultiplied_alpha(premultiplied_alpha_); + texture_layer->set_blend_background_color(blend_background_color_); if (uses_mailbox_ && own_mailbox_) { texture_layer->SetTextureMailbox(texture_mailbox_, release_callback_.Pass()); @@ -104,7 +105,7 @@ bool TextureLayerImpl::WillDraw(DrawMode draw_mode, // Have to upload a copy to a texture for it to be used in a // hardware draw. if (!texture_copy_) - texture_copy_ = ScopedResource::create(resource_provider); + texture_copy_ = ScopedResource::Create(resource_provider); if (texture_copy_->size() != texture_mailbox_.shared_memory_size() || resource_provider->InUseByConsumer(texture_copy_->id())) texture_copy_->Free(); @@ -183,12 +184,7 @@ void TextureLayerImpl::AppendQuads(QuadSink* quad_sink, bg_color, vertex_opacity_, flipped_); - - // Perform explicit clipping on a quad to avoid setting a scissor later. - if (shared_quad_state->is_clipped && quad->PerformClipping()) - shared_quad_state->is_clipped = false; - if (!quad->rect.IsEmpty()) - quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); + quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); } void TextureLayerImpl::DidDraw(ResourceProvider* resource_provider) { @@ -229,10 +225,6 @@ const char* TextureLayerImpl::LayerTypeAsString() const { return "cc::TextureLayerImpl"; } -bool TextureLayerImpl::CanClipSelf() const { - return true; -} - void TextureLayerImpl::FreeTextureMailbox() { if (!uses_mailbox_) return; diff --git a/chromium/cc/layers/texture_layer_impl.h b/chromium/cc/layers/texture_layer_impl.h index 90c26923c8e..c20d9604387 100644 --- a/chromium/cc/layers/texture_layer_impl.h +++ b/chromium/cc/layers/texture_layer_impl.h @@ -60,8 +60,6 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl { vertex_opacity_[3] = vertex_opacity[3]; } - virtual bool CanClipSelf() const OVERRIDE; - void SetTextureMailbox(const TextureMailbox& mailbox, scoped_ptr<SingleReleaseCallback> release_callback); diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc index 239c5b8fa22..3ae0c2944cd 100644 --- a/chromium/cc/layers/texture_layer_unittest.cc +++ b/chromium/cc/layers/texture_layer_unittest.cc @@ -12,7 +12,6 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "base/time/time.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/layers/solid_color_layer.h" #include "cc/layers/texture_layer_client.h" #include "cc/layers/texture_layer_impl.h" @@ -25,6 +24,7 @@ #include "cc/test/fake_output_surface.h" #include "cc/test/layer_test_common.h" #include "cc/test/layer_tree_test.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "cc/trees/blocking_task_runner.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_impl.h" @@ -43,16 +43,16 @@ namespace { class MockLayerTreeHost : public LayerTreeHost { public: - explicit MockLayerTreeHost(LayerTreeHostClient* client) - : LayerTreeHost(client, LayerTreeSettings()) { - Initialize(NULL); + explicit MockLayerTreeHost(FakeLayerTreeHostClient* client) + : LayerTreeHost(client, NULL, LayerTreeSettings()) { + InitializeSingleThreaded(client); } MOCK_METHOD0(AcquireLayerTextures, void()); MOCK_METHOD0(SetNeedsCommit, void()); MOCK_METHOD0(SetNeedsUpdateLayers, void()); - MOCK_METHOD1(StartRateLimiter, void(WebKit::WebGraphicsContext3D* context)); - MOCK_METHOD1(StopRateLimiter, void(WebKit::WebGraphicsContext3D* context)); + MOCK_METHOD0(StartRateLimiter, void()); + MOCK_METHOD0(StopRateLimiter, void()); }; class TextureLayerTest : public testing::Test { @@ -245,16 +245,12 @@ TEST_F(TextureLayerTest, VisibleContentOpaqueRegion) { class FakeTextureLayerClient : public TextureLayerClient { public: - FakeTextureLayerClient() : context_(TestWebGraphicsContext3D::Create()) {} + FakeTextureLayerClient() {} virtual unsigned PrepareTexture() OVERRIDE { return 0; } - virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE { - return context_.get(); - } - virtual bool PrepareTextureMailbox( TextureMailbox* mailbox, scoped_ptr<SingleReleaseCallback>* release_callback, @@ -265,7 +261,6 @@ class FakeTextureLayerClient : public TextureLayerClient { } private: - scoped_ptr<TestWebGraphicsContext3D> context_; DISALLOW_COPY_AND_ASSIGN(FakeTextureLayerClient); }; @@ -278,23 +273,23 @@ TEST_F(TextureLayerTest, RateLimiter) { layer_tree_host_->SetRootLayer(test_layer); // Don't rate limit until we invalidate. - EXPECT_CALL(*layer_tree_host_, StartRateLimiter(_)).Times(0); + EXPECT_CALL(*layer_tree_host_, StartRateLimiter()).Times(0); test_layer->SetRateLimitContext(true); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); // Do rate limit after we invalidate. - EXPECT_CALL(*layer_tree_host_, StartRateLimiter(client.Context3d())); + EXPECT_CALL(*layer_tree_host_, StartRateLimiter()); test_layer->SetNeedsDisplay(); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); // Stop rate limiter when we don't want it any more. - EXPECT_CALL(*layer_tree_host_, StopRateLimiter(client.Context3d())); + EXPECT_CALL(*layer_tree_host_, StopRateLimiter()); test_layer->SetRateLimitContext(false); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); // Or we clear the client. test_layer->SetRateLimitContext(true); - EXPECT_CALL(*layer_tree_host_, StopRateLimiter(client.Context3d())); + EXPECT_CALL(*layer_tree_host_, StopRateLimiter()); EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber()); test_layer->ClearClient(); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); @@ -306,14 +301,14 @@ TEST_F(TextureLayerTest, RateLimiter) { test_layer->SetRateLimitContext(true); EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber()); layer_tree_host_->SetRootLayer(test_layer); - EXPECT_CALL(*layer_tree_host_, StartRateLimiter(_)).Times(0); + EXPECT_CALL(*layer_tree_host_, StartRateLimiter()).Times(0); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - EXPECT_CALL(*layer_tree_host_, StartRateLimiter(client.Context3d())); + EXPECT_CALL(*layer_tree_host_, StartRateLimiter()); test_layer->SetNeedsDisplay(); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); // Stop rate limiter when we're removed from the tree. - EXPECT_CALL(*layer_tree_host_, StopRateLimiter(client.Context3d())); + EXPECT_CALL(*layer_tree_host_, StopRateLimiter()); layer_tree_host_->SetRootLayer(NULL); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); } @@ -892,7 +887,8 @@ class TextureLayerNoMailboxIsActivatedDuringCommit : public LayerTreeTest, protected: TextureLayerNoMailboxIsActivatedDuringCommit() : wait_thread_("WAIT"), - wait_event_(false, false) { + wait_event_(false, false), + texture_(0u) { wait_thread_.Start(); } @@ -916,13 +912,16 @@ class TextureLayerNoMailboxIsActivatedDuringCommit : public LayerTreeTest, PostSetNeedsCommitToMainThread(); } + virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) + OVERRIDE { + scoped_refptr<TestContextProvider> provider = TestContextProvider::Create(); + texture_ = provider->UnboundTestContext3d()->createExternalTexture(); + return FakeOutputSurface::Create3d(provider).PassAs<OutputSurface>(); + } + // TextureLayerClient implementation. virtual unsigned PrepareTexture() OVERRIDE { - return OffscreenContextProviderForMainThread() - ->Context3d()->createTexture(); - } - virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE { - return OffscreenContextProviderForMainThread()->Context3d(); + return texture_; } virtual bool PrepareTextureMailbox( TextureMailbox* mailbox, @@ -1001,8 +1000,8 @@ class TextureLayerNoMailboxIsActivatedDuringCommit : public LayerTreeTest, base::Thread wait_thread_; base::WaitableEvent wait_event_; base::Lock activate_lock_; + unsigned texture_; int activate_count_; - int activate_commit_; scoped_refptr<Layer> root_; scoped_refptr<TextureLayer> layer_; }; @@ -1166,6 +1165,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { { scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, true); + impl_layer->SetDrawsContent(true); impl_layer->SetTextureMailbox( test_data_.mailbox1_, SingleReleaseCallback::Create(test_data_.release_mailbox1_)); @@ -1175,6 +1175,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { { scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, true); + impl_layer->SetDrawsContent(true); impl_layer->SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>()); EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE)); @@ -1184,6 +1185,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { // Software resource. scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, true); + impl_layer->SetDrawsContent(true); impl_layer->SetTextureMailbox( test_data_.mailbox3_, SingleReleaseCallback::Create(test_data_.release_mailbox3_)); @@ -1193,6 +1195,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { { scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, false); + impl_layer->SetDrawsContent(true); ContextProvider* context_provider = host_impl_.output_surface()->context_provider(); unsigned texture = @@ -1204,6 +1207,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { { scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, false); + impl_layer->SetDrawsContent(true); impl_layer->set_texture_id(0); EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE)); } @@ -1212,6 +1216,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { { scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, true); + impl_layer->SetDrawsContent(true); impl_layer->SetTextureMailbox( test_data_.mailbox1_, SingleReleaseCallback::Create(test_data_.release_mailbox1_)); @@ -1221,6 +1226,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { { scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, true); + impl_layer->SetDrawsContent(true); impl_layer->SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>()); EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE)); @@ -1230,6 +1236,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { // Software resource. scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, true); + impl_layer->SetDrawsContent(true); impl_layer->SetTextureMailbox( test_data_.mailbox3_, SingleReleaseCallback::Create(test_data_.release_mailbox3_)); @@ -1239,6 +1246,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { { scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, false); + impl_layer->SetDrawsContent(true); ContextProvider* context_provider = host_impl_.output_surface()->context_provider(); unsigned texture = @@ -1250,6 +1258,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { { scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, false); + impl_layer->SetDrawsContent(true); impl_layer->set_texture_id(0); EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE)); } @@ -1258,6 +1267,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { { scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, true); + impl_layer->SetDrawsContent(true); impl_layer->SetTextureMailbox( test_data_.mailbox1_, SingleReleaseCallback::Create(test_data_.release_mailbox1_)); @@ -1267,6 +1277,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) { { scoped_ptr<TextureLayerImpl> impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, false); + impl_layer->SetDrawsContent(true); ContextProvider* context_provider = host_impl_.output_surface()->context_provider(); unsigned texture = @@ -1351,6 +1362,7 @@ TEST_F(TextureLayerImplWithMailboxTest, impl_layer->SetTextureMailbox( test_data_.mailbox1_, SingleReleaseCallback::Create(test_data_.release_mailbox1_)); + impl_layer->SetDrawsContent(true); impl_layer->DidBecomeActive(); EXPECT_TRUE(impl_layer->WillDraw( DRAW_MODE_HARDWARE, host_impl_.active_tree()->resource_provider())); @@ -1391,28 +1403,19 @@ class TextureLayerClientTest public TextureLayerClient { public: TextureLayerClientTest() - : context_(NULL), - texture_(0), + : texture_(0), commit_count_(0), expected_used_textures_on_draw_(0), expected_used_textures_on_commit_(0) {} virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) OVERRIDE { - scoped_ptr<TestWebGraphicsContext3D> context( - TestWebGraphicsContext3D::Create()); - context_ = context.get(); - texture_ = context->createTexture(); - return FakeOutputSurface::Create3d(context.Pass()).PassAs<OutputSurface>(); + scoped_refptr<TestContextProvider> provider = TestContextProvider::Create(); + texture_ = provider->UnboundTestContext3d()->createExternalTexture(); + return FakeOutputSurface::Create3d(provider).PassAs<OutputSurface>(); } - virtual unsigned PrepareTexture() OVERRIDE { - return texture_; - } - - virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE { - return context_; - } + virtual unsigned PrepareTexture() OVERRIDE { return texture_; } virtual bool PrepareTextureMailbox( TextureMailbox* mailbox, @@ -1455,7 +1458,6 @@ class TextureLayerClientTest base::AutoLock lock(lock_); expected_used_textures_on_commit_ = 0; } - texture_ = 0; break; case 2: EndTest(); @@ -1474,21 +1476,26 @@ class TextureLayerClientTest virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, LayerTreeHostImpl::FrameData* frame_data, bool result) OVERRIDE { - context_->ResetUsedTextures(); + ContextForImplThread(host_impl)->ResetUsedTextures(); return true; } virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) OVERRIDE { ASSERT_TRUE(result); - EXPECT_EQ(expected_used_textures_on_draw_, context_->NumUsedTextures()); + EXPECT_EQ(expected_used_textures_on_draw_, + ContextForImplThread(host_impl)->NumUsedTextures()); } virtual void AfterTest() OVERRIDE {} private: + TestWebGraphicsContext3D* ContextForImplThread(LayerTreeHostImpl* host_impl) { + return static_cast<TestWebGraphicsContext3D*>( + host_impl->output_surface()->context_provider()->Context3d()); + } + scoped_refptr<TextureLayer> texture_layer_; - TestWebGraphicsContext3D* context_; unsigned texture_; int commit_count_; @@ -1513,27 +1520,25 @@ class TextureLayerChangeInvisibleTest public TextureLayerClient { public: TextureLayerChangeInvisibleTest() - : client_context_(TestWebGraphicsContext3D::Create()), - texture_(client_context_->createTexture()), - texture_to_delete_on_next_commit_(0), + : texture_(0u), prepare_called_(0), commit_count_(0), expected_texture_on_draw_(0) {} + virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) + OVERRIDE { + scoped_refptr<TestContextProvider> provider = TestContextProvider::Create(); + texture_ = provider->UnboundTestContext3d()->createExternalTexture(); + return FakeOutputSurface::Create3d(provider).PassAs<OutputSurface>(); + } + // TextureLayerClient implementation. virtual unsigned PrepareTexture() OVERRIDE { ++prepare_called_; return texture_; } - - // TextureLayerClient implementation. - virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE { - return client_context_.get(); - } - - // TextureLayerClient implementation. virtual bool PrepareTextureMailbox( - cc::TextureMailbox* mailbox, + TextureMailbox* mailbox, scoped_ptr<SingleReleaseCallback>* release_callback, bool use_shared_memory) OVERRIDE { return false; @@ -1582,9 +1587,6 @@ class TextureLayerChangeInvisibleTest case 2: { // Layer shouldn't have been updated. EXPECT_EQ(1, prepare_called_); - // Change the texture. - texture_to_delete_on_next_commit_ = texture_; - texture_ = client_context_->createTexture(); texture_layer_->SetNeedsDisplay(); // Force a change to make sure we draw a frame. solid_layer_->SetBackgroundColor(SK_ColorGRAY); @@ -1592,8 +1594,6 @@ class TextureLayerChangeInvisibleTest } case 3: EXPECT_EQ(1, prepare_called_); - client_context_->deleteTexture(texture_to_delete_on_next_commit_); - texture_to_delete_on_next_commit_ = 0; // Make layer visible again. parent_layer_->SetOpacity(1.f); break; @@ -1601,7 +1601,6 @@ class TextureLayerChangeInvisibleTest // Layer should have been updated. EXPECT_EQ(2, prepare_called_); texture_layer_->ClearClient(); - client_context_->deleteTexture(texture_); texture_ = 0; break; } @@ -1661,14 +1660,12 @@ class TextureLayerChangeInvisibleTest scoped_refptr<SolidColorLayer> solid_layer_; scoped_refptr<Layer> parent_layer_; scoped_refptr<TextureLayer> texture_layer_; - scoped_ptr<TestWebGraphicsContext3D> client_context_; // Used on the main thread, and on the impl thread while the main thread is // blocked. unsigned texture_; // Used on the main thread. - unsigned texture_to_delete_on_next_commit_; int prepare_called_; int commit_count_; @@ -1680,6 +1677,114 @@ class TextureLayerChangeInvisibleTest // delegating renderer. SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerChangeInvisibleTest); +// Checks that TextureLayer::Update does not cause an extra commit when setting +// the texture mailbox. +class TextureLayerNoExtraCommitForMailboxTest + : public LayerTreeTest, + public TextureLayerClient { + public: + // TextureLayerClient implementation. + virtual unsigned PrepareTexture() OVERRIDE { + NOTREACHED(); + return 0; + } + virtual bool PrepareTextureMailbox( + TextureMailbox* mailbox, + scoped_ptr<SingleReleaseCallback>* release_callback, + bool use_shared_memory) OVERRIDE { + if (layer_tree_host()->source_frame_number() == 1) { + *mailbox = TextureMailbox(); + return true; + } + + *mailbox = TextureMailbox(std::string(64, '1')); + *release_callback = SingleReleaseCallback::Create( + base::Bind(&TextureLayerNoExtraCommitForMailboxTest::MailboxReleased, + base::Unretained(this))); + return true; + } + + void MailboxReleased(unsigned sync_point, bool lost_resource) { + EXPECT_EQ(2, layer_tree_host()->source_frame_number()); + EndTest(); + } + + virtual void SetupTree() OVERRIDE { + scoped_refptr<Layer> root = Layer::Create(); + root->SetBounds(gfx::Size(10, 10)); + root->SetAnchorPoint(gfx::PointF()); + root->SetIsDrawable(true); + + solid_layer_ = SolidColorLayer::Create(); + solid_layer_->SetBounds(gfx::Size(10, 10)); + solid_layer_->SetIsDrawable(true); + solid_layer_->SetBackgroundColor(SK_ColorWHITE); + root->AddChild(solid_layer_); + + parent_layer_ = Layer::Create(); + parent_layer_->SetBounds(gfx::Size(10, 10)); + parent_layer_->SetIsDrawable(true); + root->AddChild(parent_layer_); + + texture_layer_ = TextureLayer::CreateForMailbox(this); + texture_layer_->SetBounds(gfx::Size(10, 10)); + texture_layer_->SetAnchorPoint(gfx::PointF()); + texture_layer_->SetIsDrawable(true); + parent_layer_->AddChild(texture_layer_); + + layer_tree_host()->SetRootLayer(root); + LayerTreeTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { + PostSetNeedsCommitToMainThread(); + } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + switch (layer_tree_host()->source_frame_number()) { + case 1: + EXPECT_FALSE(proxy()->CommitPendingForTesting()); + // Invalidate the texture layer to clear the mailbox before + // ending the test. + texture_layer_->SetNeedsDisplay(); + break; + case 2: + break; + default: + NOTREACHED(); + break; + } + } + + virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, + bool result) OVERRIDE { + ASSERT_TRUE(result); + DelegatedFrameData* delegated_frame_data = + output_surface()->last_sent_frame().delegated_frame_data.get(); + if (!delegated_frame_data) + return; + + // Return all resources immediately. + TransferableResourceArray resources_to_return = + output_surface()->resources_held_by_parent(); + + CompositorFrameAck ack; + for (size_t i = 0; i < resources_to_return.size(); ++i) + output_surface()->ReturnResource(resources_to_return[i].id, &ack); + host_impl->ReclaimResources(&ack); + host_impl->OnSwapBuffersComplete(); + } + + virtual void AfterTest() OVERRIDE {} + + private: + scoped_refptr<SolidColorLayer> solid_layer_; + scoped_refptr<Layer> parent_layer_; + scoped_refptr<TextureLayer> texture_layer_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerNoExtraCommitForMailboxTest); + // Checks that changing a mailbox in the client for a TextureLayer that's // invisible correctly works and uses the new mailbox as soon as the layer // becomes visible (and returns the old one). @@ -1701,15 +1806,8 @@ class TextureLayerChangeInvisibleMailboxTest return 0; } - // TextureLayerClient implementation. - virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE { - NOTREACHED(); - return NULL; - } - - // TextureLayerClient implementation. virtual bool PrepareTextureMailbox( - cc::TextureMailbox* mailbox, + TextureMailbox* mailbox, scoped_ptr<SingleReleaseCallback>* release_callback, bool use_shared_memory) OVERRIDE { ++prepare_called_; @@ -1847,26 +1945,20 @@ class TextureLayerLostContextTest public TextureLayerClient { public: TextureLayerLostContextTest() - : texture_(0), + : context_lost_(false), draw_count_(0) {} virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) OVERRIDE { - texture_context_ = TestWebGraphicsContext3D::Create(); - texture_ = texture_context_->createTexture(); return CreateFakeOutputSurface(); } virtual unsigned PrepareTexture() OVERRIDE { - if (draw_count_ == 0) { - texture_context_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, - GL_INNOCENT_CONTEXT_RESET_ARB); - } - return texture_; - } - - virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE { - return texture_context_.get(); + if (draw_count_ == 0) + context_lost_ = true; + if (context_lost_) + return 0u; + return 1u; } virtual bool PrepareTextureMailbox( @@ -1903,7 +1995,7 @@ class TextureLayerLostContextTest if (++draw_count_ == 1) EXPECT_EQ(0u, texture_layer->texture_id()); else - EXPECT_EQ(texture_, texture_layer->texture_id()); + EXPECT_EQ(1u, texture_layer->texture_id()); return true; } @@ -1915,8 +2007,7 @@ class TextureLayerLostContextTest private: scoped_refptr<TextureLayer> texture_layer_; - scoped_ptr<TestWebGraphicsContext3D> texture_context_; - unsigned texture_; + bool context_lost_; int draw_count_; }; diff --git a/chromium/cc/layers/tiled_layer.cc b/chromium/cc/layers/tiled_layer.cc index 8bbf2271bc4..24baef526eb 100644 --- a/chromium/cc/layers/tiled_layer.cc +++ b/chromium/cc/layers/tiled_layer.cc @@ -334,8 +334,10 @@ bool TiledLayer::UpdateTiles(int left, return false; } - gfx::Rect paint_rect = - MarkTilesForUpdate(left, top, right, bottom, ignore_occlusions); + gfx::Rect update_rect; + gfx::Rect paint_rect; + MarkTilesForUpdate( + &update_rect, &paint_rect, left, top, right, bottom, ignore_occlusions); if (occlusion) occlusion->overdraw_metrics()->DidPaint(paint_rect); @@ -345,7 +347,7 @@ bool TiledLayer::UpdateTiles(int left, *updated = true; UpdateTileTextures( - paint_rect, left, top, right, bottom, queue, occlusion); + update_rect, paint_rect, left, top, right, bottom, queue, occlusion); return true; } @@ -378,10 +380,7 @@ void TiledLayer::MarkOcclusionsAndRequestTextures( if (occlusion && occlusion->Occluded(render_target(), visible_tile_rect, draw_transform(), - draw_transform_is_animating(), - is_clipped(), - clip_rect(), - NULL)) { + draw_transform_is_animating())) { tile->occluded = true; occluded_tile_count++; } else { @@ -425,12 +424,13 @@ bool TiledLayer::HaveTexturesForTiles(int left, return true; } -gfx::Rect TiledLayer::MarkTilesForUpdate(int left, - int top, - int right, - int bottom, - bool ignore_occlusions) { - gfx::Rect paint_rect; +void TiledLayer::MarkTilesForUpdate(gfx::Rect* update_rect, + gfx::Rect* paint_rect, + int left, + int top, + int right, + int bottom, + bool ignore_occlusions) { for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { UpdatableTile* tile = TileAt(i, j); @@ -440,10 +440,14 @@ gfx::Rect TiledLayer::MarkTilesForUpdate(int left, continue; if (tile->occluded && !ignore_occlusions) continue; + + // Prepare update rect from original dirty rects. + update_rect->Union(tile->dirty_rect); + // TODO(reveman): Decide if partial update should be allowed based on cost // of update. https://bugs.webkit.org/show_bug.cgi?id=77376 - if (tile->is_dirty() && layer_tree_host() && - layer_tree_host()->buffered_updates()) { + if (tile->is_dirty() && + !layer_tree_host()->AlwaysUsePartialTextureUpdates()) { // If we get a partial update, we use the same texture, otherwise return // the current texture backing, so we don't update visible textures // non-atomically. If the current backing is in-use, it won't be @@ -458,14 +462,14 @@ gfx::Rect TiledLayer::MarkTilesForUpdate(int left, } } - paint_rect.Union(tile->dirty_rect); + paint_rect->Union(tile->dirty_rect); tile->MarkForUpdate(); } } - return paint_rect; } -void TiledLayer::UpdateTileTextures(gfx::Rect paint_rect, +void TiledLayer::UpdateTileTextures(gfx::Rect update_rect, + gfx::Rect paint_rect, int left, int top, int right, @@ -480,7 +484,7 @@ void TiledLayer::UpdateTileTextures(gfx::Rect paint_rect, float height_scale = paint_properties().bounds.height() / static_cast<float>(content_bounds().height()); - update_rect_ = gfx::ScaleRect(paint_rect, width_scale, height_scale); + update_rect_ = gfx::ScaleRect(update_rect, width_scale, height_scale); // Calling PrepareToUpdate() calls into WebKit to paint, which may have the // side effect of disabling compositing, which causes our reference to the @@ -853,6 +857,19 @@ bool TiledLayer::Update(ResourceUpdateQueue* queue, return updated; } +void TiledLayer::OnOutputSurfaceCreated() { + // Ensure that all textures are of the right format. + for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin(); + iter != tiler_->tiles().end(); + ++iter) { + UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); + if (!tile) + continue; + PrioritizedResource* resource = tile->managed_resource(); + resource->SetDimensions(resource->size(), texture_format_); + } +} + bool TiledLayer::NeedsIdlePaint() { // Don't trigger more paints if we failed (as we'll just fail again). if (failed_update_ || visible_content_rect().IsEmpty() || diff --git a/chromium/cc/layers/tiled_layer.h b/chromium/cc/layers/tiled_layer.h index 3870d69956b..82063600c71 100644 --- a/chromium/cc/layers/tiled_layer.h +++ b/chromium/cc/layers/tiled_layer.h @@ -36,6 +36,7 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer { virtual Region VisibleContentOpaqueRegion() const OVERRIDE; virtual bool Update(ResourceUpdateQueue* queue, const OcclusionTracker* occlusion) OVERRIDE; + virtual void OnOutputSurfaceCreated() OVERRIDE; protected: TiledLayer(); @@ -102,12 +103,15 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer { int right, int bottom, bool ignore_occlusions); - gfx::Rect MarkTilesForUpdate(int left, - int top, - int right, - int bottom, - bool ignore_occlusions); - void UpdateTileTextures(gfx::Rect paint_rect, + void MarkTilesForUpdate(gfx::Rect* update_rect, + gfx::Rect* paint_rect, + int left, + int top, + int right, + int bottom, + bool ignore_occlusions); + void UpdateTileTextures(gfx::Rect update_rect, + gfx::Rect paint_rect, int left, int top, int right, diff --git a/chromium/cc/layers/tiled_layer_impl.cc b/chromium/cc/layers/tiled_layer_impl.cc index e3852129da4..88797c224dd 100644 --- a/chromium/cc/layers/tiled_layer_impl.cc +++ b/chromium/cc/layers/tiled_layer_impl.cc @@ -21,17 +21,12 @@ namespace cc { -// Temporary diagnostic. -static bool s_safe_to_delete_drawable_tile = false; - class DrawableTile : public LayerTilingData::Tile { public: static scoped_ptr<DrawableTile> Create() { return make_scoped_ptr(new DrawableTile()); } - virtual ~DrawableTile() { CHECK(s_safe_to_delete_drawable_tile); } - ResourceProvider::ResourceId resource_id() const { return resource_id_; } void set_resource_id(ResourceProvider::ResourceId resource_id) { resource_id_ = resource_id; @@ -54,10 +49,6 @@ TiledLayerImpl::TiledLayerImpl(LayerTreeImpl* tree_impl, int id) : LayerImpl(tree_impl, id), skips_draw_(true) {} TiledLayerImpl::~TiledLayerImpl() { - s_safe_to_delete_drawable_tile = true; - if (tiler_) - tiler_->reset(); - s_safe_to_delete_drawable_tile = false; } ResourceProvider::ResourceId TiledLayerImpl::ContentsResourceId() const { @@ -88,10 +79,6 @@ DrawableTile* TiledLayerImpl::CreateTile(int i, int j) { DrawableTile* added_tile = tile.get(); tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j); - // Temporary diagnostic checks. - CHECK(added_tile); - CHECK(TileAt(i, j)); - return added_tile; } @@ -232,8 +219,9 @@ void TiledLayerImpl::AppendQuads(QuadSink* quad_sink, continue; } - gfx::Rect tile_opaque_rect = contents_opaque() ? tile_rect : - gfx::IntersectRects(tile->opaque_rect(), content_rect); + gfx::Rect tile_opaque_rect = + contents_opaque() ? tile_rect : gfx::IntersectRects( + tile->opaque_rect(), tile_rect); // Keep track of how the top left has moved, so the texture can be // offset the same amount. @@ -260,8 +248,6 @@ void TiledLayerImpl::AppendQuads(QuadSink* quad_sink, } void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) { - s_safe_to_delete_drawable_tile = true; - if (tiler_) { tiler_->reset(); } else { @@ -271,8 +257,6 @@ void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) { : LayerTilingData::NO_BORDER_TEXELS); } *tiler_ = tiler; - - s_safe_to_delete_drawable_tile = false; } void TiledLayerImpl::PushTileProperties( @@ -307,11 +291,7 @@ Region TiledLayerImpl::VisibleContentOpaqueRegion() const { } void TiledLayerImpl::DidLoseOutputSurface() { - s_safe_to_delete_drawable_tile = true; - // Temporary diagnostic check. - CHECK(tiler_); tiler_->reset(); - s_safe_to_delete_drawable_tile = false; } const char* TiledLayerImpl::LayerTypeAsString() const { diff --git a/chromium/cc/layers/tiled_layer_impl_unittest.cc b/chromium/cc/layers/tiled_layer_impl_unittest.cc index 42913ef70b7..801cbf4dc27 100644 --- a/chromium/cc/layers/tiled_layer_impl_unittest.cc +++ b/chromium/cc/layers/tiled_layer_impl_unittest.cc @@ -52,11 +52,15 @@ class TiledLayerImplTest : public testing::Test { scoped_ptr<TiledLayerImpl> layer = CreateLayerNoTiles(tile_size, layer_size, border_texels); + layer->SetDrawsContent(true); + ResourceProvider::ResourceId resource_id = 1; for (int i = 0; i < layer->TilingForTesting()->num_tiles_x(); ++i) { for (int j = 0; j < layer->TilingForTesting()->num_tiles_y(); ++j) { - layer->PushTileProperties( - i, j, resource_id++, gfx::Rect(0, 0, 1, 1), false); + gfx::Rect opaque_rect( + layer->TilingForTesting()->tile_bounds(i, j).origin(), + gfx::Size(1, 1)); + layer->PushTileProperties(i, j, resource_id++, opaque_rect, false); } } @@ -266,7 +270,7 @@ TEST_F(TiledLayerImplTest, TextureInfoForLayerNoBorders) { << LayerTestCommon::quad_string << i; EXPECT_EQ(tile_size, quad->texture_size) << LayerTestCommon::quad_string << i; - EXPECT_EQ(gfx::Rect(0, 0, 1, 1), quad->opaque_rect) + EXPECT_EQ(gfx::Size(1, 1).ToString(), quad->opaque_rect.size().ToString()) << LayerTestCommon::quad_string << i; } } diff --git a/chromium/cc/layers/tiled_layer_unittest.cc b/chromium/cc/layers/tiled_layer_unittest.cc index b6da0769f95..42ef29cc93e 100644 --- a/chromium/cc/layers/tiled_layer_unittest.cc +++ b/chromium/cc/layers/tiled_layer_unittest.cc @@ -50,18 +50,23 @@ class TiledLayerTest : public testing::Test { : proxy_(NULL), output_surface_(FakeOutputSurface::Create3d()), queue_(make_scoped_ptr(new ResourceUpdateQueue)), - fake_layer_impl_tree_host_client_(FakeLayerTreeHostClient::DIRECT_3D), + impl_thread_("ImplThread"), + fake_layer_tree_host_client_(FakeLayerTreeHostClient::DIRECT_3D), occlusion_(NULL) { settings_.max_partial_texture_updates = std::numeric_limits<size_t>::max(); settings_.layer_transforms_should_scale_layer_contents = true; } virtual void SetUp() { - layer_tree_host_ = LayerTreeHost::Create(&fake_layer_impl_tree_host_client_, - settings_, - NULL); + impl_thread_.Start(); + layer_tree_host_ = LayerTreeHost::CreateThreaded( + &fake_layer_tree_host_client_, + NULL, + settings_, + impl_thread_.message_loop_proxy()); proxy_ = layer_tree_host_->proxy(); resource_manager_ = PrioritizedResourceManager::Create(proxy_); + layer_tree_host_->SetLayerTreeHostClientReady(); layer_tree_host_->InitializeOutputSurfaceIfNeeded(); layer_tree_host_->SetRootLayer(Layer::Create()); @@ -70,7 +75,7 @@ class TiledLayerTest : public testing::Test { DebugScopedSetImplThreadAndMainThreadBlocked impl_thread_and_main_thread_blocked(proxy_); resource_provider_ = - ResourceProvider::Create(output_surface_.get(), 0, false); + ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1); host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(proxy_)); } @@ -192,7 +197,8 @@ class TiledLayerTest : public testing::Test { scoped_ptr<ResourceProvider> resource_provider_; scoped_ptr<ResourceUpdateQueue> queue_; PriorityCalculator priority_calculator_; - FakeLayerTreeHostClient fake_layer_impl_tree_host_client_; + base::Thread impl_thread_; + FakeLayerTreeHostClient fake_layer_tree_host_client_; scoped_ptr<LayerTreeHost> layer_tree_host_; scoped_ptr<FakeLayerTreeHostImpl> host_impl_; scoped_ptr<PrioritizedResourceManager> resource_manager_; diff --git a/chromium/cc/layers/ui_resource_layer.cc b/chromium/cc/layers/ui_resource_layer.cc new file mode 100644 index 00000000000..09b8d9af4cc --- /dev/null +++ b/chromium/cc/layers/ui_resource_layer.cc @@ -0,0 +1,165 @@ +// Copyright 2013 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 "cc/layers/ui_resource_layer.h" + +#include "cc/layers/ui_resource_layer_impl.h" +#include "cc/resources/prioritized_resource.h" +#include "cc/resources/resource_update.h" +#include "cc/resources/resource_update_queue.h" +#include "cc/resources/scoped_ui_resource.h" +#include "cc/resources/ui_resource_bitmap.h" +#include "cc/trees/layer_tree_host.h" + +namespace cc { + + +namespace { + +class ScopedUIResourceHolder : public UIResourceLayer::UIResourceHolder { + public: + static scoped_ptr<ScopedUIResourceHolder> Create(LayerTreeHost* host, + const SkBitmap& skbitmap) { + return make_scoped_ptr(new ScopedUIResourceHolder(host, skbitmap)); + } + virtual UIResourceId id() OVERRIDE { return resource_->id(); } + + private: + ScopedUIResourceHolder(LayerTreeHost* host, const SkBitmap& skbitmap) { + resource_ = ScopedUIResource::Create(host, UIResourceBitmap(skbitmap)); + } + + scoped_ptr<ScopedUIResource> resource_; +}; + +class SharedUIResourceHolder : public UIResourceLayer::UIResourceHolder { + public: + static scoped_ptr<SharedUIResourceHolder> Create(UIResourceId id) { + return make_scoped_ptr(new SharedUIResourceHolder(id)); + } + + virtual UIResourceId id() OVERRIDE { return id_; } + + private: + explicit SharedUIResourceHolder(UIResourceId id) : id_(id) {} + + UIResourceId id_; +}; + +} // anonymous namespace + +UIResourceLayer::UIResourceHolder::~UIResourceHolder() {} + +scoped_refptr<UIResourceLayer> UIResourceLayer::Create() { + return make_scoped_refptr(new UIResourceLayer()); +} + +UIResourceLayer::UIResourceLayer() + : Layer(), + uv_top_left_(0.f, 0.f), + uv_bottom_right_(1.f, 1.f) { + vertex_opacity_[0] = 1.0f; + vertex_opacity_[1] = 1.0f; + vertex_opacity_[2] = 1.0f; + vertex_opacity_[3] = 1.0f; +} + +UIResourceLayer::~UIResourceLayer() {} + +scoped_ptr<LayerImpl> UIResourceLayer::CreateLayerImpl( + LayerTreeImpl* tree_impl) { + return UIResourceLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); +} + +void UIResourceLayer::SetUV(gfx::PointF top_left, gfx::PointF bottom_right) { + if (uv_top_left_ == top_left && uv_bottom_right_ == bottom_right) + return; + uv_top_left_ = top_left; + uv_bottom_right_ = bottom_right; + SetNeedsCommit(); +} + +void UIResourceLayer::SetVertexOpacity(float bottom_left, + float top_left, + float top_right, + float bottom_right) { + // Indexing according to the quad vertex generation: + // 1--2 + // | | + // 0--3 + if (vertex_opacity_[0] == bottom_left && + vertex_opacity_[1] == top_left && + vertex_opacity_[2] == top_right && + vertex_opacity_[3] == bottom_right) + return; + vertex_opacity_[0] = bottom_left; + vertex_opacity_[1] = top_left; + vertex_opacity_[2] = top_right; + vertex_opacity_[3] = bottom_right; + SetNeedsCommit(); +} + +void UIResourceLayer::SetLayerTreeHost(LayerTreeHost* host) { + if (host == layer_tree_host()) + return; + + Layer::SetLayerTreeHost(host); + + // Recreate the resource hold against the new LTH. + RecreateUIResourceHolder(); +} + +void UIResourceLayer::RecreateUIResourceHolder() { + ui_resource_holder_.reset(); + if (!layer_tree_host() || bitmap_.empty()) + return; + + ui_resource_holder_ = + ScopedUIResourceHolder::Create(layer_tree_host(), bitmap_); +} + +void UIResourceLayer::SetBitmap(const SkBitmap& skbitmap) { + bitmap_ = skbitmap; + + RecreateUIResourceHolder(); + SetNeedsCommit(); +} + +void UIResourceLayer::SetUIResourceId(UIResourceId resource_id) { + if (ui_resource_holder_ && ui_resource_holder_->id() == resource_id) + return; + + if (resource_id) { + ui_resource_holder_ = SharedUIResourceHolder::Create(resource_id); + } else { + ui_resource_holder_.reset(); + } + + SetNeedsCommit(); +} + +bool UIResourceLayer::DrawsContent() const { + return ui_resource_holder_ && ui_resource_holder_->id() && + Layer::DrawsContent(); +} + +void UIResourceLayer::PushPropertiesTo(LayerImpl* layer) { + Layer::PushPropertiesTo(layer); + UIResourceLayerImpl* layer_impl = static_cast<UIResourceLayerImpl*>(layer); + + if (!ui_resource_holder_) { + layer_impl->SetUIResourceId(0); + } else { + DCHECK(layer_tree_host()); + + gfx::Size image_size = + layer_tree_host()->GetUIResourceSize(ui_resource_holder_->id()); + layer_impl->SetUIResourceId(ui_resource_holder_->id()); + layer_impl->SetImageBounds(image_size); + layer_impl->SetUV(uv_top_left_, uv_bottom_right_); + layer_impl->SetVertexOpacity(vertex_opacity_); + } +} + +} // namespace cc diff --git a/chromium/cc/layers/ui_resource_layer.h b/chromium/cc/layers/ui_resource_layer.h new file mode 100644 index 00000000000..69721a30faa --- /dev/null +++ b/chromium/cc/layers/ui_resource_layer.h @@ -0,0 +1,73 @@ +// Copyright 2013 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 CC_LAYERS_UI_RESOURCE_LAYER_H_ +#define CC_LAYERS_UI_RESOURCE_LAYER_H_ + +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "cc/layers/layer.h" +#include "cc/resources/ui_resource_client.h" +#include "ui/gfx/rect.h" + +namespace cc { + +class LayerTreeHost; +class ScopedUIResource; + +class CC_EXPORT UIResourceLayer : public Layer { + public: + static scoped_refptr<UIResourceLayer> Create(); + + virtual bool DrawsContent() const OVERRIDE; + + virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; + + virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE; + + void SetBitmap(const SkBitmap& skbitmap); + + // An alternative way of setting the resource to allow for sharing. + void SetUIResourceId(UIResourceId resource_id); + + // Sets a UV transform to be used at draw time. Defaults to (0, 0) and (1, 1). + void SetUV(gfx::PointF top_left, gfx::PointF bottom_right); + + // Sets an opacity value per vertex. It will be multiplied by the layer + // opacity value. + void SetVertexOpacity(float bottom_left, + float top_left, + float top_right, + float bottom_right); + + class UIResourceHolder { + public: + virtual UIResourceId id() = 0; + virtual ~UIResourceHolder(); + }; + + protected: + UIResourceLayer(); + virtual ~UIResourceLayer(); + + scoped_ptr<UIResourceHolder> ui_resource_holder_; + SkBitmap bitmap_; + + gfx::PointF uv_top_left_; + gfx::PointF uv_bottom_right_; + float vertex_opacity_[4]; + + private: + virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) + OVERRIDE; + void RecreateUIResourceHolder(); + + + + DISALLOW_COPY_AND_ASSIGN(UIResourceLayer); +}; + +} // namespace cc + +#endif // CC_LAYERS_UI_RESOURCE_LAYER_H_ diff --git a/chromium/cc/layers/ui_resource_layer_impl.cc b/chromium/cc/layers/ui_resource_layer_impl.cc new file mode 100644 index 00000000000..2c9a28681ce --- /dev/null +++ b/chromium/cc/layers/ui_resource_layer_impl.cc @@ -0,0 +1,157 @@ +// Copyright 2013 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 "cc/layers/ui_resource_layer_impl.h" + +#include "base/strings/stringprintf.h" +#include "base/values.h" +#include "cc/base/math_util.h" +#include "cc/layers/quad_sink.h" +#include "cc/quads/texture_draw_quad.h" +#include "cc/trees/layer_tree_impl.h" +#include "ui/gfx/rect_f.h" + +namespace cc { + +UIResourceLayerImpl::UIResourceLayerImpl(LayerTreeImpl* tree_impl, int id) + : LayerImpl(tree_impl, id), + ui_resource_id_(0), + uv_top_left_(0.f, 0.f), + uv_bottom_right_(1.f, 1.f) { + vertex_opacity_[0] = 1.0f; + vertex_opacity_[1] = 1.0f; + vertex_opacity_[2] = 1.0f; + vertex_opacity_[3] = 1.0f; +} + +UIResourceLayerImpl::~UIResourceLayerImpl() {} + +scoped_ptr<LayerImpl> UIResourceLayerImpl::CreateLayerImpl( + LayerTreeImpl* tree_impl) { + return UIResourceLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); +} + +void UIResourceLayerImpl::PushPropertiesTo(LayerImpl* layer) { + LayerImpl::PushPropertiesTo(layer); + UIResourceLayerImpl* layer_impl = static_cast<UIResourceLayerImpl*>(layer); + + layer_impl->SetUIResourceId(ui_resource_id_); + layer_impl->SetImageBounds(image_bounds_); + layer_impl->SetUV(uv_top_left_, uv_bottom_right_); + layer_impl->SetVertexOpacity(vertex_opacity_); +} + +void UIResourceLayerImpl::SetUIResourceId(UIResourceId uid) { + if (uid == ui_resource_id_) + return; + ui_resource_id_ = uid; + NoteLayerPropertyChanged(); +} + +void UIResourceLayerImpl::SetImageBounds(gfx::Size image_bounds) { + // This check imposes an ordering on the call sequence. An UIResource must + // exist before SetImageBounds can be called. + DCHECK(ui_resource_id_); + + if (image_bounds_ == image_bounds) + return; + + image_bounds_ = image_bounds; + + NoteLayerPropertyChanged(); +} + +void UIResourceLayerImpl::SetUV(gfx::PointF top_left, + gfx::PointF bottom_right) { + if (uv_top_left_ == top_left && uv_bottom_right_ == bottom_right) + return; + uv_top_left_ = top_left; + uv_bottom_right_ = bottom_right; + NoteLayerPropertyChanged(); +} + +void UIResourceLayerImpl::SetVertexOpacity(const float vertex_opacity[4]) { + if (vertex_opacity_[0] == vertex_opacity[0] && + vertex_opacity_[1] == vertex_opacity[1] && + vertex_opacity_[2] == vertex_opacity[2] && + vertex_opacity_[3] == vertex_opacity[3]) + return; + vertex_opacity_[0] = vertex_opacity[0]; + vertex_opacity_[1] = vertex_opacity[1]; + vertex_opacity_[2] = vertex_opacity[2]; + vertex_opacity_[3] = vertex_opacity[3]; + NoteLayerPropertyChanged(); +} + +bool UIResourceLayerImpl::WillDraw(DrawMode draw_mode, + ResourceProvider* resource_provider) { + if (!ui_resource_id_ || draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) + return false; + return LayerImpl::WillDraw(draw_mode, resource_provider); +} + +void UIResourceLayerImpl::AppendQuads(QuadSink* quad_sink, + AppendQuadsData* append_quads_data) { + SharedQuadState* shared_quad_state = + quad_sink->UseSharedQuadState(CreateSharedQuadState()); + AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data); + + if (!ui_resource_id_) + return; + + ResourceProvider::ResourceId resource = + layer_tree_impl()->ResourceIdForUIResource(ui_resource_id_); + + if (!resource) + return; + + static const bool flipped = false; + static const bool premultiplied_alpha = true; + + DCHECK(!bounds().IsEmpty()); + + gfx::Rect quad_rect(bounds()); + + bool opaque = layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_) || + contents_opaque(); + gfx::Rect opaque_rect(opaque ? quad_rect : gfx::Rect()); + scoped_ptr<TextureDrawQuad> quad; + + quad = TextureDrawQuad::Create(); + quad->SetNew(shared_quad_state, + quad_rect, + opaque_rect, + resource, + premultiplied_alpha, + uv_top_left_, + uv_bottom_right_, + SK_ColorTRANSPARENT, + vertex_opacity_, + flipped); + quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); +} + +const char* UIResourceLayerImpl::LayerTypeAsString() const { + return "cc::UIResourceLayerImpl"; +} + +base::DictionaryValue* UIResourceLayerImpl::LayerTreeAsJson() const { + base::DictionaryValue* result = LayerImpl::LayerTreeAsJson(); + + result->Set("ImageBounds", MathUtil::AsValue(image_bounds_).release()); + + base::ListValue* list = new base::ListValue; + list->AppendDouble(vertex_opacity_[0]); + list->AppendDouble(vertex_opacity_[1]); + list->AppendDouble(vertex_opacity_[2]); + list->AppendDouble(vertex_opacity_[3]); + result->Set("VertexOpacity", list); + + result->Set("UVTopLeft", MathUtil::AsValue(uv_top_left_).release()); + result->Set("UVBottomRight", MathUtil::AsValue(uv_bottom_right_).release()); + + return result; +} + +} // namespace cc diff --git a/chromium/cc/layers/ui_resource_layer_impl.h b/chromium/cc/layers/ui_resource_layer_impl.h new file mode 100644 index 00000000000..7f20050e99b --- /dev/null +++ b/chromium/cc/layers/ui_resource_layer_impl.h @@ -0,0 +1,73 @@ +// Copyright 2013 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 CC_LAYERS_UI_RESOURCE_LAYER_IMPL_H_ +#define CC_LAYERS_UI_RESOURCE_LAYER_IMPL_H_ + +#include <string> + +#include "cc/base/cc_export.h" +#include "cc/layers/layer_impl.h" +#include "cc/resources/resource_provider.h" +#include "cc/resources/ui_resource_client.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" + +namespace base { +class DictionaryValue; +} + +namespace cc { + +class CC_EXPORT UIResourceLayerImpl : public LayerImpl { + public: + static scoped_ptr<UIResourceLayerImpl> Create(LayerTreeImpl* tree_impl, + int id) { + return make_scoped_ptr(new UIResourceLayerImpl(tree_impl, id)); + } + virtual ~UIResourceLayerImpl(); + + void SetUIResourceId(UIResourceId uid); + + void SetImageBounds(gfx::Size image_bounds); + + // Sets a UV transform to be used at draw time. Defaults to (0, 0) and (1, 1). + void SetUV(gfx::PointF top_left, gfx::PointF bottom_right); + + // Sets an opacity value per vertex. It will be multiplied by the layer + // opacity value. + void SetVertexOpacity(const float vertex_opacity[4]); + + virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) + OVERRIDE; + virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; + + virtual bool WillDraw(DrawMode draw_mode, + ResourceProvider* resource_provider) OVERRIDE; + virtual void AppendQuads(QuadSink* quad_sink, + AppendQuadsData* append_quads_data) OVERRIDE; + + virtual base::DictionaryValue* LayerTreeAsJson() const OVERRIDE; + + protected: + UIResourceLayerImpl(LayerTreeImpl* tree_impl, int id); + + // The size of the resource bitmap in pixels. + gfx::Size image_bounds_; + + UIResourceId ui_resource_id_; + + gfx::PointF uv_top_left_; + gfx::PointF uv_bottom_right_; + float vertex_opacity_[4]; + + private: + virtual const char* LayerTypeAsString() const OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(UIResourceLayerImpl); +}; + +} // namespace cc + +#endif // CC_LAYERS_UI_RESOURCE_LAYER_IMPL_H_ diff --git a/chromium/cc/layers/ui_resource_layer_impl_unittest.cc b/chromium/cc/layers/ui_resource_layer_impl_unittest.cc new file mode 100644 index 00000000000..4a2a1164182 --- /dev/null +++ b/chromium/cc/layers/ui_resource_layer_impl_unittest.cc @@ -0,0 +1,152 @@ +// Copyright 2013 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 "cc/layers/append_quads_data.h" +#include "cc/layers/ui_resource_layer_impl.h" +#include "cc/resources/ui_resource_bitmap.h" +#include "cc/resources/ui_resource_client.h" +#include "cc/test/fake_impl_proxy.h" +#include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/fake_ui_resource_layer_tree_host_impl.h" +#include "cc/test/layer_test_common.h" +#include "cc/test/mock_quad_culler.h" +#include "cc/trees/single_thread_proxy.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/transform.h" + +namespace cc { +namespace { + +scoped_ptr<UIResourceLayerImpl> GenerateUIResourceLayer( + FakeUIResourceLayerTreeHostImpl* host_impl, + gfx::Size bitmap_size, + gfx::Size layer_size, + bool opaque, + UIResourceId uid) { + gfx::Rect visible_content_rect(layer_size); + scoped_ptr<UIResourceLayerImpl> layer = + UIResourceLayerImpl::Create(host_impl->active_tree(), 1); + layer->draw_properties().visible_content_rect = visible_content_rect; + layer->SetBounds(layer_size); + layer->SetContentBounds(layer_size); + layer->CreateRenderSurface(); + layer->draw_properties().render_target = layer.get(); + + SkBitmap skbitmap; + skbitmap.setConfig(SkBitmap::kARGB_8888_Config, + bitmap_size.width(), + bitmap_size.height(), + 0, + opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); + skbitmap.allocPixels(); + skbitmap.setImmutable(); + UIResourceBitmap bitmap(skbitmap); + + host_impl->CreateUIResource(uid, bitmap); + layer->SetUIResourceId(uid); + + return layer.Pass(); +} + +void QuadSizeTest(scoped_ptr<UIResourceLayerImpl> layer, + size_t expected_quad_size) { + MockQuadCuller quad_culler; + AppendQuadsData data; + layer->AppendQuads(&quad_culler, &data); + + // Verify quad rects + const QuadList& quads = quad_culler.quad_list(); + EXPECT_EQ(expected_quad_size, quads.size()); +} + +TEST(UIResourceLayerImplTest, VerifyDrawQuads) { + FakeImplProxy proxy; + FakeUIResourceLayerTreeHostImpl host_impl(&proxy); + // Make sure we're appending quads when there are valid values. + gfx::Size bitmap_size(100, 100); + gfx::Size layer_size(100, 100);; + size_t expected_quad_size = 1; + bool opaque = true; + UIResourceId uid = 1; + scoped_ptr<UIResourceLayerImpl> layer = GenerateUIResourceLayer(&host_impl, + bitmap_size, + layer_size, + opaque, + uid); + QuadSizeTest(layer.Pass(), expected_quad_size); + + // Make sure we're not appending quads when there are invalid values. + expected_quad_size = 0; + uid = 0; + layer = GenerateUIResourceLayer(&host_impl, + bitmap_size, + layer_size, + opaque, + uid); + QuadSizeTest(layer.Pass(), expected_quad_size); +} + +void OpaqueBoundsTest(scoped_ptr<UIResourceLayerImpl> layer, + gfx::Rect expected_opaque_bounds) { + MockQuadCuller quad_culler; + AppendQuadsData data; + layer->AppendQuads(&quad_culler, &data); + + // Verify quad rects + const QuadList& quads = quad_culler.quad_list(); + EXPECT_GE(quads.size(), (size_t)0); + gfx::Rect opaque_rect = quads.at(0)->opaque_rect; + EXPECT_EQ(expected_opaque_bounds, opaque_rect); +} + +TEST(UIResourceLayerImplTest, VerifySetOpaqueOnSkBitmap) { + FakeImplProxy proxy; + FakeUIResourceLayerTreeHostImpl host_impl(&proxy); + + gfx::Size bitmap_size(100, 100); + gfx::Size layer_size(100, 100);; + bool opaque = false; + UIResourceId uid = 1; + scoped_ptr<UIResourceLayerImpl> layer = GenerateUIResourceLayer(&host_impl, + bitmap_size, + layer_size, + opaque, + uid); + gfx::Rect expected_opaque_bounds; + OpaqueBoundsTest(layer.Pass(), expected_opaque_bounds); + + opaque = true; + layer = GenerateUIResourceLayer(&host_impl, + bitmap_size, + layer_size, + opaque, + uid); + expected_opaque_bounds = gfx::Rect(layer->bounds()); + OpaqueBoundsTest(layer.Pass(), expected_opaque_bounds); +} + +TEST(UIResourceLayerImplTest, VerifySetOpaqueOnLayer) { + FakeImplProxy proxy; + FakeUIResourceLayerTreeHostImpl host_impl(&proxy); + + gfx::Size bitmap_size(100, 100); + gfx::Size layer_size(100, 100); + bool skbitmap_opaque = false; + UIResourceId uid = 1; + scoped_ptr<UIResourceLayerImpl> layer = GenerateUIResourceLayer( + &host_impl, bitmap_size, layer_size, skbitmap_opaque, uid); + layer->SetContentsOpaque(false); + gfx::Rect expected_opaque_bounds; + OpaqueBoundsTest(layer.Pass(), expected_opaque_bounds); + + layer = GenerateUIResourceLayer( + &host_impl, bitmap_size, layer_size, skbitmap_opaque, uid); + layer->SetContentsOpaque(true); + expected_opaque_bounds = gfx::Rect(layer->bounds()); + OpaqueBoundsTest(layer.Pass(), expected_opaque_bounds); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/layers/ui_resource_layer_unittest.cc b/chromium/cc/layers/ui_resource_layer_unittest.cc new file mode 100644 index 00000000000..48dbdf58f71 --- /dev/null +++ b/chromium/cc/layers/ui_resource_layer_unittest.cc @@ -0,0 +1,114 @@ +// Copyright 2013 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 "cc/layers/ui_resource_layer.h" + +#include "cc/debug/overdraw_metrics.h" +#include "cc/resources/prioritized_resource_manager.h" +#include "cc/resources/resource_provider.h" +#include "cc/resources/resource_update_queue.h" +#include "cc/resources/scoped_ui_resource.h" +#include "cc/scheduler/texture_uploader.h" +#include "cc/test/fake_layer_tree_host.h" +#include "cc/test/fake_layer_tree_host_client.h" +#include "cc/test/fake_output_surface.h" +#include "cc/test/fake_output_surface_client.h" +#include "cc/test/geometry_test_utils.h" +#include "cc/trees/layer_tree_host.h" +#include "cc/trees/occlusion_tracker.h" +#include "cc/trees/single_thread_proxy.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" + +using ::testing::Mock; +using ::testing::_; +using ::testing::AtLeast; +using ::testing::AnyNumber; + +namespace cc { +namespace { + +class UIResourceLayerTest : public testing::Test { + public: + UIResourceLayerTest() : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {} + + protected: + virtual void SetUp() { + layer_tree_host_ = FakeLayerTreeHost::Create(); + layer_tree_host_->InitializeSingleThreaded(&fake_client_); + } + + virtual void TearDown() { + Mock::VerifyAndClearExpectations(layer_tree_host_.get()); + } + + scoped_ptr<FakeLayerTreeHost> layer_tree_host_; + FakeLayerTreeHostClient fake_client_; +}; + +TEST_F(UIResourceLayerTest, SetBitmap) { + scoped_refptr<UIResourceLayer> test_layer = UIResourceLayer::Create(); + ASSERT_TRUE(test_layer.get()); + test_layer->SetIsDrawable(true); + test_layer->SetBounds(gfx::Size(100, 100)); + + layer_tree_host_->SetRootLayer(test_layer); + Mock::VerifyAndClearExpectations(layer_tree_host_.get()); + EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get()); + + layer_tree_host_->InitializeOutputSurfaceIfNeeded(); + + ResourceUpdateQueue queue; + OcclusionTracker occlusion_tracker(gfx::Rect(), false); + test_layer->SavePaintProperties(); + test_layer->Update(&queue, &occlusion_tracker); + + EXPECT_FALSE(test_layer->DrawsContent()); + + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10); + bitmap.allocPixels(); + bitmap.setImmutable(); + + test_layer->SetBitmap(bitmap); + test_layer->Update(&queue, &occlusion_tracker); + + EXPECT_TRUE(test_layer->DrawsContent()); +} + +TEST_F(UIResourceLayerTest, SetUIResourceId) { + scoped_refptr<UIResourceLayer> test_layer = UIResourceLayer::Create(); + ASSERT_TRUE(test_layer.get()); + test_layer->SetIsDrawable(true); + test_layer->SetBounds(gfx::Size(100, 100)); + + layer_tree_host_->SetRootLayer(test_layer); + Mock::VerifyAndClearExpectations(layer_tree_host_.get()); + EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get()); + + layer_tree_host_->InitializeOutputSurfaceIfNeeded(); + + ResourceUpdateQueue queue; + OcclusionTracker occlusion_tracker(gfx::Rect(), false); + test_layer->SavePaintProperties(); + test_layer->Update(&queue, &occlusion_tracker); + + EXPECT_FALSE(test_layer->DrawsContent()); + + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10); + bitmap.allocPixels(); + bitmap.setImmutable(); + + scoped_ptr<ScopedUIResource> resource = ScopedUIResource::Create( + layer_tree_host_.get(), UIResourceBitmap(bitmap)); + test_layer->SetUIResourceId(resource->id()); + test_layer->Update(&queue, &occlusion_tracker); + + EXPECT_TRUE(test_layer->DrawsContent()); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc index 28e470e7c3b..314fed624ca 100644 --- a/chromium/cc/layers/video_layer_impl.cc +++ b/chromium/cc/layers/video_layer_impl.cc @@ -18,9 +18,9 @@ #include "cc/trees/proxy.h" #include "media/base/video_frame.h" -#if defined(GOOGLE_TV) +#if defined(VIDEO_HOLE) #include "cc/quads/solid_color_draw_quad.h" -#endif +#endif // defined(VIDEO_HOLE) namespace cc { @@ -214,16 +214,16 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink, DCHECK_EQ(frame_resources_.size(), 1u); if (frame_resources_.size() < 1u) break; - gfx::Transform transform( - provider_client_impl_->stream_texture_matrix()); - transform.Scale(tex_width_scale, tex_height_scale); + gfx::Transform scale; + scale.Scale(tex_width_scale, tex_height_scale); scoped_ptr<StreamVideoDrawQuad> stream_video_quad = StreamVideoDrawQuad::Create(); - stream_video_quad->SetNew(shared_quad_state, - quad_rect, - opaque_rect, - frame_resources_[0], - transform); + stream_video_quad->SetNew( + shared_quad_state, + quad_rect, + opaque_rect, + frame_resources_[0], + scale * provider_client_impl_->stream_texture_matrix()); quad_sink->Append(stream_video_quad.PassAs<DrawQuad>(), append_quads_data); break; @@ -245,7 +245,7 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink, append_quads_data); break; } -#if defined(GOOGLE_TV) +#if defined(VIDEO_HOLE) // This block and other blocks wrapped around #if defined(GOOGLE_TV) is not // maintained by the general compositor team. Please contact the following // people instead: @@ -266,7 +266,7 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink, append_quads_data); break; } -#endif +#endif // defined(VIDEO_HOLE) case VideoFrameExternalResources::NONE: NOTIMPLEMENTED(); break; diff --git a/chromium/cc/output/begin_frame_args.cc b/chromium/cc/output/begin_frame_args.cc index d7da76c3bcb..92901afb1f3 100644 --- a/chromium/cc/output/begin_frame_args.cc +++ b/chromium/cc/output/begin_frame_args.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "cc/output/begin_frame_args.h" +#include "ui/gfx/frame_time.h" namespace cc { @@ -29,20 +30,20 @@ BeginFrameArgs BeginFrameArgs::Create(base::TimeTicks frame_time, BeginFrameArgs BeginFrameArgs::CreateForSynchronousCompositor() { // For WebView/SynchronousCompositor, we always want to draw immediately, // so we set the deadline to 0 and guess that the interval is 16 milliseconds. - return BeginFrameArgs(base::TimeTicks::Now(), + return BeginFrameArgs(gfx::FrameTime::Now(), base::TimeTicks(), DefaultInterval()); } BeginFrameArgs BeginFrameArgs::CreateForTesting() { - base::TimeTicks now = base::TimeTicks::Now(); + base::TimeTicks now = gfx::FrameTime::Now(); return BeginFrameArgs(now, now + (DefaultInterval() / 2), DefaultInterval()); } BeginFrameArgs BeginFrameArgs::CreateExpiredForTesting() { - base::TimeTicks now = base::TimeTicks::Now(); + base::TimeTicks now = gfx::FrameTime::Now(); return BeginFrameArgs(now, now - DefaultInterval(), DefaultInterval()); diff --git a/chromium/cc/output/context_provider.cc b/chromium/cc/output/context_provider.cc index 7f46f7ccc67..11b4bc5d889 100644 --- a/chromium/cc/output/context_provider.cc +++ b/chromium/cc/output/context_provider.cc @@ -9,22 +9,32 @@ namespace cc { ContextProvider::Capabilities::Capabilities() - : bind_uniform_location(false), - discard_backbuffer(false), - egl_image_external(false), + : egl_image_external(false), fast_npot_mo8_textures(false), iosurface(false), map_image(false), - map_sub(false), post_sub_buffer(false), - set_visibility(false), - shallow_flush(false), - swapbuffers_complete_callback(false), texture_format_bgra8888(false), + texture_format_etc1(false), texture_rectangle(false), texture_storage(false), texture_usage(false), discard_framebuffer(false), max_transfer_buffer_usage_bytes(std::numeric_limits<size_t>::max()) {} +ContextProvider::Capabilities::Capabilities( + const gpu::Capabilities& gpu_capabilities) + : egl_image_external(gpu_capabilities.egl_image_external), + fast_npot_mo8_textures(gpu_capabilities.fast_npot_mo8_textures), + iosurface(gpu_capabilities.iosurface), + map_image(gpu_capabilities.map_image), + post_sub_buffer(gpu_capabilities.post_sub_buffer), + texture_format_bgra8888(gpu_capabilities.texture_format_bgra8888), + texture_format_etc1(gpu_capabilities.texture_format_etc1), + texture_rectangle(gpu_capabilities.texture_rectangle), + texture_storage(gpu_capabilities.texture_storage), + texture_usage(gpu_capabilities.texture_usage), + discard_framebuffer(gpu_capabilities.discard_framebuffer), + max_transfer_buffer_usage_bytes(std::numeric_limits<size_t>::max()) {} + } // namespace cc diff --git a/chromium/cc/output/context_provider.h b/chromium/cc/output/context_provider.h index c873b58c8d6..0b6d48232c6 100644 --- a/chromium/cc/output/context_provider.h +++ b/chromium/cc/output/context_provider.h @@ -8,9 +8,15 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "cc/base/cc_export.h" +#include "gpu/command_buffer/common/capabilities.h" class GrContext; -namespace WebKit { class WebGraphicsContext3D; } + +namespace blink { class WebGraphicsContext3D; } +namespace gpu { +class ContextSupport; +namespace gles2 { class GLES2Interface; } +} namespace cc { struct ManagedMemoryPolicy; @@ -23,33 +29,38 @@ class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> { // from the same thread. virtual bool BindToCurrentThread() = 0; - virtual WebKit::WebGraphicsContext3D* Context3d() = 0; + virtual blink::WebGraphicsContext3D* Context3d() = 0; + virtual gpu::gles2::GLES2Interface* ContextGL() = 0; + virtual gpu::ContextSupport* ContextSupport() = 0; virtual class GrContext* GrContext() = 0; + virtual void MakeGrContextCurrent() = 0; struct Capabilities { - bool bind_uniform_location; - bool discard_backbuffer; - bool egl_image_external; - bool fast_npot_mo8_textures; - bool iosurface; - bool map_image; - bool map_sub; - bool post_sub_buffer; - bool set_visibility; - bool shallow_flush; - bool swapbuffers_complete_callback; - bool texture_format_bgra8888; - bool texture_rectangle; - bool texture_storage; - bool texture_usage; - bool discard_framebuffer; + bool egl_image_external : 1; + bool fast_npot_mo8_textures : 1; + bool iosurface : 1; + bool map_image : 1; + bool post_sub_buffer : 1; + bool texture_format_bgra8888 : 1; + bool texture_format_etc1 : 1; + bool texture_rectangle : 1; + bool texture_storage : 1; + bool texture_usage : 1; + bool discard_framebuffer : 1; size_t max_transfer_buffer_usage_bytes; CC_EXPORT Capabilities(); + + // TODO(boliu): Compose a gpu::Capabilities instead and remove this + // constructor. + explicit CC_EXPORT Capabilities(const gpu::Capabilities& gpu_capabilities); }; // Returns the capabilities of the currently bound 3d context. virtual Capabilities ContextCapabilities() = 0; + // Checks if the context is currently known to be lost. + virtual bool IsContextLost() = 0; + // Ask the provider to check if the contexts are valid or lost. If they are, // this should invalidate the provider so that it can be replaced with a new // one. @@ -67,17 +78,10 @@ class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> { virtual void SetLostContextCallback( const LostContextCallback& lost_context_callback) = 0; - // Sets a callback to be called when swap buffers completes. This should be - // called from the same thread that the context is bound to. - typedef base::Closure SwapBuffersCompleteCallback; - virtual void SetSwapBuffersCompleteCallback( - const SwapBuffersCompleteCallback& swap_buffers_complete_callback) = 0; - // Sets a callback to be called when the memory policy changes. This should be // called from the same thread that the context is bound to. - typedef base::Callback<void( - const cc::ManagedMemoryPolicy& policy, - bool discard_backbuffer_when_not_visible)> MemoryPolicyChangedCallback; + typedef base::Callback<void(const ManagedMemoryPolicy& policy)> + MemoryPolicyChangedCallback; virtual void SetMemoryPolicyChangedCallback( const MemoryPolicyChangedCallback& memory_policy_changed_callback) = 0; diff --git a/chromium/cc/output/copy_output_request.cc b/chromium/cc/output/copy_output_request.cc index 6163d5d3c60..50173d5853d 100644 --- a/chromium/cc/output/copy_output_request.cc +++ b/chromium/cc/output/copy_output_request.cc @@ -14,6 +14,19 @@ namespace cc { +// static +scoped_ptr<CopyOutputRequest> CopyOutputRequest::CreateRelayRequest( + const CopyOutputRequest& original_request, + const CopyOutputRequestCallback& result_callback) { + scoped_ptr<CopyOutputRequest> relay = CreateRequest(result_callback); + relay->force_bitmap_result_ = original_request.force_bitmap_result_; + relay->has_area_ = original_request.has_area_; + relay->area_ = original_request.area_; + relay->has_texture_mailbox_ = original_request.has_texture_mailbox_; + relay->texture_mailbox_ = original_request.texture_mailbox_; + return relay.Pass(); +} + CopyOutputRequest::CopyOutputRequest() {} CopyOutputRequest::CopyOutputRequest( @@ -21,8 +34,8 @@ CopyOutputRequest::CopyOutputRequest( const CopyOutputRequestCallback& result_callback) : force_bitmap_result_(force_bitmap_result), has_area_(false), - result_callback_(result_callback) { -} + has_texture_mailbox_(false), + result_callback_(result_callback) {} CopyOutputRequest::~CopyOutputRequest() { if (!result_callback_.is_null()) @@ -50,4 +63,12 @@ void CopyOutputRequest::SendTextureResult( size, texture_mailbox, release_callback.Pass())); } +void CopyOutputRequest::SetTextureMailbox( + const TextureMailbox& texture_mailbox) { + DCHECK(!force_bitmap_result_); + DCHECK(texture_mailbox.IsTexture()); + has_texture_mailbox_ = true; + texture_mailbox_ = texture_mailbox; +} + } // namespace cc diff --git a/chromium/cc/output/copy_output_request.h b/chromium/cc/output/copy_output_request.h index c4a92481dbc..4b74b419fca 100644 --- a/chromium/cc/output/copy_output_request.h +++ b/chromium/cc/output/copy_output_request.h @@ -8,6 +8,7 @@ #include "base/callback.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" +#include "cc/resources/texture_mailbox.h" #include "ui/gfx/rect.h" class SkBitmap; @@ -15,7 +16,6 @@ class SkBitmap; namespace cc { class CopyOutputResult; class SingleReleaseCallback; -class TextureMailbox; class CC_EXPORT CopyOutputRequest { public: @@ -35,13 +35,7 @@ class CC_EXPORT CopyOutputRequest { } static scoped_ptr<CopyOutputRequest> CreateRelayRequest( const CopyOutputRequest& original_request, - const CopyOutputRequestCallback& result_callback) { - scoped_ptr<CopyOutputRequest> relay = CreateRequest(result_callback); - relay->force_bitmap_result_ = original_request.force_bitmap_result_; - relay->has_area_ = original_request.has_area_; - relay->area_ = original_request.area_; - return relay.Pass(); - } + const CopyOutputRequestCallback& result_callback); ~CopyOutputRequest(); @@ -59,6 +53,13 @@ class CC_EXPORT CopyOutputRequest { bool has_area() const { return has_area_; } gfx::Rect area() const { return area_; } + // By default copy requests create a new TextureMailbox to return contents + // in. This allows a client to provide a TextureMailbox, and the compositor + // will place the result inside the TextureMailbox. + void SetTextureMailbox(const TextureMailbox& texture_mailbox); + bool has_texture_mailbox() const { return has_texture_mailbox_; } + const TextureMailbox& texture_mailbox() const { return texture_mailbox_; } + void SendEmptyResult(); void SendBitmapResult(scoped_ptr<SkBitmap> bitmap); void SendTextureResult(gfx::Size size, @@ -67,19 +68,16 @@ class CC_EXPORT CopyOutputRequest { void SendResult(scoped_ptr<CopyOutputResult> result); - bool Equals(const CopyOutputRequest& other) const { - return result_callback_.Equals(other.result_callback_) && - force_bitmap_result_ == other.force_bitmap_result_; - } - private: CopyOutputRequest(); - explicit CopyOutputRequest(bool force_bitmap_result, - const CopyOutputRequestCallback& result_callback); + CopyOutputRequest(bool force_bitmap_result, + const CopyOutputRequestCallback& result_callback); bool force_bitmap_result_; bool has_area_; + bool has_texture_mailbox_; gfx::Rect area_; + TextureMailbox texture_mailbox_; CopyOutputRequestCallback result_callback_; }; diff --git a/chromium/cc/output/delegating_renderer.cc b/chromium/cc/output/delegating_renderer.cc index 1b4021fbbc0..1b5716160fa 100644 --- a/chromium/cc/output/delegating_renderer.cc +++ b/chromium/cc/output/delegating_renderer.cc @@ -22,11 +22,13 @@ #include "cc/quads/tile_draw_quad.h" #include "cc/quads/yuv_video_draw_quad.h" #include "cc/resources/resource_provider.h" +#include "gpu/command_buffer/client/context_support.h" +#include "gpu/command_buffer/common/gpu_memory_allocation.h" #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" -using WebKit::WebGraphicsContext3D; +using blink::WebGraphicsContext3D; namespace cc { @@ -61,22 +63,16 @@ bool DelegatingRenderer::Initialize() { capabilities_.using_offscreen_context3d = false; if (!output_surface_->context_provider()) { - // TODO(danakj): Make software compositing work. + capabilities_.using_shared_memory_resources = true; + capabilities_.using_map_image = settings_->use_map_image; return true; } - WebGraphicsContext3D* context3d = - output_surface_->context_provider()->Context3d(); - - if (!context3d->makeContextCurrent()) - return false; - const ContextProvider::Capabilities& caps = output_surface_->context_provider()->ContextCapabilities(); DCHECK(!caps.iosurface || caps.texture_rectangle); - capabilities_.using_set_visibility = caps.set_visibility; capabilities_.using_egl_image = caps.egl_image_external; capabilities_.using_map_image = settings_->use_map_image && caps.map_image; @@ -101,16 +97,16 @@ static ResourceProvider::ResourceId AppendToArray( void DelegatingRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order, ContextProvider* offscreen_context_provider, float device_scale_factor, - bool allow_partial_swap) { + gfx::Rect device_viewport_rect, + gfx::Rect device_clip_rect, + bool allow_partial_swap, + bool disable_picture_quad_image_filtering) { TRACE_EVENT0("cc", "DelegatingRenderer::DrawFrame"); - DCHECK(!frame_for_swap_buffers_.delegated_frame_data); - - frame_for_swap_buffers_.metadata = client_->MakeCompositorFrameMetadata(); + DCHECK(!delegated_frame_data_); - frame_for_swap_buffers_.delegated_frame_data = - make_scoped_ptr(new DelegatedFrameData); - DelegatedFrameData& out_data = *frame_for_swap_buffers_.delegated_frame_data; + delegated_frame_data_ = make_scoped_ptr(new DelegatedFrameData); + DelegatedFrameData& out_data = *delegated_frame_data_; // Move the render passes and resources into the |out_frame|. out_data.render_pass_list.swap(*render_passes_in_draw_order); @@ -126,11 +122,12 @@ void DelegatingRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order, resource_provider_->PrepareSendToParent(resources, &out_data.resource_list); } -void DelegatingRenderer::SwapBuffers() { +void DelegatingRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) { TRACE_EVENT0("cc", "DelegatingRenderer::SwapBuffers"); - - output_surface_->SwapBuffers(&frame_for_swap_buffers_); - frame_for_swap_buffers_.delegated_frame_data.reset(); + CompositorFrame compositor_frame; + compositor_frame.metadata = metadata; + compositor_frame.delegated_frame_data = delegated_frame_data_.Pass(); + output_surface_->SwapBuffers(&compositor_frame); } void DelegatingRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) { @@ -146,8 +143,7 @@ bool DelegatingRenderer::IsContextLost() { ContextProvider* context_provider = output_surface_->context_provider(); if (!context_provider) return false; - return context_provider->Context3d()->getGraphicsResetStatusARB() != - GL_NO_ERROR; + return context_provider->IsContextLost(); } void DelegatingRenderer::SetVisible(bool visible) { @@ -162,13 +158,11 @@ void DelegatingRenderer::SetVisible(bool visible) { if (context_provider) context_provider->Context3d()->flush(); } - if (capabilities_.using_set_visibility) { - // We loop visibility to the GPU process, since that's what manages memory. - // That will allow it to feed us with memory allocations that we can act - // upon. - DCHECK(context_provider); - context_provider->Context3d()->setVisibilityCHROMIUM(visible); - } + // We loop visibility to the GPU process, since that's what manages memory. + // That will allow it to feed us with memory allocations that we can act + // upon. + DCHECK(context_provider); + context_provider->ContextSupport()->SetSurfaceVisible(visible); } void DelegatingRenderer::SendManagedMemoryStats(size_t bytes_visible, @@ -180,16 +174,13 @@ void DelegatingRenderer::SendManagedMemoryStats(size_t bytes_visible, NOTIMPLEMENTED(); return; } - WebKit::WebGraphicsManagedMemoryStats stats; - stats.bytesVisible = bytes_visible; - stats.bytesVisibleAndNearby = bytes_visible_and_nearby; - stats.bytesAllocated = bytes_allocated; - stats.backbufferRequested = false; - context_provider->Context3d()->sendManagedMemoryStatsCHROMIUM(&stats); -} + gpu::ManagedMemoryStats stats; + stats.bytes_required = bytes_visible; + stats.bytes_nice_to_have = bytes_visible_and_nearby; + stats.bytes_allocated = bytes_allocated; + stats.backbuffer_requested = false; -void DelegatingRenderer::SetDiscardBackBufferWhenNotVisible(bool discard) { - // Nothing to do, we don't have a back buffer. + context_provider->ContextSupport()->SendManagedMemoryStats(stats); } } // namespace cc diff --git a/chromium/cc/output/delegating_renderer.h b/chromium/cc/output/delegating_renderer.h index 57a2418c452..c18bfa7d7ac 100644 --- a/chromium/cc/output/delegating_renderer.h +++ b/chromium/cc/output/delegating_renderer.h @@ -31,11 +31,14 @@ class CC_EXPORT DelegatingRenderer : public Renderer { virtual void DrawFrame(RenderPassList* render_passes_in_draw_order, ContextProvider* offscreen_context_provider, float device_scale_factor, - bool allow_partial_swap) OVERRIDE; + gfx::Rect device_viewport_rect, + gfx::Rect device_clip_rect, + bool allow_partial_swap, + bool disable_picture_quad_image_filtering) OVERRIDE; virtual void Finish() OVERRIDE {} - virtual void SwapBuffers() OVERRIDE; + virtual void SwapBuffers(const CompositorFrameMetadata& metadata) OVERRIDE; virtual void ReceiveSwapBuffersAck(const CompositorFrameAck&) OVERRIDE; virtual void GetFramebufferPixels(void* pixels, gfx::Rect rect) OVERRIDE; @@ -48,8 +51,6 @@ class CC_EXPORT DelegatingRenderer : public Renderer { size_t bytes_visible_and_nearby, size_t bytes_allocated) OVERRIDE; - virtual void SetDiscardBackBufferWhenNotVisible(bool discard) OVERRIDE; - private: DelegatingRenderer(RendererClient* client, const LayerTreeSettings* settings, @@ -60,7 +61,7 @@ class CC_EXPORT DelegatingRenderer : public Renderer { OutputSurface* output_surface_; ResourceProvider* resource_provider_; RendererCapabilities capabilities_; - CompositorFrame frame_for_swap_buffers_; + scoped_ptr<DelegatedFrameData> delegated_frame_data_; bool visible_; DISALLOW_COPY_AND_ASSIGN(DelegatingRenderer); diff --git a/chromium/cc/output/direct_renderer.cc b/chromium/cc/output/direct_renderer.cc index aad41ed293f..84788c5d13d 100644 --- a/chromium/cc/output/direct_renderer.cc +++ b/chromium/cc/output/direct_renderer.cc @@ -28,14 +28,14 @@ static gfx::Transform OrthoProjectionMatrix(float left, gfx::Transform proj; if (!delta_x || !delta_y) return proj; - proj.matrix().setDouble(0, 0, 2.0f / delta_x); - proj.matrix().setDouble(0, 3, -(right + left) / delta_x); - proj.matrix().setDouble(1, 1, 2.0f / delta_y); - proj.matrix().setDouble(1, 3, -(top + bottom) / delta_y); + proj.matrix().set(0, 0, 2.0f / delta_x); + proj.matrix().set(0, 3, -(right + left) / delta_x); + proj.matrix().set(1, 1, 2.0f / delta_y); + proj.matrix().set(1, 3, -(top + bottom) / delta_y); // Z component of vertices is always set to zero as we don't use the depth // buffer while drawing. - proj.matrix().setDouble(2, 2, 0); + proj.matrix().set(2, 2, 0); return proj; } @@ -148,35 +148,32 @@ void DirectRenderer::DecideRenderPassAllocationsForFrame( if (!resource_provider_) return; - base::hash_map<RenderPass::Id, const RenderPass*> render_passes_in_frame; + base::hash_map<RenderPass::Id, gfx::Size> render_passes_in_frame; for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i) - render_passes_in_frame.insert(std::pair<RenderPass::Id, const RenderPass*>( - render_passes_in_draw_order[i]->id, render_passes_in_draw_order[i])); + render_passes_in_frame.insert(std::pair<RenderPass::Id, gfx::Size>( + render_passes_in_draw_order[i]->id, + RenderPassTextureSize(render_passes_in_draw_order[i]))); std::vector<RenderPass::Id> passes_to_delete; - base::ScopedPtrHashMap<RenderPass::Id, CachedResource>::const_iterator + base::ScopedPtrHashMap<RenderPass::Id, ScopedResource>::const_iterator pass_iter; for (pass_iter = render_pass_textures_.begin(); pass_iter != render_pass_textures_.end(); ++pass_iter) { - base::hash_map<RenderPass::Id, const RenderPass*>::const_iterator it = + base::hash_map<RenderPass::Id, gfx::Size>::const_iterator it = render_passes_in_frame.find(pass_iter->first); if (it == render_passes_in_frame.end()) { passes_to_delete.push_back(pass_iter->first); continue; } - const RenderPass* render_pass_in_frame = it->second; - gfx::Size required_size = RenderPassTextureSize(render_pass_in_frame); - ResourceFormat required_format = - RenderPassTextureFormat(render_pass_in_frame); - CachedResource* texture = pass_iter->second; + gfx::Size required_size = it->second; + ScopedResource* texture = pass_iter->second; DCHECK(texture); bool size_appropriate = texture->size().width() >= required_size.width() && texture->size().height() >= required_size.height(); - if (texture->id() && - (!size_appropriate || texture->format() != required_format)) + if (texture->id() && !size_appropriate) texture->Free(); } @@ -187,8 +184,8 @@ void DirectRenderer::DecideRenderPassAllocationsForFrame( for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i) { if (!render_pass_textures_.contains(render_passes_in_draw_order[i]->id)) { - scoped_ptr<CachedResource> texture = - CachedResource::Create(resource_provider_); + scoped_ptr<ScopedResource> texture = + ScopedResource::Create(resource_provider_); render_pass_textures_.set(render_passes_in_draw_order[i]->id, texture.Pass()); } @@ -198,7 +195,10 @@ void DirectRenderer::DecideRenderPassAllocationsForFrame( void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order, ContextProvider* offscreen_context_provider, float device_scale_factor, - bool allow_partial_swap) { + gfx::Rect device_viewport_rect, + gfx::Rect device_clip_rect, + bool allow_partial_swap, + bool disable_picture_quad_image_filtering) { TRACE_EVENT0("cc", "DirectRenderer::DrawFrame"); UMA_HISTOGRAM_COUNTS("Renderer4.renderPassCount", render_passes_in_draw_order->size()); @@ -212,16 +212,19 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order, Capabilities().using_partial_swap && allow_partial_swap ? root_render_pass->damage_rect : root_render_pass->output_rect; - frame.root_damage_rect.Intersect(gfx::Rect(client_->DeviceViewport().size())); + frame.root_damage_rect.Intersect(gfx::Rect(device_viewport_rect.size())); + frame.device_viewport_rect = device_viewport_rect; + frame.device_clip_rect = device_clip_rect; frame.offscreen_context_provider = offscreen_context_provider; + frame.disable_picture_quad_image_filtering = + disable_picture_quad_image_filtering; EnsureBackbuffer(); // Only reshape when we know we are going to draw. Otherwise, the reshape // can leave the window at the wrong size if we never draw and the proper // viewport size is never set. - output_surface_->Reshape(client_->DeviceViewport().size(), - device_scale_factor); + output_surface_->Reshape(device_viewport_rect.size(), device_scale_factor); BeginDrawingFrame(&frame); for (size_t i = 0; i < render_passes_in_draw_order->size(); ++i) { @@ -269,11 +272,12 @@ bool DirectRenderer::NeedDeviceClip(const DrawingFrame* frame) const { if (frame->current_render_pass != frame->root_render_pass) return false; - return !client_->DeviceClip().Contains(client_->DeviceViewport()); + return !frame->device_clip_rect.Contains(frame->device_viewport_rect); } -gfx::Rect DirectRenderer::DeviceClipRect(const DrawingFrame* frame) const { - gfx::Rect device_clip_rect = client_->DeviceClip(); +gfx::Rect DirectRenderer::DeviceClipRectInWindowSpace(const DrawingFrame* frame) + const { + gfx::Rect device_clip_rect = frame->device_clip_rect; if (FlippedFramebuffer()) device_clip_rect.set_y(current_surface_size_.height() - device_clip_rect.bottom()); @@ -287,7 +291,7 @@ void DirectRenderer::SetScissorStateForQuad(const DrawingFrame* frame, return; } if (NeedDeviceClip(frame)) { - SetScissorTestRect(DeviceClipRect(frame)); + SetScissorTestRect(DeviceClipRectInWindowSpace(frame)); return; } @@ -317,7 +321,7 @@ void DirectRenderer::SetScissorTestRectInDrawSpace(const DrawingFrame* frame, gfx::RectF draw_space_rect) { gfx::Rect window_space_rect = MoveFromDrawToWindowSpace(draw_space_rect); if (NeedDeviceClip(frame)) - window_space_rect.Intersect(DeviceClipRect(frame)); + window_space_rect.Intersect(DeviceClipRectInWindowSpace(frame)); SetScissorTestRect(window_space_rect); } @@ -335,7 +339,7 @@ void DirectRenderer::DrawRenderPass(DrawingFrame* frame, gfx::RectF render_pass_scissor; bool draw_rect_covers_full_surface = true; if (frame->current_render_pass == frame->root_render_pass && - !client_->DeviceViewport().Contains( + !frame->device_viewport_rect.Contains( gfx::Rect(output_surface_->SurfaceSize()))) draw_rect_covers_full_surface = false; @@ -349,7 +353,7 @@ void DirectRenderer::DrawRenderPass(DrawingFrame* frame, if (frame->current_render_pass != frame->root_render_pass || settings_->should_clear_root_render_pass) { if (NeedDeviceClip(frame)) { - SetScissorTestRect(DeviceClipRect(frame)); + SetScissorTestRect(DeviceClipRectInWindowSpace(frame)); draw_rect_covers_full_surface = false; } else if (!using_scissor_as_optimization) { EnsureScissorTestDisabled(); @@ -381,12 +385,6 @@ void DirectRenderer::DrawRenderPass(DrawingFrame* frame, DoDrawQuad(frame, *it); } FinishDrawingQuadList(); - - CachedResource* texture = render_pass_textures_.get(render_pass->id); - if (texture) { - texture->set_is_complete( - !render_pass->has_occlusion_from_outside_target_surface); - } } bool DirectRenderer::UseRenderPass(DrawingFrame* frame, @@ -398,36 +396,29 @@ bool DirectRenderer::UseRenderPass(DrawingFrame* frame, BindFramebufferToOutputSurface(frame); InitializeViewport(frame, render_pass->output_rect, - client_->DeviceViewport(), + frame->device_viewport_rect, output_surface_->SurfaceSize()); return true; } - if (!resource_provider_) - return false; - - CachedResource* texture = render_pass_textures_.get(render_pass->id); + ScopedResource* texture = render_pass_textures_.get(render_pass->id); DCHECK(texture); gfx::Size size = RenderPassTextureSize(render_pass); size.Enlarge(enlarge_pass_texture_amount_.x(), enlarge_pass_texture_amount_.y()); - if (!texture->id() && - !texture->Allocate(size, - ResourceProvider::TextureUsageFramebuffer, - RenderPassTextureFormat(render_pass))) - return false; + if (!texture->id()) + texture->Allocate( + size, ResourceProvider::TextureUsageFramebuffer, RGBA_8888); + DCHECK(texture->id()); return BindFramebufferToTexture(frame, texture, render_pass->output_rect); } -bool DirectRenderer::HaveCachedResourcesForRenderPassId(RenderPass::Id id) +bool DirectRenderer::HasAllocatedResourcesForTesting(RenderPass::Id id) const { - if (!settings_->cache_render_pass_contents) - return false; - - CachedResource* texture = render_pass_textures_.get(id); - return texture && texture->id() && texture->is_complete(); + ScopedResource* texture = render_pass_textures_.get(id); + return texture && texture->id(); } // static @@ -435,10 +426,4 @@ gfx::Size DirectRenderer::RenderPassTextureSize(const RenderPass* render_pass) { return render_pass->output_rect.size(); } -// static -ResourceFormat DirectRenderer::RenderPassTextureFormat( - const RenderPass* render_pass) { - return RGBA_8888; -} - } // namespace cc diff --git a/chromium/cc/output/direct_renderer.h b/chromium/cc/output/direct_renderer.h index e5ee83c87bd..5c4dc7e23f4 100644 --- a/chromium/cc/output/direct_renderer.h +++ b/chromium/cc/output/direct_renderer.h @@ -29,12 +29,15 @@ class CC_EXPORT DirectRenderer : public Renderer { virtual bool CanReadPixels() const OVERRIDE; virtual void DecideRenderPassAllocationsForFrame( const RenderPassList& render_passes_in_draw_order) OVERRIDE; - virtual bool HaveCachedResourcesForRenderPassId(RenderPass::Id id) const + virtual bool HasAllocatedResourcesForTesting(RenderPass::Id id) const OVERRIDE; virtual void DrawFrame(RenderPassList* render_passes_in_draw_order, ContextProvider* offscreen_context_provider, float device_scale_factor, - bool allow_partial_swap) OVERRIDE; + gfx::Rect device_viewport_rect, + gfx::Rect device_clip_rect, + bool allow_partial_swap, + bool disable_picture_quad_image_filtering) OVERRIDE; struct CC_EXPORT DrawingFrame { DrawingFrame(); @@ -45,11 +48,15 @@ class CC_EXPORT DirectRenderer : public Renderer { const ScopedResource* current_texture; gfx::RectF root_damage_rect; + gfx::Rect device_viewport_rect; + gfx::Rect device_clip_rect; gfx::Transform projection_matrix; gfx::Transform window_matrix; ContextProvider* offscreen_context_provider; + + bool disable_picture_quad_image_filtering; }; void SetEnlargePassTextureAmountForTesting(gfx::Vector2d amount); @@ -60,28 +67,6 @@ class CC_EXPORT DirectRenderer : public Renderer { OutputSurface* output_surface, ResourceProvider* resource_provider); - class CachedResource : public ScopedResource { - public: - static scoped_ptr<CachedResource> Create( - ResourceProvider* resource_provider) { - return make_scoped_ptr(new CachedResource(resource_provider)); - } - virtual ~CachedResource() {} - - bool is_complete() const { return is_complete_; } - void set_is_complete(bool is_complete) { is_complete_ = is_complete; } - - protected: - explicit CachedResource(ResourceProvider* resource_provider) - : ScopedResource(resource_provider), - is_complete_(false) {} - - private: - bool is_complete_; - - DISALLOW_COPY_AND_ASSIGN(CachedResource); - }; - static gfx::RectF QuadVertexRect(); static void QuadRectTransform(gfx::Transform* quad_rect_transform, const gfx::Transform& quad_transform, @@ -93,7 +78,7 @@ class CC_EXPORT DirectRenderer : public Renderer { gfx::Rect MoveFromDrawToWindowSpace(const gfx::RectF& draw_rect) const; bool NeedDeviceClip(const DrawingFrame* frame) const; - gfx::Rect DeviceClipRect(const DrawingFrame* frame) const; + gfx::Rect DeviceClipRectInWindowSpace(const DrawingFrame* frame) const; static gfx::RectF ComputeScissorRectForRenderPass(const DrawingFrame* frame); void SetScissorStateForQuad(const DrawingFrame* frame, const DrawQuad& quad); void SetScissorStateForQuadWithRenderPassScissor( @@ -105,7 +90,6 @@ class CC_EXPORT DirectRenderer : public Renderer { gfx::RectF draw_space_rect); static gfx::Size RenderPassTextureSize(const RenderPass* render_pass); - static ResourceFormat RenderPassTextureFormat(const RenderPass* render_pass); void DrawRenderPass(DrawingFrame* frame, const RenderPass* render_pass, @@ -136,7 +120,7 @@ class CC_EXPORT DirectRenderer : public Renderer { DrawingFrame* frame, scoped_ptr<CopyOutputRequest> request) = 0; - base::ScopedPtrHashMap<RenderPass::Id, CachedResource> render_pass_textures_; + base::ScopedPtrHashMap<RenderPass::Id, ScopedResource> render_pass_textures_; OutputSurface* output_surface_; ResourceProvider* resource_provider_; diff --git a/chromium/cc/output/filter_operation.cc b/chromium/cc/output/filter_operation.cc index f4e3dde0ce5..50f111fc2d6 100644 --- a/chromium/cc/output/filter_operation.cc +++ b/chromium/cc/output/filter_operation.cc @@ -8,6 +8,7 @@ #include "cc/base/math_util.h" #include "cc/output/filter_operation.h" #include "third_party/skia/include/core/SkMath.h" +#include "ui/gfx/animation/tween.h" namespace cc { @@ -21,6 +22,8 @@ bool FilterOperation::operator==(const FilterOperation& other) const { drop_shadow_offset_ == other.drop_shadow_offset_ && drop_shadow_color_ == other.drop_shadow_color_; } + if (type_ == REFERENCE) + return image_filter_.get() == other.image_filter_.get(); return amount_ == other.amount_; } @@ -32,6 +35,7 @@ FilterOperation::FilterOperation(FilterType type, float amount) zoom_inset_(0) { DCHECK_NE(type_, DROP_SHADOW); DCHECK_NE(type_, COLOR_MATRIX); + DCHECK_NE(type_, REFERENCE); memset(matrix_, 0, sizeof(matrix_)); } @@ -68,50 +72,30 @@ FilterOperation::FilterOperation(FilterType type, float amount, int inset) memset(matrix_, 0, sizeof(matrix_)); } -// TODO(ajuma): Define a version of gfx::Tween::ValueBetween for floats, and use -// that instead. -static float BlendFloats(float from, float to, double progress) { - return from * (1.0 - progress) + to * progress; +FilterOperation::FilterOperation( + FilterType type, + const skia::RefPtr<SkImageFilter>& image_filter) + : type_(type), + amount_(0), + drop_shadow_offset_(0, 0), + drop_shadow_color_(0), + image_filter_(image_filter), + zoom_inset_(0) { + DCHECK_EQ(type_, REFERENCE); + memset(matrix_, 0, sizeof(matrix_)); } -static int BlendInts(int from, int to, double progress) { - return static_cast<int>( - MathUtil::Round(from * (1.0 - progress) + to * progress)); +FilterOperation::FilterOperation(const FilterOperation& other) + : type_(other.type_), + amount_(other.amount_), + drop_shadow_offset_(other.drop_shadow_offset_), + drop_shadow_color_(other.drop_shadow_color_), + image_filter_(other.image_filter_), + zoom_inset_(other.zoom_inset_) { + memcpy(matrix_, other.matrix_, sizeof(matrix_)); } -static uint8_t BlendColorComponents(uint8_t from, - uint8_t to, - uint8_t from_alpha, - uint8_t to_alpha, - uint8_t blended_alpha, - double progress) { - // Since progress can be outside [0, 1], blending can produce a value outside - // [0, 255]. - int blended_premultiplied = BlendInts(SkMulDiv255Round(from, from_alpha), - SkMulDiv255Round(to, to_alpha), - progress); - int blended = static_cast<int>( - MathUtil::Round(blended_premultiplied * 255.f / blended_alpha)); - return static_cast<uint8_t>(MathUtil::ClampToRange(blended, 0, 255)); -} - -static SkColor BlendSkColors(SkColor from, SkColor to, double progress) { - int from_a = SkColorGetA(from); - int to_a = SkColorGetA(to); - int blended_a = BlendInts(from_a, to_a, progress); - if (blended_a <= 0) - return SkColorSetARGB(0, 0, 0, 0); - blended_a = std::min(blended_a, 255); - - // TODO(ajuma): Use SkFourByteInterp once http://crbug.com/260369 is fixed. - uint8_t blended_r = BlendColorComponents( - SkColorGetR(from), SkColorGetR(to), from_a, to_a, blended_a, progress); - uint8_t blended_g = BlendColorComponents( - SkColorGetG(from), SkColorGetG(to), from_a, to_a, blended_a, progress); - uint8_t blended_b = BlendColorComponents( - SkColorGetB(from), SkColorGetB(to), from_a, to_a, blended_a, progress); - - return SkColorSetARGB(blended_a, blended_r, blended_g, blended_b); +FilterOperation::~FilterOperation() { } static FilterOperation CreateNoOpFilter(FilterOperation::FilterType type) { @@ -147,6 +131,9 @@ static FilterOperation CreateNoOpFilter(FilterOperation::FilterType type) { return FilterOperation::CreateZoomFilter(1.f, 0); case FilterOperation::SATURATING_BRIGHTNESS: return FilterOperation::CreateSaturatingBrightnessFilter(0.f); + case FilterOperation::REFERENCE: + return FilterOperation::CreateReferenceFilter( + skia::RefPtr<SkImageFilter>()); } NOTREACHED(); return FilterOperation::CreateEmptyFilter(); @@ -172,6 +159,7 @@ static float ClampAmountForFilterType(float amount, case FilterOperation::SATURATING_BRIGHTNESS: return amount; case FilterOperation::COLOR_MATRIX: + case FilterOperation::REFERENCE: NOTREACHED(); return amount; } @@ -197,22 +185,34 @@ FilterOperation FilterOperation::Blend(const FilterOperation* from, DCHECK(to_op.type() != FilterOperation::COLOR_MATRIX); blended_filter.set_type(to_op.type()); + if (to_op.type() == FilterOperation::REFERENCE) { + if (progress > 0.5) + blended_filter.set_image_filter(to_op.image_filter()); + else + blended_filter.set_image_filter(from_op.image_filter()); + return blended_filter; + } + blended_filter.set_amount(ClampAmountForFilterType( - BlendFloats(from_op.amount(), to_op.amount(), progress), to_op.type())); + gfx::Tween::FloatValueBetween(progress, from_op.amount(), to_op.amount()), + to_op.type())); if (to_op.type() == FilterOperation::DROP_SHADOW) { - gfx::Point blended_offset(BlendInts(from_op.drop_shadow_offset().x(), - to_op.drop_shadow_offset().x(), - progress), - BlendInts(from_op.drop_shadow_offset().y(), - to_op.drop_shadow_offset().y(), - progress)); + gfx::Point blended_offset( + gfx::Tween::LinearIntValueBetween(progress, + from_op.drop_shadow_offset().x(), + to_op.drop_shadow_offset().x()), + gfx::Tween::LinearIntValueBetween(progress, + from_op.drop_shadow_offset().y(), + to_op.drop_shadow_offset().y())); blended_filter.set_drop_shadow_offset(blended_offset); - blended_filter.set_drop_shadow_color(BlendSkColors( - from_op.drop_shadow_color(), to_op.drop_shadow_color(), progress)); + blended_filter.set_drop_shadow_color(gfx::Tween::ColorValueBetween( + progress, from_op.drop_shadow_color(), to_op.drop_shadow_color())); } else if (to_op.type() == FilterOperation::ZOOM) { - blended_filter.set_zoom_inset(std::max( - BlendInts(from_op.zoom_inset(), to_op.zoom_inset(), progress), 0)); + blended_filter.set_zoom_inset( + std::max(gfx::Tween::LinearIntValueBetween( + from_op.zoom_inset(), to_op.zoom_inset(), progress), + 0)); } return blended_filter; @@ -250,6 +250,18 @@ scoped_ptr<base::Value> FilterOperation::AsValue() const { value->SetDouble("amount", amount_); value->SetDouble("inset", zoom_inset_); break; + case FilterOperation::REFERENCE: { + int count_inputs = 0; + bool can_filter_image_gpu = false; + if (image_filter_) { + count_inputs = image_filter_->countInputs(); + can_filter_image_gpu = image_filter_->canFilterImageGPU(); + } + value->SetBoolean("is_null", !image_filter_); + value->SetInteger("count_inputs", count_inputs); + value->SetBoolean("can_filter_image_gpu", can_filter_image_gpu); + break; + } } return value.PassAs<base::Value>(); } diff --git a/chromium/cc/output/filter_operation.h b/chromium/cc/output/filter_operation.h index f56176213b1..f5c6a8264fa 100644 --- a/chromium/cc/output/filter_operation.h +++ b/chromium/cc/output/filter_operation.h @@ -8,7 +8,9 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" +#include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkScalar.h" #include "ui/gfx/point.h" @@ -33,13 +35,19 @@ class CC_EXPORT FilterOperation { DROP_SHADOW, COLOR_MATRIX, ZOOM, + REFERENCE, SATURATING_BRIGHTNESS, // Not used in CSS/SVG. }; + FilterOperation(const FilterOperation& other); + + ~FilterOperation(); + FilterType type() const { return type_; } float amount() const { DCHECK_NE(type_, COLOR_MATRIX); + DCHECK_NE(type_, REFERENCE); return amount_; } @@ -53,6 +61,11 @@ class CC_EXPORT FilterOperation { return drop_shadow_color_; } + skia::RefPtr<SkImageFilter> image_filter() const { + DCHECK_EQ(type_, REFERENCE); + return image_filter_; + } + const SkScalar* matrix() const { DCHECK_EQ(type_, COLOR_MATRIX); return matrix_; @@ -113,6 +126,11 @@ class CC_EXPORT FilterOperation { return FilterOperation(ZOOM, amount, inset); } + static FilterOperation CreateReferenceFilter( + const skia::RefPtr<SkImageFilter>& image_filter) { + return FilterOperation(REFERENCE, image_filter); + } + static FilterOperation CreateSaturatingBrightnessFilter(float amount) { return FilterOperation(SATURATING_BRIGHTNESS, amount); } @@ -132,6 +150,7 @@ class CC_EXPORT FilterOperation { void set_amount(float amount) { DCHECK_NE(type_, COLOR_MATRIX); + DCHECK_NE(type_, REFERENCE); amount_ = amount; } @@ -145,6 +164,11 @@ class CC_EXPORT FilterOperation { drop_shadow_color_ = color; } + void set_image_filter(const skia::RefPtr<SkImageFilter>& image_filter) { + DCHECK_EQ(type_, REFERENCE); + image_filter_ = image_filter; + } + void set_matrix(const SkScalar matrix[20]) { DCHECK_EQ(type_, COLOR_MATRIX); for (unsigned i = 0; i < 20; ++i) @@ -180,10 +204,14 @@ class CC_EXPORT FilterOperation { FilterOperation(FilterType type, float amount, int inset); + FilterOperation(FilterType type, + const skia::RefPtr<SkImageFilter>& image_filter); + FilterType type_; float amount_; gfx::Point drop_shadow_offset_; SkColor drop_shadow_color_; + skia::RefPtr<SkImageFilter> image_filter_; SkScalar matrix_[20]; int zoom_inset_; }; diff --git a/chromium/cc/output/filter_operations.cc b/chromium/cc/output/filter_operations.cc index e526f5c419b..21d222e94bf 100644 --- a/chromium/cc/output/filter_operations.cc +++ b/chromium/cc/output/filter_operations.cc @@ -59,7 +59,10 @@ void FilterOperations::GetOutsets(int* top, int* left) const { *top = *right = *bottom = *left = 0; for (size_t i = 0; i < operations_.size(); ++i) { - const FilterOperation op = operations_[i]; + const FilterOperation& op = operations_[i]; + // TODO(ajuma): Add support for reference filters once SkImageFilter + // reports its outsets. + DCHECK(op.type() != FilterOperation::REFERENCE); if (op.type() == FilterOperation::BLUR || op.type() == FilterOperation::DROP_SHADOW) { int spread = SpreadForStdDeviation(op.amount()); @@ -80,11 +83,14 @@ void FilterOperations::GetOutsets(int* top, bool FilterOperations::HasFilterThatMovesPixels() const { for (size_t i = 0; i < operations_.size(); ++i) { - const FilterOperation op = operations_[i]; + const FilterOperation& op = operations_[i]; + // TODO(ajuma): Once SkImageFilter reports its outsets, use those here to + // determine whether a reference filter really moves pixels. switch (op.type()) { case FilterOperation::BLUR: case FilterOperation::DROP_SHADOW: case FilterOperation::ZOOM: + case FilterOperation::REFERENCE: return true; case FilterOperation::OPACITY: case FilterOperation::COLOR_MATRIX: @@ -104,12 +110,15 @@ bool FilterOperations::HasFilterThatMovesPixels() const { bool FilterOperations::HasFilterThatAffectsOpacity() const { for (size_t i = 0; i < operations_.size(); ++i) { - const FilterOperation op = operations_[i]; + const FilterOperation& op = operations_[i]; + // TODO(ajuma): Make this smarter for reference filters. Once SkImageFilter + // can report affectsOpacity(), call that. switch (op.type()) { case FilterOperation::OPACITY: case FilterOperation::BLUR: case FilterOperation::DROP_SHADOW: case FilterOperation::ZOOM: + case FilterOperation::REFERENCE: return true; case FilterOperation::COLOR_MATRIX: { const SkScalar* matrix = op.matrix(); @@ -135,36 +144,53 @@ bool FilterOperations::HasFilterThatAffectsOpacity() const { return false; } +bool FilterOperations::HasReferenceFilter() const { + for (size_t i = 0; i < operations_.size(); ++i) { + if (operations_[i].type() == FilterOperation::REFERENCE) + return true; + } + return false; +} + FilterOperations FilterOperations::Blend(const FilterOperations& from, double progress) const { - FilterOperations blended_filters; - if (from.size() == 0) { - for (size_t i = 0; i < size(); i++) - blended_filters.Append(FilterOperation::Blend(NULL, &at(i), progress)); - return blended_filters; - } + if (HasReferenceFilter() || from.HasReferenceFilter()) + return *this; - if (size() == 0) { - for (size_t i = 0; i < from.size(); i++) { - blended_filters.Append( - FilterOperation::Blend(&from.at(i), NULL, progress)); - } - return blended_filters; + bool from_is_longer = from.size() > size(); + + size_t shorter_size, longer_size; + if (size() == from.size()) { + shorter_size = longer_size = size(); + } else if (from_is_longer) { + longer_size = from.size(); + shorter_size = size(); + } else { + longer_size = size(); + shorter_size = from.size(); } - if (from.size() != size()) - return *this; - - for (size_t i = 0; i < size(); i++) { + for (size_t i = 0; i < shorter_size; i++) { if (from.at(i).type() != at(i).type()) return *this; } - for (size_t i = 0; i < size(); i++) { + FilterOperations blended_filters; + for (size_t i = 0; i < shorter_size; i++) { blended_filters.Append( FilterOperation::Blend(&from.at(i), &at(i), progress)); } + if (from_is_longer) { + for (size_t i = shorter_size; i < longer_size; i++) { + blended_filters.Append( + FilterOperation::Blend(&from.at(i), NULL, progress)); + } + } else { + for (size_t i = shorter_size; i < longer_size; i++) + blended_filters.Append(FilterOperation::Blend(NULL, &at(i), progress)); + } + return blended_filters; } diff --git a/chromium/cc/output/filter_operations.h b/chromium/cc/output/filter_operations.h index aa8d58dd8d2..66f586573ba 100644 --- a/chromium/cc/output/filter_operations.h +++ b/chromium/cc/output/filter_operations.h @@ -44,6 +44,7 @@ class CC_EXPORT FilterOperations { void GetOutsets(int* top, int* right, int* bottom, int* left) const; bool HasFilterThatMovesPixels() const; bool HasFilterThatAffectsOpacity() const; + bool HasReferenceFilter() const; size_t size() const { return operations_.size(); @@ -55,18 +56,18 @@ class CC_EXPORT FilterOperations { } // If |from| is of the same size as this, where in each position, the filter - // in |from| is of the same type as the filter in this, returns a - // FilterOperations formed by linearly interpolating at each position a - // |progress| fraction of the way from the filter in |from| - // to the filter in this. If either |from| or this is an empty sequence, - // it is treated as a sequence of the same length as the other sequence, - // where the filter at each position is a no-op filter of the same type - // as the filter in that position in the other sequence. Otherwise, if - // both |from| and this are non-empty sequences but are either of different - // lengths or if there is a type mismatch at some position, returns a copy - // of this. + // in |from| is of the same type as the filter in this, and if this doesn't + // contain any reference filters, returns a FilterOperations formed by + // linearly interpolating at each position a |progress| fraction of the way + // from the filter in |from| to the filter in this. If |from| and this are of + // different lengths, they are treated as having the same length by padding + // the shorter sequence with no-op filters of the same type as the filters in + // the corresponding positions in the longer sequence. If either sequence has + // a reference filter or if there is a type mismatch at some position, returns + // a copy of this. FilterOperations Blend(const FilterOperations& from, double progress) const; + scoped_ptr<base::Value> AsValue() const; private: diff --git a/chromium/cc/output/filter_operations_unittest.cc b/chromium/cc/output/filter_operations_unittest.cc index dbf3736ccb0..329601fd726 100644 --- a/chromium/cc/output/filter_operations_unittest.cc +++ b/chromium/cc/output/filter_operations_unittest.cc @@ -3,7 +3,9 @@ // found in the LICENSE file. #include "cc/output/filter_operations.h" +#include "skia/ext/refptr.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/effects/SkBlurImageFilter.h" #include "ui/gfx/point.h" namespace cc { @@ -410,6 +412,11 @@ TEST(FilterOperationsTest, BlendDropShadowFilters) { gfx::Point(-2, -4), 0.f, SkColorSetARGB(0, 0, 0, 0)); EXPECT_EQ(expected, blended); + blended = FilterOperation::Blend(&from, &to, 0.25); + expected = FilterOperation::CreateDropShadowFilter( + gfx::Point(1, 1), 3.f, SkColorSetARGB(24, 32, 64, 128)); + EXPECT_EQ(expected, blended); + blended = FilterOperation::Blend(&from, &to, 0.75); expected = FilterOperation::CreateDropShadowFilter( gfx::Point(2, 4), 5.f, SkColorSetARGB(42, 30, 61, 121)); @@ -497,6 +504,45 @@ TEST(FilterOperationsTest, BlendSaturatingBrightnessWithNull) { EXPECT_EQ(expected, blended); } +TEST(FilterOperationsTest, BlendReferenceFilters) { + skia::RefPtr<SkImageFilter> from_filter = skia::AdoptRef( + new SkBlurImageFilter(1.f, 1.f)); + skia::RefPtr<SkImageFilter> to_filter = skia::AdoptRef( + new SkBlurImageFilter(2.f, 2.f)); + FilterOperation from = FilterOperation::CreateReferenceFilter(from_filter); + FilterOperation to = FilterOperation::CreateReferenceFilter(to_filter); + + FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75); + EXPECT_EQ(from, blended); + + blended = FilterOperation::Blend(&from, &to, 0.5); + EXPECT_EQ(from, blended); + + blended = FilterOperation::Blend(&from, &to, 0.6); + EXPECT_EQ(to, blended); + + blended = FilterOperation::Blend(&from, &to, 1.5); + EXPECT_EQ(to, blended); +} + +TEST(FilterOperationsTest, BlendReferenceWithNull) { + skia::RefPtr<SkImageFilter> image_filter = skia::AdoptRef( + new SkBlurImageFilter(1.f, 1.f)); + FilterOperation filter = FilterOperation::CreateReferenceFilter(image_filter); + FilterOperation null_filter = + FilterOperation::CreateReferenceFilter(skia::RefPtr<SkImageFilter>()); + + FilterOperation blended = FilterOperation::Blend(&filter, NULL, 0.25); + EXPECT_EQ(filter, blended); + blended = FilterOperation::Blend(&filter, NULL, 0.75); + EXPECT_EQ(null_filter, blended); + + blended = FilterOperation::Blend(NULL, &filter, 0.25); + EXPECT_EQ(null_filter, blended); + blended = FilterOperation::Blend(NULL, &filter, 0.75); + EXPECT_EQ(filter, blended); +} + // Tests blending non-empty sequences that have the same length and matching // operations. TEST(FilterOperationsTest, BlendMatchingSequences) { @@ -598,8 +644,7 @@ TEST(FilterOperationsTest, BlendEmptySequences) { EXPECT_EQ(blended, empty); } -// Tests blending non-empty sequences that either have different lengths or -// have non-matching operations. +// Tests blending non-empty sequences that have non-matching operations. TEST(FilterOperationsTest, BlendNonMatchingSequences) { FilterOperations from; FilterOperations to; @@ -607,6 +652,7 @@ TEST(FilterOperationsTest, BlendNonMatchingSequences) { from.Append(FilterOperation::CreateSaturateFilter(3.f)); from.Append(FilterOperation::CreateBlurFilter(2.f)); to.Append(FilterOperation::CreateSaturateFilter(4.f)); + to.Append(FilterOperation::CreateHueRotateFilter(0.5f)); FilterOperations blended = to.Blend(from, -0.75); EXPECT_EQ(to, blended); @@ -614,8 +660,37 @@ TEST(FilterOperationsTest, BlendNonMatchingSequences) { EXPECT_EQ(to, blended); blended = to.Blend(from, 1.5); EXPECT_EQ(to, blended); +} - to.Append(FilterOperation::CreateHueRotateFilter(0.5f)); +// Tests blending non-empty sequences of different sizes. +TEST(FilterOperationsTest, BlendRaggedSequences) { + FilterOperations from; + FilterOperations to; + + from.Append(FilterOperation::CreateSaturateFilter(3.f)); + from.Append(FilterOperation::CreateBlurFilter(2.f)); + to.Append(FilterOperation::CreateSaturateFilter(4.f)); + + FilterOperations blended = to.Blend(from, -0.75); + FilterOperations expected; + expected.Append(FilterOperation::CreateSaturateFilter(2.25f)); + expected.Append(FilterOperation::CreateBlurFilter(3.5f)); + EXPECT_EQ(expected, blended); + + blended = to.Blend(from, 0.75); + expected.Clear(); + expected.Append(FilterOperation::CreateSaturateFilter(3.75f)); + expected.Append(FilterOperation::CreateBlurFilter(0.5f)); + EXPECT_EQ(expected, blended); + + blended = to.Blend(from, 1.5); + expected.Clear(); + expected.Append(FilterOperation::CreateSaturateFilter(4.5f)); + expected.Append(FilterOperation::CreateBlurFilter(0.f)); + EXPECT_EQ(expected, blended); + + from.Append(FilterOperation::CreateOpacityFilter(1.f)); + to.Append(FilterOperation::CreateOpacityFilter(1.f)); blended = to.Blend(from, -0.75); EXPECT_EQ(to, blended); blended = to.Blend(from, 0.75); diff --git a/chromium/cc/output/geometry_binding.cc b/chromium/cc/output/geometry_binding.cc index 3b177c2fe20..bf87b1e8900 100644 --- a/chromium/cc/output/geometry_binding.cc +++ b/chromium/cc/output/geometry_binding.cc @@ -5,17 +5,15 @@ #include "cc/output/geometry_binding.h" #include "cc/output/gl_renderer.h" // For the GLC() macro. -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" +#include "gpu/command_buffer/client/gles2_interface.h" #include "third_party/khronos/GLES2/gl2.h" #include "ui/gfx/rect_f.h" namespace cc { -GeometryBinding::GeometryBinding(WebKit::WebGraphicsContext3D* context, +GeometryBinding::GeometryBinding(gpu::gles2::GLES2Interface* gl, const gfx::RectF& quad_vertex_rect) - : context_(context), - quad_vertices_vbo_(0), - quad_elements_vbo_(0) { + : gl_(gl), quad_vertices_vbo_(0), quad_elements_vbo_(0) { struct Vertex { float a_position[3]; float a_texCoord[2]; @@ -29,9 +27,8 @@ GeometryBinding::GeometryBinding(WebKit::WebGraphicsContext3D* context, uint16 data[6]; }; - COMPILE_ASSERT( - sizeof(Quad) == 24 * sizeof(float), // NOLINT(runtime/sizeof) - struct_is_densely_packed); + COMPILE_ASSERT(sizeof(Quad) == 24 * sizeof(float), // NOLINT(runtime/sizeof) + struct_is_densely_packed); COMPILE_ASSERT( sizeof(QuadIndex) == 6 * sizeof(uint16_t), // NOLINT(runtime/sizeof) struct_is_densely_packed); @@ -39,84 +36,80 @@ GeometryBinding::GeometryBinding(WebKit::WebGraphicsContext3D* context, Quad quad_list[8]; QuadIndex quad_index_list[8]; for (int i = 0; i < 8; i++) { - Vertex v0 = { { quad_vertex_rect.x(), quad_vertex_rect.bottom(), 0.0f, }, - { 0.0f, 1.0f, }, - i * 4.0f + 0.0f }; - Vertex v1 = { { quad_vertex_rect.x(), quad_vertex_rect.y(), 0.0f, }, - { 0.0f, 0.0f, }, - i * 4.0f + 1.0f }; - Vertex v2 = { { quad_vertex_rect.right(), quad_vertex_rect.y(), 0.0f, }, - { 1.0f, .0f, }, - i * 4.0f + 2.0f }; - Vertex v3 = { { quad_vertex_rect.right(), - quad_vertex_rect.bottom(), - 0.0f, }, - { 1.0f, 1.0f, }, - i * 4.0f + 3.0f }; - Quad x = { v0, v1, v2, v3 }; + Vertex v0 = {{quad_vertex_rect.x(), quad_vertex_rect.bottom(), 0.0f, }, + {0.0f, 1.0f, }, i * 4.0f + 0.0f}; + Vertex v1 = {{quad_vertex_rect.x(), quad_vertex_rect.y(), 0.0f, }, + {0.0f, 0.0f, }, i * 4.0f + 1.0f}; + Vertex v2 = {{quad_vertex_rect.right(), quad_vertex_rect.y(), 0.0f, }, + {1.0f, .0f, }, i * 4.0f + 2.0f}; + Vertex v3 = {{quad_vertex_rect.right(), quad_vertex_rect.bottom(), 0.0f, }, + {1.0f, 1.0f, }, i * 4.0f + 3.0f}; + Quad x = {v0, v1, v2, v3}; quad_list[i] = x; - QuadIndex y = { { static_cast<uint16>(0 + 4 * i), - static_cast<uint16>(1 + 4 * i), - static_cast<uint16>(2 + 4 * i), - static_cast<uint16>(3 + 4 * i), - static_cast<uint16>(0 + 4 * i), - static_cast<uint16>(2 + 4 * i) } }; + QuadIndex y = { + {static_cast<uint16>(0 + 4 * i), static_cast<uint16>(1 + 4 * i), + static_cast<uint16>(2 + 4 * i), static_cast<uint16>(3 + 4 * i), + static_cast<uint16>(0 + 4 * i), static_cast<uint16>(2 + 4 * i)}}; quad_index_list[i] = y; } - GLC(context_, quad_vertices_vbo_ = context_->createBuffer()); - GLC(context_, quad_elements_vbo_ = context_->createBuffer()); - GLC(context_, context_->bindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_)); - GLC(context_, - context_->bufferData( + gl_->GenBuffers(1, &quad_vertices_vbo_); + gl_->GenBuffers(1, &quad_elements_vbo_); + GLC(gl_, gl_->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_)); + GLC(gl_, + gl_->BufferData( GL_ARRAY_BUFFER, sizeof(quad_list), quad_list, GL_STATIC_DRAW)); - GLC(context_, - context_->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_)); - GLC(context_, - context_->bufferData(GL_ELEMENT_ARRAY_BUFFER, - sizeof(quad_index_list), - quad_index_list, - GL_STATIC_DRAW)); + GLC(gl_, gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_)); + GLC(gl_, + gl_->BufferData(GL_ELEMENT_ARRAY_BUFFER, + sizeof(quad_index_list), + quad_index_list, + GL_STATIC_DRAW)); } GeometryBinding::~GeometryBinding() { - GLC(context_, context_->deleteBuffer(quad_vertices_vbo_)); - GLC(context_, context_->deleteBuffer(quad_elements_vbo_)); + gl_->DeleteBuffers(1, &quad_vertices_vbo_); + gl_->DeleteBuffers(1, &quad_elements_vbo_); } void GeometryBinding::PrepareForDraw() { - GLC(context_, - context_->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_)); + GLC(gl_, gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_)); + + GLC(gl_, gl_->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_)); + // OpenGL defines the last parameter to VertexAttribPointer as type + // "const GLvoid*" even though it is actually an offset into the buffer + // object's data store and not a pointer to the client's address space. + const void* offsets[3] = { + 0, reinterpret_cast<const void*>( + 3 * sizeof(float)), // NOLINT(runtime/sizeof) + reinterpret_cast<const void*>(5 * + sizeof(float)), // NOLINT(runtime/sizeof) + }; - GLC(context_, context_->bindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_)); - GLC(context_, - context_->vertexAttribPointer( - PositionAttribLocation(), - 3, - GL_FLOAT, - false, - 6 * sizeof(float), // NOLINT(runtime/sizeof) - 0)); - GLC(context_, - context_->vertexAttribPointer( - TexCoordAttribLocation(), - 2, - GL_FLOAT, - false, - 6 * sizeof(float), // NOLINT(runtime/sizeof) - 3 * sizeof(float))); // NOLINT(runtime/sizeof) - GLC(context_, - context_->vertexAttribPointer( - TriangleIndexAttribLocation(), - 1, - GL_FLOAT, - false, - 6 * sizeof(float), // NOLINT(runtime/sizeof) - 5 * sizeof(float))); // NOLINT(runtime/sizeof) - GLC(context_, context_->enableVertexAttribArray(PositionAttribLocation())); - GLC(context_, context_->enableVertexAttribArray(TexCoordAttribLocation())); - GLC(context_, - context_->enableVertexAttribArray(TriangleIndexAttribLocation())); + GLC(gl_, + gl_->VertexAttribPointer(PositionAttribLocation(), + 3, + GL_FLOAT, + false, + 6 * sizeof(float), // NOLINT(runtime/sizeof) + offsets[0])); + GLC(gl_, + gl_->VertexAttribPointer(TexCoordAttribLocation(), + 2, + GL_FLOAT, + false, + 6 * sizeof(float), // NOLINT(runtime/sizeof) + offsets[1])); + GLC(gl_, + gl_->VertexAttribPointer(TriangleIndexAttribLocation(), + 1, + GL_FLOAT, + false, + 6 * sizeof(float), // NOLINT(runtime/sizeof) + offsets[2])); + GLC(gl_, gl_->EnableVertexAttribArray(PositionAttribLocation())); + GLC(gl_, gl_->EnableVertexAttribArray(TexCoordAttribLocation())); + GLC(gl_, gl_->EnableVertexAttribArray(TriangleIndexAttribLocation())); } } // namespace cc diff --git a/chromium/cc/output/geometry_binding.h b/chromium/cc/output/geometry_binding.h index 2318b27ecff..cfa21efd1fc 100644 --- a/chromium/cc/output/geometry_binding.h +++ b/chromium/cc/output/geometry_binding.h @@ -6,16 +6,22 @@ #define CC_OUTPUT_GEOMETRY_BINDING_H_ #include "base/basictypes.h" +#include "third_party/khronos/GLES2/gl2.h" -namespace gfx { class RectF; } - -namespace WebKit { class WebGraphicsContext3D; } +namespace gfx { +class RectF; +} +namespace gpu { +namespace gles2 { +class GLES2Interface; +} +} namespace cc { class GeometryBinding { public: - GeometryBinding(WebKit::WebGraphicsContext3D* context, + GeometryBinding(gpu::gles2::GLES2Interface* gl, const gfx::RectF& quad_vertex_rect); ~GeometryBinding(); @@ -29,10 +35,10 @@ class GeometryBinding { static int TriangleIndexAttribLocation() { return 2; } private: - WebKit::WebGraphicsContext3D* context_; + gpu::gles2::GLES2Interface* gl_; - unsigned quad_vertices_vbo_; - unsigned quad_elements_vbo_; + GLuint quad_vertices_vbo_; + GLuint quad_elements_vbo_; DISALLOW_COPY_AND_ASSIGN(GeometryBinding); }; diff --git a/chromium/cc/output/gl_renderer.cc b/chromium/cc/output/gl_renderer.cc index f4b1e575d39..f0e32f43083 100644 --- a/chromium/cc/output/gl_renderer.cc +++ b/chromium/cc/output/gl_renderer.cc @@ -16,6 +16,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" +#include "cc/base/util.h" #include "cc/base/math_util.h" #include "cc/layers/video_layer_impl.h" #include "cc/output/compositor_frame.h" @@ -32,12 +33,14 @@ #include "cc/quads/texture_draw_quad.h" #include "cc/resources/layer_quad.h" #include "cc/resources/scoped_resource.h" -#include "cc/resources/sync_point_helper.h" #include "cc/resources/texture_mailbox_deleter.h" #include "cc/trees/damage_tracker.h" #include "cc/trees/proxy.h" #include "cc/trees/single_thread_proxy.h" #include "gpu/GLES2/gl2extchromium.h" +#include "gpu/command_buffer/client/context_support.h" +#include "gpu/command_buffer/client/gles2_interface.h" +#include "gpu/command_buffer/common/gpu_memory_allocation.h" #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" @@ -53,7 +56,8 @@ #include "ui/gfx/quad_f.h" #include "ui/gfx/rect_conversions.h" -using WebKit::WebGraphicsContext3D; +using blink::WebGraphicsContext3D; +using gpu::gles2::GLES2Interface; namespace cc { @@ -71,6 +75,7 @@ class SimpleSwapFence : public ResourceProvider::Fence { SimpleSwapFence() : has_passed_(false) {} virtual bool HasPassed() OVERRIDE { return has_passed_; } void SetHasPassed() { has_passed_ = true; } + private: virtual ~SimpleSwapFence() {} bool has_passed_; @@ -89,7 +94,7 @@ bool NeedsIOSurfaceReadbackWorkaround() { Float4 UVTransform(const TextureDrawQuad* quad) { gfx::PointF uv0 = quad->uv_top_left; gfx::PointF uv1 = quad->uv_bottom_right; - Float4 xform = { { uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y() } }; + Float4 xform = {{uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y()}}; if (quad->flipped) { xform.data[1] = 1.0f - xform.data[1]; xform.data[3] = -xform.data[3]; @@ -101,15 +106,26 @@ Float4 PremultipliedColor(SkColor color) { const float factor = 1.0f / 255.0f; const float alpha = SkColorGetA(color) * factor; - Float4 result = { { - SkColorGetR(color) * factor * alpha, - SkColorGetG(color) * factor * alpha, - SkColorGetB(color) * factor * alpha, - alpha - } }; + Float4 result = { + {SkColorGetR(color) * factor * alpha, SkColorGetG(color) * factor * alpha, + SkColorGetB(color) * factor * alpha, alpha}}; return result; } +SamplerType SamplerTypeFromTextureTarget(GLenum target) { + switch (target) { + case GL_TEXTURE_2D: + return SamplerType2D; + case GL_TEXTURE_RECTANGLE_ARB: + return SamplerType2DRect; + case GL_TEXTURE_EXTERNAL_OES: + return SamplerTypeExternalOES; + default: + NOTREACHED(); + return SamplerType2D; + } +} + // Smallest unit that impact anti-aliasing output. We use this to // determine when anti-aliasing is unnecessary. const float kAntiAliasingEpsilon = 1.0f / 1024.0f; @@ -133,23 +149,13 @@ scoped_ptr<GLRenderer> GLRenderer::Create( OutputSurface* output_surface, ResourceProvider* resource_provider, TextureMailboxDeleter* texture_mailbox_deleter, - int highp_threshold_min, - bool use_skia_gpu_backend) { - scoped_ptr<GLRenderer> renderer(new GLRenderer(client, - settings, - output_surface, - resource_provider, - texture_mailbox_deleter, - highp_threshold_min)); - if (!renderer->Initialize()) - return scoped_ptr<GLRenderer>(); - if (use_skia_gpu_backend) { - renderer->InitializeGrContext(); - DCHECK(renderer->CanUseSkiaGPUBackend()) - << "Requested Skia GPU backend, but can't use it."; - } - - return renderer.Pass(); + int highp_threshold_min) { + return make_scoped_ptr(new GLRenderer(client, + settings, + output_surface, + resource_provider, + texture_mailbox_deleter, + highp_threshold_min)); } GLRenderer::GLRenderer(RendererClient* client, @@ -162,32 +168,27 @@ GLRenderer::GLRenderer(RendererClient* client, offscreen_framebuffer_id_(0), shared_geometry_quad_(gfx::RectF(-0.5f, -0.5f, 1.0f, 1.0f)), context_(output_surface->context_provider()->Context3d()), + gl_(output_surface->context_provider()->ContextGL()), + context_support_(output_surface->context_provider()->ContextSupport()), texture_mailbox_deleter_(texture_mailbox_deleter), is_backbuffer_discarded_(false), - discard_backbuffer_when_not_visible_(false), - is_using_bind_uniform_(false), visible_(true), is_scissor_enabled_(false), + scissor_rect_needs_reset_(true), stencil_shadow_(false), blend_shadow_(false), highp_threshold_min_(highp_threshold_min), highp_threshold_cache_(0), on_demand_tile_raster_resource_id_(0) { DCHECK(context_); -} - -bool GLRenderer::Initialize() { - if (!context_->makeContextCurrent()) - return false; + DCHECK(context_support_); ContextProvider::Capabilities context_caps = - output_surface_->context_provider()->ContextCapabilities(); + output_surface_->context_provider()->ContextCapabilities(); capabilities_.using_partial_swap = settings_->partial_swap_enabled && context_caps.post_sub_buffer; - capabilities_.using_set_visibility = context_caps.set_visibility; - DCHECK(!context_caps.iosurface || context_caps.texture_rectangle); capabilities_.using_egl_image = context_caps.egl_image_external; @@ -207,29 +208,9 @@ bool GLRenderer::Initialize() { capabilities_.using_map_image = settings_->use_map_image && context_caps.map_image; - capabilities_.using_discard_framebuffer = - context_caps.discard_framebuffer; - - is_using_bind_uniform_ = context_caps.bind_uniform_location; + capabilities_.using_discard_framebuffer = context_caps.discard_framebuffer; - if (!InitializeSharedObjects()) - return false; - - // Make sure the viewport and context gets initialized, even if it is to zero. - ViewportChanged(); - return true; -} - -void GLRenderer::InitializeGrContext() { - skia::RefPtr<GrGLInterface> interface = skia::AdoptRef( - context_->createGrGLInterface()); - if (!interface) - return; - - gr_context_ = skia::AdoptRef(GrContext::Create( - kOpenGL_GrBackend, - reinterpret_cast<GrBackendContext>(interface.get()))); - ReinitializeGrCanvas(); + InitializeSharedObjects(); } GLRenderer::~GLRenderer() { @@ -248,11 +229,11 @@ const RendererCapabilities& GLRenderer::Capabilities() const { WebGraphicsContext3D* GLRenderer::Context() { return context_; } -void GLRenderer::DebugGLCall(WebGraphicsContext3D* context, +void GLRenderer::DebugGLCall(GLES2Interface* gl, const char* command, const char* file, int line) { - unsigned error = context->getError(); + GLuint error = gl->GetError(); if (error != GL_NO_ERROR) LOG(ERROR) << "GL command failed: File: " << file << "\n\tLine " << line << "\n\tcommand: " << command << ", error " @@ -266,30 +247,22 @@ void GLRenderer::SetVisible(bool visible) { EnforceMemoryPolicy(); - // TODO(jamesr): Replace setVisibilityCHROMIUM() with an extension to - // explicitly manage front/backbuffers - // crbug.com/116049 - if (capabilities_.using_set_visibility) - context_->setVisibilityCHROMIUM(visible); + context_support_->SetSurfaceVisible(visible); } void GLRenderer::SendManagedMemoryStats(size_t bytes_visible, size_t bytes_visible_and_nearby, size_t bytes_allocated) { - WebKit::WebGraphicsManagedMemoryStats stats; - stats.bytesVisible = bytes_visible; - stats.bytesVisibleAndNearby = bytes_visible_and_nearby; - stats.bytesAllocated = bytes_allocated; - stats.backbufferRequested = !is_backbuffer_discarded_; - context_->sendManagedMemoryStatsCHROMIUM(&stats); + gpu::ManagedMemoryStats stats; + stats.bytes_required = bytes_visible; + stats.bytes_nice_to_have = bytes_visible_and_nearby; + stats.bytes_allocated = bytes_allocated; + stats.backbuffer_requested = !is_backbuffer_discarded_; + context_support_->SendManagedMemoryStats(stats); } void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); } -void GLRenderer::ViewportChanged() { - ReinitializeGrCanvas(); -} - void GLRenderer::DiscardPixels(bool has_external_stencil_test, bool draw_rect_covers_full_surface) { if (has_external_stencil_test || !draw_rect_covers_full_surface || @@ -300,7 +273,7 @@ void GLRenderer::DiscardPixels(bool has_external_stencil_test, output_surface_->capabilities().uses_default_gl_framebuffer; GLenum attachments[] = {static_cast<GLenum>( using_default_framebuffer ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0_EXT)}; - context_->discardFramebufferEXT( + gl_->DiscardFramebufferEXT( GL_FRAMEBUFFER, arraysize(attachments), attachments); } @@ -316,9 +289,9 @@ void GLRenderer::ClearFramebuffer(DrawingFrame* frame, // On DEBUG builds, opaque render passes are cleared to blue to easily see // regions that were not drawn on the screen. if (frame->current_render_pass->has_transparent_background) - GLC(context_, context_->clearColor(0, 0, 0, 0)); + GLC(gl_, gl_->ClearColor(0, 0, 0, 0)); else - GLC(context_, context_->clearColor(0, 0, 1, 1)); + GLC(gl_, gl_->ClearColor(0, 0, 1, 1)); bool always_clear = false; #ifndef NDEBUG @@ -326,30 +299,25 @@ void GLRenderer::ClearFramebuffer(DrawingFrame* frame, #endif if (always_clear || frame->current_render_pass->has_transparent_background) { GLbitfield clear_bits = GL_COLOR_BUFFER_BIT; - // Only the Skia GPU backend uses the stencil buffer. No need to clear it - // otherwise. - if (always_clear || CanUseSkiaGPUBackend()) { - GLC(context_, context_->clearStencil(0)); + if (always_clear) clear_bits |= GL_STENCIL_BUFFER_BIT; - } - context_->clear(clear_bits); + gl_->Clear(clear_bits); } } void GLRenderer::BeginDrawingFrame(DrawingFrame* frame) { - if (client_->DeviceViewport().IsEmpty()) + if (frame->device_viewport_rect.IsEmpty()) return; - TRACE_EVENT0("cc", "GLRenderer::DrawLayers"); - - MakeContextCurrent(); + TRACE_EVENT0("cc", "GLRenderer::BeginDrawingFrame"); + // TODO(enne): Do we need to reinitialize all of this state per frame? ReinitializeGLState(); } void GLRenderer::DoNoOp() { - GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0)); - GLC(context_, context_->flush()); + GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, 0)); + GLC(gl_, gl_->Flush()); } void GLRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) { @@ -404,12 +372,12 @@ void GLRenderer::DrawCheckerboardQuad(const DrawingFrame* frame, SetUseProgram(program->program()); SkColor color = quad->color; - GLC(Context(), - Context()->uniform4f(program->fragment_shader().color_location(), - SkColorGetR(color) * (1.0f / 255.0f), - SkColorGetG(color) * (1.0f / 255.0f), - SkColorGetB(color) * (1.0f / 255.0f), - 1)); + GLC(gl_, + gl_->Uniform4f(program->fragment_shader().color_location(), + SkColorGetR(color) * (1.0f / 255.0f), + SkColorGetG(color) * (1.0f / 255.0f), + SkColorGetB(color) * (1.0f / 255.0f), + 1)); const int checkerboard_width = 16; float frequency = 1.0f / checkerboard_width; @@ -419,16 +387,16 @@ void GLRenderer::DrawCheckerboardQuad(const DrawingFrame* frame, float tex_offset_y = tile_rect.y() % checkerboard_width; float tex_scale_x = tile_rect.width(); float tex_scale_y = tile_rect.height(); - GLC(Context(), - Context()->uniform4f(program->fragment_shader().tex_transform_location(), - tex_offset_x, - tex_offset_y, - tex_scale_x, - tex_scale_y)); + GLC(gl_, + gl_->Uniform4f(program->fragment_shader().tex_transform_location(), + tex_offset_x, + tex_offset_y, + tex_scale_x, + tex_scale_y)); - GLC(Context(), - Context()->uniform1f(program->fragment_shader().frequency_location(), - frequency)); + GLC(gl_, + gl_->Uniform1f(program->fragment_shader().frequency_location(), + frequency)); SetShaderOpacity(quad->opacity(), program->fragment_shader().alpha_location()); @@ -456,66 +424,25 @@ void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame, render_matrix.Scale(layer_rect.width(), layer_rect.height()); GLRenderer::ToGLMatrix(&gl_matrix[0], frame->projection_matrix * render_matrix); - GLC(Context(), - Context()->uniformMatrix4fv( + GLC(gl_, + gl_->UniformMatrix4fv( program->vertex_shader().matrix_location(), 1, false, &gl_matrix[0])); SkColor color = quad->color; float alpha = SkColorGetA(color) * (1.0f / 255.0f); - GLC(Context(), - Context()->uniform4f(program->fragment_shader().color_location(), - (SkColorGetR(color) * (1.0f / 255.0f)) * alpha, - (SkColorGetG(color) * (1.0f / 255.0f)) * alpha, - (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, - alpha)); + GLC(gl_, + gl_->Uniform4f(program->fragment_shader().color_location(), + (SkColorGetR(color) * (1.0f / 255.0f)) * alpha, + (SkColorGetG(color) * (1.0f / 255.0f)) * alpha, + (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, + alpha)); - GLC(Context(), Context()->lineWidth(quad->width)); + GLC(gl_, gl_->LineWidth(quad->width)); // The indices for the line are stored in the same array as the triangle // indices. - GLC(Context(), - Context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0)); -} - -static inline SkBitmap ApplyFilters(GLRenderer* renderer, - ContextProvider* offscreen_contexts, - const FilterOperations& filters, - ScopedResource* source_texture_resource) { - if (filters.IsEmpty()) - return SkBitmap(); - - if (!offscreen_contexts || !offscreen_contexts->GrContext()) - return SkBitmap(); - - ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(), - source_texture_resource->id()); - - // Flush the compositor context to ensure that textures there are available - // in the shared context. Do this after locking/creating the compositor - // texture. - renderer->resource_provider()->Flush(); - - // Make sure skia uses the correct GL context. - offscreen_contexts->Context3d()->makeContextCurrent(); - - SkBitmap source = - RenderSurfaceFilters::Apply(filters, - lock.texture_id(), - source_texture_resource->size(), - offscreen_contexts->GrContext()); - - // Flush skia context so that all the rendered stuff appears on the - // texture. - offscreen_contexts->GrContext()->flush(); - - // Flush the GL context so rendering results from this context are - // visible in the compositor's context. - offscreen_contexts->Context3d()->flush(); - - // Use the compositor's GL context again. - renderer->Context()->makeContextCurrent(); - return source; + GLC(gl_, gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0)); } static SkBitmap ApplyImageFilter(GLRenderer* renderer, @@ -538,7 +465,7 @@ static SkBitmap ApplyImageFilter(GLRenderer* renderer, renderer->resource_provider()->Flush(); // Make sure skia uses the correct GL context. - offscreen_contexts->Context3d()->makeContextCurrent(); + offscreen_contexts->MakeGrContextCurrent(); // Wrap the source texture in a Ganesh platform texture. GrBackendTextureDesc backend_texture_description; @@ -552,13 +479,17 @@ static SkBitmap ApplyImageFilter(GLRenderer* renderer, skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture( backend_texture_description)); + SkImageInfo info = { + source_texture_resource->size().width(), + source_texture_resource->size().height(), + kPMColor_SkColorType, + kPremul_SkAlphaType + }; // Place the platform texture inside an SkBitmap. SkBitmap source; - source.setConfig(SkBitmap::kARGB_8888_Config, - source_texture_resource->size().width(), - source_texture_resource->size().height()); + source.setConfig(info); skia::RefPtr<SkGrPixelRef> pixel_ref = - skia::AdoptRef(new SkGrPixelRef(texture.get())); + skia::AdoptRef(new SkGrPixelRef(info, texture.get())); source.setPixelRef(pixel_ref.get()); // Create a scratch texture for backing store. @@ -597,17 +528,140 @@ static SkBitmap ApplyImageFilter(GLRenderer* renderer, // visible in the compositor's context. offscreen_contexts->Context3d()->flush(); - // Use the compositor's GL context again. - renderer->Context()->makeContextCurrent(); + return device.accessBitmap(false); +} + +static SkBitmap ApplyBlendModeWithBackdrop( + GLRenderer* renderer, + ContextProvider* offscreen_contexts, + SkBitmap source_bitmap_with_filters, + ScopedResource* source_texture_resource, + ScopedResource* background_texture_resource, + SkXfermode::Mode blend_mode) { + if (!offscreen_contexts || !offscreen_contexts->GrContext()) + return source_bitmap_with_filters; + + DCHECK(background_texture_resource); + DCHECK(source_texture_resource); + + gfx::Size source_size = source_texture_resource->size(); + gfx::Size background_size = background_texture_resource->size(); + + DCHECK_LE(background_size.width(), source_size.width()); + DCHECK_LE(background_size.height(), source_size.height()); + + int source_texture_with_filters_id; + scoped_ptr<ResourceProvider::ScopedReadLockGL> lock; + if (source_bitmap_with_filters.getTexture()) { + DCHECK_EQ(source_size.width(), source_bitmap_with_filters.width()); + DCHECK_EQ(source_size.height(), source_bitmap_with_filters.height()); + GrTexture* texture = + reinterpret_cast<GrTexture*>(source_bitmap_with_filters.getTexture()); + source_texture_with_filters_id = texture->getTextureHandle(); + } else { + lock.reset(new ResourceProvider::ScopedReadLockGL( + renderer->resource_provider(), source_texture_resource->id())); + source_texture_with_filters_id = lock->texture_id(); + } + + ResourceProvider::ScopedReadLockGL lock_background( + renderer->resource_provider(), background_texture_resource->id()); + + // Flush the compositor context to ensure that textures there are available + // in the shared context. Do this after locking/creating the compositor + // texture. + renderer->resource_provider()->Flush(); + + // Make sure skia uses the correct GL context. + offscreen_contexts->MakeGrContextCurrent(); + + // Wrap the source texture in a Ganesh platform texture. + GrBackendTextureDesc backend_texture_description; + backend_texture_description.fConfig = kSkia8888_GrPixelConfig; + backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin; + + backend_texture_description.fWidth = source_size.width(); + backend_texture_description.fHeight = source_size.height(); + backend_texture_description.fTextureHandle = source_texture_with_filters_id; + skia::RefPtr<GrTexture> source_texture = + skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture( + backend_texture_description)); + + backend_texture_description.fWidth = background_size.width(); + backend_texture_description.fHeight = background_size.height(); + backend_texture_description.fTextureHandle = lock_background.texture_id(); + skia::RefPtr<GrTexture> background_texture = + skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture( + backend_texture_description)); + + SkImageInfo source_info = { + source_size.width(), + source_size.height(), + kPMColor_SkColorType, + kPremul_SkAlphaType + }; + // Place the platform texture inside an SkBitmap. + SkBitmap source; + source.setConfig(source_info); + skia::RefPtr<SkGrPixelRef> source_pixel_ref = + skia::AdoptRef(new SkGrPixelRef(source_info, source_texture.get())); + source.setPixelRef(source_pixel_ref.get()); + + SkImageInfo background_info = { + background_size.width(), + background_size.height(), + kPMColor_SkColorType, + kPremul_SkAlphaType + }; + + SkBitmap background; + background.setConfig(background_info); + skia::RefPtr<SkGrPixelRef> background_pixel_ref = + skia::AdoptRef(new SkGrPixelRef( + background_info, background_texture.get())); + background.setPixelRef(background_pixel_ref.get()); + + // Create a scratch texture for backing store. + GrTextureDesc desc; + desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; + desc.fSampleCnt = 0; + desc.fWidth = source.width(); + desc.fHeight = source.height(); + desc.fConfig = kSkia8888_GrPixelConfig; + desc.fOrigin = kBottomLeft_GrSurfaceOrigin; + GrAutoScratchTexture scratch_texture( + offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch); + skia::RefPtr<GrTexture> backing_store = + skia::AdoptRef(scratch_texture.detach()); + + // Create a device and canvas using that backing store. + SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get()); + SkCanvas canvas(&device); + + // Draw the source bitmap through the filter to the canvas. + canvas.clear(SK_ColorTRANSPARENT); + canvas.drawSprite(background, 0, 0); + SkPaint paint; + paint.setXfermodeMode(blend_mode); + canvas.drawSprite(source, 0, 0, &paint); + + // Flush skia context so that all the rendered stuff appears on the + // texture. + offscreen_contexts->GrContext()->flush(); + + // Flush the GL context so rendering results from this context are + // visible in the compositor's context. + offscreen_contexts->Context3d()->flush(); return device.accessBitmap(false); } -scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( +scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters( DrawingFrame* frame, const RenderPassDrawQuad* quad, const gfx::Transform& contents_device_transform, - const gfx::Transform& contents_device_transform_inverse) { + const gfx::Transform& contents_device_transform_inverse, + bool* background_changed) { // This method draws a background filter, which applies a filter to any pixels // behind the quad and seen through its background. The algorithm works as // follows: @@ -631,61 +685,74 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( // TODO(danakj): When this algorithm changes, update // LayerTreeHost::PrioritizeTextures() accordingly. - FilterOperations filters = - RenderSurfaceFilters::Optimize(quad->background_filters); - DCHECK(!filters.IsEmpty()); - // TODO(danakj): We only allow background filters on an opaque render surface // because other surfaces may contain translucent pixels, and the contents // behind those translucent pixels wouldn't have the filter applied. - if (frame->current_render_pass->has_transparent_background) - return scoped_ptr<ScopedResource>(); + bool apply_background_filters = + !frame->current_render_pass->has_transparent_background; DCHECK(!frame->current_texture); + // TODO(ajuma): Add support for reference filters once + // FilterOperations::GetOutsets supports reference filters. + if (apply_background_filters && quad->background_filters.HasReferenceFilter()) + apply_background_filters = false; + // TODO(danakj): Do a single readback for both the surface and replica and // cache the filtered results (once filter textures are not reused). gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect( contents_device_transform, SharedGeometryQuad().BoundingBox())); int top, right, bottom, left; - filters.GetOutsets(&top, &right, &bottom, &left); + quad->background_filters.GetOutsets(&top, &right, &bottom, &left); window_rect.Inset(-left, -top, -right, -bottom); window_rect.Intersect( MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect)); scoped_ptr<ScopedResource> device_background_texture = - ScopedResource::create(resource_provider_); - if (!device_background_texture->Allocate(window_rect.size(), - ResourceProvider::TextureUsageAny, - RGBA_8888)) { - return scoped_ptr<ScopedResource>(); - } else { + ScopedResource::Create(resource_provider_); + // The TextureUsageFramebuffer hint makes ResourceProvider avoid immutable + // storage allocation (texStorage2DEXT) for this texture. copyTexImage2D fails + // when called on a texture having immutable storage. + device_background_texture->Allocate( + window_rect.size(), ResourceProvider::TextureUsageFramebuffer, RGBA_8888); + { ResourceProvider::ScopedWriteLockGL lock(resource_provider_, device_background_texture->id()); - GetFramebufferTexture(lock.texture_id(), - device_background_texture->format(), - window_rect); + GetFramebufferTexture( + lock.texture_id(), device_background_texture->format(), window_rect); } - SkBitmap filtered_device_background = - ApplyFilters(this, - frame->offscreen_context_provider, - filters, - device_background_texture.get()); - if (!filtered_device_background.getTexture()) - return scoped_ptr<ScopedResource>(); + skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( + quad->background_filters, device_background_texture->size()); + + SkBitmap filtered_device_background; + if (apply_background_filters) { + filtered_device_background = + ApplyImageFilter(this, + frame->offscreen_context_provider, + quad->rect.origin(), + filter.get(), + device_background_texture.get()); + } + *background_changed = (filtered_device_background.getTexture() != NULL); - GrTexture* texture = - reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); - int filtered_device_background_texture_id = texture->getTextureHandle(); + int filtered_device_background_texture_id = 0; + scoped_ptr<ResourceProvider::ScopedReadLockGL> lock; + if (filtered_device_background.getTexture()) { + GrTexture* texture = + reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); + filtered_device_background_texture_id = texture->getTextureHandle(); + } else { + lock.reset(new ResourceProvider::ScopedReadLockGL( + resource_provider_, device_background_texture->id())); + filtered_device_background_texture_id = lock->texture_id(); + } scoped_ptr<ScopedResource> background_texture = - ScopedResource::create(resource_provider_); - if (!background_texture->Allocate(quad->rect.size(), - ResourceProvider::TextureUsageFramebuffer, - RGBA_8888)) - return scoped_ptr<ScopedResource>(); + ScopedResource::Create(resource_provider_); + background_texture->Allocate( + quad->rect.size(), ResourceProvider::TextureUsageFramebuffer, RGBA_8888); const RenderPass* target_render_pass = frame->current_render_pass; bool using_background_texture = @@ -704,8 +771,8 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( contents_device_transform_inverse); #ifndef NDEBUG - GLC(Context(), Context()->clearColor(0, 0, 1, 1)); - Context()->clear(GL_COLOR_BUFFER_BIT); + GLC(gl_, gl_->ClearColor(0, 0, 1, 1)); + gl_->Clear(GL_COLOR_BUFFER_BIT); #endif // The filtered_deveice_background_texture is oriented the same as the frame @@ -732,7 +799,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, const RenderPassDrawQuad* quad) { SetBlendEnabled(quad->ShouldDrawWithBlending()); - CachedResource* contents_texture = + ScopedResource* contents_texture = render_pass_textures_.get(quad->render_pass_id); if (!contents_texture || !contents_texture->id()) return; @@ -749,19 +816,24 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) return; + bool need_background_texture = + quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode || + !quad->background_filters.IsEmpty(); + bool background_changed = false; scoped_ptr<ScopedResource> background_texture; - if (!quad->background_filters.IsEmpty()) { + if (need_background_texture) { // The pixels from the filtered background should completely replace the // current pixel values. bool disable_blending = blend_enabled(); if (disable_blending) SetBlendEnabled(false); - background_texture = DrawBackgroundFilters( - frame, - quad, - contents_device_transform, - contents_device_transform_inverse); + background_texture = + GetBackgroundWithFilters(frame, + quad, + contents_device_transform, + contents_device_transform_inverse, + &background_changed); if (disable_blending) SetBlendEnabled(true); @@ -772,45 +844,47 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, SkBitmap filter_bitmap; SkScalar color_matrix[20]; bool use_color_matrix = false; - if (quad->filter) { - skia::RefPtr<SkColorFilter> cf; + // TODO(ajuma): Always use RenderSurfaceFilters::BuildImageFilter, not just + // when we have a reference filter. + if (!quad->filters.IsEmpty()) { + skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( + quad->filters, contents_texture->size()); + if (filter) { + skia::RefPtr<SkColorFilter> cf; + + { + SkColorFilter* colorfilter_rawptr = NULL; + filter->asColorFilter(&colorfilter_rawptr); + cf = skia::AdoptRef(colorfilter_rawptr); + } - { - SkColorFilter* colorfilter_rawptr = NULL; - quad->filter->asColorFilter(&colorfilter_rawptr); - cf = skia::AdoptRef(colorfilter_rawptr); + if (cf && cf->asColorMatrix(color_matrix) && !filter->getInput(0)) { + // We have a single color matrix as a filter; apply it locally + // in the compositor. + use_color_matrix = true; + } else { + filter_bitmap = ApplyImageFilter(this, + frame->offscreen_context_provider, + quad->rect.origin(), + filter.get(), + contents_texture); + } } + } - if (cf && cf->asColorMatrix(color_matrix) && !quad->filter->getInput(0)) { - // We have a single color matrix as a filter; apply it locally - // in the compositor. - use_color_matrix = true; - } else { - filter_bitmap = ApplyImageFilter(this, - frame->offscreen_context_provider, - quad->rect.origin(), - quad->filter.get(), - contents_texture); - } - } else if (!quad->filters.IsEmpty()) { - FilterOperations optimized_filters = - RenderSurfaceFilters::Optimize(quad->filters); - - if ((optimized_filters.size() == 1) && - (optimized_filters.at(0).type() == FilterOperation::COLOR_MATRIX)) { - memcpy( - color_matrix, optimized_filters.at(0).matrix(), sizeof(color_matrix)); - use_color_matrix = true; - } else { - filter_bitmap = ApplyFilters(this, + if (quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode && + background_texture) { + filter_bitmap = + ApplyBlendModeWithBackdrop(this, frame->offscreen_context_provider, - optimized_filters, - contents_texture); - } + filter_bitmap, + contents_texture, + background_texture.get(), + quad->shared_quad_state->blend_mode); } - // Draw the background texture if there is one. - if (background_texture) { + // Draw the background texture if it has some filters applied. + if (background_texture && background_changed) { DCHECK(background_texture->size() == quad->rect.size()); ResourceProvider::ScopedReadLockGL lock(resource_provider_, background_texture->id()); @@ -834,10 +908,10 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, LayerQuad device_layer_edges(device_quad); // Use anti-aliasing programs only when necessary. - bool use_aa = !clipped && - (!device_quad.IsRectilinear() || - !gfx::IsNearestRectWithinDistance(device_quad.BoundingBox(), - kAntiAliasingEpsilon)); + bool use_aa = + !clipped && (!device_quad.IsRectilinear() || + !gfx::IsNearestRectWithinDistance(device_quad.BoundingBox(), + kAntiAliasingEpsilon)); if (use_aa) { device_layer_bounds.InflateAntiAliasingDistance(); device_layer_edges.InflateAntiAliasingDistance(); @@ -854,22 +928,24 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, // TODO(danakj): use the background_texture and blend the background in with // this draw instead of having a separate copy of the background texture. - scoped_ptr<ResourceProvider::ScopedReadLockGL> contents_resource_lock; + scoped_ptr<ResourceProvider::ScopedSamplerGL> contents_resource_lock; if (filter_bitmap.getTexture()) { GrTexture* texture = reinterpret_cast<GrTexture*>(filter_bitmap.getTexture()); - DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(Context())); - Context()->bindTexture(GL_TEXTURE_2D, texture->getTextureHandle()); + DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_)); + gl_->BindTexture(GL_TEXTURE_2D, texture->getTextureHandle()); } else { - contents_resource_lock = make_scoped_ptr( - new ResourceProvider::ScopedSamplerGL(resource_provider_, - contents_texture->id(), - GL_TEXTURE_2D, - GL_LINEAR)); + contents_resource_lock = + make_scoped_ptr(new ResourceProvider::ScopedSamplerGL( + resource_provider_, contents_texture->id(), GL_LINEAR)); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), + contents_resource_lock->target()); } TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( - context_, &highp_threshold_cache_, highp_threshold_min_, + gl_, + &highp_threshold_cache_, + highp_threshold_min_, quad->shared_quad_state->visible_content_rect.bottom_right()); int shader_quad_location = -1; @@ -888,8 +964,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, const RenderPassMaskProgramAA* program = GetRenderPassMaskProgramAA(tex_coord_precision); SetUseProgram(program->program()); - GLC(Context(), - Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); shader_quad_location = program->vertex_shader().quad_location(); shader_edge_location = program->vertex_shader().edge_location(); @@ -908,8 +983,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, const RenderPassMaskProgram* program = GetRenderPassMaskProgram(tex_coord_precision); SetUseProgram(program->program()); - GLC(Context(), - Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); shader_mask_sampler_location = program->fragment_shader().mask_sampler_location(); @@ -925,8 +999,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, const RenderPassProgramAA* program = GetRenderPassProgramAA(tex_coord_precision); SetUseProgram(program->program()); - GLC(Context(), - Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); shader_quad_location = program->vertex_shader().quad_location(); shader_edge_location = program->vertex_shader().edge_location(); @@ -939,8 +1012,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, const RenderPassMaskColorMatrixProgramAA* program = GetRenderPassMaskColorMatrixProgramAA(tex_coord_precision); SetUseProgram(program->program()); - GLC(Context(), - Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); shader_matrix_location = program->vertex_shader().matrix_location(); shader_quad_location = program->vertex_shader().quad_location(); @@ -963,8 +1035,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, const RenderPassColorMatrixProgramAA* program = GetRenderPassColorMatrixProgramAA(tex_coord_precision); SetUseProgram(program->program()); - GLC(Context(), - Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); shader_matrix_location = program->vertex_shader().matrix_location(); shader_quad_location = program->vertex_shader().quad_location(); @@ -981,8 +1052,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, const RenderPassMaskColorMatrixProgram* program = GetRenderPassMaskColorMatrixProgram(tex_coord_precision); SetUseProgram(program->program()); - GLC(Context(), - Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); shader_matrix_location = program->vertex_shader().matrix_location(); shader_tex_transform_location = @@ -1002,8 +1072,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, const RenderPassColorMatrixProgram* program = GetRenderPassColorMatrixProgram(tex_coord_precision); SetUseProgram(program->program()); - GLC(Context(), - Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); shader_matrix_location = program->vertex_shader().matrix_location(); shader_tex_transform_location = @@ -1017,8 +1086,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, const RenderPassProgram* program = GetRenderPassProgram(tex_coord_precision); SetUseProgram(program->program()); - GLC(Context(), - Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); shader_matrix_location = program->vertex_shader().matrix_location(); shader_alpha_location = program->fragment_shader().alpha_location(); @@ -1036,17 +1104,18 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, // Flip the content vertically in the shader, as the RenderPass input // texture is already oriented the same way as the framebuffer, but the // projection transform does a flip. - GLC(Context(), Context()->uniform4f(shader_tex_transform_location, - 0.0f, - tex_scale_y, - tex_scale_x, - -tex_scale_y)); - - scoped_ptr<ResourceProvider::ScopedReadLockGL> shader_mask_sampler_lock; + GLC(gl_, + gl_->Uniform4f(shader_tex_transform_location, + 0.0f, + tex_scale_y, + tex_scale_x, + -tex_scale_y)); + + scoped_ptr<ResourceProvider::ScopedSamplerGL> shader_mask_sampler_lock; if (shader_mask_sampler_location != -1) { DCHECK_NE(shader_mask_tex_coord_scale_location, 1); DCHECK_NE(shader_mask_tex_coord_offset_location, 1); - GLC(Context(), Context()->uniform1i(shader_mask_sampler_location, 1)); + GLC(gl_, gl_->Uniform1i(shader_mask_sampler_location, 1)); float mask_tex_scale_x = quad->mask_uv_rect.width() / tex_scale_x; float mask_tex_scale_y = quad->mask_uv_rect.height() / tex_scale_y; @@ -1054,38 +1123,36 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, // Mask textures are oriented vertically flipped relative to the framebuffer // and the RenderPass contents texture, so we flip the tex coords from the // RenderPass texture to find the mask texture coords. - GLC(Context(), - Context()->uniform2f(shader_mask_tex_coord_offset_location, - quad->mask_uv_rect.x(), - quad->mask_uv_rect.y() + mask_tex_scale_y)); - GLC(Context(), - Context()->uniform2f(shader_mask_tex_coord_scale_location, - mask_tex_scale_x, - -mask_tex_scale_y)); + GLC(gl_, + gl_->Uniform2f(shader_mask_tex_coord_offset_location, + quad->mask_uv_rect.x(), + quad->mask_uv_rect.y() + quad->mask_uv_rect.height())); + GLC(gl_, + gl_->Uniform2f(shader_mask_tex_coord_scale_location, + mask_tex_scale_x, + -mask_tex_scale_y)); shader_mask_sampler_lock = make_scoped_ptr( new ResourceProvider::ScopedSamplerGL(resource_provider_, quad->mask_resource_id, - GL_TEXTURE_2D, GL_TEXTURE1, GL_LINEAR)); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), + shader_mask_sampler_lock->target()); } if (shader_edge_location != -1) { float edge[24]; device_layer_edges.ToFloatArray(edge); device_layer_bounds.ToFloatArray(&edge[12]); - GLC(Context(), Context()->uniform3fv(shader_edge_location, 8, edge)); + GLC(gl_, gl_->Uniform3fv(shader_edge_location, 8, edge)); } if (shader_viewport_location != -1) { - float viewport[4] = { - static_cast<float>(viewport_.x()), - static_cast<float>(viewport_.y()), - static_cast<float>(viewport_.width()), - static_cast<float>(viewport_.height()), - }; - GLC(Context(), - Context()->uniform4fv(shader_viewport_location, 1, viewport)); + float viewport[4] = {static_cast<float>(viewport_.x()), + static_cast<float>(viewport_.y()), + static_cast<float>(viewport_.width()), + static_cast<float>(viewport_.height()), }; + GLC(gl_, gl_->Uniform4fv(shader_viewport_location, 1, viewport)); } if (shader_color_matrix_location != -1) { @@ -1094,9 +1161,8 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, for (int j = 0; j < 4; ++j) matrix[i * 4 + j] = SkScalarToFloat(color_matrix[j * 5 + i]); } - GLC(Context(), - Context()->uniformMatrix4fv( - shader_color_matrix_location, 1, false, matrix)); + GLC(gl_, + gl_->UniformMatrix4fv(shader_color_matrix_location, 1, false, matrix)); } static const float kScale = 1.0f / 255.0f; if (shader_color_offset_location != -1) { @@ -1104,8 +1170,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, for (int i = 0; i < 4; ++i) offset[i] = SkScalarToFloat(color_matrix[i * 5 + 4]) * kScale; - GLC(Context(), - Context()->uniform4fv(shader_color_offset_location, 1, offset)); + GLC(gl_, gl_->Uniform4fv(shader_color_offset_location, 1, offset)); } // Map device space quad to surface space. contents_device_transform has no 3d @@ -1122,7 +1187,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, // Flush the compositor context before the filter bitmap goes out of // scope, so the draw gets processed before the filter texture gets deleted. if (filter_bitmap.getTexture()) - context_->flush(); + GLC(gl_, gl_->Flush()); } struct SolidColorProgramUniforms { @@ -1134,7 +1199,7 @@ struct SolidColorProgramUniforms { unsigned color_location; }; -template<class T> +template <class T> static void SolidColorUniformLocation(T program, SolidColorProgramUniforms* uniforms) { uniforms->program = program->program(); @@ -1158,7 +1223,8 @@ bool GLRenderer::SetupQuadForAntialiasing( device_transform, gfx::QuadF(quad->visibleContentRect()), &clipped); bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear(); - bool is_nearest_rect_within_epsilon = is_axis_aligned_in_target && + bool is_nearest_rect_within_epsilon = + is_axis_aligned_in_target && gfx::IsNearestRectWithinDistance(device_layer_quad.BoundingBox(), kAntiAliasingEpsilon); // AAing clipped quads is not supported by the code yet. @@ -1217,8 +1283,7 @@ bool GLRenderer::SetupQuadForAntialiasing( // Map device space quad to local space. device_transform has no 3d // component since it was flattened, so we don't need to project. We should // have already checked that the transform was uninvertible above. - gfx::Transform inverse_device_transform( - gfx::Transform::kSkipInitialization); + gfx::Transform inverse_device_transform(gfx::Transform::kSkipInitialization); bool did_invert = device_transform.GetInverse(&inverse_device_transform); DCHECK(did_invert); *local_quad = MathUtil::MapQuad( @@ -1262,22 +1327,19 @@ void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame, SolidColorUniformLocation(GetSolidColorProgram(), &uniforms); SetUseProgram(uniforms.program); - GLC(Context(), - Context()->uniform4f(uniforms.color_location, - (SkColorGetR(color) * (1.0f / 255.0f)) * alpha, - (SkColorGetG(color) * (1.0f / 255.0f)) * alpha, - (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, - alpha)); + GLC(gl_, + gl_->Uniform4f(uniforms.color_location, + (SkColorGetR(color) * (1.0f / 255.0f)) * alpha, + (SkColorGetG(color) * (1.0f / 255.0f)) * alpha, + (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, + alpha)); if (use_aa) { - float viewport[4] = { - static_cast<float>(viewport_.x()), - static_cast<float>(viewport_.y()), - static_cast<float>(viewport_.width()), - static_cast<float>(viewport_.height()), - }; - GLC(Context(), - Context()->uniform4fv(uniforms.viewport_location, 1, viewport)); - GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge)); + float viewport[4] = {static_cast<float>(viewport_.x()), + static_cast<float>(viewport_.y()), + static_cast<float>(viewport_.width()), + static_cast<float>(viewport_.height()), }; + GLC(gl_, gl_->Uniform4fv(uniforms.viewport_location, 1, viewport)); + GLC(gl_, gl_->Uniform3fv(uniforms.edge_location, 8, edge)); } // Enable blending when the quad properties require it or if we decided @@ -1293,11 +1355,11 @@ void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame, // un-antialiased quad should have and which vertex this is and the float // quad passed in via uniform is the actual geometry that gets used to draw // it. This is why this centered rect is used and not the original quad_rect. - gfx::RectF centered_rect(gfx::PointF(-0.5f * tile_rect.width(), - -0.5f * tile_rect.height()), - tile_rect.size()); - DrawQuadGeometry(frame, quad->quadTransform(), - centered_rect, uniforms.matrix_location); + gfx::RectF centered_rect( + gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()), + tile_rect.size()); + DrawQuadGeometry( + frame, quad->quadTransform(), centered_rect, uniforms.matrix_location); } struct TileProgramUniforms { @@ -1352,16 +1414,16 @@ void GLRenderer::DrawContentQuad(const DrawingFrame* frame, // is mapped to the unit square by the vertex shader and mapped // back to normalized texture coordinates by the fragment shader // after being clamped to 0-1 range. - float tex_clamp_x = std::min( - 0.5f, 0.5f * clamp_tex_rect.width() - kAntiAliasingEpsilon); - float tex_clamp_y = std::min( - 0.5f, 0.5f * clamp_tex_rect.height() - kAntiAliasingEpsilon); - float geom_clamp_x = std::min( - tex_clamp_x * tex_to_geom_scale_x, - 0.5f * clamp_geom_rect.width() - kAntiAliasingEpsilon); - float geom_clamp_y = std::min( - tex_clamp_y * tex_to_geom_scale_y, - 0.5f * clamp_geom_rect.height() - kAntiAliasingEpsilon); + float tex_clamp_x = + std::min(0.5f, 0.5f * clamp_tex_rect.width() - kAntiAliasingEpsilon); + float tex_clamp_y = + std::min(0.5f, 0.5f * clamp_tex_rect.height() - kAntiAliasingEpsilon); + float geom_clamp_x = + std::min(tex_clamp_x * tex_to_geom_scale_x, + 0.5f * clamp_geom_rect.width() - kAntiAliasingEpsilon); + float geom_clamp_y = + std::min(tex_clamp_y * tex_to_geom_scale_y, + 0.5f * clamp_geom_rect.height() - kAntiAliasingEpsilon); clamp_geom_rect.Inset(geom_clamp_x, geom_clamp_y, geom_clamp_x, geom_clamp_y); clamp_tex_rect.Inset(tex_clamp_x, tex_clamp_y, tex_clamp_x, tex_clamp_y); @@ -1373,15 +1435,7 @@ void GLRenderer::DrawContentQuad(const DrawingFrame* frame, float vertex_tex_scale_y = tile_rect.height() / clamp_geom_rect.height(); TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( - context_, &highp_threshold_cache_, highp_threshold_min_, - quad->texture_size); - - // Map to normalized texture coordinates. - gfx::Size texture_size = quad->texture_size; - float fragment_tex_translate_x = clamp_tex_rect.x() / texture_size.width(); - float fragment_tex_translate_y = clamp_tex_rect.y() / texture_size.height(); - float fragment_tex_scale_x = clamp_tex_rect.width() / texture_size.width(); - float fragment_tex_scale_y = clamp_tex_rect.height() / texture_size.height(); + gl_, &highp_threshold_cache_, highp_threshold_min_, quad->texture_size); gfx::Transform device_transform = frame->window_matrix * frame->projection_matrix * quad->quadTransform(); @@ -1391,69 +1445,88 @@ void GLRenderer::DrawContentQuad(const DrawingFrame* frame, gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); float edge[24]; - bool use_aa = settings_->allow_antialiasing && SetupQuadForAntialiasing( - device_transform, quad, &local_quad, edge); + bool use_aa = + settings_->allow_antialiasing && + SetupQuadForAntialiasing(device_transform, quad, &local_quad, edge); + + bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f); + GLenum filter = (use_aa || scaled || + !quad->quadTransform().IsIdentityOrIntegerTranslation()) + ? GL_LINEAR + : GL_NEAREST; + ResourceProvider::ScopedSamplerGL quad_resource_lock( + resource_provider_, resource_id, filter); + SamplerType sampler = + SamplerTypeFromTextureTarget(quad_resource_lock.target()); + + float fragment_tex_translate_x = clamp_tex_rect.x(); + float fragment_tex_translate_y = clamp_tex_rect.y(); + float fragment_tex_scale_x = clamp_tex_rect.width(); + float fragment_tex_scale_y = clamp_tex_rect.height(); + + // Map to normalized texture coordinates. + if (sampler != SamplerType2DRect) { + gfx::Size texture_size = quad->texture_size; + DCHECK(!texture_size.IsEmpty()); + fragment_tex_translate_x /= texture_size.width(); + fragment_tex_translate_y /= texture_size.height(); + fragment_tex_scale_x /= texture_size.width(); + fragment_tex_scale_y /= texture_size.height(); + } TileProgramUniforms uniforms; if (use_aa) { if (quad->swizzle_contents) { - TileUniformLocation(GetTileProgramSwizzleAA(tex_coord_precision), + TileUniformLocation(GetTileProgramSwizzleAA(tex_coord_precision, sampler), &uniforms); } else { - TileUniformLocation(GetTileProgramAA(tex_coord_precision), &uniforms); + TileUniformLocation(GetTileProgramAA(tex_coord_precision, sampler), + &uniforms); } } else { if (quad->ShouldDrawWithBlending()) { if (quad->swizzle_contents) { - TileUniformLocation(GetTileProgramSwizzle(tex_coord_precision), + TileUniformLocation(GetTileProgramSwizzle(tex_coord_precision, sampler), &uniforms); } else { - TileUniformLocation(GetTileProgram(tex_coord_precision), &uniforms); + TileUniformLocation(GetTileProgram(tex_coord_precision, sampler), + &uniforms); } } else { if (quad->swizzle_contents) { - TileUniformLocation(GetTileProgramSwizzleOpaque(tex_coord_precision), - &uniforms); + TileUniformLocation( + GetTileProgramSwizzleOpaque(tex_coord_precision, sampler), + &uniforms); } else { - TileUniformLocation(GetTileProgramOpaque(tex_coord_precision), + TileUniformLocation(GetTileProgramOpaque(tex_coord_precision, sampler), &uniforms); } } } SetUseProgram(uniforms.program); - GLC(Context(), Context()->uniform1i(uniforms.sampler_location, 0)); - bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f); - GLenum filter = (use_aa || scaled || - !quad->quadTransform().IsIdentityOrIntegerTranslation()) - ? GL_LINEAR - : GL_NEAREST; - ResourceProvider::ScopedSamplerGL quad_resource_lock( - resource_provider_, resource_id, GL_TEXTURE_2D, filter); + GLC(gl_, gl_->Uniform1i(uniforms.sampler_location, 0)); if (use_aa) { - float viewport[4] = { - static_cast<float>(viewport_.x()), - static_cast<float>(viewport_.y()), - static_cast<float>(viewport_.width()), - static_cast<float>(viewport_.height()), - }; - GLC(Context(), - Context()->uniform4fv(uniforms.viewport_location, 1, viewport)); - GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge)); - - GLC(Context(), - Context()->uniform4f(uniforms.vertex_tex_transform_location, - vertex_tex_translate_x, - vertex_tex_translate_y, - vertex_tex_scale_x, - vertex_tex_scale_y)); - GLC(Context(), - Context()->uniform4f(uniforms.fragment_tex_transform_location, - fragment_tex_translate_x, - fragment_tex_translate_y, - fragment_tex_scale_x, - fragment_tex_scale_y)); + float viewport[4] = {static_cast<float>(viewport_.x()), + static_cast<float>(viewport_.y()), + static_cast<float>(viewport_.width()), + static_cast<float>(viewport_.height()), }; + GLC(gl_, gl_->Uniform4fv(uniforms.viewport_location, 1, viewport)); + GLC(gl_, gl_->Uniform3fv(uniforms.edge_location, 8, edge)); + + GLC(gl_, + gl_->Uniform4f(uniforms.vertex_tex_transform_location, + vertex_tex_translate_x, + vertex_tex_translate_y, + vertex_tex_scale_x, + vertex_tex_scale_y)); + GLC(gl_, + gl_->Uniform4f(uniforms.fragment_tex_transform_location, + fragment_tex_translate_x, + fragment_tex_translate_y, + fragment_tex_scale_x, + fragment_tex_scale_y)); } else { // Move fragment shader transform to vertex shader. We can do this while // still producing correct results as fragment_tex_transform_location @@ -1466,12 +1539,12 @@ void GLRenderer::DrawContentQuad(const DrawingFrame* frame, vertex_tex_translate_x += fragment_tex_translate_x; vertex_tex_translate_y += fragment_tex_translate_y; - GLC(Context(), - Context()->uniform4f(uniforms.vertex_tex_transform_location, - vertex_tex_translate_x, - vertex_tex_translate_y, - vertex_tex_scale_x, - vertex_tex_scale_y)); + GLC(gl_, + gl_->Uniform4f(uniforms.vertex_tex_transform_location, + vertex_tex_translate_x, + vertex_tex_translate_y, + vertex_tex_scale_x, + vertex_tex_scale_y)); } // Enable blending when the quad properties require it or if we decided @@ -1500,37 +1573,27 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame, SetBlendEnabled(quad->ShouldDrawWithBlending()); TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( - context_, &highp_threshold_cache_, highp_threshold_min_, + gl_, + &highp_threshold_cache_, + highp_threshold_min_, quad->shared_quad_state->visible_content_rect.bottom_right()); bool use_alpha_plane = quad->a_plane_resource_id != 0; ResourceProvider::ScopedSamplerGL y_plane_lock( - resource_provider_, - quad->y_plane_resource_id, - GL_TEXTURE_2D, - GL_TEXTURE1, - GL_LINEAR); + resource_provider_, quad->y_plane_resource_id, GL_TEXTURE1, GL_LINEAR); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), y_plane_lock.target()); ResourceProvider::ScopedSamplerGL u_plane_lock( - resource_provider_, - quad->u_plane_resource_id, - GL_TEXTURE_2D, - GL_TEXTURE2, - GL_LINEAR); + resource_provider_, quad->u_plane_resource_id, GL_TEXTURE2, GL_LINEAR); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), u_plane_lock.target()); ResourceProvider::ScopedSamplerGL v_plane_lock( - resource_provider_, - quad->v_plane_resource_id, - GL_TEXTURE_2D, - GL_TEXTURE3, - GL_LINEAR); + resource_provider_, quad->v_plane_resource_id, GL_TEXTURE3, GL_LINEAR); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), v_plane_lock.target()); scoped_ptr<ResourceProvider::ScopedSamplerGL> a_plane_lock; if (use_alpha_plane) { a_plane_lock.reset(new ResourceProvider::ScopedSamplerGL( - resource_provider_, - quad->a_plane_resource_id, - GL_TEXTURE_2D, - GL_TEXTURE4, - GL_LINEAR)); + resource_provider_, quad->a_plane_resource_id, GL_TEXTURE4, GL_LINEAR)); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), a_plane_lock->target()); } int tex_scale_location = -1; @@ -1569,26 +1632,22 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame, alpha_location = program->fragment_shader().alpha_location(); } - GLC(Context(), - Context()->uniform2f(tex_scale_location, - quad->tex_scale.width(), - quad->tex_scale.height())); - GLC(Context(), Context()->uniform1i(y_texture_location, 1)); - GLC(Context(), Context()->uniform1i(u_texture_location, 2)); - GLC(Context(), Context()->uniform1i(v_texture_location, 3)); + GLC(gl_, + gl_->Uniform2f(tex_scale_location, + quad->tex_scale.width(), + quad->tex_scale.height())); + GLC(gl_, gl_->Uniform1i(y_texture_location, 1)); + GLC(gl_, gl_->Uniform1i(u_texture_location, 2)); + GLC(gl_, gl_->Uniform1i(v_texture_location, 3)); if (use_alpha_plane) - GLC(Context(), Context()->uniform1i(a_texture_location, 4)); + GLC(gl_, gl_->Uniform1i(a_texture_location, 4)); // These values are magic numbers that are used in the transformation from YUV // to RGB color values. They are taken from the following webpage: // http://www.fourcc.org/fccyvrgb.php - float yuv_to_rgb[9] = { - 1.164f, 1.164f, 1.164f, - 0.0f, -.391f, 2.018f, - 1.596f, -.813f, 0.0f, - }; - GLC(Context(), - Context()->uniformMatrix3fv(yuv_matrix_location, 1, 0, yuv_to_rgb)); + float yuv_to_rgb[9] = {1.164f, 1.164f, 1.164f, 0.0f, -.391f, + 2.018f, 1.596f, -.813f, 0.0f, }; + GLC(gl_, gl_->UniformMatrix3fv(yuv_matrix_location, 1, 0, yuv_to_rgb)); // These values map to 16, 128, and 128 respectively, and are computed // as a fraction over 256 (e.g. 16 / 256 = 0.0625). @@ -1596,9 +1655,8 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame, // Y - 16 : Gives 16 values of head and footroom for overshooting // U - 128 : Turns unsigned U into signed U [-128,127] // V - 128 : Turns unsigned V into signed V [-128,127] - float yuv_adjust[3] = { -0.0625f, -0.5f, -0.5f, }; - GLC(Context(), Context()->uniform3fv(yuv_adj_location, 1, yuv_adjust)); - + float yuv_adjust[3] = {-0.0625f, -0.5f, -0.5f, }; + GLC(gl_, gl_->Uniform3fv(yuv_adj_location, 1, yuv_adjust)); SetShaderOpacity(quad->opacity(), alpha_location); DrawQuadGeometry(frame, quad->quadTransform(), quad->rect, matrix_location); @@ -1613,7 +1671,9 @@ void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame, DCHECK(capabilities_.using_egl_image); TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( - context_, &highp_threshold_cache_, highp_threshold_min_, + gl_, + &highp_threshold_cache_, + highp_threshold_min_, quad->shared_quad_state->visible_content_rect.bottom_right()); const VideoStreamTextureProgram* program = @@ -1621,18 +1681,16 @@ void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame, SetUseProgram(program->program()); ToGLMatrix(&gl_matrix[0], quad->matrix); - GLC(Context(), - Context()->uniformMatrix4fv( + GLC(gl_, + gl_->UniformMatrix4fv( program->vertex_shader().tex_matrix_location(), 1, false, gl_matrix)); ResourceProvider::ScopedReadLockGL lock(resource_provider_, quad->resource_id); - DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(Context())); - GLC(Context(), - Context()->bindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id())); + DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_)); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id())); - GLC(Context(), - Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); SetShaderOpacity(quad->opacity(), program->fragment_shader().alpha_location()); @@ -1642,85 +1700,36 @@ void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame, program->vertex_shader().matrix_location()); } -void GLRenderer::DrawPictureQuadDirectToBackbuffer( - const DrawingFrame* frame, - const PictureDrawQuad* quad) { - DCHECK(CanUseSkiaGPUBackend()); - DCHECK_EQ(quad->opacity(), 1.f) << "Need to composite to a bitmap or a " - "render surface for non-1 opacity quads"; - - // TODO(enne): This should be done more lazily / efficiently. - gr_context_->resetContext(); - - // Reset the canvas matrix to identity because the clip rect is in target - // space. - SkMatrix sk_identity; - sk_identity.setIdentity(); - sk_canvas_->setMatrix(sk_identity); - - if (is_scissor_enabled_) { - sk_canvas_->clipRect(gfx::RectToSkRect(scissor_rect_), - SkRegion::kReplace_Op); - } else { - sk_canvas_->clipRect(gfx::RectToSkRect(client_->DeviceViewport()), - SkRegion::kReplace_Op); - } - - gfx::Transform contents_device_transform = frame->window_matrix * - frame->projection_matrix * quad->quadTransform(); - contents_device_transform.Translate(quad->rect.x(), - quad->rect.y()); - contents_device_transform.FlattenTo2d(); - SkMatrix sk_device_matrix; - gfx::TransformToFlattenedSkMatrix(contents_device_transform, - &sk_device_matrix); - sk_canvas_->setMatrix(sk_device_matrix); - - quad->picture_pile->RasterDirect( - sk_canvas_.get(), quad->content_rect, quad->contents_scale, NULL); - - // Flush any drawing buffers that have been deferred. - sk_canvas_->flush(); - - // TODO(enne): This should be done more lazily / efficiently. - ReinitializeGLState(); -} - void GLRenderer::DrawPictureQuad(const DrawingFrame* frame, const PictureDrawQuad* quad) { - if (quad->can_draw_direct_to_backbuffer && CanUseSkiaGPUBackend()) { - DrawPictureQuadDirectToBackbuffer(frame, quad); - return; - } - if (on_demand_tile_raster_bitmap_.width() != quad->texture_size.width() || on_demand_tile_raster_bitmap_.height() != quad->texture_size.height()) { - on_demand_tile_raster_bitmap_.setConfig( - SkBitmap::kARGB_8888_Config, - quad->texture_size.width(), - quad->texture_size.height()); + on_demand_tile_raster_bitmap_.setConfig(SkBitmap::kARGB_8888_Config, + quad->texture_size.width(), + quad->texture_size.height()); on_demand_tile_raster_bitmap_.allocPixels(); if (on_demand_tile_raster_resource_id_) resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_); - on_demand_tile_raster_resource_id_ = resource_provider_->CreateGLTexture( - quad->texture_size, - GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, - GL_CLAMP_TO_EDGE, - ResourceProvider::TextureUsageAny, - quad->texture_format); + on_demand_tile_raster_resource_id_ = + resource_provider_->CreateGLTexture(quad->texture_size, + GL_TEXTURE_2D, + GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, + GL_CLAMP_TO_EDGE, + ResourceProvider::TextureUsageAny, + quad->texture_format); } SkBitmapDevice device(on_demand_tile_raster_bitmap_); SkCanvas canvas(&device); - quad->picture_pile->RasterToBitmap(&canvas, quad->content_rect, - quad->contents_scale, NULL); + quad->picture_pile->RasterToBitmap( + &canvas, quad->content_rect, quad->contents_scale, NULL); uint8_t* bitmap_pixels = NULL; SkBitmap on_demand_tile_raster_bitmap_dest; - SkBitmap::Config config = SkBitmapConfigFromFormat(quad->texture_format); + SkBitmap::Config config = SkBitmapConfig(quad->texture_format); if (on_demand_tile_raster_bitmap_.getConfig() != config) { on_demand_tile_raster_bitmap_.copyTo(&on_demand_tile_raster_bitmap_dest, config); @@ -1730,24 +1739,23 @@ void GLRenderer::DrawPictureQuad(const DrawingFrame* frame, bitmap_pixels = reinterpret_cast<uint8_t*>( on_demand_tile_raster_bitmap_dest.getPixels()); } else { - bitmap_pixels = reinterpret_cast<uint8_t*>( - on_demand_tile_raster_bitmap_.getPixels()); + bitmap_pixels = + reinterpret_cast<uint8_t*>(on_demand_tile_raster_bitmap_.getPixels()); } - resource_provider_->SetPixels( - on_demand_tile_raster_resource_id_, - bitmap_pixels, - gfx::Rect(quad->texture_size), - gfx::Rect(quad->texture_size), - gfx::Vector2d()); + resource_provider_->SetPixels(on_demand_tile_raster_resource_id_, + bitmap_pixels, + gfx::Rect(quad->texture_size), + gfx::Rect(quad->texture_size), + gfx::Vector2d()); DrawContentQuad(frame, quad, on_demand_tile_raster_resource_id_); } struct TextureProgramBinding { template <class Program> - void Set(Program* program, WebKit::WebGraphicsContext3D* context) { - DCHECK(program && (program->initialized() || context->isContextLost())); + void Set(Program* program) { + DCHECK(program); program_id = program->program(); sampler_location = program->fragment_shader().sampler_location(); matrix_location = program->vertex_shader().matrix_location(); @@ -1762,8 +1770,8 @@ struct TextureProgramBinding { struct TexTransformTextureProgramBinding : TextureProgramBinding { template <class Program> - void Set(Program* program, WebKit::WebGraphicsContext3D* context) { - TextureProgramBinding::Set(program, context); + void Set(Program* program) { + TextureProgramBinding::Set(program); tex_transform_location = program->vertex_shader().tex_transform_location(); vertex_opacity_location = program->vertex_shader().vertex_opacity_location(); @@ -1784,54 +1792,52 @@ void GLRenderer::FlushTextureQuadCache() { SetUseProgram(draw_cache_.program_id); // Bind the correct texture sampler location. - GLC(Context(), Context()->uniform1i(draw_cache_.sampler_location, 0)); + GLC(gl_, gl_->Uniform1i(draw_cache_.sampler_location, 0)); // Assume the current active textures is 0. ResourceProvider::ScopedReadLockGL locked_quad(resource_provider_, draw_cache_.resource_id); - DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(Context())); - GLC(Context(), - Context()->bindTexture(GL_TEXTURE_2D, locked_quad.texture_id())); + DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_)); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, locked_quad.texture_id())); - COMPILE_ASSERT( - sizeof(Float4) == 4 * sizeof(float), // NOLINT(runtime/sizeof) - struct_is_densely_packed); + COMPILE_ASSERT(sizeof(Float4) == 4 * sizeof(float), // NOLINT(runtime/sizeof) + struct_is_densely_packed); COMPILE_ASSERT( sizeof(Float16) == 16 * sizeof(float), // NOLINT(runtime/sizeof) struct_is_densely_packed); // Upload the tranforms for both points and uvs. - GLC(context_, - context_->uniformMatrix4fv( + GLC(gl_, + gl_->UniformMatrix4fv( static_cast<int>(draw_cache_.matrix_location), static_cast<int>(draw_cache_.matrix_data.size()), false, reinterpret_cast<float*>(&draw_cache_.matrix_data.front()))); - GLC(context_, - context_->uniform4fv( + GLC(gl_, + gl_->Uniform4fv( static_cast<int>(draw_cache_.uv_xform_location), static_cast<int>(draw_cache_.uv_xform_data.size()), reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front()))); if (draw_cache_.background_color != SK_ColorTRANSPARENT) { Float4 background_color = PremultipliedColor(draw_cache_.background_color); - GLC(context_, - context_->uniform4fv( + GLC(gl_, + gl_->Uniform4fv( draw_cache_.background_color_location, 1, background_color.data)); } - GLC(context_, - context_->uniform1fv( + GLC(gl_, + gl_->Uniform1fv( static_cast<int>(draw_cache_.vertex_opacity_location), static_cast<int>(draw_cache_.vertex_opacity_data.size()), static_cast<float*>(&draw_cache_.vertex_opacity_data.front()))); // Draw the quads! - GLC(context_, - context_->drawElements(GL_TRIANGLES, - 6 * draw_cache_.matrix_data.size(), - GL_UNSIGNED_SHORT, - 0)); + GLC(gl_, + gl_->DrawElements(GL_TRIANGLES, + 6 * draw_cache_.matrix_data.size(), + GL_UNSIGNED_SHORT, + 0)); // Clear the cache. draw_cache_.program_id = 0; @@ -1843,25 +1849,25 @@ void GLRenderer::FlushTextureQuadCache() { void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame, const TextureDrawQuad* quad) { TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( - context_, &highp_threshold_cache_, highp_threshold_min_, + gl_, + &highp_threshold_cache_, + highp_threshold_min_, quad->shared_quad_state->visible_content_rect.bottom_right()); // Choose the correct texture program binding TexTransformTextureProgramBinding binding; if (quad->premultiplied_alpha) { if (quad->background_color == SK_ColorTRANSPARENT) { - binding.Set(GetTextureProgram(tex_coord_precision), Context()); + binding.Set(GetTextureProgram(tex_coord_precision)); } else { - binding.Set(GetTextureBackgroundProgram(tex_coord_precision), Context()); + binding.Set(GetTextureBackgroundProgram(tex_coord_precision)); } } else { if (quad->background_color == SK_ColorTRANSPARENT) { - binding.Set(GetNonPremultipliedTextureProgram(tex_coord_precision), - Context()); + binding.Set(GetNonPremultipliedTextureProgram(tex_coord_precision)); } else { binding.Set( - GetNonPremultipliedTextureBackgroundProgram(tex_coord_precision), - Context()); + GetNonPremultipliedTextureBackgroundProgram(tex_coord_precision)); } } @@ -1910,54 +1916,52 @@ void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame* frame, SetBlendEnabled(quad->ShouldDrawWithBlending()); TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( - context_, &highp_threshold_cache_, highp_threshold_min_, + gl_, + &highp_threshold_cache_, + highp_threshold_min_, quad->shared_quad_state->visible_content_rect.bottom_right()); TexTransformTextureProgramBinding binding; - binding.Set(GetTextureIOSurfaceProgram(tex_coord_precision), Context()); + binding.Set(GetTextureIOSurfaceProgram(tex_coord_precision)); SetUseProgram(binding.program_id); - GLC(Context(), Context()->uniform1i(binding.sampler_location, 0)); + GLC(gl_, gl_->Uniform1i(binding.sampler_location, 0)); if (quad->orientation == IOSurfaceDrawQuad::FLIPPED) { - GLC(Context(), - Context()->uniform4f(binding.tex_transform_location, - 0, - quad->io_surface_size.height(), - quad->io_surface_size.width(), - quad->io_surface_size.height() * -1.0f)); + GLC(gl_, + gl_->Uniform4f(binding.tex_transform_location, + 0, + quad->io_surface_size.height(), + quad->io_surface_size.width(), + quad->io_surface_size.height() * -1.0f)); } else { - GLC(Context(), - Context()->uniform4f(binding.tex_transform_location, - 0, - 0, - quad->io_surface_size.width(), - quad->io_surface_size.height())); + GLC(gl_, + gl_->Uniform4f(binding.tex_transform_location, + 0, + 0, + quad->io_surface_size.width(), + quad->io_surface_size.height())); } - const float vertex_opacity[] = { quad->opacity(), quad->opacity(), - quad->opacity(), quad->opacity() }; - GLC(Context(), - Context()->uniform1fv( - binding.vertex_opacity_location, 4, vertex_opacity)); + const float vertex_opacity[] = {quad->opacity(), quad->opacity(), + quad->opacity(), quad->opacity()}; + GLC(gl_, gl_->Uniform1fv(binding.vertex_opacity_location, 4, vertex_opacity)); ResourceProvider::ScopedReadLockGL lock(resource_provider_, quad->io_surface_resource_id); - DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(Context())); - GLC(Context(), - Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB, - lock.texture_id())); + DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_)); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, lock.texture_id())); DrawQuadGeometry( frame, quad->quadTransform(), quad->rect, binding.matrix_location); - GLC(Context(), Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB, 0)); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, 0)); } void GLRenderer::FinishDrawingFrame(DrawingFrame* frame) { current_framebuffer_lock_.reset(); swap_buffer_rect_.Union(gfx::ToEnclosingRect(frame->root_damage_rect)); - GLC(context_, context_->disable(GL_BLEND)); + GLC(gl_, gl_->Disable(GL_BLEND)); blend_shadow_ = false; } @@ -1970,7 +1974,7 @@ void GLRenderer::EnsureScissorTestEnabled() { return; FlushTextureQuadCache(); - GLC(context_, context_->enable(GL_SCISSOR_TEST)); + GLC(gl_, gl_->Enable(GL_SCISSOR_TEST)); is_scissor_enabled_ = true; } @@ -1979,7 +1983,7 @@ void GLRenderer::EnsureScissorTestDisabled() { return; FlushTextureQuadCache(); - GLC(context_, context_->disable(GL_SCISSOR_TEST)); + GLC(gl_, gl_->Disable(GL_SCISSOR_TEST)); is_scissor_enabled_ = false; } @@ -2009,12 +2013,12 @@ void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad, int quad_location) { gl_quad[5] = quad.p3().y(); gl_quad[6] = quad.p4().x(); gl_quad[7] = quad.p4().y(); - GLC(context_, context_->uniform2fv(quad_location, 4, gl_quad)); + GLC(gl_, gl_->Uniform2fv(quad_location, 4, gl_quad)); } void GLRenderer::SetShaderOpacity(float opacity, int alpha_location) { if (alpha_location != -1) - GLC(context_, context_->uniform1f(alpha_location, opacity)); + GLC(gl_, gl_->Uniform1f(alpha_location, opacity)); } void GLRenderer::SetStencilEnabled(bool enabled) { @@ -2022,9 +2026,9 @@ void GLRenderer::SetStencilEnabled(bool enabled) { return; if (enabled) - GLC(context_, context_->enable(GL_STENCIL_TEST)); + GLC(gl_, gl_->Enable(GL_STENCIL_TEST)); else - GLC(context_, context_->disable(GL_STENCIL_TEST)); + GLC(gl_, gl_->Disable(GL_STENCIL_TEST)); stencil_shadow_ = enabled; } @@ -2033,16 +2037,16 @@ void GLRenderer::SetBlendEnabled(bool enabled) { return; if (enabled) - GLC(context_, context_->enable(GL_BLEND)); + GLC(gl_, gl_->Enable(GL_BLEND)); else - GLC(context_, context_->disable(GL_BLEND)); + GLC(gl_, gl_->Disable(GL_BLEND)); blend_shadow_ = enabled; } void GLRenderer::SetUseProgram(unsigned program) { if (program == program_shadow_) return; - GLC(context_, context_->useProgram(program)); + gl_->UseProgram(program); program_shadow_ = program; } @@ -2054,10 +2058,9 @@ void GLRenderer::DrawQuadGeometry(const DrawingFrame* frame, QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect); static float gl_matrix[16]; ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad_rect_matrix); - GLC(context_, - context_->uniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0])); + GLC(gl_, gl_->UniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0])); - GLC(context_, context_->drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0)); + GLC(gl_, gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0)); } void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame* frame, @@ -2066,61 +2069,60 @@ void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame* frame, const gfx::Transform& draw_matrix, bool flip_vertically) { TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( - context_, &highp_threshold_cache_, highp_threshold_min_, - rect.bottom_right()); + gl_, &highp_threshold_cache_, highp_threshold_min_, rect.bottom_right()); const RenderPassProgram* program = GetRenderPassProgram(tex_coord_precision); SetUseProgram(program->program()); - GLC(Context(), Context()->uniform1i( - program->fragment_shader().sampler_location(), 0)); + GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); if (flip_vertically) { - GLC(Context(), Context()->uniform4f( - program->vertex_shader().tex_transform_location(), - 0.f, - 1.f, - 1.f, - -1.f)); + GLC(gl_, + gl_->Uniform4f(program->vertex_shader().tex_transform_location(), + 0.f, + 1.f, + 1.f, + -1.f)); } else { - GLC(Context(), Context()->uniform4f( - program->vertex_shader().tex_transform_location(), - 0.f, - 0.f, - 1.f, - 1.f)); + GLC(gl_, + gl_->Uniform4f(program->vertex_shader().tex_transform_location(), + 0.f, + 0.f, + 1.f, + 1.f)); } SetShaderOpacity(1.f, program->fragment_shader().alpha_location()); - DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(Context())); - GLC(Context(), Context()->bindTexture(GL_TEXTURE_2D, texture_id)); + DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_)); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, texture_id)); DrawQuadGeometry( frame, draw_matrix, rect, program->vertex_shader().matrix_location()); } void GLRenderer::Finish() { - TRACE_EVENT0("cc", "GLRenderer::finish"); - context_->finish(); + TRACE_EVENT0("cc", "GLRenderer::Finish"); + GLC(gl_, gl_->Finish()); } -void GLRenderer::SwapBuffers() { - DCHECK(visible_); +void GLRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) { DCHECK(!is_backbuffer_discarded_); TRACE_EVENT0("cc", "GLRenderer::SwapBuffers"); // We're done! Time to swapbuffers! + gfx::Size surface_size = output_surface_->SurfaceSize(); + CompositorFrame compositor_frame; - compositor_frame.metadata = client_->MakeCompositorFrameMetadata(); + compositor_frame.metadata = metadata; compositor_frame.gl_frame_data = make_scoped_ptr(new GLFrameData); - compositor_frame.gl_frame_data->size = output_surface_->SurfaceSize(); + compositor_frame.gl_frame_data->size = surface_size; if (capabilities_.using_partial_swap) { // If supported, we can save significant bandwidth by only swapping the - // damaged/scissored region (clamped to the viewport) - swap_buffer_rect_.Intersect(client_->DeviceViewport()); - int flipped_y_pos_of_rect_bottom = - client_->DeviceViewport().height() - swap_buffer_rect_.y() - - swap_buffer_rect_.height(); + // damaged/scissored region (clamped to the viewport). + swap_buffer_rect_.Intersect(gfx::Rect(surface_size)); + int flipped_y_pos_of_rect_bottom = surface_size.height() - + swap_buffer_rect_.y() - + swap_buffer_rect_.height(); compositor_frame.gl_frame_data->sub_buffer_rect = gfx::Rect(swap_buffer_rect_.x(), flipped_y_pos_of_rect_bottom, @@ -2143,19 +2145,13 @@ void GLRenderer::SwapBuffers() { resource_provider_->SetReadLockFence(new SimpleSwapFence()); } -void GLRenderer::SetDiscardBackBufferWhenNotVisible(bool discard) { - discard_backbuffer_when_not_visible_ = discard; - EnforceMemoryPolicy(); -} - void GLRenderer::EnforceMemoryPolicy() { if (!visible_) { TRACE_EVENT0("cc", "GLRenderer::EnforceMemoryPolicy dropping resources"); ReleaseRenderPassTextures(); - if (discard_backbuffer_when_not_visible_) - DiscardBackbuffer(); + DiscardBackbuffer(); resource_provider_->ReleaseCachedData(); - GLC(context_, context_->flush()); + GLC(gl_, gl_->Flush()); } } @@ -2198,7 +2194,8 @@ void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) { } void GLRenderer::GetFramebufferPixelsAsync( - gfx::Rect rect, scoped_ptr<CopyOutputRequest> request) { + gfx::Rect rect, + scoped_ptr<CopyOutputRequest> request) { DCHECK(!request->IsEmpty()); if (request->IsEmpty()) return; @@ -2208,48 +2205,69 @@ void GLRenderer::GetFramebufferPixelsAsync( gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect); if (!request->force_bitmap_result()) { - unsigned int texture_id = context_->createTexture(); - GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id)); - GLC(context_, context_->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GLC(context_, context_->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GLC(context_, context_->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GLC(context_, context_->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - GetFramebufferTexture(texture_id, RGBA_8888, window_rect); + bool own_mailbox = !request->has_texture_mailbox(); + + GLuint texture_id = 0; + gl_->GenTextures(1, &texture_id); gpu::Mailbox mailbox; - unsigned sync_point = 0; - GLC(context_, context_->genMailboxCHROMIUM(mailbox.name)); - if (mailbox.IsZero()) { - context_->deleteTexture(texture_id); - request->SendEmptyResult(); - return; + if (own_mailbox) { + GLC(gl_, gl_->GenMailboxCHROMIUM(mailbox.name)); + if (mailbox.IsZero()) { + gl_->DeleteTextures(1, &texture_id); + request->SendEmptyResult(); + return; + } + } else { + mailbox = request->texture_mailbox().name(); + DCHECK_EQ(static_cast<unsigned>(GL_TEXTURE_2D), + request->texture_mailbox().target()); + DCHECK(!mailbox.IsZero()); + unsigned incoming_sync_point = request->texture_mailbox().sync_point(); + if (incoming_sync_point) + GLC(gl_, gl_->WaitSyncPointCHROMIUM(incoming_sync_point)); } - GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id)); - GLC(context_, context_->produceTextureCHROMIUM( - GL_TEXTURE_2D, mailbox.name)); - GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0)); - sync_point = context_->insertSyncPoint(); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, texture_id)); + if (own_mailbox) { + GLC(gl_, + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GLC(gl_, + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GLC(gl_, + gl_->TexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLC(gl_, + gl_->TexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GLC(gl_, gl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name)); + } else { + GLC(gl_, gl_->ConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name)); + } + GetFramebufferTexture(texture_id, RGBA_8888, window_rect); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, 0)); + + unsigned sync_point = gl_->InsertSyncPointCHROMIUM(); TextureMailbox texture_mailbox(mailbox, GL_TEXTURE_2D, sync_point); - scoped_ptr<SingleReleaseCallback> release_callback = - texture_mailbox_deleter_->GetReleaseCallback( - output_surface_->context_provider(), texture_id); - request->SendTextureResult(window_rect.size(), - texture_mailbox, - release_callback.Pass()); + + scoped_ptr<SingleReleaseCallback> release_callback; + if (own_mailbox) { + release_callback = texture_mailbox_deleter_->GetReleaseCallback( + output_surface_->context_provider(), texture_id); + } else { + gl_->DeleteTextures(1, &texture_id); + } + + request->SendTextureResult( + window_rect.size(), texture_mailbox, release_callback.Pass()); return; } DCHECK(request->force_bitmap_result()); scoped_ptr<SkBitmap> bitmap(new SkBitmap); - bitmap->setConfig(SkBitmap::kARGB_8888_Config, - window_rect.width(), - window_rect.height()); + bitmap->setConfig( + SkBitmap::kARGB_8888_Config, window_rect.width(), window_rect.height()); bitmap->allocPixels(); scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap)); @@ -2257,11 +2275,11 @@ void GLRenderer::GetFramebufferPixelsAsync( // Save a pointer to the pixels, the bitmap is owned by the cleanup_callback. uint8* pixels = static_cast<uint8*>(bitmap->getPixels()); - AsyncGetFramebufferPixelsCleanupCallback cleanup_callback = base::Bind( - &GLRenderer::PassOnSkBitmap, - base::Unretained(this), - base::Passed(&bitmap), - base::Passed(&lock)); + AsyncGetFramebufferPixelsCleanupCallback cleanup_callback = + base::Bind(&GLRenderer::PassOnSkBitmap, + base::Unretained(this), + base::Passed(&bitmap), + base::Passed(&lock)); scoped_ptr<PendingAsyncReadPixels> pending_read(new PendingAsyncReadPixels); pending_read->copy_request = request.Pass(); @@ -2283,8 +2301,6 @@ void GLRenderer::DoGetFramebufferPixels( bool is_async = !cleanup_callback.is_null(); - MakeContextCurrent(); - bool do_workaround = NeedsIOSurfaceReadbackWorkaround(); unsigned temporary_texture = 0; @@ -2297,78 +2313,75 @@ void GLRenderer::DoGetFramebufferPixels( // is the root cause of top crasher // http://crbug.com/99393. <rdar://problem/10949687> - temporary_texture = context_->createTexture(); - GLC(context_, context_->bindTexture(GL_TEXTURE_2D, temporary_texture)); - GLC(context_, context_->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GLC(context_, context_->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GLC(context_, context_->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GLC(context_, context_->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + gl_->GenTextures(1, &temporary_texture); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, temporary_texture)); + GLC(gl_, + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GLC(gl_, + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GLC(gl_, + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLC(gl_, + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); // Copy the contents of the current (IOSurface-backed) framebuffer into a // temporary texture. - GetFramebufferTexture(temporary_texture, - RGBA_8888, - gfx::Rect(current_surface_size_)); - temporary_fbo = context_->createFramebuffer(); + GetFramebufferTexture( + temporary_texture, RGBA_8888, gfx::Rect(current_surface_size_)); + gl_->GenFramebuffers(1, &temporary_fbo); // Attach this texture to an FBO, and perform the readback from that FBO. - GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, temporary_fbo)); - GLC(context_, context_->framebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - temporary_texture, - 0)); + GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, temporary_fbo)); + GLC(gl_, + gl_->FramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + temporary_texture, + 0)); DCHECK_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE), - context_->checkFramebufferStatus(GL_FRAMEBUFFER)); + gl_->CheckFramebufferStatus(GL_FRAMEBUFFER)); } - unsigned buffer = context_->createBuffer(); - GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, - buffer)); - GLC(context_, context_->bufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, - 4 * window_rect.size().GetArea(), - NULL, - GL_STREAM_READ)); + GLuint buffer = 0; + gl_->GenBuffers(1, &buffer); + GLC(gl_, gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, buffer)); + GLC(gl_, + gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, + 4 * window_rect.size().GetArea(), + NULL, + GL_STREAM_READ)); - WebKit::WebGLId query = 0; + GLuint query = 0; if (is_async) { - query = context_->createQueryEXT(); - GLC(context_, context_->beginQueryEXT( - GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, - query)); + gl_->GenQueriesEXT(1, &query); + GLC(gl_, gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, query)); } - GLC(context_, - context_->readPixels(window_rect.x(), - window_rect.y(), - window_rect.width(), - window_rect.height(), - GL_RGBA, - GL_UNSIGNED_BYTE, - NULL)); + GLC(gl_, + gl_->ReadPixels(window_rect.x(), + window_rect.y(), + window_rect.width(), + window_rect.height(), + GL_RGBA, + GL_UNSIGNED_BYTE, + NULL)); - GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, - 0)); + GLC(gl_, gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0)); if (do_workaround) { // Clean up. - GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0)); - GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0)); - GLC(context_, context_->deleteFramebuffer(temporary_fbo)); - GLC(context_, context_->deleteTexture(temporary_texture)); - } - - base::Closure finished_callback = - base::Bind(&GLRenderer::FinishedReadback, - base::Unretained(this), - cleanup_callback, - buffer, - query, - dest_pixels, - window_rect.size()); + GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, 0)); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, 0)); + GLC(gl_, gl_->DeleteFramebuffers(1, &temporary_fbo)); + GLC(gl_, gl_->DeleteTextures(1, &temporary_texture)); + } + + base::Closure finished_callback = base::Bind(&GLRenderer::FinishedReadback, + base::Unretained(this), + cleanup_callback, + buffer, + query, + dest_pixels, + window_rect.size()); // Save the finished_callback so it can be cancelled. pending_async_read_pixels_.front()->finished_read_pixels_callback.Reset( finished_callback); @@ -2377,12 +2390,8 @@ void GLRenderer::DoGetFramebufferPixels( pending_async_read_pixels_.front()->buffer = buffer; if (is_async) { - GLC(context_, context_->endQueryEXT( - GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM)); - SyncPointHelper::SignalQuery( - context_, - query, - finished_callback); + GLC(gl_, gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM)); + context_support_->SignalQuery(query, finished_callback); } else { resource_provider_->Finish(); finished_callback.Run(); @@ -2400,7 +2409,7 @@ void GLRenderer::FinishedReadback( DCHECK(!pending_async_read_pixels_.empty()); if (query != 0) { - GLC(context_, context_->deleteQueryEXT(query)); + GLC(gl_, gl_->DeleteQueriesEXT(1, &query)); } PendingAsyncReadPixels* current_read = pending_async_read_pixels_.back(); @@ -2410,11 +2419,10 @@ void GLRenderer::FinishedReadback( uint8* src_pixels = NULL; if (source_buffer != 0) { - GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, - source_buffer)); - src_pixels = static_cast<uint8*>( - context_->mapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, - GL_READ_ONLY)); + GLC(gl_, + gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, source_buffer)); + src_pixels = static_cast<uint8*>(gl_->MapBufferCHROMIUM( + GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY)); if (src_pixels) { size_t row_bytes = size.width() * 4; @@ -2425,19 +2433,22 @@ void GLRenderer::FinishedReadback( size_t src_y = total_bytes - dest_y - row_bytes; // Swizzle OpenGL -> Skia byte order. for (size_t x = 0; x < row_bytes; x += 4) { - dest_pixels[dest_y + x + SK_R32_SHIFT/8] = src_pixels[src_y + x + 0]; - dest_pixels[dest_y + x + SK_G32_SHIFT/8] = src_pixels[src_y + x + 1]; - dest_pixels[dest_y + x + SK_B32_SHIFT/8] = src_pixels[src_y + x + 2]; - dest_pixels[dest_y + x + SK_A32_SHIFT/8] = src_pixels[src_y + x + 3]; + dest_pixels[dest_y + x + SK_R32_SHIFT / 8] = + src_pixels[src_y + x + 0]; + dest_pixels[dest_y + x + SK_G32_SHIFT / 8] = + src_pixels[src_y + x + 1]; + dest_pixels[dest_y + x + SK_B32_SHIFT / 8] = + src_pixels[src_y + x + 2]; + dest_pixels[dest_y + x + SK_A32_SHIFT / 8] = + src_pixels[src_y + x + 3]; } } - GLC(context_, context_->unmapBufferCHROMIUM( - GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM)); + GLC(gl_, + gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM)); } - GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, - 0)); - GLC(context_, context_->deleteBuffer(source_buffer)); + GLC(gl_, gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0)); + GLC(gl_, gl_->DeleteBuffers(1, &source_buffer)); } // TODO(danakj): This can go away when synchronous readback is no more and its @@ -2448,11 +2459,10 @@ void GLRenderer::FinishedReadback( pending_async_read_pixels_.pop_back(); } -void GLRenderer::PassOnSkBitmap( - scoped_ptr<SkBitmap> bitmap, - scoped_ptr<SkAutoLockPixels> lock, - scoped_ptr<CopyOutputRequest> request, - bool success) { +void GLRenderer::PassOnSkBitmap(scoped_ptr<SkBitmap> bitmap, + scoped_ptr<SkAutoLockPixels> lock, + scoped_ptr<CopyOutputRequest> request, + bool success) { DCHECK(request->force_bitmap_result()); lock.reset(); @@ -2460,26 +2470,26 @@ void GLRenderer::PassOnSkBitmap( request->SendBitmapResult(bitmap.Pass()); } -void GLRenderer::GetFramebufferTexture( - unsigned texture_id, ResourceFormat texture_format, gfx::Rect window_rect) { +void GLRenderer::GetFramebufferTexture(unsigned texture_id, + ResourceFormat texture_format, + gfx::Rect window_rect) { DCHECK(texture_id); DCHECK_GE(window_rect.x(), 0); DCHECK_GE(window_rect.y(), 0); DCHECK_LE(window_rect.right(), current_surface_size_.width()); DCHECK_LE(window_rect.bottom(), current_surface_size_.height()); - GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id)); - GLC(context_, - context_->copyTexImage2D( - GL_TEXTURE_2D, - 0, - ResourceProvider::GetGLDataFormat(texture_format), - window_rect.x(), - window_rect.y(), - window_rect.width(), - window_rect.height(), - 0)); - GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0)); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, texture_id)); + GLC(gl_, + gl_->CopyTexImage2D(GL_TEXTURE_2D, + 0, + GLDataFormat(texture_format), + window_rect.x(), + window_rect.y(), + window_rect.width(), + window_rect.height(), + 0)); + GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, 0)); } bool GLRenderer::UseScopedTexture(DrawingFrame* frame, @@ -2498,7 +2508,7 @@ void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) { if (output_surface_->HasExternalStencilTest()) { SetStencilEnabled(true); - GLC(context_, context_->stencilFunc(GL_EQUAL, 1, 1)); + GLC(gl_, gl_->StencilFunc(GL_EQUAL, 1, 1)); } else { SetStencilEnabled(false); } @@ -2512,23 +2522,21 @@ bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame, current_framebuffer_lock_.reset(); SetStencilEnabled(false); - GLC(context_, - context_->bindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_)); + GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_)); current_framebuffer_lock_ = make_scoped_ptr(new ResourceProvider::ScopedWriteLockGL( resource_provider_, texture->id())); unsigned texture_id = current_framebuffer_lock_->texture_id(); - GLC(context_, - context_->framebufferTexture2D( + GLC(gl_, + gl_->FramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0)); - DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) == - GL_FRAMEBUFFER_COMPLETE || IsContextLost()); + DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) == + GL_FRAMEBUFFER_COMPLETE || + IsContextLost()); - InitializeViewport(frame, - target_rect, - gfx::Rect(target_rect.size()), - target_rect.size()); + InitializeViewport( + frame, target_rect, gfx::Rect(target_rect.size()), target_rect.size()); return true; } @@ -2537,550 +2545,441 @@ void GLRenderer::SetScissorTestRect(gfx::Rect scissor_rect) { // Don't unnecessarily ask the context to change the scissor, because it // may cause undesired GPU pipeline flushes. - if (scissor_rect == scissor_rect_) + if (scissor_rect == scissor_rect_ && !scissor_rect_needs_reset_) return; scissor_rect_ = scissor_rect; FlushTextureQuadCache(); - GLC(context_, - context_->scissor(scissor_rect.x(), - scissor_rect.y(), - scissor_rect.width(), - scissor_rect.height())); + GLC(gl_, + gl_->Scissor(scissor_rect.x(), + scissor_rect.y(), + scissor_rect.width(), + scissor_rect.height())); + + scissor_rect_needs_reset_ = false; } void GLRenderer::SetDrawViewport(gfx::Rect window_space_viewport) { viewport_ = window_space_viewport; - GLC(context_, context_->viewport(window_space_viewport.x(), - window_space_viewport.y(), - window_space_viewport.width(), - window_space_viewport.height())); + GLC(gl_, + gl_->Viewport(window_space_viewport.x(), + window_space_viewport.y(), + window_space_viewport.width(), + window_space_viewport.height())); } -bool GLRenderer::MakeContextCurrent() { return context_->makeContextCurrent(); } - -bool GLRenderer::InitializeSharedObjects() { +void GLRenderer::InitializeSharedObjects() { TRACE_EVENT0("cc", "GLRenderer::InitializeSharedObjects"); - MakeContextCurrent(); // Create an FBO for doing offscreen rendering. - GLC(context_, offscreen_framebuffer_id_ = context_->createFramebuffer()); + GLC(gl_, gl_->GenFramebuffers(1, &offscreen_framebuffer_id_)); - // We will always need these programs to render, so create the programs - // eagerly so that the shader compilation can start while we do other work. - // Other programs are created lazily on first access. shared_geometry_ = make_scoped_ptr( - new GeometryBinding(context_, QuadVertexRect())); - render_pass_program_ = make_scoped_ptr( - new RenderPassProgram(context_, TexCoordPrecisionMedium)); - render_pass_program_highp_ = make_scoped_ptr( - new RenderPassProgram(context_, TexCoordPrecisionHigh)); - tile_program_ = make_scoped_ptr( - new TileProgram(context_, TexCoordPrecisionMedium)); - tile_program_opaque_ = make_scoped_ptr( - new TileProgramOpaque(context_, TexCoordPrecisionMedium)); - tile_program_highp_ = make_scoped_ptr( - new TileProgram(context_, TexCoordPrecisionHigh)); - tile_program_opaque_highp_ = make_scoped_ptr( - new TileProgramOpaque(context_, TexCoordPrecisionHigh)); - - GLC(context_, context_->flush()); - - return true; + new GeometryBinding(gl_, QuadVertexRect())); } const GLRenderer::TileCheckerboardProgram* GLRenderer::GetTileCheckerboardProgram() { - if (!tile_checkerboard_program_) - tile_checkerboard_program_ = make_scoped_ptr( - new TileCheckerboardProgram(context_, TexCoordPrecisionNA)); - if (!tile_checkerboard_program_->initialized()) { + if (!tile_checkerboard_program_.initialized()) { TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize"); - tile_checkerboard_program_->Initialize(context_, is_using_bind_uniform_); + tile_checkerboard_program_.Initialize(output_surface_->context_provider(), + TexCoordPrecisionNA, + SamplerTypeNA); } - return tile_checkerboard_program_.get(); + return &tile_checkerboard_program_; } const GLRenderer::DebugBorderProgram* GLRenderer::GetDebugBorderProgram() { - if (!debug_border_program_) - debug_border_program_ = make_scoped_ptr( - new DebugBorderProgram(context_, TexCoordPrecisionNA)); - if (!debug_border_program_->initialized()) { + if (!debug_border_program_.initialized()) { TRACE_EVENT0("cc", "GLRenderer::debugBorderProgram::initialize"); - debug_border_program_->Initialize(context_, is_using_bind_uniform_); + debug_border_program_.Initialize(output_surface_->context_provider(), + TexCoordPrecisionNA, + SamplerTypeNA); } - return debug_border_program_.get(); + return &debug_border_program_; } const GLRenderer::SolidColorProgram* GLRenderer::GetSolidColorProgram() { - if (!solid_color_program_) - solid_color_program_ = make_scoped_ptr( - new SolidColorProgram(context_, TexCoordPrecisionNA)); - if (!solid_color_program_->initialized()) { + if (!solid_color_program_.initialized()) { TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize"); - solid_color_program_->Initialize(context_, is_using_bind_uniform_); + solid_color_program_.Initialize(output_surface_->context_provider(), + TexCoordPrecisionNA, + SamplerTypeNA); } - return solid_color_program_.get(); + return &solid_color_program_; } const GLRenderer::SolidColorProgramAA* GLRenderer::GetSolidColorProgramAA() { - if (!solid_color_program_aa_) { - solid_color_program_aa_ = - make_scoped_ptr(new SolidColorProgramAA(context_, TexCoordPrecisionNA)); - } - if (!solid_color_program_aa_->initialized()) { + if (!solid_color_program_aa_.initialized()) { TRACE_EVENT0("cc", "GLRenderer::solidColorProgramAA::initialize"); - solid_color_program_aa_->Initialize(context_, is_using_bind_uniform_); + solid_color_program_aa_.Initialize(output_surface_->context_provider(), + TexCoordPrecisionNA, + SamplerTypeNA); } - return solid_color_program_aa_.get(); + return &solid_color_program_aa_; } const GLRenderer::RenderPassProgram* GLRenderer::GetRenderPassProgram( - TexCoordPrecision precision) { - scoped_ptr<RenderPassProgram>& program = - (precision == TexCoordPrecisionHigh) ? render_pass_program_highp_ - : render_pass_program_; - DCHECK(program); + TexCoordPrecision precision) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + RenderPassProgram* program = &render_pass_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA( - TexCoordPrecision precision) { - scoped_ptr<RenderPassProgramAA>& program = - (precision == TexCoordPrecisionHigh) ? render_pass_program_aa_highp_ - : render_pass_program_aa_; - if (!program) - program = - make_scoped_ptr(new RenderPassProgramAA(context_, precision)); + TexCoordPrecision precision) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + RenderPassProgramAA* program = &render_pass_program_aa_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } -const GLRenderer::RenderPassMaskProgram* -GLRenderer::GetRenderPassMaskProgram(TexCoordPrecision precision) { - scoped_ptr<RenderPassMaskProgram>& program = - (precision == TexCoordPrecisionHigh) ? render_pass_mask_program_highp_ - : render_pass_mask_program_; - if (!program) - program = make_scoped_ptr(new RenderPassMaskProgram(context_, precision)); +const GLRenderer::RenderPassMaskProgram* GLRenderer::GetRenderPassMaskProgram( + TexCoordPrecision precision) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + RenderPassMaskProgram* program = &render_pass_mask_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::RenderPassMaskProgramAA* GLRenderer::GetRenderPassMaskProgramAA(TexCoordPrecision precision) { - scoped_ptr<RenderPassMaskProgramAA>& program = - (precision == TexCoordPrecisionHigh) ? render_pass_mask_program_aa_highp_ - : render_pass_mask_program_aa_; - if (!program) - program = - make_scoped_ptr(new RenderPassMaskProgramAA(context_, precision)); + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + RenderPassMaskProgramAA* program = &render_pass_mask_program_aa_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::RenderPassColorMatrixProgram* GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision) { - scoped_ptr<RenderPassColorMatrixProgram>& program = - (precision == TexCoordPrecisionHigh) ? - render_pass_color_matrix_program_highp_ : - render_pass_color_matrix_program_; - if (!program) - program = make_scoped_ptr( - new RenderPassColorMatrixProgram(context_, precision)); + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + RenderPassColorMatrixProgram* program = + &render_pass_color_matrix_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::renderPassColorMatrixProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::RenderPassColorMatrixProgramAA* GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision) { - scoped_ptr<RenderPassColorMatrixProgramAA>& program = - (precision == TexCoordPrecisionHigh) ? - render_pass_color_matrix_program_aa_highp_ : - render_pass_color_matrix_program_aa_; - if (!program) - program = make_scoped_ptr( - new RenderPassColorMatrixProgramAA(context_, precision)); + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + RenderPassColorMatrixProgramAA* program = + &render_pass_color_matrix_program_aa_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::renderPassColorMatrixProgramAA::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::RenderPassMaskColorMatrixProgram* GLRenderer::GetRenderPassMaskColorMatrixProgram(TexCoordPrecision precision) { - scoped_ptr<RenderPassMaskColorMatrixProgram>& program = - (precision == TexCoordPrecisionHigh) ? - render_pass_mask_color_matrix_program_highp_ : - render_pass_mask_color_matrix_program_; - if (!program) - program = make_scoped_ptr( - new RenderPassMaskColorMatrixProgram(context_, precision)); + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + RenderPassMaskColorMatrixProgram* program = + &render_pass_mask_color_matrix_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::renderPassMaskColorMatrixProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::RenderPassMaskColorMatrixProgramAA* GLRenderer::GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision) { - scoped_ptr<RenderPassMaskColorMatrixProgramAA>& program = - (precision == TexCoordPrecisionHigh) ? - render_pass_mask_color_matrix_program_aa_highp_ : - render_pass_mask_color_matrix_program_aa_; - if (!program) - program = make_scoped_ptr( - new RenderPassMaskColorMatrixProgramAA(context_, precision)); + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + RenderPassMaskColorMatrixProgramAA* program = + &render_pass_mask_color_matrix_program_aa_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::renderPassMaskColorMatrixProgramAA::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::TileProgram* GLRenderer::GetTileProgram( - TexCoordPrecision precision) { - scoped_ptr<TileProgram>& program = - (precision == TexCoordPrecisionHigh) ? tile_program_highp_ - : tile_program_; - DCHECK(program); + TexCoordPrecision precision, + SamplerType sampler) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + DCHECK_GE(sampler, 0); + DCHECK_LT(sampler, NumSamplerTypes); + TileProgram* program = &tile_program_[precision][sampler]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, sampler); } - return program.get(); + return program; } const GLRenderer::TileProgramOpaque* GLRenderer::GetTileProgramOpaque( - TexCoordPrecision precision) { - scoped_ptr<TileProgramOpaque>& program = - (precision == TexCoordPrecisionHigh) ? tile_program_opaque_highp_ - : tile_program_opaque_; - DCHECK(program); + TexCoordPrecision precision, + SamplerType sampler) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + DCHECK_GE(sampler, 0); + DCHECK_LT(sampler, NumSamplerTypes); + TileProgramOpaque* program = &tile_program_opaque_[precision][sampler]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, sampler); } - return program.get(); + return program; } const GLRenderer::TileProgramAA* GLRenderer::GetTileProgramAA( - TexCoordPrecision precision) { - scoped_ptr<TileProgramAA>& program = - (precision == TexCoordPrecisionHigh) ? tile_program_aa_highp_ - : tile_program_aa_; - if (!program) - program = make_scoped_ptr(new TileProgramAA(context_, precision)); + TexCoordPrecision precision, + SamplerType sampler) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + DCHECK_GE(sampler, 0); + DCHECK_LT(sampler, NumSamplerTypes); + TileProgramAA* program = &tile_program_aa_[precision][sampler]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, sampler); } - return program.get(); + return program; } const GLRenderer::TileProgramSwizzle* GLRenderer::GetTileProgramSwizzle( - TexCoordPrecision precision) { - scoped_ptr<TileProgramSwizzle>& program = - (precision == TexCoordPrecisionHigh) ? tile_program_swizzle_highp_ - : tile_program_swizzle_; - if (!program) - program = make_scoped_ptr(new TileProgramSwizzle(context_, precision)); + TexCoordPrecision precision, + SamplerType sampler) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + DCHECK_GE(sampler, 0); + DCHECK_LT(sampler, NumSamplerTypes); + TileProgramSwizzle* program = &tile_program_swizzle_[precision][sampler]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, sampler); } - return program.get(); + return program; } const GLRenderer::TileProgramSwizzleOpaque* -GLRenderer::GetTileProgramSwizzleOpaque(TexCoordPrecision precision) { - scoped_ptr<TileProgramSwizzleOpaque>& program = - (precision == TexCoordPrecisionHigh) ? tile_program_swizzle_opaque_highp_ - : tile_program_swizzle_opaque_; - if (!program) - program = make_scoped_ptr( - new TileProgramSwizzleOpaque(context_, precision)); +GLRenderer::GetTileProgramSwizzleOpaque(TexCoordPrecision precision, + SamplerType sampler) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + DCHECK_GE(sampler, 0); + DCHECK_LT(sampler, NumSamplerTypes); + TileProgramSwizzleOpaque* program = + &tile_program_swizzle_opaque_[precision][sampler]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleOpaque::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, sampler); } - return program.get(); + return program; } const GLRenderer::TileProgramSwizzleAA* GLRenderer::GetTileProgramSwizzleAA( - TexCoordPrecision precision) { - scoped_ptr<TileProgramSwizzleAA>& program = - (precision == TexCoordPrecisionHigh) ? tile_program_swizzle_aa_highp_ - : tile_program_swizzle_aa_; - if (!program) - program = make_scoped_ptr(new TileProgramSwizzleAA(context_, precision)); + TexCoordPrecision precision, + SamplerType sampler) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + DCHECK_GE(sampler, 0); + DCHECK_LT(sampler, NumSamplerTypes); + TileProgramSwizzleAA* program = &tile_program_swizzle_aa_[precision][sampler]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, sampler); } - return program.get(); + return program; } const GLRenderer::TextureProgram* GLRenderer::GetTextureProgram( TexCoordPrecision precision) { - scoped_ptr<TextureProgram>& program = - (precision == TexCoordPrecisionHigh) ? texture_program_highp_ - : texture_program_; - if (!program) - program = make_scoped_ptr(new TextureProgram(context_, precision)); + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + TextureProgram* program = &texture_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::NonPremultipliedTextureProgram* - GLRenderer::GetNonPremultipliedTextureProgram(TexCoordPrecision precision) { - scoped_ptr<NonPremultipliedTextureProgram>& program = - (precision == TexCoordPrecisionHigh) ? - nonpremultiplied_texture_program_highp_ : - nonpremultiplied_texture_program_; - if (!program) { - program = make_scoped_ptr( - new NonPremultipliedTextureProgram(context_, precision)); - } +GLRenderer::GetNonPremultipliedTextureProgram(TexCoordPrecision precision) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + NonPremultipliedTextureProgram* program = + &nonpremultiplied_texture_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::NonPremultipliedTextureProgram::Initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::TextureBackgroundProgram* GLRenderer::GetTextureBackgroundProgram(TexCoordPrecision precision) { - scoped_ptr<TextureBackgroundProgram>& program = - (precision == TexCoordPrecisionHigh) ? texture_background_program_highp_ - : texture_background_program_; - if (!program) { - program = make_scoped_ptr( - new TextureBackgroundProgram(context_, precision)); - } + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + TextureBackgroundProgram* program = &texture_background_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::NonPremultipliedTextureBackgroundProgram* GLRenderer::GetNonPremultipliedTextureBackgroundProgram( TexCoordPrecision precision) { - scoped_ptr<NonPremultipliedTextureBackgroundProgram>& program = - (precision == TexCoordPrecisionHigh) ? - nonpremultiplied_texture_background_program_highp_ : - nonpremultiplied_texture_background_program_; - if (!program) { - program = make_scoped_ptr( - new NonPremultipliedTextureBackgroundProgram(context_, precision)); - } + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + NonPremultipliedTextureBackgroundProgram* program = + &nonpremultiplied_texture_background_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::NonPremultipliedTextureProgram::Initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } -const GLRenderer::TextureIOSurfaceProgram* -GLRenderer::GetTextureIOSurfaceProgram(TexCoordPrecision precision) { - scoped_ptr<TextureIOSurfaceProgram>& program = - (precision == TexCoordPrecisionHigh) ? texture_io_surface_program_highp_ - : texture_io_surface_program_; - if (!program) - program = - make_scoped_ptr(new TextureIOSurfaceProgram(context_, precision)); +const GLRenderer::TextureProgram* GLRenderer::GetTextureIOSurfaceProgram( + TexCoordPrecision precision) { + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + TextureProgram* program = &texture_io_surface_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2DRect); } - return program.get(); + return program; } const GLRenderer::VideoYUVProgram* GLRenderer::GetVideoYUVProgram( TexCoordPrecision precision) { - scoped_ptr<VideoYUVProgram>& program = - (precision == TexCoordPrecisionHigh) ? video_yuv_program_highp_ - : video_yuv_program_; - if (!program) - program = make_scoped_ptr(new VideoYUVProgram(context_, precision)); + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + VideoYUVProgram* program = &video_yuv_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::VideoYUVAProgram* GLRenderer::GetVideoYUVAProgram( TexCoordPrecision precision) { - scoped_ptr<VideoYUVAProgram>& program = - (precision == TexCoordPrecisionHigh) ? video_yuva_program_highp_ - : video_yuva_program_; - if (!program) - program = make_scoped_ptr(new VideoYUVAProgram(context_, precision)); + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + VideoYUVAProgram* program = &video_yuva_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::videoYUVAProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerType2D); } - return program.get(); + return program; } const GLRenderer::VideoStreamTextureProgram* GLRenderer::GetVideoStreamTextureProgram(TexCoordPrecision precision) { if (!Capabilities().using_egl_image) return NULL; - scoped_ptr<VideoStreamTextureProgram>& program = - (precision == TexCoordPrecisionHigh) ? video_stream_texture_program_highp_ - : video_stream_texture_program_; - if (!program) - program = - make_scoped_ptr(new VideoStreamTextureProgram(context_, precision)); + DCHECK_GE(precision, 0); + DCHECK_LT(precision, NumTexCoordPrecisions); + VideoStreamTextureProgram* program = + &video_stream_texture_program_[precision]; if (!program->initialized()) { TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize"); - program->Initialize(context_, is_using_bind_uniform_); + program->Initialize( + output_surface_->context_provider(), precision, SamplerTypeExternalOES); } - return program.get(); + return program; } void GLRenderer::CleanupSharedObjects() { - MakeContextCurrent(); - shared_geometry_.reset(); - if (tile_program_) - tile_program_->Cleanup(context_); - if (tile_program_opaque_) - tile_program_opaque_->Cleanup(context_); - if (tile_program_swizzle_) - tile_program_swizzle_->Cleanup(context_); - if (tile_program_swizzle_opaque_) - tile_program_swizzle_opaque_->Cleanup(context_); - if (tile_program_aa_) - tile_program_aa_->Cleanup(context_); - if (tile_program_swizzle_aa_) - tile_program_swizzle_aa_->Cleanup(context_); - if (tile_checkerboard_program_) - tile_checkerboard_program_->Cleanup(context_); - - if (tile_program_highp_) - tile_program_highp_->Cleanup(context_); - if (tile_program_opaque_highp_) - tile_program_opaque_highp_->Cleanup(context_); - if (tile_program_swizzle_highp_) - tile_program_swizzle_highp_->Cleanup(context_); - if (tile_program_swizzle_opaque_highp_) - tile_program_swizzle_opaque_highp_->Cleanup(context_); - if (tile_program_aa_highp_) - tile_program_aa_highp_->Cleanup(context_); - if (tile_program_swizzle_aa_highp_) - tile_program_swizzle_aa_highp_->Cleanup(context_); - - if (render_pass_mask_program_) - render_pass_mask_program_->Cleanup(context_); - if (render_pass_program_) - render_pass_program_->Cleanup(context_); - if (render_pass_mask_program_aa_) - render_pass_mask_program_aa_->Cleanup(context_); - if (render_pass_program_aa_) - render_pass_program_aa_->Cleanup(context_); - if (render_pass_color_matrix_program_) - render_pass_color_matrix_program_->Cleanup(context_); - if (render_pass_mask_color_matrix_program_aa_) - render_pass_mask_color_matrix_program_aa_->Cleanup(context_); - if (render_pass_color_matrix_program_aa_) - render_pass_color_matrix_program_aa_->Cleanup(context_); - if (render_pass_mask_color_matrix_program_) - render_pass_mask_color_matrix_program_->Cleanup(context_); - - if (render_pass_mask_program_highp_) - render_pass_mask_program_highp_->Cleanup(context_); - if (render_pass_program_highp_) - render_pass_program_highp_->Cleanup(context_); - if (render_pass_mask_program_aa_highp_) - render_pass_mask_program_aa_highp_->Cleanup(context_); - if (render_pass_program_aa_highp_) - render_pass_program_aa_highp_->Cleanup(context_); - if (render_pass_color_matrix_program_highp_) - render_pass_color_matrix_program_highp_->Cleanup(context_); - if (render_pass_mask_color_matrix_program_aa_highp_) - render_pass_mask_color_matrix_program_aa_highp_->Cleanup(context_); - if (render_pass_color_matrix_program_aa_highp_) - render_pass_color_matrix_program_aa_highp_->Cleanup(context_); - if (render_pass_mask_color_matrix_program_highp_) - render_pass_mask_color_matrix_program_highp_->Cleanup(context_); - - if (texture_program_) - texture_program_->Cleanup(context_); - if (nonpremultiplied_texture_program_) - nonpremultiplied_texture_program_->Cleanup(context_); - if (texture_background_program_) - texture_background_program_->Cleanup(context_); - if (nonpremultiplied_texture_background_program_) - nonpremultiplied_texture_background_program_->Cleanup(context_); - if (texture_io_surface_program_) - texture_io_surface_program_->Cleanup(context_); - - if (texture_program_highp_) - texture_program_highp_->Cleanup(context_); - if (nonpremultiplied_texture_program_highp_) - nonpremultiplied_texture_program_highp_->Cleanup(context_); - if (texture_background_program_highp_) - texture_background_program_highp_->Cleanup(context_); - if (nonpremultiplied_texture_background_program_highp_) - nonpremultiplied_texture_background_program_highp_->Cleanup(context_); - if (texture_io_surface_program_highp_) - texture_io_surface_program_highp_->Cleanup(context_); - - if (video_yuv_program_) - video_yuv_program_->Cleanup(context_); - if (video_yuva_program_) - video_yuva_program_->Cleanup(context_); - if (video_stream_texture_program_) - video_stream_texture_program_->Cleanup(context_); - - if (video_yuv_program_highp_) - video_yuv_program_highp_->Cleanup(context_); - if (video_yuva_program_highp_) - video_yuva_program_highp_->Cleanup(context_); - if (video_stream_texture_program_highp_) - video_stream_texture_program_highp_->Cleanup(context_); - - if (debug_border_program_) - debug_border_program_->Cleanup(context_); - if (solid_color_program_) - solid_color_program_->Cleanup(context_); - if (solid_color_program_aa_) - solid_color_program_aa_->Cleanup(context_); + for (int i = 0; i < NumTexCoordPrecisions; ++i) { + for (int j = 0; j < NumSamplerTypes; ++j) { + tile_program_[i][j].Cleanup(gl_); + tile_program_opaque_[i][j].Cleanup(gl_); + tile_program_swizzle_[i][j].Cleanup(gl_); + tile_program_swizzle_opaque_[i][j].Cleanup(gl_); + tile_program_aa_[i][j].Cleanup(gl_); + tile_program_swizzle_aa_[i][j].Cleanup(gl_); + } + + render_pass_mask_program_[i].Cleanup(gl_); + render_pass_program_[i].Cleanup(gl_); + render_pass_mask_program_aa_[i].Cleanup(gl_); + render_pass_program_aa_[i].Cleanup(gl_); + render_pass_color_matrix_program_[i].Cleanup(gl_); + render_pass_mask_color_matrix_program_aa_[i].Cleanup(gl_); + render_pass_color_matrix_program_aa_[i].Cleanup(gl_); + render_pass_mask_color_matrix_program_[i].Cleanup(gl_); + + texture_program_[i].Cleanup(gl_); + nonpremultiplied_texture_program_[i].Cleanup(gl_); + texture_background_program_[i].Cleanup(gl_); + nonpremultiplied_texture_background_program_[i].Cleanup(gl_); + texture_io_surface_program_[i].Cleanup(gl_); + + video_yuv_program_[i].Cleanup(gl_); + video_yuva_program_[i].Cleanup(gl_); + video_stream_texture_program_[i].Cleanup(gl_); + } + + tile_checkerboard_program_.Cleanup(gl_); + + debug_border_program_.Cleanup(gl_); + solid_color_program_.Cleanup(gl_); + solid_color_program_aa_.Cleanup(gl_); if (offscreen_framebuffer_id_) - GLC(context_, context_->deleteFramebuffer(offscreen_framebuffer_id_)); + GLC(gl_, gl_->DeleteFramebuffers(1, &offscreen_framebuffer_id_)); if (on_demand_tile_raster_resource_id_) resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_); @@ -3088,54 +2987,29 @@ void GLRenderer::CleanupSharedObjects() { ReleaseRenderPassTextures(); } -void GLRenderer::ReinitializeGrCanvas() { - if (!CanUseSkiaGPUBackend()) - return; - - GrBackendRenderTargetDesc desc; - desc.fWidth = client_->DeviceViewport().width(); - desc.fHeight = client_->DeviceViewport().height(); - desc.fConfig = kRGBA_8888_GrPixelConfig; - desc.fOrigin = kTopLeft_GrSurfaceOrigin; - desc.fSampleCnt = 1; - desc.fStencilBits = 8; - desc.fRenderTargetHandle = 0; - - skia::RefPtr<GrSurface> surface( - skia::AdoptRef(gr_context_->wrapBackendRenderTarget(desc))); - skia::RefPtr<SkBaseDevice> device( - skia::AdoptRef(SkGpuDevice::Create(surface.get()))); - sk_canvas_ = skia::AdoptRef(new SkCanvas(device.get())); -} - void GLRenderer::ReinitializeGLState() { // Bind the common vertex attributes used for drawing all the layers. shared_geometry_->PrepareForDraw(); - GLC(context_, context_->disable(GL_DEPTH_TEST)); - GLC(context_, context_->disable(GL_CULL_FACE)); - GLC(context_, context_->colorMask(true, true, true, true)); - GLC(context_, context_->disable(GL_STENCIL_TEST)); + GLC(gl_, gl_->Disable(GL_DEPTH_TEST)); + GLC(gl_, gl_->Disable(GL_CULL_FACE)); + GLC(gl_, gl_->ColorMask(true, true, true, true)); + GLC(gl_, gl_->Disable(GL_STENCIL_TEST)); stencil_shadow_ = false; - GLC(context_, context_->enable(GL_BLEND)); + GLC(gl_, gl_->Enable(GL_BLEND)); blend_shadow_ = true; - GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); - GLC(context_, context_->activeTexture(GL_TEXTURE0)); + GLC(gl_, gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); + GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0)); program_shadow_ = 0; // Make sure scissoring starts as disabled. is_scissor_enabled_ = false; - GLC(context_, context_->disable(GL_SCISSOR_TEST)); -} - -bool GLRenderer::CanUseSkiaGPUBackend() const { - // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas - // implementation. - return gr_context_ && context_->getContextAttributes().stencil; + GLC(gl_, gl_->Disable(GL_SCISSOR_TEST)); + scissor_rect_needs_reset_ = true; } bool GLRenderer::IsContextLost() { - return (context_->getGraphicsResetStatusARB() != GL_NO_ERROR); + return output_surface_->context_provider()->IsContextLost(); } } // namespace cc diff --git a/chromium/cc/output/gl_renderer.h b/chromium/cc/output/gl_renderer.h index bc47870063d..cf672f0afa4 100644 --- a/chromium/cc/output/gl_renderer.h +++ b/chromium/cc/output/gl_renderer.h @@ -23,7 +23,13 @@ class SkBitmap; -namespace WebKit { class WebGraphicsContext3D; } +namespace blink { class WebGraphicsContext3D; } + +namespace gpu { +namespace gles2 { +class GLES2Interface; +} +} namespace cc { @@ -46,22 +52,19 @@ class CC_EXPORT GLRenderer : public DirectRenderer { OutputSurface* output_surface, ResourceProvider* resource_provider, TextureMailboxDeleter* texture_mailbox_deleter, - int highp_threshold_min, - bool use_skia_gpu_backend); + int highp_threshold_min); virtual ~GLRenderer(); virtual const RendererCapabilities& Capabilities() const OVERRIDE; - WebKit::WebGraphicsContext3D* Context(); - - virtual void ViewportChanged() OVERRIDE; + blink::WebGraphicsContext3D* Context(); // Waits for rendering to finish. virtual void Finish() OVERRIDE; virtual void DoNoOp() OVERRIDE; - virtual void SwapBuffers() OVERRIDE; + virtual void SwapBuffers(const CompositorFrameMetadata& metadata) OVERRIDE; virtual void GetFramebufferPixels(void* pixels, gfx::Rect rect) OVERRIDE; @@ -73,15 +76,11 @@ class CC_EXPORT GLRenderer : public DirectRenderer { size_t bytes_visible_and_nearby, size_t bytes_allocated) OVERRIDE; - virtual void SetDiscardBackBufferWhenNotVisible(bool discard) OVERRIDE; - - static void DebugGLCall(WebKit::WebGraphicsContext3D* context, + static void DebugGLCall(gpu::gles2::GLES2Interface* gl, const char* command, const char* file, int line); - bool CanUseSkiaGPUBackend() const; - protected: GLRenderer(RendererClient* client, const LayerTreeSettings* settings, @@ -91,7 +90,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer { int highp_threshold_min); bool IsBackbufferDiscarded() const { return is_backbuffer_discarded_; } - bool Initialize(); void InitializeGrContext(); const gfx::QuadF& SharedGeometryQuad() const { return shared_geometry_quad_; } @@ -153,11 +151,12 @@ class CC_EXPORT GLRenderer : public DirectRenderer { const CheckerboardDrawQuad* quad); void DrawDebugBorderQuad(const DrawingFrame* frame, const DebugBorderDrawQuad* quad); - scoped_ptr<ScopedResource> DrawBackgroundFilters( + scoped_ptr<ScopedResource> GetBackgroundWithFilters( DrawingFrame* frame, const RenderPassDrawQuad* quad, const gfx::Transform& contents_device_transform, - const gfx::Transform& contents_device_transformInverse); + const gfx::Transform& contents_device_transformInverse, + bool* background_changed); void DrawRenderPassQuad(DrawingFrame* frame, const RenderPassDrawQuad* quad); void DrawSolidColorQuad(const DrawingFrame* frame, const SolidColorDrawQuad* quad); @@ -176,8 +175,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer { const YUVVideoDrawQuad* quad); void DrawPictureQuad(const DrawingFrame* frame, const PictureDrawQuad* quad); - void DrawPictureQuadDirectToBackbuffer(const DrawingFrame* frame, - const PictureDrawQuad* quad); void SetShaderOpacity(float opacity, int alpha_location); void SetShaderQuadF(const gfx::QuadF& quad, int quad_location); @@ -199,7 +196,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer { bool MakeContextCurrent(); - bool InitializeSharedObjects(); + void InitializeSharedObjects(); void CleanupSharedObjects(); typedef base::Callback<void(scoped_ptr<CopyOutputRequest> copy_request, @@ -220,7 +217,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer { scoped_ptr<CopyOutputRequest> request, bool success); - void ReinitializeGrCanvas(); void ReinitializeGLState(); virtual void DiscardBackbuffer() OVERRIDE; @@ -266,9 +262,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer { typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderTexBackgroundPremultiplyAlpha> NonPremultipliedTextureBackgroundProgram; - typedef ProgramBinding<VertexShaderPosTexTransform, - FragmentShaderRGBATexRectVaryingAlpha> - TextureIOSurfaceProgram; // Render surface shaders. typedef ProgramBinding<VertexShaderPosTexTransform, @@ -294,8 +287,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer { RenderPassMaskColorMatrixProgram; // Video shaders. - typedef ProgramBinding<VertexShaderVideoTransform, - FragmentShaderOESImageExternal> + typedef ProgramBinding<VertexShaderVideoTransform, FragmentShaderRGBATex> VideoStreamTextureProgram; typedef ProgramBinding<VertexShaderPosTexYUVStretch, FragmentShaderYUVVideo> VideoYUVProgram; @@ -310,14 +302,19 @@ class CC_EXPORT GLRenderer : public DirectRenderer { typedef ProgramBinding<VertexShaderQuadAA, FragmentShaderColorAA> SolidColorProgramAA; - const TileProgram* GetTileProgram(TexCoordPrecision precision); - const TileProgramOpaque* GetTileProgramOpaque(TexCoordPrecision precision); - const TileProgramAA* GetTileProgramAA(TexCoordPrecision precision); - const TileProgramSwizzle* GetTileProgramSwizzle(TexCoordPrecision precision); + const TileProgram* GetTileProgram( + TexCoordPrecision precision, SamplerType sampler); + const TileProgramOpaque* GetTileProgramOpaque( + TexCoordPrecision precision, SamplerType sampler); + const TileProgramAA* GetTileProgramAA( + TexCoordPrecision precision, SamplerType sampler); + const TileProgramSwizzle* GetTileProgramSwizzle( + TexCoordPrecision precision, SamplerType sampler); const TileProgramSwizzleOpaque* GetTileProgramSwizzleOpaque( - TexCoordPrecision precision); + TexCoordPrecision precision, SamplerType sampler); const TileProgramSwizzleAA* GetTileProgramSwizzleAA( - TexCoordPrecision precision); + TexCoordPrecision precision, SamplerType sampler); + const TileCheckerboardProgram* GetTileCheckerboardProgram(); const RenderPassProgram* GetRenderPassProgram( @@ -345,7 +342,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer { TexCoordPrecision precision); const NonPremultipliedTextureBackgroundProgram* GetNonPremultipliedTextureBackgroundProgram(TexCoordPrecision precision); - const TextureIOSurfaceProgram* GetTextureIOSurfaceProgram( + const TextureProgram* GetTextureIOSurfaceProgram( TexCoordPrecision precision); const VideoYUVProgram* GetVideoYUVProgram( @@ -359,74 +356,52 @@ class CC_EXPORT GLRenderer : public DirectRenderer { const SolidColorProgram* GetSolidColorProgram(); const SolidColorProgramAA* GetSolidColorProgramAA(); - scoped_ptr<TileProgram> tile_program_; - scoped_ptr<TileProgramOpaque> tile_program_opaque_; - scoped_ptr<TileProgramAA> tile_program_aa_; - scoped_ptr<TileProgramSwizzle> tile_program_swizzle_; - scoped_ptr<TileProgramSwizzleOpaque> tile_program_swizzle_opaque_; - scoped_ptr<TileProgramSwizzleAA> tile_program_swizzle_aa_; - scoped_ptr<TileCheckerboardProgram> tile_checkerboard_program_; - - scoped_ptr<TileProgram> tile_program_highp_; - scoped_ptr<TileProgramOpaque> tile_program_opaque_highp_; - scoped_ptr<TileProgramAA> tile_program_aa_highp_; - scoped_ptr<TileProgramSwizzle> tile_program_swizzle_highp_; - scoped_ptr<TileProgramSwizzleOpaque> tile_program_swizzle_opaque_highp_; - scoped_ptr<TileProgramSwizzleAA> tile_program_swizzle_aa_highp_; - - scoped_ptr<TextureProgram> texture_program_; - scoped_ptr<NonPremultipliedTextureProgram> nonpremultiplied_texture_program_; - scoped_ptr<TextureBackgroundProgram> texture_background_program_; - scoped_ptr<NonPremultipliedTextureBackgroundProgram> - nonpremultiplied_texture_background_program_; - scoped_ptr<TextureIOSurfaceProgram> texture_io_surface_program_; - - scoped_ptr<TextureProgram> texture_program_highp_; - scoped_ptr<NonPremultipliedTextureProgram> - nonpremultiplied_texture_program_highp_; - scoped_ptr<TextureBackgroundProgram> texture_background_program_highp_; - scoped_ptr<NonPremultipliedTextureBackgroundProgram> - nonpremultiplied_texture_background_program_highp_; - scoped_ptr<TextureIOSurfaceProgram> texture_io_surface_program_highp_; - - scoped_ptr<RenderPassProgram> render_pass_program_; - scoped_ptr<RenderPassProgramAA> render_pass_program_aa_; - scoped_ptr<RenderPassMaskProgram> render_pass_mask_program_; - scoped_ptr<RenderPassMaskProgramAA> render_pass_mask_program_aa_; - scoped_ptr<RenderPassColorMatrixProgram> render_pass_color_matrix_program_; - scoped_ptr<RenderPassColorMatrixProgramAA> - render_pass_color_matrix_program_aa_; - scoped_ptr<RenderPassMaskColorMatrixProgram> - render_pass_mask_color_matrix_program_; - scoped_ptr<RenderPassMaskColorMatrixProgramAA> - render_pass_mask_color_matrix_program_aa_; - - scoped_ptr<RenderPassProgram> render_pass_program_highp_; - scoped_ptr<RenderPassProgramAA> render_pass_program_aa_highp_; - scoped_ptr<RenderPassMaskProgram> render_pass_mask_program_highp_; - scoped_ptr<RenderPassMaskProgramAA> render_pass_mask_program_aa_highp_; - scoped_ptr<RenderPassColorMatrixProgram> - render_pass_color_matrix_program_highp_; - scoped_ptr<RenderPassColorMatrixProgramAA> - render_pass_color_matrix_program_aa_highp_; - scoped_ptr<RenderPassMaskColorMatrixProgram> - render_pass_mask_color_matrix_program_highp_; - scoped_ptr<RenderPassMaskColorMatrixProgramAA> - render_pass_mask_color_matrix_program_aa_highp_; - - scoped_ptr<VideoYUVProgram> video_yuv_program_; - scoped_ptr<VideoYUVAProgram> video_yuva_program_; - scoped_ptr<VideoStreamTextureProgram> video_stream_texture_program_; - - scoped_ptr<VideoYUVProgram> video_yuv_program_highp_; - scoped_ptr<VideoYUVAProgram> video_yuva_program_highp_; - scoped_ptr<VideoStreamTextureProgram> video_stream_texture_program_highp_; - - scoped_ptr<DebugBorderProgram> debug_border_program_; - scoped_ptr<SolidColorProgram> solid_color_program_; - scoped_ptr<SolidColorProgramAA> solid_color_program_aa_; - - WebKit::WebGraphicsContext3D* context_; + TileProgram tile_program_[NumTexCoordPrecisions][NumSamplerTypes]; + TileProgramOpaque + tile_program_opaque_[NumTexCoordPrecisions][NumSamplerTypes]; + TileProgramAA tile_program_aa_[NumTexCoordPrecisions][NumSamplerTypes]; + TileProgramSwizzle + tile_program_swizzle_[NumTexCoordPrecisions][NumSamplerTypes]; + TileProgramSwizzleOpaque + tile_program_swizzle_opaque_[NumTexCoordPrecisions][NumSamplerTypes]; + TileProgramSwizzleAA + tile_program_swizzle_aa_[NumTexCoordPrecisions][NumSamplerTypes]; + + TileCheckerboardProgram tile_checkerboard_program_; + + TextureProgram texture_program_[NumTexCoordPrecisions]; + NonPremultipliedTextureProgram + nonpremultiplied_texture_program_[NumTexCoordPrecisions]; + TextureBackgroundProgram texture_background_program_[NumTexCoordPrecisions]; + NonPremultipliedTextureBackgroundProgram + nonpremultiplied_texture_background_program_[NumTexCoordPrecisions]; + TextureProgram texture_io_surface_program_[NumTexCoordPrecisions]; + + RenderPassProgram render_pass_program_[NumTexCoordPrecisions]; + RenderPassProgramAA render_pass_program_aa_[NumTexCoordPrecisions]; + RenderPassMaskProgram render_pass_mask_program_[NumTexCoordPrecisions]; + RenderPassMaskProgramAA render_pass_mask_program_aa_[NumTexCoordPrecisions]; + RenderPassColorMatrixProgram + render_pass_color_matrix_program_[NumTexCoordPrecisions]; + RenderPassColorMatrixProgramAA + render_pass_color_matrix_program_aa_[NumTexCoordPrecisions]; + RenderPassMaskColorMatrixProgram + render_pass_mask_color_matrix_program_[NumTexCoordPrecisions]; + RenderPassMaskColorMatrixProgramAA + render_pass_mask_color_matrix_program_aa_[NumTexCoordPrecisions]; + + VideoYUVProgram video_yuv_program_[NumTexCoordPrecisions]; + VideoYUVAProgram video_yuva_program_[NumTexCoordPrecisions]; + VideoStreamTextureProgram + video_stream_texture_program_[NumTexCoordPrecisions]; + + DebugBorderProgram debug_border_program_; + SolidColorProgram solid_color_program_; + SolidColorProgramAA solid_color_program_aa_; + + blink::WebGraphicsContext3D* context_; + gpu::gles2::GLES2Interface* gl_; + gpu::ContextSupport* context_support_; skia::RefPtr<GrContext> gr_context_; skia::RefPtr<SkCanvas> sk_canvas_; @@ -437,10 +412,10 @@ class CC_EXPORT GLRenderer : public DirectRenderer { gfx::Rect scissor_rect_; gfx::Rect viewport_; bool is_backbuffer_discarded_; - bool discard_backbuffer_when_not_visible_; bool is_using_bind_uniform_; bool visible_; bool is_scissor_enabled_; + bool scissor_rect_needs_reset_; bool stencil_shadow_; bool blend_shadow_; unsigned program_shadow_; diff --git a/chromium/cc/output/gl_renderer_unittest.cc b/chromium/cc/output/gl_renderer_unittest.cc index 836287f4448..f165e153bf0 100644 --- a/chromium/cc/output/gl_renderer_unittest.cc +++ b/chromium/cc/output/gl_renderer_unittest.cc @@ -7,11 +7,9 @@ #include <set> #include "cc/base/math_util.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/output/compositor_frame_metadata.h" #include "cc/resources/prioritized_resource_manager.h" #include "cc/resources/resource_provider.h" -#include "cc/resources/sync_point_helper.h" #include "cc/test/fake_impl_proxy.h" #include "cc/test/fake_layer_tree_host_impl.h" #include "cc/test/fake_output_surface.h" @@ -20,7 +18,9 @@ #include "cc/test/pixel_test.h" #include "cc/test/render_pass_test_common.h" #include "cc/test/render_pass_test_utils.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "gpu/GLES2/gl2extchromium.h" +#include "gpu/command_buffer/client/context_support.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/khronos/GLES2/gl2.h" @@ -40,25 +40,32 @@ using testing::InSequence; using testing::Mock; using testing::Return; using testing::StrictMock; -using WebKit::WebGLId; -using WebKit::WebString; -using WebKit::WGC3Dbitfield; -using WebKit::WGC3Dboolean; -using WebKit::WGC3Dchar; -using WebKit::WGC3Denum; -using WebKit::WGC3Dfloat; -using WebKit::WGC3Dint; -using WebKit::WGC3Dintptr; -using WebKit::WGC3Dsizei; -using WebKit::WGC3Dsizeiptr; -using WebKit::WGC3Duint; +using blink::WebGLId; +using blink::WebString; +using blink::WGC3Dbitfield; +using blink::WGC3Dboolean; +using blink::WGC3Dchar; +using blink::WGC3Denum; +using blink::WGC3Dfloat; +using blink::WGC3Dint; +using blink::WGC3Dintptr; +using blink::WGC3Dsizei; +using blink::WGC3Dsizeiptr; +using blink::WGC3Duint; namespace cc { -#define EXPECT_PROGRAM_VALID(program_binding) \ - do { \ - EXPECT_TRUE(program_binding->program()); \ - EXPECT_TRUE(program_binding->initialized()); \ +class GLRendererTest : public testing::Test { + protected: + RenderPass* root_render_pass() { return render_passes_in_draw_order_.back(); } + + RenderPassList render_passes_in_draw_order_; +}; + +#define EXPECT_PROGRAM_VALID(program_binding) \ + do { \ + EXPECT_TRUE((program_binding)->program()); \ + EXPECT_TRUE((program_binding)->initialized()); \ } while (false) // Explicitly named to be a friend in GLRenderer for shader access. @@ -76,12 +83,6 @@ class GLRendererShaderPixelTest : public GLRendererPixelTest { } void TestShadersWithTexCoordPrecision(TexCoordPrecision precision) { - EXPECT_PROGRAM_VALID(renderer()->GetTileProgram(precision)); - EXPECT_PROGRAM_VALID(renderer()->GetTileProgramOpaque(precision)); - EXPECT_PROGRAM_VALID(renderer()->GetTileProgramAA(precision)); - EXPECT_PROGRAM_VALID(renderer()->GetTileProgramSwizzle(precision)); - EXPECT_PROGRAM_VALID(renderer()->GetTileProgramSwizzleOpaque(precision)); - EXPECT_PROGRAM_VALID(renderer()->GetTileProgramSwizzleAA(precision)); EXPECT_PROGRAM_VALID(renderer()->GetRenderPassProgram(precision)); EXPECT_PROGRAM_VALID(renderer()->GetRenderPassProgramAA(precision)); EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgram(precision)); @@ -108,6 +109,23 @@ class GLRendererShaderPixelTest : public GLRendererPixelTest { EXPECT_PROGRAM_VALID(renderer()->GetVideoStreamTextureProgram(precision)); else EXPECT_FALSE(renderer()->GetVideoStreamTextureProgram(precision)); + TestShadersWithSamplerType(precision, SamplerType2D); + TestShadersWithSamplerType(precision, SamplerType2DRect); + // This is unlikely to be ever true in tests due to usage of osmesa. + if (renderer()->Capabilities().using_egl_image) + TestShadersWithSamplerType(precision, SamplerTypeExternalOES); + } + + void TestShadersWithSamplerType(TexCoordPrecision precision, + SamplerType sampler) { + EXPECT_PROGRAM_VALID(renderer()->GetTileProgram(precision, sampler)); + EXPECT_PROGRAM_VALID(renderer()->GetTileProgramOpaque(precision, sampler)); + EXPECT_PROGRAM_VALID(renderer()->GetTileProgramAA(precision, sampler)); + EXPECT_PROGRAM_VALID(renderer()->GetTileProgramSwizzle(precision, sampler)); + EXPECT_PROGRAM_VALID( + renderer()->GetTileProgramSwizzleOpaque(precision, sampler)); + EXPECT_PROGRAM_VALID( + renderer()->GetTileProgramSwizzleAA(precision, sampler)); } }; @@ -117,73 +135,22 @@ namespace { TEST_F(GLRendererShaderPixelTest, AllShadersCompile) { TestShaders(); } #endif -class FrameCountingContext : public TestWebGraphicsContext3D { - public: - FrameCountingContext() - : frame_(0) { - test_capabilities_.set_visibility = true; - test_capabilities_.discard_backbuffer = true; - } - - // WebGraphicsContext3D methods. - - // This method would normally do a glSwapBuffers under the hood. - virtual void prepareTexture() { frame_++; } - - // Methods added for test. - int frame_count() { return frame_; } - - private: - int frame_; -}; - class FakeRendererClient : public RendererClient { public: - FakeRendererClient() - : host_impl_(&proxy_), - set_full_root_layer_damage_count_(0), - root_layer_(LayerImpl::Create(host_impl_.active_tree(), 1)), - viewport_(gfx::Rect(0, 0, 1, 1)), - clip_(gfx::Rect(0, 0, 1, 1)) { - root_layer_->CreateRenderSurface(); - RenderPass::Id render_pass_id = - root_layer_->render_surface()->RenderPassId(); - scoped_ptr<RenderPass> root_render_pass = RenderPass::Create(); - root_render_pass->SetNew( - render_pass_id, gfx::Rect(), gfx::Rect(), gfx::Transform()); - render_passes_in_draw_order_.push_back(root_render_pass.Pass()); - } + FakeRendererClient() : set_full_root_layer_damage_count_(0) {} // RendererClient methods. - virtual gfx::Rect DeviceViewport() const OVERRIDE { return viewport_; } - virtual gfx::Rect DeviceClip() const OVERRIDE { return clip_; } virtual void SetFullRootLayerDamage() OVERRIDE { set_full_root_layer_damage_count_++; } - virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const OVERRIDE { - return CompositorFrameMetadata(); - } // Methods added for test. int set_full_root_layer_damage_count() const { return set_full_root_layer_damage_count_; } - void set_viewport(gfx::Rect viewport) { viewport_ = viewport; } - void set_clip(gfx::Rect clip) { clip_ = clip; } - - RenderPass* root_render_pass() { return render_passes_in_draw_order_.back(); } - RenderPassList* render_passes_in_draw_order() { - return &render_passes_in_draw_order_; - } private: - FakeImplProxy proxy_; - FakeLayerTreeHostImpl host_impl_; int set_full_root_layer_damage_count_; - scoped_ptr<LayerImpl> root_layer_; - RenderPassList render_passes_in_draw_order_; - gfx::Rect viewport_; - gfx::Rect clip_; }; class FakeRendererGL : public GLRenderer { @@ -202,7 +169,6 @@ class FakeRendererGL : public GLRenderer { // GLRenderer methods. // Changing visibility to public. - using GLRenderer::Initialize; using GLRenderer::IsBackbufferDiscarded; using GLRenderer::DoDrawQuad; using GLRenderer::BeginDrawingFrame; @@ -210,30 +176,24 @@ class FakeRendererGL : public GLRenderer { using GLRenderer::stencil_enabled; }; -class GLRendererTest : public testing::Test { +class GLRendererWithDefaultHarnessTest : public GLRendererTest { protected: - GLRendererTest() { - scoped_ptr<FrameCountingContext> context3d(new FrameCountingContext); - context3d_ = context3d.get(); - + GLRendererWithDefaultHarnessTest() { output_surface_ = FakeOutputSurface::Create3d( - context3d.PassAs<TestWebGraphicsContext3D>()).Pass(); + TestWebGraphicsContext3D::Create()).Pass(); CHECK(output_surface_->BindToClient(&output_surface_client_)); - resource_provider_ = - ResourceProvider::Create(output_surface_.get(), 0, false).Pass(); + resource_provider_ = ResourceProvider::Create( + output_surface_.get(), NULL, 0, false, 1).Pass(); renderer_ = make_scoped_ptr(new FakeRendererGL(&renderer_client_, &settings_, output_surface_.get(), resource_provider_.get())); } - virtual void SetUp() { renderer_->Initialize(); } - - void SwapBuffers() { renderer_->SwapBuffers(); } + void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); } LayerTreeSettings settings_; - FrameCountingContext* context3d_; FakeOutputSurfaceClient output_surface_client_; scoped_ptr<FakeOutputSurface> output_surface_; FakeRendererClient renderer_client_; @@ -246,132 +206,78 @@ class GLRendererTest : public testing::Test { // declared above it. } // namespace - -// Gives unique shader ids and unique program ids for tests that need them. -class ShaderCreatorMockGraphicsContext : public TestWebGraphicsContext3D { - public: - ShaderCreatorMockGraphicsContext() - : next_program_id_number_(10000), - next_shader_id_number_(1) {} - - bool hasShader(WebGLId shader) { - return shader_set_.find(shader) != shader_set_.end(); - } - - bool hasProgram(WebGLId program) { - return program_set_.find(program) != program_set_.end(); - } - - virtual WebGLId createProgram() { - unsigned program = next_program_id_number_; - program_set_.insert(program); - next_program_id_number_++; - return program; - } - - virtual void deleteProgram(WebGLId program) { - ASSERT_TRUE(hasProgram(program)); - program_set_.erase(program); - } - - virtual void useProgram(WebGLId program) { - if (!program) - return; - ASSERT_TRUE(hasProgram(program)); - } - - virtual WebKit::WebGLId createShader(WebKit::WGC3Denum) { - unsigned shader = next_shader_id_number_; - shader_set_.insert(shader); - next_shader_id_number_++; - return shader; - } - - virtual void deleteShader(WebKit::WebGLId shader) { - ASSERT_TRUE(hasShader(shader)); - shader_set_.erase(shader); - } - - virtual void attachShader(WebGLId program, WebGLId shader) { - ASSERT_TRUE(hasProgram(program)); - ASSERT_TRUE(hasShader(shader)); - } - - protected: - unsigned next_program_id_number_; - unsigned next_shader_id_number_; - std::set<unsigned> program_set_; - std::set<unsigned> shader_set_; -}; - -class GLRendererShaderTest : public testing::Test { +class GLRendererShaderTest : public GLRendererTest { protected: GLRendererShaderTest() { - output_surface_ = FakeOutputSurface::Create3d( - scoped_ptr<TestWebGraphicsContext3D>( - new ShaderCreatorMockGraphicsContext())).Pass(); + output_surface_ = FakeOutputSurface::Create3d().Pass(); CHECK(output_surface_->BindToClient(&output_surface_client_)); resource_provider_ = ResourceProvider::Create( - output_surface_.get(), 0, false).Pass(); + output_surface_.get(), NULL, 0, false, 1).Pass(); renderer_.reset(new FakeRendererGL(&renderer_client_, &settings_, output_surface_.get(), resource_provider_.get())); - renderer_->Initialize(); } - void TestRenderPassProgram() { - EXPECT_PROGRAM_VALID(renderer_->render_pass_program_); - EXPECT_EQ(renderer_->render_pass_program_->program(), + void TestRenderPassProgram(TexCoordPrecision precision) { + EXPECT_PROGRAM_VALID(&renderer_->render_pass_program_[precision]); + EXPECT_EQ(renderer_->render_pass_program_[precision].program(), renderer_->program_shadow_); } - void TestRenderPassColorMatrixProgram() { - EXPECT_PROGRAM_VALID(renderer_->render_pass_color_matrix_program_); - EXPECT_EQ(renderer_->render_pass_color_matrix_program_->program(), + void TestRenderPassColorMatrixProgram(TexCoordPrecision precision) { + EXPECT_PROGRAM_VALID( + &renderer_->render_pass_color_matrix_program_[precision]); + EXPECT_EQ(renderer_->render_pass_color_matrix_program_[precision].program(), renderer_->program_shadow_); } - void TestRenderPassMaskProgram() { - EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_program_); - EXPECT_EQ(renderer_->render_pass_mask_program_->program(), + void TestRenderPassMaskProgram(TexCoordPrecision precision) { + EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_program_[precision]); + EXPECT_EQ(renderer_->render_pass_mask_program_[precision].program(), renderer_->program_shadow_); } - void TestRenderPassMaskColorMatrixProgram() { - EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_color_matrix_program_); - EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_->program(), - renderer_->program_shadow_); + void TestRenderPassMaskColorMatrixProgram(TexCoordPrecision precision) { + EXPECT_PROGRAM_VALID( + &renderer_->render_pass_mask_color_matrix_program_[precision]); + EXPECT_EQ( + renderer_->render_pass_mask_color_matrix_program_[precision].program(), + renderer_->program_shadow_); } - void TestRenderPassProgramAA() { - EXPECT_PROGRAM_VALID(renderer_->render_pass_program_aa_); - EXPECT_EQ(renderer_->render_pass_program_aa_->program(), + void TestRenderPassProgramAA(TexCoordPrecision precision) { + EXPECT_PROGRAM_VALID(&renderer_->render_pass_program_aa_[precision]); + EXPECT_EQ(renderer_->render_pass_program_aa_[precision].program(), renderer_->program_shadow_); } - void TestRenderPassColorMatrixProgramAA() { - EXPECT_PROGRAM_VALID(renderer_->render_pass_color_matrix_program_aa_); - EXPECT_EQ(renderer_->render_pass_color_matrix_program_aa_->program(), - renderer_->program_shadow_); + void TestRenderPassColorMatrixProgramAA(TexCoordPrecision precision) { + EXPECT_PROGRAM_VALID( + &renderer_->render_pass_color_matrix_program_aa_[precision]); + EXPECT_EQ( + renderer_->render_pass_color_matrix_program_aa_[precision].program(), + renderer_->program_shadow_); } - void TestRenderPassMaskProgramAA() { - EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_program_aa_); - EXPECT_EQ(renderer_->render_pass_mask_program_aa_->program(), + void TestRenderPassMaskProgramAA(TexCoordPrecision precision) { + EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_program_aa_[precision]); + EXPECT_EQ(renderer_->render_pass_mask_program_aa_[precision].program(), renderer_->program_shadow_); } - void TestRenderPassMaskColorMatrixProgramAA() { - EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_color_matrix_program_aa_); - EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_aa_->program(), + void TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision) { + EXPECT_PROGRAM_VALID( + &renderer_->render_pass_mask_color_matrix_program_aa_[precision]); + EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_aa_[precision] + .program(), renderer_->program_shadow_); } void TestSolidColorProgramAA() { - EXPECT_PROGRAM_VALID(renderer_->solid_color_program_aa_); - EXPECT_EQ(renderer_->solid_color_program_aa_->program(), + EXPECT_PROGRAM_VALID(&renderer_->solid_color_program_aa_); + EXPECT_EQ(renderer_->solid_color_program_aa_.program(), renderer_->program_shadow_); } @@ -385,27 +291,14 @@ class GLRendererShaderTest : public testing::Test { namespace { -// Test GLRenderer discardBackbuffer functionality: -// Suggest recreating framebuffer when one already exists. -// Expected: it does nothing. -TEST_F(GLRendererTest, SuggestBackbufferYesWhenItAlreadyExistsShouldDoNothing) { - renderer_->SetDiscardBackBufferWhenNotVisible(false); - EXPECT_EQ(0, renderer_client_.set_full_root_layer_damage_count()); - EXPECT_FALSE(renderer_->IsBackbufferDiscarded()); - - SwapBuffers(); - EXPECT_EQ(1, context3d_->frame_count()); -} - // Test GLRenderer DiscardBackbuffer functionality: // Suggest discarding framebuffer when one exists and the renderer is not // visible. // Expected: it is discarded and damage tracker is reset. TEST_F( - GLRendererTest, + GLRendererWithDefaultHarnessTest, SuggestBackbufferNoShouldDiscardBackbufferAndDamageRootLayerIfNotVisible) { renderer_->SetVisible(false); - renderer_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count()); EXPECT_TRUE(renderer_->IsBackbufferDiscarded()); } @@ -413,9 +306,9 @@ TEST_F( // Test GLRenderer DiscardBackbuffer functionality: // Suggest discarding framebuffer when one exists and the renderer is visible. // Expected: the allocation is ignored. -TEST_F(GLRendererTest, SuggestBackbufferNoDoNothingWhenVisible) { +TEST_F(GLRendererWithDefaultHarnessTest, + SuggestBackbufferNoDoNothingWhenVisible) { renderer_->SetVisible(true); - renderer_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_EQ(0, renderer_client_.set_full_root_layer_damage_count()); EXPECT_FALSE(renderer_->IsBackbufferDiscarded()); } @@ -423,13 +316,12 @@ TEST_F(GLRendererTest, SuggestBackbufferNoDoNothingWhenVisible) { // Test GLRenderer DiscardBackbuffer functionality: // Suggest discarding framebuffer when one does not exist. // Expected: it does nothing. -TEST_F(GLRendererTest, SuggestBackbufferNoWhenItDoesntExistShouldDoNothing) { +TEST_F(GLRendererWithDefaultHarnessTest, + SuggestBackbufferNoWhenItDoesntExistShouldDoNothing) { renderer_->SetVisible(false); - renderer_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count()); EXPECT_TRUE(renderer_->IsBackbufferDiscarded()); - renderer_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count()); EXPECT_TRUE(renderer_->IsBackbufferDiscarded()); } @@ -437,30 +329,52 @@ TEST_F(GLRendererTest, SuggestBackbufferNoWhenItDoesntExistShouldDoNothing) { // Test GLRenderer DiscardBackbuffer functionality: // Begin drawing a frame while a framebuffer is discarded. // Expected: will recreate framebuffer. -TEST_F(GLRendererTest, DiscardedBackbufferIsRecreatedForScopeDuration) { +TEST_F(GLRendererWithDefaultHarnessTest, + DiscardedBackbufferIsRecreatedForScopeDuration) { + gfx::Rect viewport_rect(1, 1); renderer_->SetVisible(false); - renderer_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_TRUE(renderer_->IsBackbufferDiscarded()); EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count()); + AddRenderPass(&render_passes_in_draw_order_, + RenderPass::Id(1, 0), + viewport_rect, + gfx::Transform()); + renderer_->SetVisible(true); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); EXPECT_FALSE(renderer_->IsBackbufferDiscarded()); SwapBuffers(); - EXPECT_EQ(1, context3d_->frame_count()); + EXPECT_EQ(1u, output_surface_->num_sent_frames()); } -TEST_F(GLRendererTest, FramebufferDiscardedAfterReadbackWhenNotVisible) { +TEST_F(GLRendererWithDefaultHarnessTest, + FramebufferDiscardedAfterReadbackWhenNotVisible) { + gfx::Rect viewport_rect(1, 1); renderer_->SetVisible(false); - renderer_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_TRUE(renderer_->IsBackbufferDiscarded()); EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count()); + AddRenderPass(&render_passes_in_draw_order_, + RenderPass::Id(1, 0), + viewport_rect, + gfx::Transform()); + char pixels[4]; - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); EXPECT_FALSE(renderer_->IsBackbufferDiscarded()); renderer_->GetFramebufferPixels(pixels, gfx::Rect(0, 0, 1, 1)); @@ -468,14 +382,25 @@ TEST_F(GLRendererTest, FramebufferDiscardedAfterReadbackWhenNotVisible) { EXPECT_EQ(2, renderer_client_.set_full_root_layer_damage_count()); } -TEST_F(GLRendererTest, ExternalStencil) { +TEST_F(GLRendererWithDefaultHarnessTest, ExternalStencil) { + gfx::Rect viewport_rect(1, 1); EXPECT_FALSE(renderer_->stencil_enabled()); output_surface_->set_has_external_stencil_test(true); - renderer_client_.root_render_pass()->has_transparent_background = false; - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + RenderPass::Id(1, 0), + viewport_rect, + gfx::Transform()); + root_pass->has_transparent_background = false; + + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); EXPECT_TRUE(renderer_->stencil_enabled()); } @@ -625,16 +550,14 @@ class ForbidSynchronousCallContext : public TestWebGraphicsContext3D { } }; -// This test isn't using the same fixture as GLRendererTest, and you can't mix -// TEST() and TEST_F() with the same name, Hence LRC2. -TEST(GLRendererTest2, InitializationDoesNotMakeSynchronousCalls) { +TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) { FakeOutputSurfaceClient output_surface_client; scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( scoped_ptr<TestWebGraphicsContext3D>(new ForbidSynchronousCallContext))); CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; FakeRendererClient renderer_client; @@ -642,44 +565,35 @@ TEST(GLRendererTest2, InitializationDoesNotMakeSynchronousCalls) { &settings, output_surface.get(), resource_provider.get()); - - EXPECT_TRUE(renderer.Initialize()); } class LoseContextOnFirstGetContext : public TestWebGraphicsContext3D { public: - LoseContextOnFirstGetContext() : context_lost_(false) {} + LoseContextOnFirstGetContext() {} - virtual bool makeContextCurrent() OVERRIDE { return !context_lost_; } - - virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value) - OVERRIDE { + virtual void getProgramiv(WebGLId program, + WGC3Denum pname, + WGC3Dint* value) OVERRIDE { context_lost_ = true; *value = 0; } - virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) - OVERRIDE { + virtual void getShaderiv(WebGLId shader, + WGC3Denum pname, + WGC3Dint* value) OVERRIDE { context_lost_ = true; *value = 0; } - - virtual WGC3Denum getGraphicsResetStatusARB() OVERRIDE { - return context_lost_ ? 1 : 0; - } - - private: - bool context_lost_; }; -TEST(GLRendererTest2, InitializationWithQuicklyLostContextDoesNotAssert) { +TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) { FakeOutputSurfaceClient output_surface_client; scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( scoped_ptr<TestWebGraphicsContext3D>(new LoseContextOnFirstGetContext))); CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; FakeRendererClient renderer_client; @@ -687,15 +601,11 @@ TEST(GLRendererTest2, InitializationWithQuicklyLostContextDoesNotAssert) { &settings, output_surface.get(), resource_provider.get()); - - renderer.Initialize(); } class ClearCountingContext : public TestWebGraphicsContext3D { public: - ClearCountingContext() { - test_capabilities_.discard_framebuffer = true; - } + ClearCountingContext() { test_capabilities_.discard_framebuffer = true; } MOCK_METHOD3(discardFramebufferEXT, void(WGC3Denum target, @@ -704,7 +614,7 @@ class ClearCountingContext : public TestWebGraphicsContext3D { MOCK_METHOD1(clear, void(WGC3Dbitfield mask)); }; -TEST(GLRendererTest2, OpaqueBackground) { +TEST_F(GLRendererTest, OpaqueBackground) { scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext); ClearCountingContext* context = context_owned.get(); @@ -714,7 +624,7 @@ TEST(GLRendererTest2, OpaqueBackground) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; FakeRendererClient renderer_client; @@ -723,9 +633,12 @@ TEST(GLRendererTest2, OpaqueBackground) { output_surface.get(), resource_provider.get()); - renderer_client.root_render_pass()->has_transparent_background = false; - - EXPECT_TRUE(renderer.Initialize()); + gfx::Rect viewport_rect(1, 1); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + RenderPass::Id(1, 0), + viewport_rect, + gfx::Transform()); + root_pass->has_transparent_background = false; // On DEBUG builds, render passes with opaque background clear to blue to // easily see regions that were not drawn on the screen. @@ -737,12 +650,17 @@ TEST(GLRendererTest2, OpaqueBackground) { #else EXPECT_CALL(*context, clear(_)).Times(1); #endif - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); Mock::VerifyAndClearExpectations(context); } -TEST(GLRendererTest2, TransparentBackground) { +TEST_F(GLRendererTest, TransparentBackground) { scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext); ClearCountingContext* context = context_owned.get(); @@ -752,7 +670,7 @@ TEST(GLRendererTest2, TransparentBackground) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; FakeRendererClient renderer_client; @@ -761,20 +679,27 @@ TEST(GLRendererTest2, TransparentBackground) { output_surface.get(), resource_provider.get()); - renderer_client.root_render_pass()->has_transparent_background = true; + gfx::Rect viewport_rect(1, 1); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + RenderPass::Id(1, 0), + viewport_rect, + gfx::Transform()); + root_pass->has_transparent_background = true; - EXPECT_TRUE(renderer.Initialize()); - - EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, 1, _)) - .Times(1); + EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1); EXPECT_CALL(*context, clear(_)).Times(1); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); Mock::VerifyAndClearExpectations(context); } -TEST(GLRendererTest2, OffscreenOutputSurface) { +TEST_F(GLRendererTest, OffscreenOutputSurface) { scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext); ClearCountingContext* context = context_owned.get(); @@ -784,7 +709,7 @@ TEST(GLRendererTest2, OffscreenOutputSurface) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; FakeRendererClient renderer_client; @@ -793,14 +718,23 @@ TEST(GLRendererTest2, OffscreenOutputSurface) { output_surface.get(), resource_provider.get()); - EXPECT_TRUE(renderer.Initialize()); + gfx::Rect viewport_rect(1, 1); + AddRenderPass(&render_passes_in_draw_order_, + RenderPass::Id(1, 0), + viewport_rect, + gfx::Transform()); EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _)) .With(Args<2, 1>(ElementsAre(GL_COLOR_ATTACHMENT0))) .Times(1); EXPECT_CALL(*context, clear(_)).Times(AnyNumber()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); Mock::VerifyAndClearExpectations(context); } @@ -808,16 +742,9 @@ class VisibilityChangeIsLastCallTrackingContext : public TestWebGraphicsContext3D { public: VisibilityChangeIsLastCallTrackingContext() - : last_call_was_set_visibility_(false) { - test_capabilities_.set_visibility = true; - test_capabilities_.discard_backbuffer = true; - } + : last_call_was_set_visibility_(false) {} // WebGraphicsContext3D methods. - virtual void setVisibilityCHROMIUM(bool visible) { - DCHECK(last_call_was_set_visibility_ == false); - last_call_was_set_visibility_ = true; - } virtual void flush() { last_call_was_set_visibility_ = false; } @@ -833,14 +760,12 @@ class VisibilityChangeIsLastCallTrackingContext virtual void deleteRenderbuffer(WebGLId) { last_call_was_set_visibility_ = false; } - virtual void discardBackbufferCHROMIUM() { - last_call_was_set_visibility_ = false; - } - virtual void ensureBackbufferCHROMIUM() { - last_call_was_set_visibility_ = false; - } // Methods added for test. + void set_last_call_was_visibility(bool visible) { + DCHECK(last_call_was_set_visibility_ == false); + last_call_was_set_visibility_ = true; + } bool last_call_was_set_visibility() const { return last_call_was_set_visibility_; } @@ -849,18 +774,25 @@ class VisibilityChangeIsLastCallTrackingContext bool last_call_was_set_visibility_; }; -TEST(GLRendererTest2, VisibilityChangeIsLastCall) { +TEST_F(GLRendererTest, VisibilityChangeIsLastCall) { scoped_ptr<VisibilityChangeIsLastCallTrackingContext> context_owned( new VisibilityChangeIsLastCallTrackingContext); VisibilityChangeIsLastCallTrackingContext* context = context_owned.get(); + scoped_refptr<TestContextProvider> provider = TestContextProvider::Create( + context_owned.PassAs<TestWebGraphicsContext3D>()); + + provider->support()->SetSurfaceVisibleCallback(base::Bind( + &VisibilityChangeIsLastCallTrackingContext::set_last_call_was_visibility, + base::Unretained(context))); + FakeOutputSurfaceClient output_surface_client; scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + provider)); CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; FakeRendererClient renderer_client; @@ -869,24 +801,32 @@ TEST(GLRendererTest2, VisibilityChangeIsLastCall) { output_surface.get(), resource_provider.get()); - EXPECT_TRUE(renderer.Initialize()); + gfx::Rect viewport_rect(1, 1); + AddRenderPass(&render_passes_in_draw_order_, + RenderPass::Id(1, 0), + viewport_rect, + gfx::Transform()); - // Ensure that the call to setVisibilityCHROMIUM is the last call issue to the + // Ensure that the call to SetSurfaceVisible is the last call issue to the // GPU process, after glFlush is called, and after the RendererClient's // SetManagedMemoryPolicy is called. Plumb this tracking between both the // RenderClient and the Context by giving them both a pointer to a variable on // the stack. renderer.SetVisible(true); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); renderer.SetVisible(false); EXPECT_TRUE(context->last_call_was_set_visibility()); } class TextureStateTrackingContext : public TestWebGraphicsContext3D { public: - TextureStateTrackingContext() - : active_texture_(GL_INVALID_ENUM) { + TextureStateTrackingContext() : active_texture_(GL_INVALID_ENUM) { test_capabilities_.egl_image_external = true; } @@ -909,7 +849,7 @@ class TextureStateTrackingContext : public TestWebGraphicsContext3D { WGC3Denum active_texture_; }; -TEST(GLRendererTest2, ActiveTextureState) { +TEST_F(GLRendererTest, ActiveTextureState) { scoped_ptr<TextureStateTrackingContext> context_owned( new TextureStateTrackingContext); TextureStateTrackingContext* context = context_owned.get(); @@ -920,7 +860,7 @@ TEST(GLRendererTest2, ActiveTextureState) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; FakeRendererClient renderer_client; @@ -931,15 +871,14 @@ TEST(GLRendererTest2, ActiveTextureState) { // During initialization we are allowed to set any texture parameters. EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber()); - EXPECT_TRUE(renderer.Initialize()); - cc::RenderPass::Id id(1, 1); - scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); - pass->SetNew(id, - gfx::Rect(0, 0, 100, 100), - gfx::Rect(0, 0, 100, 100), - gfx::Transform()); - pass->AppendOneOfEveryQuadType(resource_provider.get(), RenderPass::Id(2, 1)); + RenderPass::Id id(1, 1); + TestRenderPass* root_pass = AddRenderPass( + &render_passes_in_draw_order_, id, gfx::Rect(100, 100), gfx::Transform()); + root_pass->AppendOneOfEveryQuadType(resource_provider.get(), + RenderPass::Id(2, 1)); + + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); // Set up expected texture filter state transitions that match the quads // created in AppendOneOfEveryQuadType(). @@ -971,18 +910,14 @@ TEST(GLRendererTest2, ActiveTextureState) { EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(6); } - cc::DirectRenderer::DrawingFrame drawing_frame; - renderer.BeginDrawingFrame(&drawing_frame); - EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE0), context->active_texture()); - - for (cc::QuadList::BackToFrontIterator - it = pass->quad_list.BackToFrontBegin(); - it != pass->quad_list.BackToFrontEnd(); - ++it) { - renderer.DoDrawQuad(&drawing_frame, *it); - } - renderer.FinishDrawingQuadList(); - EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE0), context->active_texture()); + gfx::Rect viewport_rect(100, 100); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); Mock::VerifyAndClearExpectations(context); } @@ -996,18 +931,18 @@ class NoClearRootRenderPassMockContext : public TestWebGraphicsContext3D { WGC3Dintptr offset)); }; -TEST(GLRendererTest2, ShouldClearRootRenderPass) { +TEST_F(GLRendererTest, ShouldClearRootRenderPass) { scoped_ptr<NoClearRootRenderPassMockContext> mock_context_owned( new NoClearRootRenderPassMockContext); NoClearRootRenderPassMockContext* mock_context = mock_context_owned.get(); FakeOutputSurfaceClient output_surface_client; scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - mock_context_owned.PassAs<TestWebGraphicsContext3D>())); + mock_context_owned.PassAs<TestWebGraphicsContext3D>())); CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; settings.should_clear_root_render_pass = false; @@ -1017,21 +952,21 @@ TEST(GLRendererTest2, ShouldClearRootRenderPass) { &settings, output_surface.get(), resource_provider.get()); - EXPECT_TRUE(renderer.Initialize()); - gfx::Rect viewport_rect(renderer_client.DeviceViewport()); - ScopedPtrVector<RenderPass>& render_passes = - *renderer_client.render_passes_in_draw_order(); - render_passes.clear(); + gfx::Rect viewport_rect(10, 10); RenderPass::Id root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass( - &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); RenderPass::Id child_pass_id(2, 0); - TestRenderPass* child_pass = AddRenderPass( - &render_passes, child_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + viewport_rect, + gfx::Transform()); AddQuad(child_pass, viewport_rect, SK_ColorBLUE); AddRenderPassQuad(root_pass, child_pass); @@ -1049,16 +984,20 @@ TEST(GLRendererTest2, ShouldClearRootRenderPass) { EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(1); // The second render pass is the root one, clearing should be prevented. - EXPECT_CALL(*mock_context, clear(clear_bits)).Times(0) - .After(first_render_pass); + EXPECT_CALL(*mock_context, clear(clear_bits)).Times(0).After( + first_render_pass); - EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(AnyNumber()) - .After(first_render_pass); + EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(AnyNumber()).After( + first_render_pass); - renderer.DecideRenderPassAllocationsForFrame( - *renderer_client.render_passes_in_draw_order()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); // In multiple render passes all but the root pass should clear the // framebuffer. @@ -1085,7 +1024,7 @@ class ScissorTestOnClearCheckingContext : public TestWebGraphicsContext3D { bool scissor_enabled_; }; -TEST(GLRendererTest2, ScissorTestWhenClearing) { +TEST_F(GLRendererTest, ScissorTestWhenClearing) { scoped_ptr<ScissorTestOnClearCheckingContext> context_owned( new ScissorTestOnClearCheckingContext); @@ -1095,7 +1034,7 @@ TEST(GLRendererTest2, ScissorTestWhenClearing) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; FakeRendererClient renderer_client; @@ -1103,38 +1042,45 @@ TEST(GLRendererTest2, ScissorTestWhenClearing) { &settings, output_surface.get(), resource_provider.get()); - EXPECT_TRUE(renderer.Initialize()); EXPECT_FALSE(renderer.Capabilities().using_partial_swap); - gfx::Rect viewport_rect(renderer_client.DeviceViewport()); - ScopedPtrVector<RenderPass>& render_passes = - *renderer_client.render_passes_in_draw_order(); - render_passes.clear(); + gfx::Rect viewport_rect(1, 1); gfx::Rect grand_child_rect(25, 25); RenderPass::Id grand_child_pass_id(3, 0); - TestRenderPass* grand_child_pass = AddRenderPass( - &render_passes, grand_child_pass_id, grand_child_rect, gfx::Transform()); + TestRenderPass* grand_child_pass = + AddRenderPass(&render_passes_in_draw_order_, + grand_child_pass_id, + grand_child_rect, + gfx::Transform()); AddClippedQuad(grand_child_pass, grand_child_rect, SK_ColorYELLOW); gfx::Rect child_rect(50, 50); RenderPass::Id child_pass_id(2, 0); - TestRenderPass* child_pass = AddRenderPass( - &render_passes, child_pass_id, child_rect, gfx::Transform()); + TestRenderPass* child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + child_rect, + gfx::Transform()); AddQuad(child_pass, child_rect, SK_ColorBLUE); RenderPass::Id root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass( - &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); AddRenderPassQuad(root_pass, child_pass); AddRenderPassQuad(child_pass, grand_child_pass); - renderer.DecideRenderPassAllocationsForFrame( - *renderer_client.render_passes_in_draw_order()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); } class DiscardCheckingContext : public TestWebGraphicsContext3D { @@ -1169,7 +1115,7 @@ class NonReshapableOutputSurface : public FakeOutputSurface { void set_fixed_size(gfx::Size size) { surface_size_ = size; } }; -TEST(GLRendererTest2, NoDiscardOnPartialUpdates) { +TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) { scoped_ptr<DiscardCheckingContext> context_owned(new DiscardCheckingContext); DiscardCheckingContext* context = context_owned.get(); @@ -1181,67 +1127,80 @@ TEST(GLRendererTest2, NoDiscardOnPartialUpdates) { output_surface->set_fixed_size(gfx::Size(100, 100)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; settings.partial_swap_enabled = true; FakeRendererClient renderer_client; - renderer_client.set_viewport(gfx::Rect(0, 0, 100, 100)); - renderer_client.set_clip(gfx::Rect(0, 0, 100, 100)); FakeRendererGL renderer(&renderer_client, &settings, output_surface.get(), resource_provider.get()); - EXPECT_TRUE(renderer.Initialize()); EXPECT_TRUE(renderer.Capabilities().using_partial_swap); - gfx::Rect viewport_rect(renderer_client.DeviceViewport()); - ScopedPtrVector<RenderPass>& render_passes = - *renderer_client.render_passes_in_draw_order(); - render_passes.clear(); + gfx::Rect viewport_rect(100, 100); + gfx::Rect clip_rect(100, 100); { // Partial frame, should not discard. RenderPass::Id root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass( - &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = gfx::RectF(2.f, 2.f, 3.f, 3.f); - renderer.DecideRenderPassAllocationsForFrame( - *renderer_client.render_passes_in_draw_order()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + clip_rect, + true, + false); EXPECT_EQ(0, context->discarded()); context->reset(); } { // Full frame, should discard. RenderPass::Id root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass( - &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = gfx::RectF(root_pass->output_rect); - renderer.DecideRenderPassAllocationsForFrame( - *renderer_client.render_passes_in_draw_order()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + clip_rect, + true, + false); EXPECT_EQ(1, context->discarded()); context->reset(); } { // Partial frame, disallow partial swap, should discard. RenderPass::Id root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass( - &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = gfx::RectF(2.f, 2.f, 3.f, 3.f); - renderer.DecideRenderPassAllocationsForFrame( - *renderer_client.render_passes_in_draw_order()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, false); + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + clip_rect, + false, + false); EXPECT_EQ(1, context->discarded()); context->reset(); } @@ -1249,68 +1208,90 @@ TEST(GLRendererTest2, NoDiscardOnPartialUpdates) { // Full frame, external scissor is set, should not discard. output_surface->set_has_external_stencil_test(true); RenderPass::Id root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass( - &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = gfx::RectF(root_pass->output_rect); root_pass->has_transparent_background = false; - renderer.DecideRenderPassAllocationsForFrame( - *renderer_client.render_passes_in_draw_order()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + clip_rect, + true, + false); EXPECT_EQ(0, context->discarded()); context->reset(); output_surface->set_has_external_stencil_test(false); } { // Full frame, clipped, should not discard. - renderer_client.set_clip(gfx::Rect(10, 10, 10, 10)); + clip_rect = gfx::Rect(10, 10, 10, 10); RenderPass::Id root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass( - &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = gfx::RectF(root_pass->output_rect); - renderer.DecideRenderPassAllocationsForFrame( - *renderer_client.render_passes_in_draw_order()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + clip_rect, + true, + false); EXPECT_EQ(0, context->discarded()); context->reset(); } { // Full frame, doesn't cover the surface, should not discard. - renderer_client.set_viewport(gfx::Rect(10, 10, 10, 10)); - viewport_rect = renderer_client.DeviceViewport(); + viewport_rect = gfx::Rect(10, 10, 10, 10); RenderPass::Id root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass( - &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = gfx::RectF(root_pass->output_rect); - renderer.DecideRenderPassAllocationsForFrame( - *renderer_client.render_passes_in_draw_order()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + clip_rect, + true, + false); EXPECT_EQ(0, context->discarded()); context->reset(); } { // Full frame, doesn't cover the surface (no offset), should not discard. - renderer_client.set_viewport(gfx::Rect(0, 0, 50, 50)); - renderer_client.set_clip(gfx::Rect(0, 0, 100, 100)); - viewport_rect = renderer_client.DeviceViewport(); + clip_rect = gfx::Rect(100, 100); + viewport_rect = gfx::Rect(50, 50); RenderPass::Id root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass( - &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = gfx::RectF(root_pass->output_rect); - renderer.DecideRenderPassAllocationsForFrame( - *renderer_client.render_passes_in_draw_order()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + clip_rect, + true, + false); EXPECT_EQ(0, context->discarded()); context->reset(); } @@ -1346,7 +1327,7 @@ class FlippedScissorAndViewportContext : public TestWebGraphicsContext3D { bool did_call_scissor_; }; -TEST(GLRendererTest2, ScissorAndViewportWithinNonreshapableSurface) { +TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) { // In Android WebView, the OutputSurface is unable to respect reshape() calls // and maintains a fixed size. This test verifies that glViewport and // glScissor's Y coordinate is flipped correctly in this environment, and that @@ -1360,40 +1341,39 @@ TEST(GLRendererTest2, ScissorAndViewportWithinNonreshapableSurface) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); LayerTreeSettings settings; FakeRendererClient renderer_client; - renderer_client.set_viewport(gfx::Rect(10, 10, 100, 100)); - renderer_client.set_clip(gfx::Rect(10, 10, 100, 100)); FakeRendererGL renderer(&renderer_client, &settings, output_surface.get(), resource_provider.get()); - EXPECT_TRUE(renderer.Initialize()); EXPECT_FALSE(renderer.Capabilities().using_partial_swap); - gfx::Rect viewport_rect(renderer_client.DeviceViewport().size()); + gfx::Rect device_viewport_rect(10, 10, 100, 100); + gfx::Rect viewport_rect(device_viewport_rect.size()); gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20); - ScopedPtrVector<RenderPass>& render_passes = - *renderer_client.render_passes_in_draw_order(); - render_passes.clear(); RenderPass::Id root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass( - &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN); - renderer.DecideRenderPassAllocationsForFrame( - *renderer_client.render_passes_in_draw_order()); - renderer.DrawFrame( - renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer.DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + device_viewport_rect, + device_viewport_rect, + true, + false); } TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) { - gfx::Rect viewport_rect(renderer_client_.DeviceViewport()); - ScopedPtrVector<RenderPass>* render_passes = - renderer_client_.render_passes_in_draw_order(); + gfx::Rect viewport_rect(1, 1); gfx::Rect child_rect(50, 50); RenderPass::Id child_pass_id(2, 0); @@ -1402,11 +1382,11 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) { RenderPass::Id root_pass_id(1, 0); TestRenderPass* root_pass; - cc::ResourceProvider::ResourceId mask = - resource_provider_->CreateResource(gfx::Size(20, 12), - GL_CLAMP_TO_EDGE, - ResourceProvider::TextureUsageAny, - resource_provider_->best_texture_format()); + ResourceProvider::ResourceId mask = resource_provider_->CreateResource( + gfx::Size(20, 12), + GL_CLAMP_TO_EDGE, + ResourceProvider::TextureUsageAny, + resource_provider_->best_texture_format()); resource_provider_->AllocateForTesting(mask); SkScalar matrix[20]; @@ -1429,158 +1409,213 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) { skia::AdoptRef(new SkColorMatrixFilter(matrix))); skia::RefPtr<SkImageFilter> filter = skia::AdoptRef( SkColorFilterImageFilter::Create(color_filter.get(), NULL)); + FilterOperations filters; + filters.Append(FilterOperation::CreateReferenceFilter(filter)); gfx::Transform transform_causing_aa; transform_causing_aa.Rotate(20.0); // RenderPassProgram - render_passes->clear(); - - child_pass = AddRenderPass( - render_passes, child_pass_id, child_rect, gfx::Transform()); - - root_pass = AddRenderPass( - render_passes, root_pass_id, viewport_rect, gfx::Transform()); - - AddRenderPassQuad(root_pass, - child_pass, - 0, - skia::RefPtr<SkImageFilter>(), - gfx::Transform()); - - renderer_->DecideRenderPassAllocationsForFrame( - *renderer_client_.render_passes_in_draw_order()); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); - TestRenderPassProgram(); + child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + child_rect, + gfx::Transform()); + + root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); + + AddRenderPassQuad( + root_pass, child_pass, 0, FilterOperations(), gfx::Transform()); + + renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); + TestRenderPassProgram(TexCoordPrecisionMedium); // RenderPassColorMatrixProgram - render_passes->clear(); - - child_pass = AddRenderPass( - render_passes, child_pass_id, child_rect, transform_causing_aa); - - root_pass = AddRenderPass( - render_passes, root_pass_id, viewport_rect, gfx::Transform()); - - AddRenderPassQuad(root_pass, child_pass, 0, filter, gfx::Transform()); - - renderer_->DecideRenderPassAllocationsForFrame( - *renderer_client_.render_passes_in_draw_order()); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); - TestRenderPassColorMatrixProgram(); + render_passes_in_draw_order_.clear(); + + child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + child_rect, + transform_causing_aa); + + root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); + + AddRenderPassQuad(root_pass, child_pass, 0, filters, gfx::Transform()); + + renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); + TestRenderPassColorMatrixProgram(TexCoordPrecisionMedium); // RenderPassMaskProgram - render_passes->clear(); - - child_pass = AddRenderPass( - render_passes, child_pass_id, child_rect, gfx::Transform()); - - root_pass = AddRenderPass( - render_passes, root_pass_id, viewport_rect, gfx::Transform()); - - AddRenderPassQuad(root_pass, - child_pass, - mask, - skia::RefPtr<SkImageFilter>(), - gfx::Transform()); - - renderer_->DecideRenderPassAllocationsForFrame( - *renderer_client_.render_passes_in_draw_order()); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); - TestRenderPassMaskProgram(); + render_passes_in_draw_order_.clear(); + + child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + child_rect, + gfx::Transform()); + + root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); + + AddRenderPassQuad( + root_pass, child_pass, mask, FilterOperations(), gfx::Transform()); + + renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); + TestRenderPassMaskProgram(TexCoordPrecisionMedium); // RenderPassMaskColorMatrixProgram - render_passes->clear(); - - child_pass = AddRenderPass( - render_passes, child_pass_id, child_rect, gfx::Transform()); - - root_pass = AddRenderPass( - render_passes, root_pass_id, viewport_rect, gfx::Transform()); - - AddRenderPassQuad(root_pass, child_pass, mask, filter, gfx::Transform()); - - renderer_->DecideRenderPassAllocationsForFrame( - *renderer_client_.render_passes_in_draw_order()); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); - TestRenderPassMaskColorMatrixProgram(); + render_passes_in_draw_order_.clear(); + + child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + child_rect, + gfx::Transform()); + + root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); + + AddRenderPassQuad(root_pass, child_pass, mask, filters, gfx::Transform()); + + renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); + TestRenderPassMaskColorMatrixProgram(TexCoordPrecisionMedium); // RenderPassProgramAA - render_passes->clear(); - - child_pass = AddRenderPass( - render_passes, child_pass_id, child_rect, transform_causing_aa); - - root_pass = AddRenderPass( - render_passes, root_pass_id, viewport_rect, gfx::Transform()); - - AddRenderPassQuad(root_pass, - child_pass, - 0, - skia::RefPtr<SkImageFilter>(), - transform_causing_aa); - - renderer_->DecideRenderPassAllocationsForFrame( - *renderer_client_.render_passes_in_draw_order()); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); - TestRenderPassProgramAA(); + render_passes_in_draw_order_.clear(); + + child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + child_rect, + transform_causing_aa); + + root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); + + AddRenderPassQuad( + root_pass, child_pass, 0, FilterOperations(), transform_causing_aa); + + renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); + TestRenderPassProgramAA(TexCoordPrecisionMedium); // RenderPassColorMatrixProgramAA - render_passes->clear(); - - child_pass = AddRenderPass( - render_passes, child_pass_id, child_rect, transform_causing_aa); - - root_pass = AddRenderPass( - render_passes, root_pass_id, viewport_rect, gfx::Transform()); - - AddRenderPassQuad(root_pass, child_pass, 0, filter, transform_causing_aa); - - renderer_->DecideRenderPassAllocationsForFrame( - *renderer_client_.render_passes_in_draw_order()); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); - TestRenderPassColorMatrixProgramAA(); + render_passes_in_draw_order_.clear(); + + child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + child_rect, + transform_causing_aa); + + root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); + + AddRenderPassQuad(root_pass, child_pass, 0, filters, transform_causing_aa); + + renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); + TestRenderPassColorMatrixProgramAA(TexCoordPrecisionMedium); // RenderPassMaskProgramAA - render_passes->clear(); - - child_pass = AddRenderPass(render_passes, child_pass_id, child_rect, - transform_causing_aa); - - root_pass = AddRenderPass(render_passes, root_pass_id, viewport_rect, - gfx::Transform()); - - AddRenderPassQuad(root_pass, child_pass, mask, skia::RefPtr<SkImageFilter>(), - transform_causing_aa); - - renderer_->DecideRenderPassAllocationsForFrame( - *renderer_client_.render_passes_in_draw_order()); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); - TestRenderPassMaskProgramAA(); + render_passes_in_draw_order_.clear(); + + child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + child_rect, + transform_causing_aa); + + root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); + + AddRenderPassQuad( + root_pass, child_pass, mask, FilterOperations(), transform_causing_aa); + + renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); + TestRenderPassMaskProgramAA(TexCoordPrecisionMedium); // RenderPassMaskColorMatrixProgramAA - render_passes->clear(); - - child_pass = AddRenderPass(render_passes, child_pass_id, child_rect, - transform_causing_aa); - - root_pass = AddRenderPass(render_passes, root_pass_id, viewport_rect, - transform_causing_aa); - - AddRenderPassQuad(root_pass, child_pass, mask, filter, transform_causing_aa); - - renderer_->DecideRenderPassAllocationsForFrame( - *renderer_client_.render_passes_in_draw_order()); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); - TestRenderPassMaskColorMatrixProgramAA(); + render_passes_in_draw_order_.clear(); + + child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + child_rect, + transform_causing_aa); + + root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + transform_causing_aa); + + AddRenderPassQuad(root_pass, child_pass, mask, filters, transform_causing_aa); + + renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); + TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecisionMedium); } // At this time, the AA code path cannot be taken if the surface's rect would @@ -1590,7 +1625,7 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) { RenderPass::Id child_pass_id(2, 0); TestRenderPass* child_pass; - gfx::Rect viewport_rect(renderer_client_.DeviceViewport()); + gfx::Rect viewport_rect(1, 1); RenderPass::Id root_pass_id(1, 0); TestRenderPass* root_pass; @@ -1602,44 +1637,38 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) { // Verify that the test transform and test rect actually do cause the clipped // flag to trigger. Otherwise we are not testing the intended scenario. bool clipped = false; - MathUtil::MapQuad(transform_preventing_aa, - gfx::QuadF(child_rect), - &clipped); + MathUtil::MapQuad(transform_preventing_aa, gfx::QuadF(child_rect), &clipped); ASSERT_TRUE(clipped); - // Set up the render pass quad to be drawn - ScopedPtrVector<RenderPass>* render_passes = - renderer_client_.render_passes_in_draw_order(); - - render_passes->clear(); + child_pass = AddRenderPass(&render_passes_in_draw_order_, + child_pass_id, + child_rect, + transform_preventing_aa); - child_pass = AddRenderPass( - render_passes, child_pass_id, child_rect, transform_preventing_aa); + root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); - root_pass = AddRenderPass( - render_passes, root_pass_id, viewport_rect, gfx::Transform()); + AddRenderPassQuad( + root_pass, child_pass, 0, FilterOperations(), transform_preventing_aa); - AddRenderPassQuad(root_pass, - child_pass, - 0, - skia::RefPtr<SkImageFilter>(), - transform_preventing_aa); - - renderer_->DecideRenderPassAllocationsForFrame( - *renderer_client_.render_passes_in_draw_order()); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); + renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); // If use_aa incorrectly ignores clipping, it will use the // RenderPassProgramAA shader instead of the RenderPassProgram. - TestRenderPassProgram(); + TestRenderPassProgram(TexCoordPrecisionMedium); } TEST_F(GLRendererShaderTest, DrawSolidColorShader) { - gfx::Rect viewport_rect(renderer_client_.DeviceViewport()); - ScopedPtrVector<RenderPass>* render_passes = - renderer_client_.render_passes_in_draw_order(); - + gfx::Rect viewport_rect(1, 1); RenderPass::Id root_pass_id(1, 0); TestRenderPass* root_pass; @@ -1647,19 +1676,23 @@ TEST_F(GLRendererShaderTest, DrawSolidColorShader) { pixel_aligned_transform_causing_aa.Translate(25.5f, 25.5f); pixel_aligned_transform_causing_aa.Scale(0.5f, 0.5f); - render_passes->clear(); - - root_pass = AddRenderPass( - render_passes, root_pass_id, viewport_rect, gfx::Transform()); + root_pass = AddRenderPass(&render_passes_in_draw_order_, + root_pass_id, + viewport_rect, + gfx::Transform()); AddTransformedQuad(root_pass, viewport_rect, SK_ColorYELLOW, pixel_aligned_transform_causing_aa); - renderer_->DecideRenderPassAllocationsForFrame( - *renderer_client_.render_passes_in_draw_order()); - renderer_->DrawFrame( - renderer_client_.render_passes_in_draw_order(), NULL, 1.f, true); + renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + 1.f, + viewport_rect, + viewport_rect, + true, + false); TestSolidColorProgramAA(); } @@ -1667,7 +1700,6 @@ TEST_F(GLRendererShaderTest, DrawSolidColorShader) { class OutputSurfaceMockContext : public TestWebGraphicsContext3D { public: OutputSurfaceMockContext() { - test_capabilities_.discard_backbuffer = true; test_capabilities_.post_sub_buffer = true; } @@ -1675,10 +1707,7 @@ class OutputSurfaceMockContext : public TestWebGraphicsContext3D { // with StrictMock). We need to make sure that GLRenderer does not issue // framebuffer-related GL calls directly. Instead these are supposed to go // through the OutputSurface abstraction. - MOCK_METHOD0(ensureBackbufferCHROMIUM, void()); - MOCK_METHOD0(discardBackbufferCHROMIUM, void()); MOCK_METHOD2(bindFramebuffer, void(WGC3Denum target, WebGLId framebuffer)); - MOCK_METHOD0(prepareTexture, void()); MOCK_METHOD3(reshapeWithScaleFactor, void(int width, int height, float scale_factor)); MOCK_METHOD4(drawElements, @@ -1691,9 +1720,9 @@ class OutputSurfaceMockContext : public TestWebGraphicsContext3D { class MockOutputSurface : public OutputSurface { public: MockOutputSurface() - : OutputSurface(TestContextProvider::Create( - scoped_ptr<TestWebGraphicsContext3D>( - new StrictMock<OutputSurfaceMockContext>))) { + : OutputSurface( + TestContextProvider::Create(scoped_ptr<TestWebGraphicsContext3D>( + new StrictMock<OutputSurfaceMockContext>))) { surface_size_ = gfx::Size(100, 100); } virtual ~MockOutputSurface() {} @@ -1705,45 +1734,50 @@ class MockOutputSurface : public OutputSurface { MOCK_METHOD1(SwapBuffers, void(CompositorFrame* frame)); }; -class MockOutputSurfaceTest : public testing::Test, public FakeRendererClient { +class MockOutputSurfaceTest : public GLRendererTest { protected: virtual void SetUp() { FakeOutputSurfaceClient output_surface_client_; CHECK(output_surface_.BindToClient(&output_surface_client_)); resource_provider_ = - ResourceProvider::Create(&output_surface_, 0, false).Pass(); + ResourceProvider::Create(&output_surface_, NULL, 0, false, 1).Pass(); - renderer_.reset(new FakeRendererGL( - this, &settings_, &output_surface_, resource_provider_.get())); - EXPECT_TRUE(renderer_->Initialize()); + renderer_.reset(new FakeRendererGL(&renderer_client_, + &settings_, + &output_surface_, + resource_provider_.get())); } - void SwapBuffers() { renderer_->SwapBuffers(); } - - void DrawFrame(float device_scale_factor) { - gfx::Rect viewport_rect(DeviceViewport()); - ScopedPtrVector<RenderPass>* render_passes = render_passes_in_draw_order(); - render_passes->clear(); + void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); } + void DrawFrame(float device_scale_factor, gfx::Rect device_viewport_rect) { RenderPass::Id render_pass_id(1, 0); - TestRenderPass* render_pass = AddRenderPass( - render_passes, render_pass_id, viewport_rect, gfx::Transform()); - AddQuad(render_pass, viewport_rect, SK_ColorGREEN); + TestRenderPass* render_pass = AddRenderPass(&render_passes_in_draw_order_, + render_pass_id, + device_viewport_rect, + gfx::Transform()); + AddQuad(render_pass, device_viewport_rect, SK_ColorGREEN); EXPECT_CALL(output_surface_, EnsureBackbuffer()).WillRepeatedly(Return()); EXPECT_CALL(output_surface_, - Reshape(DeviceViewport().size(), device_scale_factor)).Times(1); + Reshape(device_viewport_rect.size(), device_scale_factor)) + .Times(1); EXPECT_CALL(output_surface_, BindFramebuffer()).Times(1); EXPECT_CALL(*Context(), drawElements(_, _, _, _)).Times(1); renderer_->DecideRenderPassAllocationsForFrame( - *render_passes_in_draw_order()); - renderer_->DrawFrame( - render_passes_in_draw_order(), NULL, device_scale_factor, true); + render_passes_in_draw_order_); + renderer_->DrawFrame(&render_passes_in_draw_order_, + NULL, + device_scale_factor, + device_viewport_rect, + device_viewport_rect, + true, + false); } OutputSurfaceMockContext* Context() { @@ -1755,38 +1789,40 @@ class MockOutputSurfaceTest : public testing::Test, public FakeRendererClient { FakeOutputSurfaceClient output_surface_client_; StrictMock<MockOutputSurface> output_surface_; scoped_ptr<ResourceProvider> resource_provider_; + FakeRendererClient renderer_client_; scoped_ptr<FakeRendererGL> renderer_; }; TEST_F(MockOutputSurfaceTest, DrawFrameAndSwap) { - DrawFrame(1.f); + gfx::Rect device_viewport_rect(1, 1); + DrawFrame(1.f, device_viewport_rect); EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); - renderer_->SwapBuffers(); + renderer_->SwapBuffers(CompositorFrameMetadata()); } TEST_F(MockOutputSurfaceTest, DrawFrameAndResizeAndSwap) { - DrawFrame(1.f); + gfx::Rect device_viewport_rect(1, 1); + + DrawFrame(1.f, device_viewport_rect); EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); - renderer_->SwapBuffers(); + renderer_->SwapBuffers(CompositorFrameMetadata()); - set_viewport(gfx::Rect(0, 0, 2, 2)); - renderer_->ViewportChanged(); + device_viewport_rect = gfx::Rect(2, 2); - DrawFrame(2.f); + DrawFrame(2.f, device_viewport_rect); EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); - renderer_->SwapBuffers(); + renderer_->SwapBuffers(CompositorFrameMetadata()); - DrawFrame(2.f); + DrawFrame(2.f, device_viewport_rect); EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); - renderer_->SwapBuffers(); + renderer_->SwapBuffers(CompositorFrameMetadata()); - set_viewport(gfx::Rect(0, 0, 1, 1)); - renderer_->ViewportChanged(); + device_viewport_rect = gfx::Rect(1, 1); - DrawFrame(1.f); + DrawFrame(1.f, device_viewport_rect); EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); - renderer_->SwapBuffers(); + renderer_->SwapBuffers(CompositorFrameMetadata()); } class GLRendererTestSyncPoint : public GLRendererPixelTest { @@ -1806,25 +1842,26 @@ class GLRendererTestSyncPoint : public GLRendererPixelTest { TEST_F(GLRendererTestSyncPoint, SignalSyncPointOnLostContext) { int sync_point_callback_count = 0; int other_callback_count = 0; - unsigned sync_point = - output_surface_->context_provider()->Context3d()->insertSyncPoint(); + blink::WebGraphicsContext3D* context3d = + output_surface_->context_provider()->Context3d(); + gpu::ContextSupport* context_support = + output_surface_->context_provider()->ContextSupport(); + + uint32 sync_point = context3d->insertSyncPoint(); - output_surface_->context_provider()->Context3d()->loseContextCHROMIUM( - GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); + context3d->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, + GL_INNOCENT_CONTEXT_RESET_ARB); - SyncPointHelper::SignalSyncPoint( - output_surface_->context_provider()->Context3d(), - sync_point, - base::Bind(&SyncPointCallback, &sync_point_callback_count)); + context_support->SignalSyncPoint( + sync_point, base::Bind(&SyncPointCallback, &sync_point_callback_count)); EXPECT_EQ(0, sync_point_callback_count); EXPECT_EQ(0, other_callback_count); // Make the sync point happen. - output_surface_->context_provider()->Context3d()->finish(); + context3d->finish(); // Post a task after the sync point. base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&OtherCallback, &other_callback_count)); + FROM_HERE, base::Bind(&OtherCallback, &other_callback_count)); base::MessageLoop::current()->Run(); @@ -1836,22 +1873,24 @@ TEST_F(GLRendererTestSyncPoint, SignalSyncPointOnLostContext) { TEST_F(GLRendererTestSyncPoint, SignalSyncPoint) { int sync_point_callback_count = 0; int other_callback_count = 0; - unsigned sync_point = - output_surface_->context_provider()->Context3d()->insertSyncPoint(); - SyncPointHelper::SignalSyncPoint( - output_surface_->context_provider()->Context3d(), - sync_point, - base::Bind(&SyncPointCallback, &sync_point_callback_count)); + blink::WebGraphicsContext3D* context3d = + output_surface_->context_provider()->Context3d(); + gpu::ContextSupport* context_support = + output_surface_->context_provider()->ContextSupport(); + + uint32 sync_point = context3d->insertSyncPoint(); + + context_support->SignalSyncPoint( + sync_point, base::Bind(&SyncPointCallback, &sync_point_callback_count)); EXPECT_EQ(0, sync_point_callback_count); EXPECT_EQ(0, other_callback_count); // Make the sync point happen. - output_surface_->context_provider()->Context3d()->finish(); + context3d->finish(); // Post a task after the sync point. base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&OtherCallback, &other_callback_count)); + FROM_HERE, base::Bind(&OtherCallback, &other_callback_count)); base::MessageLoop::current()->Run(); diff --git a/chromium/cc/output/managed_memory_policy.cc b/chromium/cc/output/managed_memory_policy.cc index 7e837662c29..049d2b03f9f 100644 --- a/chromium/cc/output/managed_memory_policy.cc +++ b/chromium/cc/output/managed_memory_policy.cc @@ -11,31 +11,30 @@ namespace cc { const size_t ManagedMemoryPolicy::kDefaultNumResourcesLimit = 10 * 1000 * 1000; +using gpu::MemoryAllocation; + ManagedMemoryPolicy::ManagedMemoryPolicy(size_t bytes_limit_when_visible) : bytes_limit_when_visible(bytes_limit_when_visible), - priority_cutoff_when_visible(CUTOFF_ALLOW_EVERYTHING), - bytes_limit_when_not_visible(0), - priority_cutoff_when_not_visible(CUTOFF_ALLOW_NOTHING), + priority_cutoff_when_visible(MemoryAllocation::CUTOFF_ALLOW_EVERYTHING), + num_resources_limit(kDefaultNumResourcesLimit) {} + +ManagedMemoryPolicy::ManagedMemoryPolicy( + const gpu::MemoryAllocation& allocation) + : bytes_limit_when_visible(allocation.bytes_limit_when_visible), + priority_cutoff_when_visible(allocation.priority_cutoff_when_visible), num_resources_limit(kDefaultNumResourcesLimit) {} ManagedMemoryPolicy::ManagedMemoryPolicy( size_t bytes_limit_when_visible, - PriorityCutoff priority_cutoff_when_visible, - size_t bytes_limit_when_not_visible, - PriorityCutoff priority_cutoff_when_not_visible, + MemoryAllocation::PriorityCutoff priority_cutoff_when_visible, size_t num_resources_limit) : bytes_limit_when_visible(bytes_limit_when_visible), priority_cutoff_when_visible(priority_cutoff_when_visible), - bytes_limit_when_not_visible(bytes_limit_when_not_visible), - priority_cutoff_when_not_visible(priority_cutoff_when_not_visible), num_resources_limit(num_resources_limit) {} bool ManagedMemoryPolicy::operator==(const ManagedMemoryPolicy& other) const { return bytes_limit_when_visible == other.bytes_limit_when_visible && priority_cutoff_when_visible == other.priority_cutoff_when_visible && - bytes_limit_when_not_visible == other.bytes_limit_when_not_visible && - priority_cutoff_when_not_visible == - other.priority_cutoff_when_not_visible && num_resources_limit == other.num_resources_limit; } @@ -44,15 +43,16 @@ bool ManagedMemoryPolicy::operator!=(const ManagedMemoryPolicy& other) const { } // static -int ManagedMemoryPolicy::PriorityCutoffToValue(PriorityCutoff priority_cutoff) { +int ManagedMemoryPolicy::PriorityCutoffToValue( + MemoryAllocation::PriorityCutoff priority_cutoff) { switch (priority_cutoff) { - case CUTOFF_ALLOW_NOTHING: + case MemoryAllocation::CUTOFF_ALLOW_NOTHING: return PriorityCalculator::AllowNothingCutoff(); - case CUTOFF_ALLOW_REQUIRED_ONLY: + case MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY: return PriorityCalculator::AllowVisibleOnlyCutoff(); - case CUTOFF_ALLOW_NICE_TO_HAVE: + case MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE: return PriorityCalculator::AllowVisibleAndNearbyCutoff(); - case CUTOFF_ALLOW_EVERYTHING: + case MemoryAllocation::CUTOFF_ALLOW_EVERYTHING: return PriorityCalculator::AllowEverythingCutoff(); } NOTREACHED(); @@ -62,15 +62,15 @@ int ManagedMemoryPolicy::PriorityCutoffToValue(PriorityCutoff priority_cutoff) { // static TileMemoryLimitPolicy ManagedMemoryPolicy::PriorityCutoffToTileMemoryLimitPolicy( - PriorityCutoff priority_cutoff) { + gpu::MemoryAllocation::PriorityCutoff priority_cutoff) { switch (priority_cutoff) { - case CUTOFF_ALLOW_NOTHING: + case MemoryAllocation::CUTOFF_ALLOW_NOTHING: return ALLOW_NOTHING; - case CUTOFF_ALLOW_REQUIRED_ONLY: + case MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY: return ALLOW_ABSOLUTE_MINIMUM; - case CUTOFF_ALLOW_NICE_TO_HAVE: + case MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE: return ALLOW_PREPAINT_ONLY; - case CUTOFF_ALLOW_EVERYTHING: + case MemoryAllocation::CUTOFF_ALLOW_EVERYTHING: return ALLOW_ANYTHING; } NOTREACHED(); diff --git a/chromium/cc/output/managed_memory_policy.h b/chromium/cc/output/managed_memory_policy.h index 5a607a7a1f2..ad0224b6c42 100644 --- a/chromium/cc/output/managed_memory_policy.h +++ b/chromium/cc/output/managed_memory_policy.h @@ -8,36 +8,31 @@ #include "base/basictypes.h" #include "cc/base/cc_export.h" #include "cc/resources/tile_priority.h" +#include "gpu/command_buffer/common/gpu_memory_allocation.h" namespace cc { struct CC_EXPORT ManagedMemoryPolicy { - enum PriorityCutoff { - CUTOFF_ALLOW_NOTHING, - CUTOFF_ALLOW_REQUIRED_ONLY, - CUTOFF_ALLOW_NICE_TO_HAVE, - CUTOFF_ALLOW_EVERYTHING, - }; static const size_t kDefaultNumResourcesLimit; explicit ManagedMemoryPolicy(size_t bytes_limit_when_visible); - ManagedMemoryPolicy(size_t bytes_limit_when_visible, - PriorityCutoff priority_cutoff_when_visible, - size_t bytes_limit_when_not_visible, - PriorityCutoff priority_cutoff_when_not_visible, - size_t num_resources_limit); + explicit ManagedMemoryPolicy( + const gpu::MemoryAllocation& allocation); + ManagedMemoryPolicy( + size_t bytes_limit_when_visible, + gpu::MemoryAllocation::PriorityCutoff priority_cutoff_when_visible, + size_t num_resources_limit); bool operator==(const ManagedMemoryPolicy&) const; bool operator!=(const ManagedMemoryPolicy&) const; size_t bytes_limit_when_visible; - PriorityCutoff priority_cutoff_when_visible; - size_t bytes_limit_when_not_visible; - PriorityCutoff priority_cutoff_when_not_visible; + gpu::MemoryAllocation::PriorityCutoff priority_cutoff_when_visible; size_t num_resources_limit; - static int PriorityCutoffToValue(PriorityCutoff priority_cutoff); + static int PriorityCutoffToValue( + gpu::MemoryAllocation::PriorityCutoff priority_cutoff); static TileMemoryLimitPolicy PriorityCutoffToTileMemoryLimitPolicy( - PriorityCutoff priority_cutoff); + gpu::MemoryAllocation::PriorityCutoff priority_cutoff); }; } // namespace cc diff --git a/chromium/cc/output/output_surface.cc b/chromium/cc/output/output_surface.cc index 555fea27911..5bad7ec89b7 100644 --- a/chromium/cc/output/output_surface.cc +++ b/chromium/cc/output/output_surface.cc @@ -13,6 +13,7 @@ #include "base/debug/trace_event.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" +#include "base/metrics/histogram.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "cc/output/compositor_frame.h" @@ -20,9 +21,13 @@ #include "cc/output/managed_memory_policy.h" #include "cc/output/output_surface_client.h" #include "cc/scheduler/delay_based_time_source.h" +#include "gpu/GLES2/gl2extchromium.h" +#include "gpu/command_buffer/client/context_support.h" +#include "gpu/command_buffer/client/gles2_interface.h" #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" +#include "ui/gfx/frame_time.h" #include "ui/gfx/rect.h" #include "ui/gfx/size.h" @@ -30,62 +35,67 @@ using std::set; using std::string; using std::vector; +namespace { + +const size_t kGpuLatencyHistorySize = 60; +const double kGpuLatencyEstimationPercentile = 100.0; + +} + namespace cc { OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider) : context_provider_(context_provider), - has_gl_discard_backbuffer_(false), - has_swap_buffers_complete_callback_(false), device_scale_factor_(-1), - weak_ptr_factory_(this), max_frames_pending_(0), pending_swap_buffers_(0), - needs_begin_frame_(false), - client_ready_for_begin_frame_(true), + needs_begin_impl_frame_(false), + client_ready_for_begin_impl_frame_(true), client_(NULL), - check_for_retroactive_begin_frame_pending_(false), - external_stencil_test_enabled_(false) {} + check_for_retroactive_begin_impl_frame_pending_(false), + external_stencil_test_enabled_(false), + weak_ptr_factory_(this), + gpu_latency_history_(kGpuLatencyHistorySize) {} -OutputSurface::OutputSurface( - scoped_ptr<cc::SoftwareOutputDevice> software_device) +OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device) : software_device_(software_device.Pass()), - has_gl_discard_backbuffer_(false), - has_swap_buffers_complete_callback_(false), device_scale_factor_(-1), - weak_ptr_factory_(this), max_frames_pending_(0), pending_swap_buffers_(0), - needs_begin_frame_(false), - client_ready_for_begin_frame_(true), + needs_begin_impl_frame_(false), + client_ready_for_begin_impl_frame_(true), client_(NULL), - check_for_retroactive_begin_frame_pending_(false), - external_stencil_test_enabled_(false) {} + check_for_retroactive_begin_impl_frame_pending_(false), + external_stencil_test_enabled_(false), + weak_ptr_factory_(this), + gpu_latency_history_(kGpuLatencyHistorySize) {} -OutputSurface::OutputSurface( - scoped_refptr<ContextProvider> context_provider, - scoped_ptr<cc::SoftwareOutputDevice> software_device) +OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider, + scoped_ptr<SoftwareOutputDevice> software_device) : context_provider_(context_provider), software_device_(software_device.Pass()), - has_gl_discard_backbuffer_(false), - has_swap_buffers_complete_callback_(false), device_scale_factor_(-1), - weak_ptr_factory_(this), max_frames_pending_(0), pending_swap_buffers_(0), - needs_begin_frame_(false), - client_ready_for_begin_frame_(true), + needs_begin_impl_frame_(false), + client_ready_for_begin_impl_frame_(true), client_(NULL), - check_for_retroactive_begin_frame_pending_(false), - external_stencil_test_enabled_(false) {} + check_for_retroactive_begin_impl_frame_pending_(false), + external_stencil_test_enabled_(false), + weak_ptr_factory_(this), + gpu_latency_history_(kGpuLatencyHistorySize) {} -void OutputSurface::InitializeBeginFrameEmulation( +void OutputSurface::InitializeBeginImplFrameEmulation( base::SingleThreadTaskRunner* task_runner, bool throttle_frame_production, base::TimeDelta interval) { if (throttle_frame_production) { - frame_rate_controller_.reset( - new FrameRateController( - DelayBasedTimeSource::Create(interval, task_runner))); + scoped_refptr<DelayBasedTimeSource> time_source; + if (gfx::FrameTime::TimestampsAreHighRes()) + time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner); + else + time_source = DelayBasedTimeSource::Create(interval, task_runner); + frame_rate_controller_.reset(new FrameRateController(time_source)); } else { frame_rate_controller_.reset(new FrameRateController(task_runner)); } @@ -121,9 +131,9 @@ void OutputSurface::FrameRateControllerTick(bool throttled, const BeginFrameArgs& args) { DCHECK(frame_rate_controller_); if (throttled) - skipped_begin_frame_args_ = args; + skipped_begin_impl_frame_args_ = args; else - BeginFrame(args); + BeginImplFrame(args); } // Forwarded to OutputSurfaceClient @@ -132,71 +142,74 @@ void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect) { client_->SetNeedsRedrawRect(damage_rect); } -void OutputSurface::SetNeedsBeginFrame(bool enable) { - TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginFrame", "enable", enable); - needs_begin_frame_ = enable; - client_ready_for_begin_frame_ = true; +void OutputSurface::SetNeedsBeginImplFrame(bool enable) { + TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginImplFrame", "enable", enable); + needs_begin_impl_frame_ = enable; + client_ready_for_begin_impl_frame_ = true; if (frame_rate_controller_) { BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable); if (skipped.IsValid()) - skipped_begin_frame_args_ = skipped; + skipped_begin_impl_frame_args_ = skipped; } - if (needs_begin_frame_) - PostCheckForRetroactiveBeginFrame(); + if (needs_begin_impl_frame_) + PostCheckForRetroactiveBeginImplFrame(); } -void OutputSurface::BeginFrame(const BeginFrameArgs& args) { - TRACE_EVENT2("cc", "OutputSurface::BeginFrame", - "client_ready_for_begin_frame_", client_ready_for_begin_frame_, +void OutputSurface::BeginImplFrame(const BeginFrameArgs& args) { + TRACE_EVENT2("cc", "OutputSurface::BeginImplFrame", + "client_ready_for_begin_impl_frame_", + client_ready_for_begin_impl_frame_, "pending_swap_buffers_", pending_swap_buffers_); - if (!needs_begin_frame_ || !client_ready_for_begin_frame_ || + if (!needs_begin_impl_frame_ || !client_ready_for_begin_impl_frame_ || (pending_swap_buffers_ >= max_frames_pending_ && max_frames_pending_ > 0)) { - skipped_begin_frame_args_ = args; + skipped_begin_impl_frame_args_ = args; } else { - client_ready_for_begin_frame_ = false; - client_->BeginFrame(args); - // args might be an alias for skipped_begin_frame_args_. - // Do not reset it before calling BeginFrame! - skipped_begin_frame_args_ = BeginFrameArgs(); + client_ready_for_begin_impl_frame_ = false; + client_->BeginImplFrame(args); + // args might be an alias for skipped_begin_impl_frame_args_. + // Do not reset it before calling BeginImplFrame! + skipped_begin_impl_frame_args_ = BeginFrameArgs(); } } -base::TimeTicks OutputSurface::RetroactiveBeginFrameDeadline() { +base::TimeTicks OutputSurface::RetroactiveBeginImplFrameDeadline() { // TODO(brianderson): Remove the alternative deadline once we have better // deadline estimations. base::TimeTicks alternative_deadline = - skipped_begin_frame_args_.frame_time + + skipped_begin_impl_frame_args_.frame_time + BeginFrameArgs::DefaultRetroactiveBeginFramePeriod(); - return std::max(skipped_begin_frame_args_.deadline, alternative_deadline); + return std::max(skipped_begin_impl_frame_args_.deadline, + alternative_deadline); } -void OutputSurface::PostCheckForRetroactiveBeginFrame() { - if (!skipped_begin_frame_args_.IsValid() || - check_for_retroactive_begin_frame_pending_) +void OutputSurface::PostCheckForRetroactiveBeginImplFrame() { + if (!skipped_begin_impl_frame_args_.IsValid() || + check_for_retroactive_begin_impl_frame_pending_) return; base::MessageLoop::current()->PostTask( FROM_HERE, - base::Bind(&OutputSurface::CheckForRetroactiveBeginFrame, + base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame, weak_ptr_factory_.GetWeakPtr())); - check_for_retroactive_begin_frame_pending_ = true; + check_for_retroactive_begin_impl_frame_pending_ = true; } -void OutputSurface::CheckForRetroactiveBeginFrame() { - TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginFrame"); - check_for_retroactive_begin_frame_pending_ = false; - if (base::TimeTicks::Now() < RetroactiveBeginFrameDeadline()) - BeginFrame(skipped_begin_frame_args_); +void OutputSurface::CheckForRetroactiveBeginImplFrame() { + TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginImplFrame"); + check_for_retroactive_begin_impl_frame_pending_ = false; + if (gfx::FrameTime::Now() < RetroactiveBeginImplFrameDeadline()) + BeginImplFrame(skipped_begin_impl_frame_args_); } void OutputSurface::DidSwapBuffers() { pending_swap_buffers_++; TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers", "pending_swap_buffers_", pending_swap_buffers_); + client_->DidSwapBuffers(); if (frame_rate_controller_) frame_rate_controller_->DidSwapBuffers(); - PostCheckForRetroactiveBeginFrame(); + PostCheckForRetroactiveBeginImplFrame(); } void OutputSurface::OnSwapBuffersComplete() { @@ -206,7 +219,7 @@ void OutputSurface::OnSwapBuffersComplete() { client_->OnSwapBuffersComplete(); if (frame_rate_controller_) frame_rate_controller_->DidSwapBuffersComplete(); - PostCheckForRetroactiveBeginFrame(); + PostCheckForRetroactiveBeginImplFrame(); } void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) { @@ -215,11 +228,13 @@ void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) { void OutputSurface::DidLoseOutputSurface() { TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface"); - client_ready_for_begin_frame_ = true; + client_ready_for_begin_impl_frame_ = true; pending_swap_buffers_ = 0; - skipped_begin_frame_args_ = BeginFrameArgs(); + skipped_begin_impl_frame_args_ = BeginFrameArgs(); if (frame_rate_controller_) frame_rate_controller_->SetActive(false); + pending_gpu_latency_query_ids_.clear(); + available_gpu_latency_query_ids_.clear(); client_->DidLoseOutputSurface(); } @@ -247,7 +262,7 @@ bool OutputSurface::HasExternalStencilTest() const { bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; } -bool OutputSurface::BindToClient(cc::OutputSurfaceClient* client) { +bool OutputSurface::BindToClient(OutputSurfaceClient* client) { DCHECK(client); client_ = client; bool success = true; @@ -296,17 +311,12 @@ void OutputSurface::SetUpContext3d() { DCHECK(context_provider_); DCHECK(client_); - const ContextProvider::Capabilities& caps = - context_provider_->ContextCapabilities(); - - has_gl_discard_backbuffer_ = caps.discard_backbuffer; - has_swap_buffers_complete_callback_ = caps.swapbuffers_complete_callback; - context_provider_->SetLostContextCallback( base::Bind(&OutputSurface::DidLoseOutputSurface, base::Unretained(this))); - context_provider_->SetSwapBuffersCompleteCallback(base::Bind( - &OutputSurface::OnSwapBuffersComplete, base::Unretained(this))); + context_provider_->ContextSupport()->SetSwapBuffersCompleteCallback( + base::Bind(&OutputSurface::OnSwapBuffersComplete, + base::Unretained(this))); context_provider_->SetMemoryPolicyChangedCallback( base::Bind(&OutputSurface::SetMemoryPolicy, base::Unretained(this))); @@ -314,26 +324,34 @@ void OutputSurface::SetUpContext3d() { void OutputSurface::ResetContext3d() { if (context_provider_.get()) { + while (!pending_gpu_latency_query_ids_.empty()) { + unsigned query_id = pending_gpu_latency_query_ids_.front(); + pending_gpu_latency_query_ids_.pop_front(); + context_provider_->Context3d()->deleteQueryEXT(query_id); + } + while (!available_gpu_latency_query_ids_.empty()) { + unsigned query_id = available_gpu_latency_query_ids_.front(); + available_gpu_latency_query_ids_.pop_front(); + context_provider_->Context3d()->deleteQueryEXT(query_id); + } context_provider_->SetLostContextCallback( ContextProvider::LostContextCallback()); - context_provider_->SetSwapBuffersCompleteCallback( - ContextProvider::SwapBuffersCompleteCallback()); context_provider_->SetMemoryPolicyChangedCallback( ContextProvider::MemoryPolicyChangedCallback()); + if (gpu::ContextSupport* support = context_provider_->ContextSupport()) + support->SetSwapBuffersCompleteCallback(base::Closure()); } context_provider_ = NULL; } void OutputSurface::EnsureBackbuffer() { - if (context_provider_ && has_gl_discard_backbuffer_) - context_provider_->Context3d()->ensureBackbufferCHROMIUM(); if (software_device_) software_device_->EnsureBackbuffer(); } void OutputSurface::DiscardBackbuffer() { - if (context_provider_ && has_gl_discard_backbuffer_) - context_provider_->Context3d()->discardBackbufferCHROMIUM(); + if (context_provider_) + context_provider_->ContextGL()->DiscardBackbufferCHROMIUM(); if (software_device_) software_device_->DiscardBackbuffer(); } @@ -361,7 +379,7 @@ void OutputSurface::BindFramebuffer() { context_provider_->Context3d()->bindFramebuffer(GL_FRAMEBUFFER, 0); } -void OutputSurface::SwapBuffers(cc::CompositorFrame* frame) { +void OutputSurface::SwapBuffers(CompositorFrame* frame) { if (frame->software_frame_data) { PostSwapBuffersComplete(); DidSwapBuffers(); @@ -371,26 +389,90 @@ void OutputSurface::SwapBuffers(cc::CompositorFrame* frame) { DCHECK(context_provider_); DCHECK(frame->gl_frame_data); + UpdateAndMeasureGpuLatency(); if (frame->gl_frame_data->sub_buffer_rect == gfx::Rect(frame->gl_frame_data->size)) { - // Note that currently this has the same effect as SwapBuffers; we should - // consider exposing a different entry point on WebGraphicsContext3D. - context_provider_->Context3d()->prepareTexture(); + context_provider_->ContextSupport()->Swap(); } else { - gfx::Rect sub_buffer_rect = frame->gl_frame_data->sub_buffer_rect; - context_provider_->Context3d()->postSubBufferCHROMIUM( - sub_buffer_rect.x(), - sub_buffer_rect.y(), - sub_buffer_rect.width(), - sub_buffer_rect.height()); + context_provider_->ContextSupport()->PartialSwapBuffers( + frame->gl_frame_data->sub_buffer_rect); } - if (!has_swap_buffers_complete_callback_) - PostSwapBuffersComplete(); - DidSwapBuffers(); } +base::TimeDelta OutputSurface::GpuLatencyEstimate() { + if (context_provider_ && !capabilities_.adjust_deadline_for_parent) + return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile); + else + return base::TimeDelta(); +} + +void OutputSurface::UpdateAndMeasureGpuLatency() { + return; // http://crbug.com/306690 tracks re-enabling latency queries. + + // We only care about GPU latency for surfaces that do not have a parent + // compositor, since surfaces that do have a parent compositor can use + // mailboxes or delegated rendering to send frames to their parent without + // incurring GPU latency. + if (capabilities_.adjust_deadline_for_parent) + return; + + while (pending_gpu_latency_query_ids_.size()) { + unsigned query_id = pending_gpu_latency_query_ids_.front(); + unsigned query_complete = 1; + context_provider_->Context3d()->getQueryObjectuivEXT( + query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &query_complete); + if (!query_complete) + break; + + unsigned value = 0; + context_provider_->Context3d()->getQueryObjectuivEXT( + query_id, GL_QUERY_RESULT_EXT, &value); + pending_gpu_latency_query_ids_.pop_front(); + available_gpu_latency_query_ids_.push_back(query_id); + + base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value); + base::TimeDelta latency_estimate = GpuLatencyEstimate(); + gpu_latency_history_.InsertSample(latency); + + base::TimeDelta latency_overestimate; + base::TimeDelta latency_underestimate; + if (latency > latency_estimate) + latency_underestimate = latency - latency_estimate; + else + latency_overestimate = latency_estimate - latency; + UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency", + latency, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds(100), + 50); + UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate", + latency_underestimate, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds(100), + 50); + UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate", + latency_overestimate, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds(100), + 50); + } + + unsigned gpu_latency_query_id; + if (available_gpu_latency_query_ids_.size()) { + gpu_latency_query_id = available_gpu_latency_query_ids_.front(); + available_gpu_latency_query_ids_.pop_front(); + } else { + gpu_latency_query_id = context_provider_->Context3d()->createQueryEXT(); + } + + context_provider_->Context3d()->beginQueryEXT(GL_LATENCY_QUERY_CHROMIUM, + gpu_latency_query_id); + context_provider_->Context3d()->endQueryEXT(GL_LATENCY_QUERY_CHROMIUM); + pending_gpu_latency_query_ids_.push_back(gpu_latency_query_id); +} + void OutputSurface::PostSwapBuffersComplete() { base::MessageLoop::current()->PostTask( FROM_HERE, @@ -398,17 +480,14 @@ void OutputSurface::PostSwapBuffersComplete() { weak_ptr_factory_.GetWeakPtr())); } -void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy, - bool discard_backbuffer) { - TRACE_EVENT2("cc", "OutputSurface::SetMemoryPolicy", - "bytes_limit_when_visible", policy.bytes_limit_when_visible, - "discard_backbuffer", discard_backbuffer); +void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) { + TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy", + "bytes_limit_when_visible", policy.bytes_limit_when_visible); // Just ignore the memory manager when it says to set the limit to zero // bytes. This will happen when the memory manager thinks that the renderer // is not visible (which the renderer knows better). if (policy.bytes_limit_when_visible) client_->SetMemoryPolicy(policy); - client_->SetDiscardBackBufferWhenNotVisible(discard_backbuffer); } } // namespace cc diff --git a/chromium/cc/output/output_surface.h b/chromium/cc/output/output_surface.h index 13db5faa06b..0d7d4e7fb96 100644 --- a/chromium/cc/output/output_surface.h +++ b/chromium/cc/output/output_surface.h @@ -5,6 +5,8 @@ #ifndef CC_OUTPUT_OUTPUT_SURFACE_H_ #define CC_OUTPUT_OUTPUT_SURFACE_H_ +#include <deque> + #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" @@ -13,6 +15,7 @@ #include "cc/output/context_provider.h" #include "cc/output/software_output_device.h" #include "cc/scheduler/frame_rate_controller.h" +#include "cc/scheduler/rolling_time_delta_history.h" namespace base { class SingleThreadTaskRunner; } @@ -46,10 +49,10 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { explicit OutputSurface(scoped_refptr<ContextProvider> context_provider); - explicit OutputSurface(scoped_ptr<cc::SoftwareOutputDevice> software_device); + explicit OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device); OutputSurface(scoped_refptr<ContextProvider> context_provider, - scoped_ptr<cc::SoftwareOutputDevice> software_device); + scoped_ptr<SoftwareOutputDevice> software_device); virtual ~OutputSurface(); @@ -65,7 +68,7 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { int max_frames_pending; bool deferred_gl_initialization; bool draw_and_swap_full_viewport_every_frame; - // This doesn't handle the <webview> case, but once BeginFrame is + // This doesn't handle the <webview> case, but once BeginImplFrame is // supported natively, we shouldn't need adjust_deadline_for_parent. bool adjust_deadline_for_parent; // Whether this output surface renders to the default OpenGL zero @@ -101,7 +104,7 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { // thread. virtual bool BindToClient(OutputSurfaceClient* client); - void InitializeBeginFrameEmulation( + void InitializeBeginImplFrameEmulation( base::SingleThreadTaskRunner* task_runner, bool throttle_frame_production, base::TimeDelta interval); @@ -125,18 +128,22 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { // processing should be stopped, or lowered in priority. virtual void UpdateSmoothnessTakesPriority(bool prefer_smoothness) {} - // Requests a BeginFrame notification from the output surface. The + // Requests a BeginImplFrame notification from the output surface. The // notification will be delivered by calling - // OutputSurfaceClient::BeginFrame until the callback is disabled. - virtual void SetNeedsBeginFrame(bool enable); + // OutputSurfaceClient::BeginImplFrame until the callback is disabled. + virtual void SetNeedsBeginImplFrame(bool enable); bool HasClient() { return !!client_; } + // Returns an estimate of the current GPU latency. When only a software + // device is present, returns 0. + base::TimeDelta GpuLatencyEstimate(); + protected: // Synchronously initialize context3d and enter hardware mode. // This can only supported in threaded compositing mode. // |offscreen_context_provider| should match what is returned by - // LayerTreeClient::OffscreenContextProviderForCompositorThread. + // LayerTreeClient::OffscreenContextProvider(). bool InitializeAndSetContext3d( scoped_refptr<ContextProvider> context_provider, scoped_refptr<ContextProvider> offscreen_context_provider); @@ -144,17 +151,14 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { void PostSwapBuffersComplete(); - struct cc::OutputSurface::Capabilities capabilities_; + struct OutputSurface::Capabilities capabilities_; scoped_refptr<ContextProvider> context_provider_; - scoped_ptr<cc::SoftwareOutputDevice> software_device_; - bool has_gl_discard_backbuffer_; - bool has_swap_buffers_complete_callback_; + scoped_ptr<SoftwareOutputDevice> software_device_; gfx::Size surface_size_; float device_scale_factor_; - base::WeakPtrFactory<OutputSurface> weak_ptr_factory_; // The FrameRateController is deprecated. - // Platforms should move to native BeginFrames instead. + // Platforms should move to native BeginImplFrames instead. void OnVSyncParametersChanged(base::TimeTicks timebase, base::TimeDelta interval); virtual void FrameRateControllerTick(bool throttled, @@ -162,17 +166,17 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { scoped_ptr<FrameRateController> frame_rate_controller_; int max_frames_pending_; int pending_swap_buffers_; - bool needs_begin_frame_; - bool client_ready_for_begin_frame_; + bool needs_begin_impl_frame_; + bool client_ready_for_begin_impl_frame_; - // This stores a BeginFrame that we couldn't process immediately, but might - // process retroactively in the near future. - BeginFrameArgs skipped_begin_frame_args_; + // This stores a BeginImplFrame that we couldn't process immediately, + // but might process retroactively in the near future. + BeginFrameArgs skipped_begin_impl_frame_args_; // Forwarded to OutputSurfaceClient but threaded through OutputSurface // first so OutputSurface has a chance to update the FrameRateController void SetNeedsRedrawRect(gfx::Rect damage_rect); - void BeginFrame(const BeginFrameArgs& args); + void BeginImplFrame(const BeginFrameArgs& args); void DidSwapBuffers(); void OnSwapBuffersComplete(); void ReclaimResources(const CompositorFrameAck* ack); @@ -184,25 +188,30 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { bool valid_for_tile_management); // virtual for testing. - virtual base::TimeTicks RetroactiveBeginFrameDeadline(); - virtual void PostCheckForRetroactiveBeginFrame(); - void CheckForRetroactiveBeginFrame(); + virtual base::TimeTicks RetroactiveBeginImplFrameDeadline(); + virtual void PostCheckForRetroactiveBeginImplFrame(); + void CheckForRetroactiveBeginImplFrame(); private: OutputSurfaceClient* client_; - friend class OutputSurfaceCallbacks; void SetUpContext3d(); void ResetContext3d(); - void SetMemoryPolicy(const ManagedMemoryPolicy& policy, - bool discard_backbuffer_when_not_visible); + void SetMemoryPolicy(const ManagedMemoryPolicy& policy); + void UpdateAndMeasureGpuLatency(); - // check_for_retroactive_begin_frame_pending_ is used to avoid posting - // redundant checks for a retroactive BeginFrame. - bool check_for_retroactive_begin_frame_pending_; + // check_for_retroactive_begin_impl_frame_pending_ is used to avoid posting + // redundant checks for a retroactive BeginImplFrame. + bool check_for_retroactive_begin_impl_frame_pending_; bool external_stencil_test_enabled_; + base::WeakPtrFactory<OutputSurface> weak_ptr_factory_; + + std::deque<unsigned> available_gpu_latency_query_ids_; + std::deque<unsigned> pending_gpu_latency_query_ids_; + RollingTimeDeltaHistory gpu_latency_history_; + DISALLOW_COPY_AND_ASSIGN(OutputSurface); }; diff --git a/chromium/cc/output/output_surface_client.h b/chromium/cc/output/output_surface_client.h index c0e2e4554b5..d82f30df499 100644 --- a/chromium/cc/output/output_surface_client.h +++ b/chromium/cc/output/output_surface_client.h @@ -31,7 +31,8 @@ class CC_EXPORT OutputSurfaceClient { scoped_refptr<ContextProvider> offscreen_context_provider) = 0; virtual void ReleaseGL() = 0; virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) = 0; - virtual void BeginFrame(const BeginFrameArgs& args) = 0; + virtual void BeginImplFrame(const BeginFrameArgs& args) = 0; + virtual void DidSwapBuffers() = 0; virtual void OnSwapBuffersComplete() = 0; virtual void ReclaimResources(const CompositorFrameAck* ack) = 0; virtual void DidLoseOutputSurface() = 0; @@ -39,7 +40,6 @@ class CC_EXPORT OutputSurfaceClient { gfx::Rect viewport, gfx::Rect clip, bool valid_for_tile_management) = 0; - virtual void SetDiscardBackBufferWhenNotVisible(bool discard) = 0; virtual void SetMemoryPolicy(const ManagedMemoryPolicy& policy) = 0; // If set, |callback| will be called subsequent to each new tree activation, // regardless of the compositor visibility or damage. |callback| must remain diff --git a/chromium/cc/output/output_surface_unittest.cc b/chromium/cc/output/output_surface_unittest.cc index 91e7c39d0b1..551ec595593 100644 --- a/chromium/cc/output/output_surface_unittest.cc +++ b/chromium/cc/output/output_surface_unittest.cc @@ -5,16 +5,17 @@ #include "cc/output/output_surface.h" #include "base/test/test_simple_task_runner.h" -#include "cc/debug/test_context_provider.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/output/managed_memory_policy.h" #include "cc/output/output_surface_client.h" #include "cc/output/software_output_device.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/scheduler_test_common.h" +#include "cc/test/test_context_provider.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "gpu/GLES2/gl2extchromium.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/frame_time.h" namespace cc { namespace { @@ -23,19 +24,18 @@ class TestOutputSurface : public OutputSurface { public: explicit TestOutputSurface(scoped_refptr<ContextProvider> context_provider) : OutputSurface(context_provider), - retroactive_begin_frame_deadline_enabled_(false), + retroactive_begin_impl_frame_deadline_enabled_(false), override_retroactive_period_(false) {} - explicit TestOutputSurface( - scoped_ptr<cc::SoftwareOutputDevice> software_device) + explicit TestOutputSurface(scoped_ptr<SoftwareOutputDevice> software_device) : OutputSurface(software_device.Pass()), - retroactive_begin_frame_deadline_enabled_(false), + retroactive_begin_impl_frame_deadline_enabled_(false), override_retroactive_period_(false) {} TestOutputSurface(scoped_refptr<ContextProvider> context_provider, - scoped_ptr<cc::SoftwareOutputDevice> software_device) + scoped_ptr<SoftwareOutputDevice> software_device) : OutputSurface(context_provider, software_device.Pass()), - retroactive_begin_frame_deadline_enabled_(false), + retroactive_begin_impl_frame_deadline_enabled_(false), override_retroactive_period_(false) {} bool InitializeNewContext3d( @@ -51,8 +51,8 @@ class TestOutputSurface : public OutputSurface { OnVSyncParametersChanged(timebase, interval); } - void BeginFrameForTesting() { - OutputSurface::BeginFrame(BeginFrameArgs::CreateExpiredForTesting()); + void BeginImplFrameForTesting() { + OutputSurface::BeginImplFrame(BeginFrameArgs::CreateExpiredForTesting()); } void DidSwapBuffersForTesting() { @@ -67,33 +67,34 @@ class TestOutputSurface : public OutputSurface { OnSwapBuffersComplete(); } - void EnableRetroactiveBeginFrameDeadline(bool enable, - bool override_retroactive_period, - base::TimeDelta period_override) { - retroactive_begin_frame_deadline_enabled_ = enable; + void EnableRetroactiveBeginImplFrameDeadline( + bool enable, + bool override_retroactive_period, + base::TimeDelta period_override) { + retroactive_begin_impl_frame_deadline_enabled_ = enable; override_retroactive_period_ = override_retroactive_period; retroactive_period_override_ = period_override; } protected: - virtual void PostCheckForRetroactiveBeginFrame() OVERRIDE { + virtual void PostCheckForRetroactiveBeginImplFrame() OVERRIDE { // For testing purposes, we check immediately rather than posting a task. - CheckForRetroactiveBeginFrame(); + CheckForRetroactiveBeginImplFrame(); } - virtual base::TimeTicks RetroactiveBeginFrameDeadline() OVERRIDE { - if (retroactive_begin_frame_deadline_enabled_) { + virtual base::TimeTicks RetroactiveBeginImplFrameDeadline() OVERRIDE { + if (retroactive_begin_impl_frame_deadline_enabled_) { if (override_retroactive_period_) { - return skipped_begin_frame_args_.frame_time + + return skipped_begin_impl_frame_args_.frame_time + retroactive_period_override_; } else { - return OutputSurface::RetroactiveBeginFrameDeadline(); + return OutputSurface::RetroactiveBeginImplFrameDeadline(); } } return base::TimeTicks(); } - bool retroactive_begin_frame_deadline_enabled_; + bool retroactive_begin_impl_frame_deadline_enabled_; bool override_retroactive_period_; base::TimeDelta retroactive_period_override_; }; @@ -151,7 +152,7 @@ TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) { TestContextProvider::Create(); // Lose the context so BindToClient fails. - context_provider->UnboundTestContext3d()->set_times_make_current_succeeds(0); + context_provider->UnboundTestContext3d()->set_context_lost(true); TestOutputSurface output_surface(context_provider); EXPECT_FALSE(output_surface.HasClient()); @@ -207,8 +208,7 @@ TEST_F(OutputSurfaceTestInitializeNewContext3d, Success) { TEST_F(OutputSurfaceTestInitializeNewContext3d, Context3dMakeCurrentFails) { BindOutputSurface(); - context_provider_->UnboundTestContext3d() - ->set_times_make_current_succeeds(0); + context_provider_->UnboundTestContext3d()->set_context_lost(true); InitializeNewContextExpectFail(); } @@ -218,7 +218,7 @@ TEST_F(OutputSurfaceTestInitializeNewContext3d, ClientDeferredInitializeFails) { InitializeNewContextExpectFail(); } -TEST(OutputSurfaceTest, BeginFrameEmulation) { +TEST(OutputSurfaceTest, BeginImplFrameEmulation) { TestOutputSurface output_surface(TestContextProvider::Create()); EXPECT_FALSE(output_surface.HasClient()); @@ -227,84 +227,86 @@ TEST(OutputSurfaceTest, BeginFrameEmulation) { EXPECT_TRUE(output_surface.HasClient()); EXPECT_FALSE(client.deferred_initialize_called()); - // Initialize BeginFrame emulation + // Initialize BeginImplFrame emulation scoped_refptr<base::TestSimpleTaskRunner> task_runner = new base::TestSimpleTaskRunner; bool throttle_frame_production = true; const base::TimeDelta display_refresh_interval = BeginFrameArgs::DefaultInterval(); - output_surface.InitializeBeginFrameEmulation( + output_surface.InitializeBeginImplFrameEmulation( task_runner.get(), throttle_frame_production, display_refresh_interval); output_surface.SetMaxFramesPending(2); - output_surface.EnableRetroactiveBeginFrameDeadline( + output_surface.EnableRetroactiveBeginImplFrameDeadline( false, false, base::TimeDelta()); - // We should start off with 0 BeginFrames - EXPECT_EQ(client.begin_frame_count(), 0); + // We should start off with 0 BeginImplFrames + EXPECT_EQ(client.begin_impl_frame_count(), 0); EXPECT_EQ(output_surface.pending_swap_buffers(), 0); - // We should not have a pending task until a BeginFrame has been requested. + // We should not have a pending task until a BeginImplFrame has been + // requested. EXPECT_FALSE(task_runner->HasPendingTask()); - output_surface.SetNeedsBeginFrame(true); + output_surface.SetNeedsBeginImplFrame(true); EXPECT_TRUE(task_runner->HasPendingTask()); - // BeginFrame should be called on the first tick. + // BeginImplFrame should be called on the first tick. task_runner->RunPendingTasks(); - EXPECT_EQ(client.begin_frame_count(), 1); + EXPECT_EQ(client.begin_impl_frame_count(), 1); EXPECT_EQ(output_surface.pending_swap_buffers(), 0); - // BeginFrame should not be called when there is a pending BeginFrame. + // BeginImplFrame should not be called when there is a pending BeginImplFrame. task_runner->RunPendingTasks(); - EXPECT_EQ(client.begin_frame_count(), 1); + EXPECT_EQ(client.begin_impl_frame_count(), 1); EXPECT_EQ(output_surface.pending_swap_buffers(), 0); - // SetNeedsBeginFrame should clear the pending BeginFrame after + // SetNeedsBeginImplFrame should clear the pending BeginImplFrame after // a SwapBuffers. output_surface.DidSwapBuffersForTesting(); - output_surface.SetNeedsBeginFrame(true); - EXPECT_EQ(client.begin_frame_count(), 1); + output_surface.SetNeedsBeginImplFrame(true); + EXPECT_EQ(client.begin_impl_frame_count(), 1); EXPECT_EQ(output_surface.pending_swap_buffers(), 1); task_runner->RunPendingTasks(); - EXPECT_EQ(client.begin_frame_count(), 2); + EXPECT_EQ(client.begin_impl_frame_count(), 2); EXPECT_EQ(output_surface.pending_swap_buffers(), 1); - // BeginFrame should be throttled by pending swap buffers. + // BeginImplFrame should be throttled by pending swap buffers. output_surface.DidSwapBuffersForTesting(); - output_surface.SetNeedsBeginFrame(true); - EXPECT_EQ(client.begin_frame_count(), 2); + output_surface.SetNeedsBeginImplFrame(true); + EXPECT_EQ(client.begin_impl_frame_count(), 2); EXPECT_EQ(output_surface.pending_swap_buffers(), 2); task_runner->RunPendingTasks(); - EXPECT_EQ(client.begin_frame_count(), 2); + EXPECT_EQ(client.begin_impl_frame_count(), 2); EXPECT_EQ(output_surface.pending_swap_buffers(), 2); - // SwapAck should decrement pending swap buffers and unblock BeginFrame again. + // SwapAck should decrement pending swap buffers and unblock BeginImplFrame + // again. output_surface.OnSwapBuffersCompleteForTesting(); - EXPECT_EQ(client.begin_frame_count(), 2); + EXPECT_EQ(client.begin_impl_frame_count(), 2); EXPECT_EQ(output_surface.pending_swap_buffers(), 1); task_runner->RunPendingTasks(); - EXPECT_EQ(client.begin_frame_count(), 3); + EXPECT_EQ(client.begin_impl_frame_count(), 3); EXPECT_EQ(output_surface.pending_swap_buffers(), 1); - // Calling SetNeedsBeginFrame again indicates a swap did not occur but - // the client still wants another BeginFrame. - output_surface.SetNeedsBeginFrame(true); + // Calling SetNeedsBeginImplFrame again indicates a swap did not occur but + // the client still wants another BeginImplFrame. + output_surface.SetNeedsBeginImplFrame(true); task_runner->RunPendingTasks(); - EXPECT_EQ(client.begin_frame_count(), 4); + EXPECT_EQ(client.begin_impl_frame_count(), 4); EXPECT_EQ(output_surface.pending_swap_buffers(), 1); - // Disabling SetNeedsBeginFrame should prevent further BeginFrames. - output_surface.SetNeedsBeginFrame(false); + // Disabling SetNeedsBeginImplFrame should prevent further BeginImplFrames. + output_surface.SetNeedsBeginImplFrame(false); task_runner->RunPendingTasks(); EXPECT_FALSE(task_runner->HasPendingTask()); - EXPECT_EQ(client.begin_frame_count(), 4); + EXPECT_EQ(client.begin_impl_frame_count(), 4); EXPECT_EQ(output_surface.pending_swap_buffers(), 1); } -TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginFrames) { +TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginImplFrames) { TestOutputSurface output_surface(TestContextProvider::Create()); EXPECT_FALSE(output_surface.HasClient()); @@ -314,47 +316,48 @@ TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginFrames) { EXPECT_FALSE(client.deferred_initialize_called()); output_surface.SetMaxFramesPending(2); - output_surface.EnableRetroactiveBeginFrameDeadline( + output_surface.EnableRetroactiveBeginImplFrameDeadline( true, false, base::TimeDelta()); - // Optimistically injected BeginFrames should be throttled if - // SetNeedsBeginFrame is false... - output_surface.SetNeedsBeginFrame(false); - output_surface.BeginFrameForTesting(); - EXPECT_EQ(client.begin_frame_count(), 0); - // ...and retroactively triggered by a SetNeedsBeginFrame. - output_surface.SetNeedsBeginFrame(true); - EXPECT_EQ(client.begin_frame_count(), 1); - - // Optimistically injected BeginFrames should be throttled by pending - // BeginFrames... - output_surface.BeginFrameForTesting(); - EXPECT_EQ(client.begin_frame_count(), 1); - // ...and retroactively triggered by a SetNeedsBeginFrame. - output_surface.SetNeedsBeginFrame(true); - EXPECT_EQ(client.begin_frame_count(), 2); + // Optimistically injected BeginImplFrames should be throttled if + // SetNeedsBeginImplFrame is false... + output_surface.SetNeedsBeginImplFrame(false); + output_surface.BeginImplFrameForTesting(); + EXPECT_EQ(client.begin_impl_frame_count(), 0); + // ...and retroactively triggered by a SetNeedsBeginImplFrame. + output_surface.SetNeedsBeginImplFrame(true); + EXPECT_EQ(client.begin_impl_frame_count(), 1); + + // Optimistically injected BeginImplFrames should be throttled by pending + // BeginImplFrames... + output_surface.BeginImplFrameForTesting(); + EXPECT_EQ(client.begin_impl_frame_count(), 1); + // ...and retroactively triggered by a SetNeedsBeginImplFrame. + output_surface.SetNeedsBeginImplFrame(true); + EXPECT_EQ(client.begin_impl_frame_count(), 2); // ...or retroactively triggered by a Swap. - output_surface.BeginFrameForTesting(); - EXPECT_EQ(client.begin_frame_count(), 2); + output_surface.BeginImplFrameForTesting(); + EXPECT_EQ(client.begin_impl_frame_count(), 2); output_surface.DidSwapBuffersForTesting(); - output_surface.SetNeedsBeginFrame(true); - EXPECT_EQ(client.begin_frame_count(), 3); + output_surface.SetNeedsBeginImplFrame(true); + EXPECT_EQ(client.begin_impl_frame_count(), 3); EXPECT_EQ(output_surface.pending_swap_buffers(), 1); - // Optimistically injected BeginFrames should be by throttled by pending + // Optimistically injected BeginImplFrames should be by throttled by pending // swap buffers... output_surface.DidSwapBuffersForTesting(); - output_surface.SetNeedsBeginFrame(true); - EXPECT_EQ(client.begin_frame_count(), 3); + output_surface.SetNeedsBeginImplFrame(true); + EXPECT_EQ(client.begin_impl_frame_count(), 3); EXPECT_EQ(output_surface.pending_swap_buffers(), 2); - output_surface.BeginFrameForTesting(); - EXPECT_EQ(client.begin_frame_count(), 3); + output_surface.BeginImplFrameForTesting(); + EXPECT_EQ(client.begin_impl_frame_count(), 3); // ...and retroactively triggered by OnSwapBuffersComplete output_surface.OnSwapBuffersCompleteForTesting(); - EXPECT_EQ(client.begin_frame_count(), 4); + EXPECT_EQ(client.begin_impl_frame_count(), 4); } -TEST(OutputSurfaceTest, RetroactiveBeginFrameDoesNotDoubleTickWhenEmulating) { +TEST(OutputSurfaceTest, + RetroactiveBeginImplFrameDoesNotDoubleTickWhenEmulating) { scoped_refptr<TestContextProvider> context_provider = TestContextProvider::Create(); @@ -368,13 +371,13 @@ TEST(OutputSurfaceTest, RetroactiveBeginFrameDoesNotDoubleTickWhenEmulating) { base::TimeDelta big_interval = base::TimeDelta::FromSeconds(10); - // Initialize BeginFrame emulation + // Initialize BeginImplFrame emulation scoped_refptr<base::TestSimpleTaskRunner> task_runner = new base::TestSimpleTaskRunner; bool throttle_frame_production = true; const base::TimeDelta display_refresh_interval = big_interval; - output_surface.InitializeBeginFrameEmulation( + output_surface.InitializeBeginImplFrameEmulation( task_runner.get(), throttle_frame_production, display_refresh_interval); @@ -382,31 +385,34 @@ TEST(OutputSurfaceTest, RetroactiveBeginFrameDoesNotDoubleTickWhenEmulating) { // We need to subtract an epsilon from Now() because some platforms have // a slow clock. output_surface.OnVSyncParametersChangedForTesting( - base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1), big_interval); + gfx::FrameTime::Now() - base::TimeDelta::FromSeconds(1), big_interval); output_surface.SetMaxFramesPending(2); - output_surface.EnableRetroactiveBeginFrameDeadline(true, true, big_interval); + output_surface.EnableRetroactiveBeginImplFrameDeadline( + true, true, big_interval); - // We should start off with 0 BeginFrames - EXPECT_EQ(client.begin_frame_count(), 0); + // We should start off with 0 BeginImplFrames + EXPECT_EQ(client.begin_impl_frame_count(), 0); EXPECT_EQ(output_surface.pending_swap_buffers(), 0); - // The first SetNeedsBeginFrame(true) should start a retroactive BeginFrame. + // The first SetNeedsBeginImplFrame(true) should start a retroactive + // BeginImplFrame. EXPECT_FALSE(task_runner->HasPendingTask()); - output_surface.SetNeedsBeginFrame(true); + output_surface.SetNeedsBeginImplFrame(true); EXPECT_TRUE(task_runner->HasPendingTask()); EXPECT_GT(task_runner->NextPendingTaskDelay(), big_interval / 2); - EXPECT_EQ(client.begin_frame_count(), 1); + EXPECT_EQ(client.begin_impl_frame_count(), 1); - output_surface.SetNeedsBeginFrame(false); + output_surface.SetNeedsBeginImplFrame(false); EXPECT_TRUE(task_runner->HasPendingTask()); - EXPECT_EQ(client.begin_frame_count(), 1); + EXPECT_EQ(client.begin_impl_frame_count(), 1); - // The second SetNeedBeginFrame(true) should not retroactively start a - // BeginFrame if the timestamp would be the same as the previous BeginFrame. - output_surface.SetNeedsBeginFrame(true); + // The second SetNeedBeginImplFrame(true) should not retroactively start a + // BeginImplFrame if the timestamp would be the same as the previous + // BeginImplFrame. + output_surface.SetNeedsBeginImplFrame(true); EXPECT_TRUE(task_runner->HasPendingTask()); - EXPECT_EQ(client.begin_frame_count(), 1); + EXPECT_EQ(client.begin_impl_frame_count(), 1); } TEST(OutputSurfaceTest, MemoryAllocation) { @@ -421,43 +427,22 @@ TEST(OutputSurfaceTest, MemoryAllocation) { ManagedMemoryPolicy policy(0); policy.bytes_limit_when_visible = 1234; policy.priority_cutoff_when_visible = - ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY; - policy.bytes_limit_when_not_visible = 4567; - policy.priority_cutoff_when_not_visible = - ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING; + gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY; - bool discard_backbuffer_when_not_visible = false; - - context_provider->SetMemoryAllocation(policy, - discard_backbuffer_when_not_visible); + context_provider->SetMemoryAllocation(policy); EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible); - EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY, + EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY, client.memory_policy().priority_cutoff_when_visible); - EXPECT_EQ(4567u, client.memory_policy().bytes_limit_when_not_visible); - EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING, - client.memory_policy().priority_cutoff_when_not_visible); - EXPECT_FALSE(client.discard_backbuffer_when_not_visible()); - - discard_backbuffer_when_not_visible = true; - context_provider->SetMemoryAllocation(policy, - discard_backbuffer_when_not_visible); - EXPECT_TRUE(client.discard_backbuffer_when_not_visible()); policy.priority_cutoff_when_visible = - ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING; - policy.priority_cutoff_when_not_visible = - ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE; - context_provider->SetMemoryAllocation(policy, - discard_backbuffer_when_not_visible); - EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING, + gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING; + context_provider->SetMemoryAllocation(policy); + EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING, client.memory_policy().priority_cutoff_when_visible); - EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE, - client.memory_policy().priority_cutoff_when_not_visible); // 0 bytes limit should be ignored. policy.bytes_limit_when_visible = 0; - context_provider->SetMemoryAllocation(policy, - discard_backbuffer_when_not_visible); + context_provider->SetMemoryAllocation(policy); EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible); } diff --git a/chromium/cc/output/program_binding.cc b/chromium/cc/output/program_binding.cc index 5b7b13ee06d..9152e5acd2c 100644 --- a/chromium/cc/output/program_binding.cc +++ b/chromium/cc/output/program_binding.cc @@ -6,11 +6,10 @@ #include "base/debug/trace_event.h" #include "cc/output/geometry_binding.h" -#include "cc/output/gl_renderer.h" // For the GLC() macro. -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" +#include "gpu/command_buffer/client/gles2_interface.h" #include "third_party/khronos/GLES2/gl2.h" -using WebKit::WebGraphicsContext3D; +using gpu::gles2::GLES2Interface; namespace cc { @@ -28,123 +27,107 @@ ProgramBindingBase::~ProgramBindingBase() { DCHECK(!initialized_); } -void ProgramBindingBase::Init(WebGraphicsContext3D* context, +bool ProgramBindingBase::Init(GLES2Interface* context, const std::string& vertex_shader, const std::string& fragment_shader) { TRACE_EVENT0("cc", "ProgramBindingBase::init"); vertex_shader_id_ = LoadShader(context, GL_VERTEX_SHADER, vertex_shader); - if (!vertex_shader_id_) { - if (!IsContextLost(context)) - LOG(ERROR) << "Failed to create vertex shader"; - return; - } + if (!vertex_shader_id_) + return false; fragment_shader_id_ = LoadShader(context, GL_FRAGMENT_SHADER, fragment_shader); if (!fragment_shader_id_) { - GLC(context, context->deleteShader(vertex_shader_id_)); + context->DeleteShader(vertex_shader_id_); vertex_shader_id_ = 0; - if (!IsContextLost(context)) - LOG(ERROR) << "Failed to create fragment shader"; - return; + return false; } program_ = CreateShaderProgram(context, vertex_shader_id_, fragment_shader_id_); - DCHECK(program_ || IsContextLost(context)); + return !!program_; } -void ProgramBindingBase::Link(WebGraphicsContext3D* context) { - GLC(context, context->linkProgram(program_)); +bool ProgramBindingBase::Link(GLES2Interface* context) { + context->LinkProgram(program_); CleanupShaders(context); if (!program_) - return; + return false; #ifndef NDEBUG int linked = 0; - GLC(context, context->getProgramiv(program_, GL_LINK_STATUS, &linked)); - if (!linked) { - if (!IsContextLost(context)) - LOG(ERROR) << "Failed to link shader program"; - GLC(context, context->deleteProgram(program_)); - } + context->GetProgramiv(program_, GL_LINK_STATUS, &linked); + if (!linked) + return false; #endif + return true; } -void ProgramBindingBase::Cleanup(WebGraphicsContext3D* context) { +void ProgramBindingBase::Cleanup(GLES2Interface* context) { initialized_ = false; if (!program_) return; DCHECK(context); - GLC(context, context->deleteProgram(program_)); + context->DeleteProgram(program_); program_ = 0; CleanupShaders(context); } -unsigned ProgramBindingBase::LoadShader(WebGraphicsContext3D* context, +unsigned ProgramBindingBase::LoadShader(GLES2Interface* context, unsigned type, const std::string& shader_source) { - unsigned shader = context->createShader(type); + unsigned shader = context->CreateShader(type); if (!shader) - return 0; - GLC(context, context->shaderSource(shader, shader_source.data())); - GLC(context, context->compileShader(shader)); + return 0u; + + const char* shader_source_str[] = { shader_source.data() }; + int shader_length[] = { static_cast<int>(shader_source.length()) }; + context->ShaderSource( + shader, 1, + shader_source_str, + shader_length); + context->CompileShader(shader); #ifndef NDEBUG int compiled = 0; - GLC(context, context->getShaderiv(shader, GL_COMPILE_STATUS, &compiled)); - if (!compiled) { - GLC(context, context->deleteShader(shader)); - return 0; - } + context->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) + return 0u; #endif return shader; } -unsigned ProgramBindingBase::CreateShaderProgram(WebGraphicsContext3D* context, +unsigned ProgramBindingBase::CreateShaderProgram(GLES2Interface* context, unsigned vertex_shader, unsigned fragment_shader) { - unsigned program_object = context->createProgram(); - if (!program_object) { - if (!IsContextLost(context)) - LOG(ERROR) << "Failed to create shader program"; + unsigned program_object = context->CreateProgram(); + if (!program_object) return 0; - } - GLC(context, context->attachShader(program_object, vertex_shader)); - GLC(context, context->attachShader(program_object, fragment_shader)); + context->AttachShader(program_object, vertex_shader); + context->AttachShader(program_object, fragment_shader); // Bind the common attrib locations. - GLC(context, - context->bindAttribLocation(program_object, - GeometryBinding::PositionAttribLocation(), - "a_position")); - GLC(context, - context->bindAttribLocation(program_object, - GeometryBinding::TexCoordAttribLocation(), - "a_texCoord")); - GLC(context, - context->bindAttribLocation( - program_object, - GeometryBinding::TriangleIndexAttribLocation(), - "a_index")); + context->BindAttribLocation( + program_object, GeometryBinding::PositionAttribLocation(), "a_position"); + context->BindAttribLocation( + program_object, GeometryBinding::TexCoordAttribLocation(), "a_texCoord"); + context->BindAttribLocation(program_object, + GeometryBinding::TriangleIndexAttribLocation(), + "a_index"); return program_object; } -void ProgramBindingBase::CleanupShaders(WebGraphicsContext3D* context) { +void ProgramBindingBase::CleanupShaders(GLES2Interface* context) { if (vertex_shader_id_) { - GLC(context, context->deleteShader(vertex_shader_id_)); + context->DeleteShader(vertex_shader_id_); vertex_shader_id_ = 0; } if (fragment_shader_id_) { - GLC(context, context->deleteShader(fragment_shader_id_)); + context->DeleteShader(fragment_shader_id_); fragment_shader_id_ = 0; } } -bool ProgramBindingBase::IsContextLost(WebGraphicsContext3D* context) { - return (context->getGraphicsResetStatusARB() != GL_NO_ERROR); -} - } // namespace cc diff --git a/chromium/cc/output/program_binding.h b/chromium/cc/output/program_binding.h index ee9d284fa7f..912329ef6bf 100644 --- a/chromium/cc/output/program_binding.h +++ b/chromium/cc/output/program_binding.h @@ -8,9 +8,14 @@ #include <string> #include "base/logging.h" +#include "cc/output/context_provider.h" #include "cc/output/shader.h" -namespace WebKit { class WebGraphicsContext3D; } +namespace gpu { +namespace gles2 { +class GLES2Interface; +} +} namespace cc { @@ -19,24 +24,23 @@ class ProgramBindingBase { ProgramBindingBase(); ~ProgramBindingBase(); - void Init(WebKit::WebGraphicsContext3D* context, + bool Init(gpu::gles2::GLES2Interface* context, const std::string& vertex_shader, const std::string& fragment_shader); - void Link(WebKit::WebGraphicsContext3D* context); - void Cleanup(WebKit::WebGraphicsContext3D* context); + bool Link(gpu::gles2::GLES2Interface* context); + void Cleanup(gpu::gles2::GLES2Interface* context); unsigned program() const { return program_; } bool initialized() const { return initialized_; } protected: - unsigned LoadShader(WebKit::WebGraphicsContext3D* context, + unsigned LoadShader(gpu::gles2::GLES2Interface* context, unsigned type, const std::string& shader_source); - unsigned CreateShaderProgram(WebKit::WebGraphicsContext3D* context, + unsigned CreateShaderProgram(gpu::gles2::GLES2Interface* context, unsigned vertex_shader, unsigned fragment_shader); - void CleanupShaders(WebKit::WebGraphicsContext3D* context); - bool IsContextLost(WebKit::WebGraphicsContext3D* context); + void CleanupShaders(gpu::gles2::GLES2Interface* context); unsigned program_; unsigned vertex_shader_id_; @@ -50,35 +54,36 @@ class ProgramBindingBase { template <class VertexShader, class FragmentShader> class ProgramBinding : public ProgramBindingBase { public: - explicit ProgramBinding(WebKit::WebGraphicsContext3D* context, - TexCoordPrecision precision) { - ProgramBindingBase::Init( - context, - vertex_shader_.GetShaderString(), - fragment_shader_.GetShaderString(precision)); - } + ProgramBinding() {} - void Initialize(WebKit::WebGraphicsContext3D* context, - bool using_bind_uniform) { - DCHECK(context); + void Initialize(ContextProvider* context_provider, + TexCoordPrecision precision, + SamplerType sampler) { + DCHECK(context_provider); DCHECK(!initialized_); - if (IsContextLost(context)) + if (context_provider->IsContextLost()) return; - // Need to bind uniforms before linking - if (!using_bind_uniform) - Link(context); + if (!ProgramBindingBase::Init( + context_provider->ContextGL(), + vertex_shader_.GetShaderString(), + fragment_shader_.GetShaderString(precision, sampler))) { + DCHECK(context_provider->IsContextLost()); + return; + } int base_uniform_index = 0; - vertex_shader_.Init( - context, program_, using_bind_uniform, &base_uniform_index); - fragment_shader_.Init( - context, program_, using_bind_uniform, &base_uniform_index); + vertex_shader_.Init(context_provider->ContextGL(), + program_, &base_uniform_index); + fragment_shader_.Init(context_provider->ContextGL(), + program_, &base_uniform_index); // Link after binding uniforms - if (using_bind_uniform) - Link(context); + if (!Link(context_provider->ContextGL())) { + DCHECK(context_provider->IsContextLost()); + return; + } initialized_ = true; } diff --git a/chromium/cc/output/render_surface_filters.cc b/chromium/cc/output/render_surface_filters.cc index 04d8c5ab9f7..e10ea885e7f 100644 --- a/chromium/cc/output/render_surface_filters.cc +++ b/chromium/cc/output/render_surface_filters.cc @@ -11,8 +11,13 @@ #include "cc/output/filter_operations.h" #include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkFlattenableBuffers.h" +#include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/effects/SkBlurImageFilter.h" +#include "third_party/skia/include/effects/SkColorFilterImageFilter.h" #include "third_party/skia/include/effects/SkColorMatrixFilter.h" +#include "third_party/skia/include/effects/SkComposeImageFilter.h" +#include "third_party/skia/include/effects/SkDropShadowImageFilter.h" #include "third_party/skia/include/effects/SkMagnifierImageFilter.h" #include "third_party/skia/include/gpu/SkGpuDevice.h" #include "third_party/skia/include/gpu/SkGrPixelRef.h" @@ -142,325 +147,122 @@ void GetSepiaMatrix(float amount, SkScalar matrix[20]) { matrix[18] = 1.f; } -// The 5x4 matrix is really a "compressed" version of a 5x5 matrix that'd have -// (0 0 0 0 1) as a last row, and that would be applied to a 5-vector extended -// from the 4-vector color with a 1. -void MultColorMatrix(SkScalar a[20], SkScalar b[20], SkScalar out[20]) { - for (int j = 0; j < 4; ++j) { - for (int i = 0; i < 5; ++i) { - out[i+j*5] = i == 4 ? a[4+j*5] : 0.f; - for (int k = 0; k < 4; ++k) - out[i+j*5] += a[k+j*5] * b[i+k*5]; - } - } -} - -// To detect if we need to apply clamping after applying a matrix, we check if -// any output component might go outside of [0, 255] for any combination of -// input components in [0..255]. -// Each output component is an affine transformation of the input component, so -// the minimum and maximum values are for any combination of minimum or maximum -// values of input components (i.e. 0 or 255). -// E.g. if R' = x*R + y*G + z*B + w*A + t -// Then the maximum value will be for R=255 if x>0 or R=0 if x<0, and the -// minimum value will be for R=0 if x>0 or R=255 if x<0. -// Same goes for all components. -bool ComponentNeedsClamping(SkScalar row[5]) { - SkScalar max_value = row[4] / 255.f; - SkScalar min_value = row[4] / 255.f; - for (int i = 0; i < 4; ++i) { - if (row[i] > 0) - max_value += row[i]; - else - min_value += row[i]; - } - return (max_value > 1.f) || (min_value < 0.f); +skia::RefPtr<SkImageFilter> CreateMatrixImageFilter( + const SkScalar matrix[20], + const skia::RefPtr<SkImageFilter>& input) { + skia::RefPtr<SkColorFilter> color_filter = + skia::AdoptRef(new SkColorMatrixFilter(matrix)); + return skia::AdoptRef( + SkColorFilterImageFilter::Create(color_filter.get(), input.get())); } -bool MatrixNeedsClamping(SkScalar matrix[20]) { - return ComponentNeedsClamping(matrix) - || ComponentNeedsClamping(matrix+5) - || ComponentNeedsClamping(matrix+10) - || ComponentNeedsClamping(matrix+15); -} - -bool GetColorMatrix(const FilterOperation& op, SkScalar matrix[20]) { - switch (op.type()) { - case FilterOperation::BRIGHTNESS: { - GetBrightnessMatrix(op.amount(), matrix); - return true; - } - case FilterOperation::SATURATING_BRIGHTNESS: { - GetSaturatingBrightnessMatrix(op.amount(), matrix); - return true; - } - case FilterOperation::CONTRAST: { - GetContrastMatrix(op.amount(), matrix); - return true; - } - case FilterOperation::GRAYSCALE: { - GetGrayscaleMatrix(1.f - op.amount(), matrix); - return true; - } - case FilterOperation::SEPIA: { - GetSepiaMatrix(1.f - op.amount(), matrix); - return true; - } - case FilterOperation::SATURATE: { - GetSaturateMatrix(op.amount(), matrix); - return true; - } - case FilterOperation::HUE_ROTATE: { - GetHueRotateMatrix(op.amount(), matrix); - return true; - } - case FilterOperation::INVERT: { - GetInvertMatrix(op.amount(), matrix); - return true; - } - case FilterOperation::OPACITY: { - GetOpacityMatrix(op.amount(), matrix); - return true; - } - case FilterOperation::COLOR_MATRIX: { - memcpy(matrix, op.matrix(), sizeof(SkScalar[20])); - return true; - } - case FilterOperation::BLUR: - case FilterOperation::DROP_SHADOW: - case FilterOperation::ZOOM: - return false; - } - NOTREACHED(); - return false; -} - -class FilterBufferState { - public: - FilterBufferState(GrContext* gr_context, - gfx::SizeF size, - unsigned texture_id) - : gr_context_(gr_context), - current_texture_(0) { - // Wrap the source texture in a Ganesh platform texture. - GrBackendTextureDesc backend_texture_description; - backend_texture_description.fWidth = size.width(); - backend_texture_description.fHeight = size.height(); - backend_texture_description.fConfig = kSkia8888_GrPixelConfig; - backend_texture_description.fTextureHandle = texture_id; - skia::RefPtr<GrTexture> texture = skia::AdoptRef( - gr_context->wrapBackendTexture(backend_texture_description)); - // Place the platform texture inside an SkBitmap. - source_.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); - skia::RefPtr<SkGrPixelRef> pixel_ref = - skia::AdoptRef(new SkGrPixelRef(texture.get())); - source_.setPixelRef(pixel_ref.get()); - } - - ~FilterBufferState() {} - - bool Init(int filter_count) { - int scratch_count = std::min(2, filter_count); - GrTextureDesc desc; - desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; - desc.fSampleCnt = 0; - desc.fWidth = source_.width(); - desc.fHeight = source_.height(); - desc.fConfig = kSkia8888_GrPixelConfig; - for (int i = 0; i < scratch_count; ++i) { - GrAutoScratchTexture scratch_texture( - gr_context_, desc, GrContext::kExact_ScratchTexMatch); - scratch_textures_[i] = skia::AdoptRef(scratch_texture.detach()); - if (!scratch_textures_[i]) - return false; - } - return true; - } - - SkCanvas* Canvas() { - if (!canvas_) - CreateCanvas(); - return canvas_.get(); - } - - const SkBitmap& Source() { return source_; } - - void Swap() { - canvas_->flush(); - canvas_.clear(); - device_.clear(); - - skia::RefPtr<SkGrPixelRef> pixel_ref = skia::AdoptRef( - new SkGrPixelRef(scratch_textures_[current_texture_].get())); - source_.setPixelRef(pixel_ref.get()); - current_texture_ = 1 - current_texture_; - } - - private: - void CreateCanvas() { - DCHECK(scratch_textures_[current_texture_].get()); - device_ = skia::AdoptRef(new SkGpuDevice( - gr_context_, scratch_textures_[current_texture_].get())); - canvas_ = skia::AdoptRef(new SkCanvas(device_.get())); - canvas_->clear(0x0); - } - - GrContext* gr_context_; - SkBitmap source_; - skia::RefPtr<GrTexture> scratch_textures_[2]; - int current_texture_; - skia::RefPtr<SkGpuDevice> device_; - skia::RefPtr<SkCanvas> canvas_; -}; - } // namespace -FilterOperations RenderSurfaceFilters::Optimize( - const FilterOperations& filters) { - FilterOperations new_list; - - SkScalar accumulated_color_matrix[20]; - bool have_accumulated_color_matrix = false; - for (unsigned i = 0; i < filters.size(); ++i) { +skia::RefPtr<SkImageFilter> RenderSurfaceFilters::BuildImageFilter( + const FilterOperations& filters, + gfx::SizeF size) { + skia::RefPtr<SkImageFilter> image_filter; + SkScalar matrix[20]; + for (size_t i = 0; i < filters.size(); ++i) { const FilterOperation& op = filters.at(i); - - // If the filter is a color matrix, we may be able to combine it with - // following Filter(s) that also are color matrices. - SkScalar matrix[20]; - if (GetColorMatrix(op, matrix)) { - if (have_accumulated_color_matrix) { - SkScalar new_matrix[20]; - MultColorMatrix(matrix, accumulated_color_matrix, new_matrix); - memcpy(accumulated_color_matrix, - new_matrix, - sizeof(accumulated_color_matrix)); - } else { - memcpy(accumulated_color_matrix, - matrix, - sizeof(accumulated_color_matrix)); - have_accumulated_color_matrix = true; - } - - // We can only combine matrices if clamping of color components - // would have no effect. - if (!MatrixNeedsClamping(accumulated_color_matrix)) - continue; - } - - if (have_accumulated_color_matrix) { - new_list.Append(FilterOperation::CreateColorMatrixFilter( - accumulated_color_matrix)); - } - have_accumulated_color_matrix = false; - switch (op.type()) { - case FilterOperation::BLUR: - case FilterOperation::DROP_SHADOW: - case FilterOperation::ZOOM: - new_list.Append(op); - break; - case FilterOperation::BRIGHTNESS: - case FilterOperation::SATURATING_BRIGHTNESS: - case FilterOperation::CONTRAST: case FilterOperation::GRAYSCALE: + GetGrayscaleMatrix(1.f - op.amount(), matrix); + image_filter = CreateMatrixImageFilter(matrix, image_filter); + break; case FilterOperation::SEPIA: + GetSepiaMatrix(1.f - op.amount(), matrix); + image_filter = CreateMatrixImageFilter(matrix, image_filter); + break; case FilterOperation::SATURATE: + GetSaturateMatrix(op.amount(), matrix); + image_filter = CreateMatrixImageFilter(matrix, image_filter); + break; case FilterOperation::HUE_ROTATE: + GetHueRotateMatrix(op.amount(), matrix); + image_filter = CreateMatrixImageFilter(matrix, image_filter); + break; case FilterOperation::INVERT: + GetInvertMatrix(op.amount(), matrix); + image_filter = CreateMatrixImageFilter(matrix, image_filter); + break; case FilterOperation::OPACITY: - case FilterOperation::COLOR_MATRIX: + GetOpacityMatrix(op.amount(), matrix); + image_filter = CreateMatrixImageFilter(matrix, image_filter); break; - } - } - if (have_accumulated_color_matrix) { - new_list.Append(FilterOperation::CreateColorMatrixFilter( - accumulated_color_matrix)); - } - return new_list; -} - -SkBitmap RenderSurfaceFilters::Apply(const FilterOperations& filters, - unsigned texture_id, - gfx::SizeF size, - GrContext* gr_context) { - DCHECK(gr_context); - - FilterBufferState state(gr_context, size, texture_id); - if (!state.Init(filters.size())) - return SkBitmap(); - - for (unsigned i = 0; i < filters.size(); ++i) { - const FilterOperation& op = filters.at(i); - SkCanvas* canvas = state.Canvas(); - switch (op.type()) { - case FilterOperation::COLOR_MATRIX: { - SkPaint paint; - skia::RefPtr<SkColorMatrixFilter> filter = - skia::AdoptRef(new SkColorMatrixFilter(op.matrix())); - paint.setColorFilter(filter.get()); - canvas->drawBitmap(state.Source(), 0, 0, &paint); + case FilterOperation::BRIGHTNESS: + GetBrightnessMatrix(op.amount(), matrix); + image_filter = CreateMatrixImageFilter(matrix, image_filter); break; - } - case FilterOperation::BLUR: { - float std_deviation = op.amount(); - skia::RefPtr<SkImageFilter> filter = - skia::AdoptRef(new SkBlurImageFilter(std_deviation, std_deviation)); - SkPaint paint; - paint.setImageFilter(filter.get()); - canvas->drawSprite(state.Source(), 0, 0, &paint); + case FilterOperation::CONTRAST: + GetContrastMatrix(op.amount(), matrix); + image_filter = CreateMatrixImageFilter(matrix, image_filter); break; - } - case FilterOperation::DROP_SHADOW: { - skia::RefPtr<SkImageFilter> blur_filter = - skia::AdoptRef(new SkBlurImageFilter(op.amount(), op.amount())); - skia::RefPtr<SkColorFilter> color_filter = - skia::AdoptRef(SkColorFilter::CreateModeFilter( - op.drop_shadow_color(), SkXfermode::kSrcIn_Mode)); - SkPaint paint; - paint.setImageFilter(blur_filter.get()); - paint.setColorFilter(color_filter.get()); - paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); - canvas->saveLayer(NULL, &paint); - canvas->drawBitmap(state.Source(), - op.drop_shadow_offset().x(), - op.drop_shadow_offset().y()); - canvas->restore(); - canvas->drawBitmap(state.Source(), 0, 0); + case FilterOperation::BLUR: + image_filter = skia::AdoptRef(new SkBlurImageFilter( + op.amount(), op.amount(), image_filter.get())); + break; + case FilterOperation::DROP_SHADOW: + image_filter = skia::AdoptRef(new SkDropShadowImageFilter( + SkIntToScalar(op.drop_shadow_offset().x()), + SkIntToScalar(op.drop_shadow_offset().y()), + SkIntToScalar(op.amount()), + op.drop_shadow_color(), + image_filter.get())); + break; + case FilterOperation::COLOR_MATRIX: + image_filter = CreateMatrixImageFilter(op.matrix(), image_filter); break; - } case FilterOperation::ZOOM: { - SkPaint paint; - int width = state.Source().width(); - int height = state.Source().height(); skia::RefPtr<SkImageFilter> zoom_filter = skia::AdoptRef( new SkMagnifierImageFilter( SkRect::MakeXYWH( - (width - (width / op.amount())) / 2.f, - (height - (height / op.amount())) / 2.f, - width / op.amount(), - height / op.amount()), + (size.width() - (size.width() / op.amount())) / 2.f, + (size.height() - (size.height() / op.amount())) / 2.f, + size.width() / op.amount(), + size.height() / op.amount()), op.zoom_inset())); - paint.setImageFilter(zoom_filter.get()); - canvas->saveLayer(NULL, &paint); - canvas->drawBitmap(state.Source(), 0, 0); - canvas->restore(); + if (image_filter.get()) { + // TODO(ajuma): When there's a 1-input version of + // SkMagnifierImageFilter, use that to handle the input filter + // instead of using an SkComposeImageFilter. + image_filter = skia::AdoptRef(new SkComposeImageFilter( + zoom_filter.get(), image_filter.get())); + } else { + image_filter = zoom_filter; + } break; } - case FilterOperation::BRIGHTNESS: case FilterOperation::SATURATING_BRIGHTNESS: - case FilterOperation::CONTRAST: - case FilterOperation::GRAYSCALE: - case FilterOperation::SEPIA: - case FilterOperation::SATURATE: - case FilterOperation::HUE_ROTATE: - case FilterOperation::INVERT: - case FilterOperation::OPACITY: - NOTREACHED(); + GetSaturatingBrightnessMatrix(op.amount(), matrix); + image_filter = CreateMatrixImageFilter(matrix, image_filter); break; + case FilterOperation::REFERENCE: { + if (!op.image_filter()) + break; + + skia::RefPtr<SkColorFilter> cf; + + { + SkColorFilter* colorfilter_rawptr = NULL; + op.image_filter()->asColorFilter(&colorfilter_rawptr); + cf = skia::AdoptRef(colorfilter_rawptr); + } + + if (cf && cf->asColorMatrix(matrix) && + !op.image_filter()->getInput(0)) { + image_filter = CreateMatrixImageFilter(matrix, image_filter); + } else if (image_filter) { + image_filter = skia::AdoptRef(new SkComposeImageFilter( + op.image_filter().get(), image_filter.get())); + } else { + image_filter = op.image_filter(); + } + break; + } } - state.Swap(); } - return state.Source(); + return image_filter; } } // namespace cc diff --git a/chromium/cc/output/render_surface_filters.h b/chromium/cc/output/render_surface_filters.h index 5ab78dc77e7..09d0f732a03 100644 --- a/chromium/cc/output/render_surface_filters.h +++ b/chromium/cc/output/render_surface_filters.h @@ -8,9 +8,11 @@ #include "base/basictypes.h" #include "cc/base/cc_export.h" +#include "skia/ext/refptr.h" class GrContext; class SkBitmap; +class SkImageFilter; namespace gfx { class SizeF; @@ -28,6 +30,10 @@ class CC_EXPORT RenderSurfaceFilters { GrContext* gr_context); static FilterOperations Optimize(const FilterOperations& filters); + static skia::RefPtr<SkImageFilter> BuildImageFilter( + const FilterOperations& filters, + gfx::SizeF size); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(RenderSurfaceFilters); }; diff --git a/chromium/cc/output/render_surface_filters_unittest.cc b/chromium/cc/output/render_surface_filters_unittest.cc deleted file mode 100644 index 38c6cc343b1..00000000000 --- a/chromium/cc/output/render_surface_filters_unittest.cc +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/output/render_surface_filters.h" - -#include "cc/output/filter_operation.h" -#include "cc/output/filter_operations.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace cc { -namespace { - -// Checks whether op can be combined with a following color matrix. -bool IsCombined(const FilterOperation& op) { - FilterOperations filters; - filters.Append(op); - // brightness(0.0f) is identity. - filters.Append(FilterOperation::CreateBrightnessFilter(0.0f)); - FilterOperations optimized = RenderSurfaceFilters::Optimize(filters); - return optimized.size() == 1; -} - -TEST(RenderSurfaceFiltersTest, TestColorMatrixFiltersCombined) { - // Several filters should always combine for any amount between 0 and 1: - // grayscale, saturate, invert, contrast, opacity. - EXPECT_TRUE(IsCombined(FilterOperation::CreateGrayscaleFilter(0.0f))); - // Note that we use 0.3f to avoid "argument is truncated from 'double' to - // 'float'" warnings on Windows. 0.5f is exactly representable as a float, so - // there is no warning. - EXPECT_TRUE(IsCombined(FilterOperation::CreateGrayscaleFilter(0.3f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateGrayscaleFilter(0.5f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateGrayscaleFilter(1.0f))); - - EXPECT_TRUE(IsCombined(FilterOperation::CreateSaturateFilter(0.0f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateSaturateFilter(0.3f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateSaturateFilter(0.5))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateSaturateFilter(1.0f))); - - EXPECT_TRUE(IsCombined(FilterOperation::CreateInvertFilter(0.0f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateInvertFilter(0.3f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateInvertFilter(0.5))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateInvertFilter(1.0f))); - - EXPECT_TRUE(IsCombined(FilterOperation::CreateContrastFilter(0.0f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateContrastFilter(0.3f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateContrastFilter(0.5))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateContrastFilter(1.0f))); - - EXPECT_TRUE(IsCombined(FilterOperation::CreateOpacityFilter(0.0f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateOpacityFilter(0.3f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateOpacityFilter(0.5))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateOpacityFilter(1.0f))); - - // Brightness combines when amount <= 1 - EXPECT_TRUE(IsCombined(FilterOperation::CreateBrightnessFilter(0.5))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateBrightnessFilter(1.0f))); - EXPECT_FALSE(IsCombined(FilterOperation::CreateBrightnessFilter(1.5))); - - // SaturatingBrightness combines only when amount == 0 - EXPECT_TRUE( - IsCombined(FilterOperation::CreateSaturatingBrightnessFilter(0.0f))); - EXPECT_FALSE( - IsCombined(FilterOperation::CreateSaturatingBrightnessFilter(0.5))); - EXPECT_FALSE( - IsCombined(FilterOperation::CreateSaturatingBrightnessFilter(1.0f))); - - // Several filters should never combine: blur, drop-shadow. - EXPECT_FALSE(IsCombined(FilterOperation::CreateBlurFilter(3.0f))); - EXPECT_FALSE(IsCombined(FilterOperation::CreateDropShadowFilter( - gfx::Point(2, 2), 3.0f, 0xffffffff))); - - // sepia and hue may or may not combine depending on the value. - EXPECT_TRUE(IsCombined(FilterOperation::CreateSepiaFilter(0.0f))); - EXPECT_FALSE(IsCombined(FilterOperation::CreateSepiaFilter(1.0f))); - EXPECT_TRUE(IsCombined(FilterOperation::CreateHueRotateFilter(0.0f))); - EXPECT_FALSE(IsCombined(FilterOperation::CreateHueRotateFilter(180.0f))); - - float matrix1[20] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; - EXPECT_TRUE(IsCombined(FilterOperation::CreateColorMatrixFilter(matrix1))); - - float matrix2[20] = { 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; - EXPECT_FALSE( - IsCombined(FilterOperation::CreateColorMatrixFilter(matrix2))); - - float matrix3[20] = { 0.25f, 0.0f, 0.0f, 0.0f, 255.0f * 0.75f, - 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; - EXPECT_TRUE(IsCombined(FilterOperation::CreateColorMatrixFilter(matrix3))); - - float matrix4[20] = { -0.25f, 0.75f, 0.0f, 0.0f, 255.0f * 0.25f, - 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; - EXPECT_TRUE(IsCombined(FilterOperation::CreateColorMatrixFilter(matrix4))); -} - -TEST(RenderSurfaceFiltersTest, TestOptimize) { - FilterOperation combines(FilterOperation::CreateBrightnessFilter(1.0f)); - FilterOperation doesnt_combine( - FilterOperation::CreateBrightnessFilter(1.5f)); - - FilterOperations filters; - FilterOperations optimized = RenderSurfaceFilters::Optimize(filters); - EXPECT_EQ(0u, optimized.size()); - - filters.Append(combines); - optimized = RenderSurfaceFilters::Optimize(filters); - EXPECT_EQ(1u, optimized.size()); - - filters.Append(combines); - optimized = RenderSurfaceFilters::Optimize(filters); - EXPECT_EQ(1u, optimized.size()); - - filters.Append(doesnt_combine); - optimized = RenderSurfaceFilters::Optimize(filters); - EXPECT_EQ(1u, optimized.size()); - - filters.Append(combines); - optimized = RenderSurfaceFilters::Optimize(filters); - EXPECT_EQ(2u, optimized.size()); - - filters.Append(doesnt_combine); - optimized = RenderSurfaceFilters::Optimize(filters); - EXPECT_EQ(2u, optimized.size()); - - filters.Append(doesnt_combine); - optimized = RenderSurfaceFilters::Optimize(filters); - EXPECT_EQ(3u, optimized.size()); -} - -} // namespace -} // namespace cc diff --git a/chromium/cc/output/renderer.cc b/chromium/cc/output/renderer.cc index 7627db7ab0a..2fe0ef75b5f 100644 --- a/chromium/cc/output/renderer.cc +++ b/chromium/cc/output/renderer.cc @@ -6,7 +6,7 @@ namespace cc { -bool Renderer::HaveCachedResourcesForRenderPassId(RenderPass::Id id) const { +bool Renderer::HasAllocatedResourcesForTesting(RenderPass::Id id) const { return false; } diff --git a/chromium/cc/output/renderer.h b/chromium/cc/output/renderer.h index 32a109fac85..147b535fd72 100644 --- a/chromium/cc/output/renderer.h +++ b/chromium/cc/output/renderer.h @@ -18,16 +18,7 @@ class ScopedResource; class CC_EXPORT RendererClient { public: - // These return the draw viewport and clip in non-y-flipped window space. - // Note that while a draw is in progress, these are guaranteed to be - // contained within the output surface size. - virtual gfx::Rect DeviceViewport() const = 0; - virtual gfx::Rect DeviceClip() const = 0; virtual void SetFullRootLayerDamage() = 0; - virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const = 0; - - protected: - virtual ~RendererClient() {} }; class CC_EXPORT Renderer { @@ -36,21 +27,24 @@ class CC_EXPORT Renderer { virtual const RendererCapabilities& Capabilities() const = 0; - virtual void ViewportChanged() {} - virtual bool CanReadPixels() const = 0; virtual void DecideRenderPassAllocationsForFrame( const RenderPassList& render_passes_in_draw_order) {} - virtual bool HaveCachedResourcesForRenderPassId(RenderPass::Id id) const; + virtual bool HasAllocatedResourcesForTesting(RenderPass::Id id) const; // This passes ownership of the render passes to the renderer. It should // consume them, and empty the list. The parameters here may change from frame // to frame and should not be cached. + // The |device_viewport_rect| and |device_clip_rect| are in non-y-flipped + // window space. virtual void DrawFrame(RenderPassList* render_passes_in_draw_order, ContextProvider* offscreen_context_provider, float device_scale_factor, - bool allow_partial_swap) = 0; + gfx::Rect device_viewport_rect, + gfx::Rect device_clip_rect, + bool allow_partial_swap, + bool disable_picture_quad_image_filtering) = 0; // Waits for rendering to finish. virtual void Finish() = 0; @@ -58,7 +52,7 @@ class CC_EXPORT Renderer { virtual void DoNoOp() {} // Puts backbuffer onscreen. - virtual void SwapBuffers() = 0; + virtual void SwapBuffers(const CompositorFrameMetadata& metadata) = 0; virtual void ReceiveSwapBuffersAck(const CompositorFrameAck& ack) {} virtual void GetFramebufferPixels(void* pixels, gfx::Rect rect) = 0; @@ -71,8 +65,6 @@ class CC_EXPORT Renderer { size_t bytes_visible_and_nearby, size_t bytes_allocated) = 0; - virtual void SetDiscardBackBufferWhenNotVisible(bool discard) = 0; - protected: explicit Renderer(RendererClient* client, const LayerTreeSettings* settings) : client_(client), settings_(settings) {} diff --git a/chromium/cc/output/renderer_pixeltest.cc b/chromium/cc/output/renderer_pixeltest.cc index f0187aacdb3..24c6126755e 100644 --- a/chromium/cc/output/renderer_pixeltest.cc +++ b/chromium/cc/output/renderer_pixeltest.cc @@ -8,7 +8,6 @@ #include "cc/quads/draw_quad.h" #include "cc/quads/picture_draw_quad.h" #include "cc/quads/texture_draw_quad.h" -#include "cc/resources/sync_point_helper.h" #include "cc/test/fake_picture_pile_impl.h" #include "cc/test/pixel_test.h" #include "gpu/GLES2/gl2extchromium.h" @@ -22,6 +21,7 @@ namespace cc { namespace { +#if !defined(OS_ANDROID) scoped_ptr<RenderPass> CreateTestRootRenderPass(RenderPass::Id id, gfx::Rect rect) { scoped_ptr<RenderPass> pass = RenderPass::Create(); @@ -50,13 +50,15 @@ scoped_ptr<SharedQuadState> CreateTestSharedQuadState( const gfx::Rect clip_rect = rect; const bool is_clipped = false; const float opacity = 1.0f; + const SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode; scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create(); shared_state->SetAll(content_to_target_transform, content_bounds, visible_content_rect, clip_rect, is_clipped, - opacity); + opacity, + blend_mode); return shared_state.Pass(); } @@ -68,13 +70,15 @@ scoped_ptr<SharedQuadState> CreateTestSharedQuadStateClipped( const gfx::Rect visible_content_rect = clip_rect; const bool is_clipped = true; const float opacity = 1.0f; + const SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode; scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create(); shared_state->SetAll(content_to_target_transform, content_bounds, visible_content_rect, clip_rect, is_clipped, - opacity); + opacity, + blend_mode); return shared_state.Pass(); } @@ -84,13 +88,12 @@ scoped_ptr<DrawQuad> CreateTestRenderPassDrawQuad( quad->SetNew(shared_state, rect, pass_id, - false, // is_replica - 0, // mask_resource_id - rect, // contents_changed_since_last_frame - gfx::RectF(), // mask_uv_rect - FilterOperations(), // foreground filters - skia::RefPtr<SkImageFilter>(), // foreground filter - FilterOperations()); // background filters + false, // is_replica + 0, // mask_resource_id + rect, // contents_changed_since_last_frame + gfx::RectF(1.f, 1.f), // mask_uv_rect + FilterOperations(), // foreground filters + FilterOperations()); // background filters return quad.PassAs<DrawQuad>(); } @@ -144,16 +147,6 @@ typedef ::testing::Types<GLRenderer, SoftwareRendererWithExpandedViewport> RendererTypes; TYPED_TEST_CASE(RendererPixelTest, RendererTypes); -typedef ::testing::Types<GLRenderer, - GLRendererWithSkiaGPUBackend, - SoftwareRenderer> RendererTypesWithSkiaGPUBackend; -template <typename RendererType> -class RendererPixelTestWithSkiaGPUBackend - : public RendererPixelTest<RendererType> { -}; -TYPED_TEST_CASE(RendererPixelTestWithSkiaGPUBackend, - RendererTypesWithSkiaGPUBackend); - // All pixels can be off by one, but any more than that is an error. class FuzzyPixelOffByOneComparator : public FuzzyPixelComparator { public: @@ -197,7 +190,6 @@ bool FuzzyForSoftwareOnlyPixelComparator<RendererType>::Compare( return exact_.Compare(actual_bmp, expected_bmp); } -#if !defined(OS_ANDROID) TYPED_TEST(RendererPixelTest, SimpleGreenRect) { gfx::Rect rect(this->device_viewport_size_); @@ -463,7 +455,7 @@ class VideoGLRendererPixelTest : public GLRendererPixelTest { gfx::Vector2d()); } - scoped_ptr<YUVVideoDrawQuad> yuv_quad = cc::YUVVideoDrawQuad::Create(); + scoped_ptr<YUVVideoDrawQuad> yuv_quad = YUVVideoDrawQuad::Create(); yuv_quad->SetNew(shared_state, rect, opaque_rect, gfx::Size(), y_resource, u_resource, v_resource, a_resource); return yuv_quad.Pass(); @@ -623,6 +615,8 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) { new SkColorMatrixFilter(matrix))); skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), NULL)); + FilterOperations filters; + filters.Append(FilterOperation::CreateReferenceFilter(filter)); scoped_ptr<RenderPassDrawQuad> render_pass_quad = RenderPassDrawQuad::Create(); @@ -633,8 +627,7 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) { 0, pass_rect, gfx::RectF(), - FilterOperations(), - filter, + filters, FilterOperations()); root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); @@ -652,6 +645,165 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) { FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false))); } +TYPED_TEST(RendererPixelTest, FastPassSaturateFilter) { + gfx::Rect viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(this->device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + shared_state->opacity = 0.5f; + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorBLUE, + false); + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(shared_state.get(), + gfx::Rect(0, + this->device_viewport_size_.height() / 2, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorYELLOW, + false); + + scoped_ptr<SharedQuadState> blank_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create(); + white->SetNew(blank_state.get(), + viewport_rect, + SK_ColorWHITE, + false); + + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(white.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), pass_rect); + + FilterOperations filters; + filters.Append(FilterOperation::CreateSaturateFilter(0.5f)); + + scoped_ptr<RenderPassDrawQuad> render_pass_quad = + RenderPassDrawQuad::Create(); + render_pass_quad->SetNew(pass_shared_state.get(), + pass_rect, + child_pass_id, + false, + 0, + pass_rect, + gfx::RectF(), + filters, + FilterOperations()); + + root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + PixelTest::NoOffscreenContext, + base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")), + ExactPixelComparator(true))); +} + +TYPED_TEST(RendererPixelTest, FastPassFilterChain) { + gfx::Rect viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(this->device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + shared_state->opacity = 0.5f; + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorBLUE, + false); + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(shared_state.get(), + gfx::Rect(0, + this->device_viewport_size_.height() / 2, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorYELLOW, + false); + + scoped_ptr<SharedQuadState> blank_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create(); + white->SetNew(blank_state.get(), + viewport_rect, + SK_ColorWHITE, + false); + + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(white.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), pass_rect); + + FilterOperations filters; + filters.Append(FilterOperation::CreateGrayscaleFilter(1.f)); + filters.Append(FilterOperation::CreateBrightnessFilter(0.5f)); + + scoped_ptr<RenderPassDrawQuad> render_pass_quad = + RenderPassDrawQuad::Create(); + render_pass_quad->SetNew(pass_shared_state.get(), + pass_rect, + child_pass_id, + false, + 0, + pass_rect, + gfx::RectF(), + filters, + FilterOperations()); + + root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + PixelTest::NoOffscreenContext, + base::FilePath(FILE_PATH_LITERAL("blue_yellow_filter_chain.png")), + ExactPixelComparator(true))); +} + TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) { gfx::Rect viewport_rect(this->device_viewport_size_); @@ -726,6 +878,8 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) { new SkColorMatrixFilter(matrix))); skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), NULL)); + FilterOperations filters; + filters.Append(FilterOperation::CreateReferenceFilter(filter)); scoped_ptr<RenderPassDrawQuad> render_pass_quad = RenderPassDrawQuad::Create(); @@ -736,8 +890,7 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) { 0, pass_rect, gfx::RectF(), - FilterOperations(), - filter, + filters, FilterOperations()); root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); @@ -881,6 +1034,107 @@ TYPED_TEST(RendererPixelTest, EnlargedRenderPassTextureWithAntiAliasing) { FuzzyPixelOffByOneComparator(true))); } +// This tests the case where we have a RenderPass with a mask, but the quad +// for the masked surface does not include the full surface texture. +TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad) { + gfx::Rect viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + scoped_ptr<SharedQuadState> root_pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root); + scoped_ptr<SharedQuadState> child_pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), viewport_rect); + + // The child render pass is just a green box. + static const SkColor kCSSGreen = 0xff008000; + scoped_ptr<SolidColorDrawQuad> green = SolidColorDrawQuad::Create(); + green->SetNew(child_pass_shared_state.get(), viewport_rect, kCSSGreen, false); + child_pass->quad_list.push_back(green.PassAs<DrawQuad>()); + + // Make a mask. + gfx::Rect mask_rect = viewport_rect; + SkBitmap bitmap; + bitmap.setConfig( + SkBitmap::kARGB_8888_Config, mask_rect.width(), mask_rect.height()); + bitmap.allocPixels(); + SkBitmapDevice bitmap_device(bitmap); + skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(new SkCanvas(&bitmap_device)); + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(SkIntToScalar(4)); + paint.setColor(SK_ColorWHITE); + canvas->clear(SK_ColorTRANSPARENT); + gfx::Rect rect = mask_rect; + while (!rect.IsEmpty()) { + rect.Inset(6, 6, 4, 4); + canvas->drawRect( + SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()), + paint); + rect.Inset(6, 6, 4, 4); + } + + ResourceProvider::ResourceId mask_resource_id = + this->resource_provider_->CreateResource( + mask_rect.size(), + GL_CLAMP_TO_EDGE, + ResourceProvider::TextureUsageAny, + RGBA_8888); + { + SkAutoLockPixels lock(bitmap); + this->resource_provider_->SetPixels( + mask_resource_id, + reinterpret_cast<uint8_t*>(bitmap.getPixels()), + mask_rect, + mask_rect, + gfx::Vector2d()); + } + + // This RenderPassDrawQuad does not include the full |viewport_rect| which is + // the size of the child render pass. + gfx::Rect sub_rect = gfx::Rect(50, 50, 100, 100); + EXPECT_NE(sub_rect.x(), child_pass->output_rect.x()); + EXPECT_NE(sub_rect.y(), child_pass->output_rect.y()); + EXPECT_NE(sub_rect.right(), child_pass->output_rect.right()); + EXPECT_NE(sub_rect.bottom(), child_pass->output_rect.bottom()); + EXPECT_TRUE(child_pass->output_rect.Contains(sub_rect)); + + // Set up a mask on the RenderPassDrawQuad. + scoped_ptr<RenderPassDrawQuad> mask_quad = RenderPassDrawQuad::Create(); + mask_quad->SetNew(root_pass_shared_state.get(), + sub_rect, + child_pass_id, + false, // is_replica + mask_resource_id, + sub_rect, // contents_changed_since_last_frame + gfx::RectF(1.f, 1.f), // mask_uv_rect + FilterOperations(), // foreground filters + FilterOperations()); // background filters + root_pass->quad_list.push_back(mask_quad.PassAs<DrawQuad>()); + + // White background behind the masked render pass. + scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create(); + white->SetNew( + root_pass_shared_state.get(), viewport_rect, SK_ColorWHITE, false); + root_pass->quad_list.push_back(white.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + PixelTest::NoOffscreenContext, + base::FilePath(FILE_PATH_LITERAL("image_mask_of_layer.png")), + ExactPixelComparator(true))); +} + template <typename RendererType> class RendererPixelTestWithBackgroundFilter : public RendererPixelTest<RendererType> { @@ -931,7 +1185,6 @@ class RendererPixelTestWithBackgroundFilter filter_pass_content_rect_, // contents_changed_since_last_frame gfx::RectF(), // mask_uv_rect FilterOperations(), // filters - skia::RefPtr<SkImageFilter>(), // filter this->background_filters_); root_pass->quad_list.push_back(filter_pass_quad.PassAs<DrawQuad>()); root_pass->shared_quad_state_list.push_back(shared_state.Pass()); @@ -1024,7 +1277,7 @@ TEST_F(GLRendererPixelTestWithBackgroundFilter, InvertFilter) { class ExternalStencilPixelTest : public GLRendererPixelTest { protected: void ClearBackgroundToGreen() { - WebKit::WebGraphicsContext3D* context3d = + blink::WebGraphicsContext3D* context3d = output_surface_->context_provider()->Context3d(); output_surface_->EnsureBackbuffer(); output_surface_->Reshape(device_viewport_size_, 1); @@ -1034,7 +1287,7 @@ class ExternalStencilPixelTest : public GLRendererPixelTest { void PopulateStencilBuffer() { // Set two quadrants of the stencil buffer to 1. - WebKit::WebGraphicsContext3D* context3d = + blink::WebGraphicsContext3D* context3d = output_surface_->context_provider()->Context3d(); ASSERT_TRUE(context3d->getContextAttributes().stencil); output_surface_->EnsureBackbuffer(); @@ -1329,10 +1582,10 @@ TEST_F(GLRendererPixelTest, AntiAliasingPerspective) { gfx::Rect red_rect(0, 0, 180, 500); gfx::Transform red_content_to_target_transform( - 1.0, 2.4520, 10.6206, 19.0, - 0.0, 0.3528, 5.9737, 9.5, - 0.0, -0.2250, -0.9744, 0.0, - 0.0, 0.0225, 0.0974, 1.0); + 1.0f, 2.4520f, 10.6206f, 19.0f, + 0.0f, 0.3528f, 5.9737f, 9.5f, + 0.0f, -0.2250f, -0.9744f, 0.0f, + 0.0f, 0.0225f, 0.0974f, 1.0f); scoped_ptr<SharedQuadState> red_shared_state = CreateTestSharedQuadState(red_content_to_target_transform, red_rect); scoped_ptr<SolidColorDrawQuad> red = SolidColorDrawQuad::Create(); @@ -1362,10 +1615,9 @@ TEST_F(GLRendererPixelTest, AntiAliasingPerspective) { FuzzyPixelOffByOneComparator(true))); } -TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, PictureDrawQuadIdentityScale) { +TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) { gfx::Size pile_tile_size(1000, 1000); gfx::Rect viewport(this->device_viewport_size_); - bool use_skia_gpu_backend = this->UseSkiaGPUBackend(); // TODO(enne): the renderer should figure this out on its own. ResourceFormat texture_format = RGBA_8888; @@ -1408,7 +1660,6 @@ TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, PictureDrawQuadIdentityScale) { texture_format, viewport, 1.f, - use_skia_gpu_backend, blue_pile); pass->quad_list.push_back(blue_quad.PassAs<DrawQuad>()); @@ -1433,7 +1684,6 @@ TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, PictureDrawQuadIdentityScale) { texture_format, viewport, 1.f, - use_skia_gpu_backend, green_pile); pass->quad_list.push_back(green_quad.PassAs<DrawQuad>()); @@ -1451,7 +1701,6 @@ TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, PictureDrawQuadIdentityScale) { TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) { gfx::Size pile_tile_size(1000, 1000); gfx::Rect viewport(this->device_viewport_size_); - bool use_skia_gpu_backend = this->UseSkiaGPUBackend(); ResourceFormat texture_format = RGBA_8888; RenderPass::Id id(1, 1); @@ -1481,7 +1730,6 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) { texture_format, viewport, 1.f, - use_skia_gpu_backend, green_pile); pass->quad_list.push_back(green_quad.PassAs<DrawQuad>()); @@ -1506,7 +1754,6 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) { texture_format, viewport, 1.f, - use_skia_gpu_backend, white_pile); pass->quad_list.push_back(white_quad.PassAs<DrawQuad>()); @@ -1520,11 +1767,87 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) { FuzzyPixelOffByOneComparator(true))); } -TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, - PictureDrawQuadNonIdentityScale) { +template<typename TypeParam> bool IsSoftwareRenderer() { + return false; +} + +template<> +bool IsSoftwareRenderer<SoftwareRenderer>() { + return true; +} + +template<> +bool IsSoftwareRenderer<SoftwareRendererWithExpandedViewport>() { + return true; +} + +// If we disable image filtering, then a 2x2 bitmap should appear as four +// huge sharp squares. +TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) { + // We only care about this in software mode since bilinear filtering is + // cheap in hardware. + if (!IsSoftwareRenderer<TypeParam>()) + return; + + gfx::Size pile_tile_size(1000, 1000); + gfx::Rect viewport(this->device_viewport_size_); + ResourceFormat texture_format = RGBA_8888; + + RenderPass::Id id(1, 1); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> pass = + CreateTestRenderPass(id, viewport, transform_to_root); + + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); + bitmap.allocPixels(); + { + SkAutoLockPixels lock(bitmap); + SkCanvas canvas(bitmap); + canvas.drawPoint(0, 0, SK_ColorGREEN); + canvas.drawPoint(0, 1, SK_ColorBLUE); + canvas.drawPoint(1, 0, SK_ColorBLUE); + canvas.drawPoint(1, 1, SK_ColorGREEN); + } + + scoped_refptr<FakePicturePileImpl> pile = + FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size()); + SkPaint paint; + paint.setFilterLevel(SkPaint::kLow_FilterLevel); + pile->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint); + pile->RerecordPile(); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport); + + scoped_ptr<PictureDrawQuad> quad = PictureDrawQuad::Create(); + quad->SetNew(shared_state.get(), + viewport, + gfx::Rect(), + gfx::RectF(0, 0, 2, 2), + viewport.size(), + texture_format, + viewport, + 1.f, + pile); + pass->quad_list.push_back(quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + this->disable_picture_quad_image_filtering_ = true; + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + PixelTest::NoOffscreenContext, + base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), + ExactPixelComparator(true))); +} + +TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) { gfx::Size pile_tile_size(1000, 1000); gfx::Rect viewport(this->device_viewport_size_); - bool use_skia_gpu_backend = this->UseSkiaGPUBackend(); // TODO(enne): the renderer should figure this out on its own. ResourceFormat texture_format = RGBA_8888; @@ -1563,7 +1886,6 @@ TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, texture_format, green_rect1, 1.f, - use_skia_gpu_backend, green_pile); pass->quad_list.push_back(green_quad1.PassAs<DrawQuad>()); @@ -1576,7 +1898,6 @@ TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, texture_format, green_rect2, 1.f, - use_skia_gpu_backend, green_pile); pass->quad_list.push_back(green_quad2.PassAs<DrawQuad>()); @@ -1648,7 +1969,6 @@ TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, texture_format, content_union_rect, contents_scale, - use_skia_gpu_backend, pile); pass->quad_list.push_back(blue_quad.PassAs<DrawQuad>()); @@ -1672,6 +1992,69 @@ TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), ExactPixelComparator(true))); } + +TYPED_TEST(RendererPixelTest, WrapModeRepeat) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + + gfx::Rect texture_rect(4, 4); + SkPMColor colors[4] = { + SkPreMultiplyColor(SkColorSetARGB(255, 0, 255, 0)), + SkPreMultiplyColor(SkColorSetARGB(255, 0, 128, 0)), + SkPreMultiplyColor(SkColorSetARGB(255, 0, 64, 0)), + SkPreMultiplyColor(SkColorSetARGB(255, 0, 0, 0)), + }; + uint32_t pixels[16] = { + colors[0], colors[0], colors[1], colors[1], + colors[0], colors[0], colors[1], colors[1], + colors[2], colors[2], colors[3], colors[3], + colors[2], colors[2], colors[3], colors[3], + }; + ResourceProvider::ResourceId resource = + this->resource_provider_->CreateResource( + texture_rect.size(), + GL_REPEAT, + ResourceProvider::TextureUsageAny, + RGBA_8888); + this->resource_provider_->SetPixels( + resource, + reinterpret_cast<uint8_t*>(pixels), + texture_rect, + texture_rect, + gfx::Vector2d()); + + float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + scoped_ptr<TextureDrawQuad> texture_quad = TextureDrawQuad::Create(); + texture_quad->SetNew( + shared_state.get(), + gfx::Rect(this->device_viewport_size_), + gfx::Rect(), + resource, + true, // premultiplied_alpha + gfx::PointF(0.0f, 0.0f), // uv_top_left + gfx::PointF( // uv_bottom_right + this->device_viewport_size_.width() / texture_rect.width(), + this->device_viewport_size_.height() / texture_rect.height()), + SK_ColorWHITE, + vertex_opacity, + false); // flipped + pass->quad_list.push_back(texture_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + PixelTest::NoOffscreenContext, + base::FilePath(FILE_PATH_LITERAL("wrap_mode_repeat.png")), + FuzzyPixelOffByOneComparator(true))); +} + #endif // !defined(OS_ANDROID) } // namespace diff --git a/chromium/cc/output/shader.cc b/chromium/cc/output/shader.cc index beabf8db755..b752f46134d 100644 --- a/chromium/cc/output/shader.cc +++ b/chromium/cc/output/shader.cc @@ -9,38 +9,33 @@ #include "base/basictypes.h" #include "base/logging.h" #include "cc/output/gl_renderer.h" // For the GLC() macro. -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" +#include "gpu/command_buffer/client/gles2_interface.h" #include "third_party/khronos/GLES2/gl2.h" #define SHADER0(Src) #Src #define VERTEX_SHADER(Src) SetVertexTexCoordPrecision(SHADER0(Src)) -#define FRAGMENT_SHADER(Src) SetFragTexCoordPrecision(precision, SHADER0(Src)) +#define FRAGMENT_SHADER(Src) SetFragmentTexCoordPrecision( \ + precision, SetFragmentSamplerType(sampler, SHADER0(Src))) -using WebKit::WebGraphicsContext3D; +using gpu::gles2::GLES2Interface; namespace cc { namespace { -static void GetProgramUniformLocations(WebGraphicsContext3D* context, +static void GetProgramUniformLocations(GLES2Interface* context, unsigned program, size_t count, const char** uniforms, int* locations, - bool using_bind_uniform, int* base_uniform_index) { for (size_t i = 0; i < count; i++) { - if (using_bind_uniform) { - locations[i] = (*base_uniform_index)++; - context->bindUniformLocationCHROMIUM(program, locations[i], uniforms[i]); - } else { - locations[i] = context->getUniformLocation(program, uniforms[i]); - DCHECK_NE(locations[i], -1); - } + locations[i] = (*base_uniform_index)++; + context->BindUniformLocationCHROMIUM(program, locations[i], uniforms[i]); } } -static std::string SetFragTexCoordPrecision( +static std::string SetFragmentTexCoordPrecision( TexCoordPrecision requested_precision, std::string shader_string) { switch (requested_precision) { case TexCoordPrecisionHigh: @@ -59,7 +54,11 @@ static std::string SetFragTexCoordPrecision( case TexCoordPrecisionNA: DCHECK_EQ(shader_string.find("TexCoordPrecision"), std::string::npos); DCHECK_EQ(shader_string.find("texture2D"), std::string::npos); + DCHECK_EQ(shader_string.find("texture2DRect"), std::string::npos); return shader_string; + default: + NOTREACHED(); + break; } return shader_string; } @@ -73,7 +72,7 @@ static std::string SetVertexTexCoordPrecision(const char* shader_string) { std::string(shader_string); } -TexCoordPrecision TexCoordPrecisionRequired(WebGraphicsContext3D* context, +TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context, int *highp_threshold_cache, int highp_threshold_min, int x, int y) { @@ -84,7 +83,7 @@ TexCoordPrecision TexCoordPrecisionRequired(WebGraphicsContext3D* context, // everywhere. GLint range[2] = { 14, 14 }; GLint precision = 10; - GLC(context, context->getShaderPrecisionFormat(GL_FRAGMENT_SHADER, + GLC(context, context->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, range, &precision)); *highp_threshold_cache = 1 << precision; @@ -96,9 +95,46 @@ TexCoordPrecision TexCoordPrecisionRequired(WebGraphicsContext3D* context, return TexCoordPrecisionMedium; } +static std::string SetFragmentSamplerType( + SamplerType requested_type, std::string shader_string) { + switch (requested_type) { + case SamplerType2D: + DCHECK_NE(shader_string.find("SamplerType"), std::string::npos); + DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos); + return + "#define SamplerType sampler2D\n" + "#define TextureLookup texture2D\n" + + shader_string; + case SamplerType2DRect: + DCHECK_NE(shader_string.find("SamplerType"), std::string::npos); + DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos); + return + "#extension GL_ARB_texture_rectangle : require\n" + "#define SamplerType sampler2DRect\n" + "#define TextureLookup texture2DRect\n" + + shader_string; + case SamplerTypeExternalOES: + DCHECK_NE(shader_string.find("SamplerType"), std::string::npos); + DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos); + return + "#extension GL_OES_EGL_image_external : require\n" + "#define SamplerType samplerExternalOES\n" + "#define TextureLookup texture2D\n" + + shader_string; + case SamplerTypeNA: + DCHECK_EQ(shader_string.find("SamplerType"), std::string::npos); + DCHECK_EQ(shader_string.find("TextureLookup"), std::string::npos); + return shader_string; + default: + NOTREACHED(); + break; + } + return shader_string; +} + } // namespace -TexCoordPrecision TexCoordPrecisionRequired(WebGraphicsContext3D* context, +TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context, int *highp_threshold_cache, int highp_threshold_min, gfx::Point max_coordinate) { @@ -107,7 +143,7 @@ TexCoordPrecision TexCoordPrecisionRequired(WebGraphicsContext3D* context, max_coordinate.x(), max_coordinate.y()); } -TexCoordPrecision TexCoordPrecisionRequired(WebGraphicsContext3D* context, +TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context, int *highp_threshold_cache, int highp_threshold_min, gfx::Size max_size) { @@ -119,9 +155,8 @@ TexCoordPrecision TexCoordPrecisionRequired(WebGraphicsContext3D* context, VertexShaderPosTex::VertexShaderPosTex() : matrix_location_(-1) {} -void VertexShaderPosTex::Init(WebGraphicsContext3D* context, +void VertexShaderPosTex::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "matrix", @@ -133,7 +168,6 @@ void VertexShaderPosTex::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); matrix_location_ = locations[0]; } @@ -155,9 +189,8 @@ VertexShaderPosTexYUVStretch::VertexShaderPosTexYUVStretch() : matrix_location_(-1), tex_scale_location_(-1) {} -void VertexShaderPosTexYUVStretch::Init(WebGraphicsContext3D* context, +void VertexShaderPosTexYUVStretch::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "matrix", @@ -170,7 +203,6 @@ void VertexShaderPosTexYUVStretch::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); matrix_location_ = locations[0]; tex_scale_location_ = locations[1]; @@ -194,9 +226,8 @@ std::string VertexShaderPosTexYUVStretch::GetShaderString() const { VertexShaderPos::VertexShaderPos() : matrix_location_(-1) {} -void VertexShaderPos::Init(WebGraphicsContext3D* context, +void VertexShaderPos::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "matrix", @@ -208,7 +239,6 @@ void VertexShaderPos::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); matrix_location_ = locations[0]; } @@ -228,9 +258,8 @@ VertexShaderPosTexTransform::VertexShaderPosTexTransform() tex_transform_location_(-1), vertex_opacity_location_(-1) {} -void VertexShaderPosTexTransform::Init(WebGraphicsContext3D* context, +void VertexShaderPosTexTransform::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "matrix", @@ -244,7 +273,6 @@ void VertexShaderPosTexTransform::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); matrix_location_ = locations[0]; tex_transform_location_ = locations[1]; @@ -286,9 +314,8 @@ VertexShaderQuad::VertexShaderQuad() : matrix_location_(-1), quad_location_(-1) {} -void VertexShaderQuad::Init(WebGraphicsContext3D* context, +void VertexShaderQuad::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "matrix", @@ -301,7 +328,6 @@ void VertexShaderQuad::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); matrix_location_ = locations[0]; quad_location_ = locations[1]; @@ -345,9 +371,8 @@ VertexShaderQuadAA::VertexShaderQuadAA() quad_location_(-1), edge_location_(-1) {} -void VertexShaderQuadAA::Init(WebGraphicsContext3D* context, +void VertexShaderQuadAA::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "matrix", @@ -362,7 +387,6 @@ void VertexShaderQuadAA::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); matrix_location_ = locations[0]; viewport_location_ = locations[1]; @@ -404,9 +428,8 @@ VertexShaderQuadTexTransformAA::VertexShaderQuadTexTransformAA() edge_location_(-1), tex_transform_location_(-1) {} -void VertexShaderQuadTexTransformAA::Init(WebGraphicsContext3D* context, +void VertexShaderQuadTexTransformAA::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "matrix", @@ -422,7 +445,6 @@ void VertexShaderQuadTexTransformAA::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); matrix_location_ = locations[0]; viewport_location_ = locations[1]; @@ -466,9 +488,8 @@ VertexShaderTile::VertexShaderTile() quad_location_(-1), vertex_tex_transform_location_(-1) {} -void VertexShaderTile::Init(WebGraphicsContext3D* context, +void VertexShaderTile::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "matrix", @@ -482,7 +503,6 @@ void VertexShaderTile::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); matrix_location_ = locations[0]; quad_location_ = locations[1]; @@ -512,9 +532,8 @@ VertexShaderTileAA::VertexShaderTileAA() edge_location_(-1), vertex_tex_transform_location_(-1) {} -void VertexShaderTileAA::Init(WebGraphicsContext3D* context, +void VertexShaderTileAA::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "matrix", @@ -530,7 +549,6 @@ void VertexShaderTileAA::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); matrix_location_ = locations[0]; viewport_location_ = locations[1]; @@ -573,9 +591,8 @@ VertexShaderVideoTransform::VertexShaderVideoTransform() : matrix_location_(-1), tex_matrix_location_(-1) {} -void VertexShaderVideoTransform::Init(WebGraphicsContext3D* context, +void VertexShaderVideoTransform::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "matrix", @@ -588,7 +605,6 @@ void VertexShaderVideoTransform::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); matrix_location_ = locations[0]; tex_matrix_location_ = locations[1]; @@ -613,9 +629,8 @@ FragmentTexAlphaBinding::FragmentTexAlphaBinding() : sampler_location_(-1), alpha_location_(-1) {} -void FragmentTexAlphaBinding::Init(WebGraphicsContext3D* context, +void FragmentTexAlphaBinding::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -628,7 +643,6 @@ void FragmentTexAlphaBinding::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; alpha_location_ = locations[1]; @@ -640,9 +654,8 @@ FragmentTexColorMatrixAlphaBinding::FragmentTexColorMatrixAlphaBinding() color_matrix_location_(-1), color_offset_location_(-1) {} -void FragmentTexColorMatrixAlphaBinding::Init(WebGraphicsContext3D* context, +void FragmentTexColorMatrixAlphaBinding::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -657,7 +670,6 @@ void FragmentTexColorMatrixAlphaBinding::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; alpha_location_ = locations[1]; @@ -668,9 +680,8 @@ void FragmentTexColorMatrixAlphaBinding::Init(WebGraphicsContext3D* context, FragmentTexOpaqueBinding::FragmentTexOpaqueBinding() : sampler_location_(-1) {} -void FragmentTexOpaqueBinding::Init(WebGraphicsContext3D* context, +void FragmentTexOpaqueBinding::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -682,73 +693,35 @@ void FragmentTexOpaqueBinding::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, - base_uniform_index); - sampler_location_ = locations[0]; -} - -FragmentShaderOESImageExternal::FragmentShaderOESImageExternal() - : sampler_location_(-1) {} - -void FragmentShaderOESImageExternal::Init(WebGraphicsContext3D* context, - unsigned program, - bool using_bind_uniform, - int* base_uniform_index) { - static const char* uniforms[] = { - "s_texture", - }; - int locations[arraysize(uniforms)]; - - GetProgramUniformLocations(context, - program, - arraysize(uniforms), - uniforms, - locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; } -std::string FragmentShaderOESImageExternal::GetShaderString( - TexCoordPrecision precision) const { - // Cannot use the SHADER() macro because of the '#' char - return "#extension GL_OES_EGL_image_external : require\n" + - FRAGMENT_SHADER( - precision mediump float; - varying TexCoordPrecision vec2 v_texCoord; - uniform samplerExternalOES s_texture; - void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); - gl_FragColor = texColor; - } - ); // NOLINT(whitespace/parens) -} - std::string FragmentShaderRGBATexAlpha::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; - uniform sampler2D s_texture; + uniform SamplerType s_texture; uniform float alpha; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); gl_FragColor = texColor * alpha; } ); // NOLINT(whitespace/parens) } std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; - uniform sampler2D s_texture; + uniform SamplerType s_texture; uniform float alpha; uniform mat4 colorMatrix; uniform vec4 colorOffset; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); float nonZeroAlpha = max(texColor.a, 0.00001); texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha); texColor = colorMatrix * texColor + colorOffset; @@ -760,28 +733,28 @@ std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderString( } std::string FragmentShaderRGBATexVaryingAlpha::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; varying float v_alpha; - uniform sampler2D s_texture; + uniform SamplerType s_texture; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); gl_FragColor = texColor * v_alpha; } ); // NOLINT(whitespace/parens) } std::string FragmentShaderRGBATexPremultiplyAlpha::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; varying float v_alpha; - uniform sampler2D s_texture; + uniform SamplerType s_texture; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); texColor.rgb *= texColor.a; gl_FragColor = texColor * v_alpha; } @@ -793,9 +766,8 @@ FragmentTexBackgroundBinding::FragmentTexBackgroundBinding() sampler_location_(-1) { } -void FragmentTexBackgroundBinding::Init(WebGraphicsContext3D* context, +void FragmentTexBackgroundBinding::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -808,7 +780,6 @@ void FragmentTexBackgroundBinding::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; @@ -819,15 +790,15 @@ void FragmentTexBackgroundBinding::Init(WebGraphicsContext3D* context, } std::string FragmentShaderTexBackgroundVaryingAlpha::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; varying float v_alpha; uniform vec4 background_color; - uniform sampler2D s_texture; + uniform SamplerType s_texture; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); texColor += background_color * (1.0 - texColor.a); gl_FragColor = texColor * v_alpha; } @@ -835,15 +806,15 @@ std::string FragmentShaderTexBackgroundVaryingAlpha::GetShaderString( } std::string FragmentShaderTexBackgroundPremultiplyAlpha::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; varying float v_alpha; uniform vec4 background_color; - uniform sampler2D s_texture; + uniform SamplerType s_texture; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); texColor.rgb *= texColor.a; texColor += background_color * (1.0 - texColor.a); gl_FragColor = texColor * v_alpha; @@ -851,55 +822,40 @@ std::string FragmentShaderTexBackgroundPremultiplyAlpha::GetShaderString( ); // NOLINT(whitespace/parens) } -std::string FragmentShaderRGBATexRectVaryingAlpha::GetShaderString( - TexCoordPrecision precision) const { - return "#extension GL_ARB_texture_rectangle : require\n" + - FRAGMENT_SHADER( - precision mediump float; - varying TexCoordPrecision vec2 v_texCoord; - varying float v_alpha; - uniform sampler2DRect s_texture; - void main() { - vec4 texColor = texture2DRect(s_texture, v_texCoord); - gl_FragColor = texColor * v_alpha; - } - ); // NOLINT(whitespace/parens) -} - std::string FragmentShaderRGBATexOpaque::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; - uniform sampler2D s_texture; + uniform SamplerType s_texture; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); gl_FragColor = vec4(texColor.rgb, 1.0); } ); // NOLINT(whitespace/parens) } std::string FragmentShaderRGBATex::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; - uniform sampler2D s_texture; + uniform SamplerType s_texture; void main() { - gl_FragColor = texture2D(s_texture, v_texCoord); + gl_FragColor = TextureLookup(s_texture, v_texCoord); } ); // NOLINT(whitespace/parens) } std::string FragmentShaderRGBATexSwizzleAlpha::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; - uniform sampler2D s_texture; + uniform SamplerType s_texture; uniform float alpha; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha; } @@ -907,13 +863,13 @@ std::string FragmentShaderRGBATexSwizzleAlpha::GetShaderString( } std::string FragmentShaderRGBATexSwizzleOpaque::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; - uniform sampler2D s_texture; + uniform SamplerType s_texture; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, 1.0); } ); // NOLINT(whitespace/parens) @@ -923,9 +879,8 @@ FragmentShaderRGBATexAlphaAA::FragmentShaderRGBATexAlphaAA() : sampler_location_(-1), alpha_location_(-1) {} -void FragmentShaderRGBATexAlphaAA::Init(WebGraphicsContext3D* context, +void FragmentShaderRGBATexAlphaAA::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -938,23 +893,22 @@ void FragmentShaderRGBATexAlphaAA::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; alpha_location_ = locations[1]; } std::string FragmentShaderRGBATexAlphaAA::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; - uniform sampler2D s_texture; + uniform SamplerType s_texture; uniform float alpha; varying TexCoordPrecision vec2 v_texCoord; varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances. void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); vec4 d4 = min(edge_dist[0], edge_dist[1]); vec2 d2 = min(d4.xz, d4.yw); float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0); @@ -968,9 +922,8 @@ FragmentTexClampAlphaAABinding::FragmentTexClampAlphaAABinding() alpha_location_(-1), fragment_tex_transform_location_(-1) {} -void FragmentTexClampAlphaAABinding::Init(WebGraphicsContext3D* context, +void FragmentTexClampAlphaAABinding::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -984,7 +937,6 @@ void FragmentTexClampAlphaAABinding::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; alpha_location_ = locations[1]; @@ -992,10 +944,10 @@ void FragmentTexClampAlphaAABinding::Init(WebGraphicsContext3D* context, } std::string FragmentShaderRGBATexClampAlphaAA::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; - uniform sampler2D s_texture; + uniform SamplerType s_texture; uniform float alpha; uniform TexCoordPrecision vec4 fragmentTexTransform; varying TexCoordPrecision vec2 v_texCoord; @@ -1005,7 +957,7 @@ std::string FragmentShaderRGBATexClampAlphaAA::GetShaderString( TexCoordPrecision vec2 texCoord = clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw + fragmentTexTransform.xy; - vec4 texColor = texture2D(s_texture, texCoord); + vec4 texColor = TextureLookup(s_texture, texCoord); vec4 d4 = min(edge_dist[0], edge_dist[1]); vec2 d2 = min(d4.xz, d4.yw); float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0); @@ -1015,10 +967,10 @@ std::string FragmentShaderRGBATexClampAlphaAA::GetShaderString( } std::string FragmentShaderRGBATexClampSwizzleAlphaAA::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; - uniform sampler2D s_texture; + uniform SamplerType s_texture; uniform float alpha; uniform TexCoordPrecision vec4 fragmentTexTransform; varying TexCoordPrecision vec2 v_texCoord; @@ -1028,7 +980,7 @@ std::string FragmentShaderRGBATexClampSwizzleAlphaAA::GetShaderString( TexCoordPrecision vec2 texCoord = clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw + fragmentTexTransform.xy; - vec4 texColor = texture2D(s_texture, texCoord); + vec4 texColor = TextureLookup(s_texture, texCoord); vec4 d4 = min(edge_dist[0], edge_dist[1]); vec2 d2 = min(d4.xz, d4.yw); float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0); @@ -1044,9 +996,8 @@ FragmentShaderRGBATexAlphaMask::FragmentShaderRGBATexAlphaMask() alpha_location_(-1), mask_tex_coord_scale_location_(-1) {} -void FragmentShaderRGBATexAlphaMask::Init(WebGraphicsContext3D* context, +void FragmentShaderRGBATexAlphaMask::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -1062,7 +1013,6 @@ void FragmentShaderRGBATexAlphaMask::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; mask_sampler_location_ = locations[1]; @@ -1072,21 +1022,21 @@ void FragmentShaderRGBATexAlphaMask::Init(WebGraphicsContext3D* context, } std::string FragmentShaderRGBATexAlphaMask::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; - uniform sampler2D s_texture; - uniform sampler2D s_mask; + uniform SamplerType s_texture; + uniform SamplerType s_mask; uniform TexCoordPrecision vec2 maskTexCoordScale; uniform TexCoordPrecision vec2 maskTexCoordOffset; uniform float alpha; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); TexCoordPrecision vec2 maskTexCoord = vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x, maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y); - vec4 maskColor = texture2D(s_mask, maskTexCoord); + vec4 maskColor = TextureLookup(s_mask, maskTexCoord); gl_FragColor = texColor * alpha * maskColor.w; } ); // NOLINT(whitespace/parens) @@ -1099,9 +1049,8 @@ FragmentShaderRGBATexAlphaMaskAA::FragmentShaderRGBATexAlphaMaskAA() mask_tex_coord_scale_location_(-1), mask_tex_coord_offset_location_(-1) {} -void FragmentShaderRGBATexAlphaMaskAA::Init(WebGraphicsContext3D* context, +void FragmentShaderRGBATexAlphaMaskAA::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -1117,7 +1066,6 @@ void FragmentShaderRGBATexAlphaMaskAA::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; mask_sampler_location_ = locations[1]; @@ -1127,11 +1075,11 @@ void FragmentShaderRGBATexAlphaMaskAA::Init(WebGraphicsContext3D* context, } std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; - uniform sampler2D s_texture; - uniform sampler2D s_mask; + uniform SamplerType s_texture; + uniform SamplerType s_mask; uniform TexCoordPrecision vec2 maskTexCoordScale; uniform TexCoordPrecision vec2 maskTexCoordOffset; uniform float alpha; @@ -1139,11 +1087,11 @@ std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderString( varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances. void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); TexCoordPrecision vec2 maskTexCoord = vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x, maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y); - vec4 maskColor = texture2D(s_mask, maskTexCoord); + vec4 maskColor = TextureLookup(s_mask, maskTexCoord); vec4 d4 = min(edge_dist[0], edge_dist[1]); vec2 d2 = min(d4.xz, d4.yw); float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0); @@ -1162,9 +1110,8 @@ FragmentShaderRGBATexAlphaMaskColorMatrixAA:: color_offset_location_(-1) {} void FragmentShaderRGBATexAlphaMaskColorMatrixAA::Init( - WebGraphicsContext3D* context, + GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -1182,7 +1129,6 @@ void FragmentShaderRGBATexAlphaMaskColorMatrixAA::Init( arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; mask_sampler_location_ = locations[1]; @@ -1194,11 +1140,11 @@ void FragmentShaderRGBATexAlphaMaskColorMatrixAA::Init( } std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; - uniform sampler2D s_texture; - uniform sampler2D s_mask; + uniform SamplerType s_texture; + uniform SamplerType s_mask; uniform vec2 maskTexCoordScale; uniform vec2 maskTexCoordOffset; uniform mat4 colorMatrix; @@ -1208,7 +1154,7 @@ std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderString( varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances. void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); float nonZeroAlpha = max(texColor.a, 0.00001); texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha); texColor = colorMatrix * texColor + colorOffset; @@ -1217,7 +1163,7 @@ std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderString( TexCoordPrecision vec2 maskTexCoord = vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x, maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y); - vec4 maskColor = texture2D(s_mask, maskTexCoord); + vec4 maskColor = TextureLookup(s_mask, maskTexCoord); vec4 d4 = min(edge_dist[0], edge_dist[1]); vec2 d2 = min(d4.xz, d4.yw); float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0); @@ -1234,9 +1180,8 @@ FragmentShaderRGBATexAlphaColorMatrixAA:: color_offset_location_(-1) {} void FragmentShaderRGBATexAlphaColorMatrixAA::Init( - WebGraphicsContext3D* context, + GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -1251,7 +1196,6 @@ void FragmentShaderRGBATexAlphaColorMatrixAA::Init( arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; alpha_location_ = locations[1]; @@ -1260,10 +1204,10 @@ void FragmentShaderRGBATexAlphaColorMatrixAA::Init( } std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; - uniform sampler2D s_texture; + uniform SamplerType s_texture; uniform float alpha; uniform mat4 colorMatrix; uniform vec4 colorOffset; @@ -1271,7 +1215,7 @@ std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderString( varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances. void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); float nonZeroAlpha = max(texColor.a, 0.00001); texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha); texColor = colorMatrix * texColor + colorOffset; @@ -1293,9 +1237,8 @@ FragmentShaderRGBATexAlphaMaskColorMatrix:: mask_tex_coord_scale_location_(-1) {} void FragmentShaderRGBATexAlphaMaskColorMatrix::Init( - WebGraphicsContext3D* context, + GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "s_texture", @@ -1313,7 +1256,6 @@ void FragmentShaderRGBATexAlphaMaskColorMatrix::Init( arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); sampler_location_ = locations[0]; mask_sampler_location_ = locations[1]; @@ -1325,19 +1267,19 @@ void FragmentShaderRGBATexAlphaMaskColorMatrix::Init( } std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; varying TexCoordPrecision vec2 v_texCoord; - uniform sampler2D s_texture; - uniform sampler2D s_mask; + uniform SamplerType s_texture; + uniform SamplerType s_mask; uniform vec2 maskTexCoordScale; uniform vec2 maskTexCoordOffset; uniform mat4 colorMatrix; uniform vec4 colorOffset; uniform float alpha; void main() { - vec4 texColor = texture2D(s_texture, v_texCoord); + vec4 texColor = TextureLookup(s_texture, v_texCoord); float nonZeroAlpha = max(texColor.a, 0.00001); texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha); texColor = colorMatrix * texColor + colorOffset; @@ -1346,7 +1288,7 @@ std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderString( TexCoordPrecision vec2 maskTexCoord = vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x, maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y); - vec4 maskColor = texture2D(s_mask, maskTexCoord); + vec4 maskColor = TextureLookup(s_mask, maskTexCoord); gl_FragColor = texColor * alpha * maskColor.w; } ); // NOLINT(whitespace/parens) @@ -1360,9 +1302,8 @@ FragmentShaderYUVVideo::FragmentShaderYUVVideo() yuv_matrix_location_(-1), yuv_adj_location_(-1) {} -void FragmentShaderYUVVideo::Init(WebGraphicsContext3D* context, +void FragmentShaderYUVVideo::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "y_texture", @@ -1379,7 +1320,6 @@ void FragmentShaderYUVVideo::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); y_texture_location_ = locations[0]; u_texture_location_ = locations[1]; @@ -1390,21 +1330,21 @@ void FragmentShaderYUVVideo::Init(WebGraphicsContext3D* context, } std::string FragmentShaderYUVVideo::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; precision mediump int; varying TexCoordPrecision vec2 v_texCoord; - uniform sampler2D y_texture; - uniform sampler2D u_texture; - uniform sampler2D v_texture; + uniform SamplerType y_texture; + uniform SamplerType u_texture; + uniform SamplerType v_texture; uniform float alpha; uniform vec3 yuv_adj; uniform mat3 yuv_matrix; void main() { - float y_raw = texture2D(y_texture, v_texCoord).x; - float u_unsigned = texture2D(u_texture, v_texCoord).x; - float v_unsigned = texture2D(v_texture, v_texCoord).x; + float y_raw = TextureLookup(y_texture, v_texCoord).x; + float u_unsigned = TextureLookup(u_texture, v_texCoord).x; + float v_unsigned = TextureLookup(v_texture, v_texCoord).x; vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj; vec3 rgb = yuv_matrix * yuv; gl_FragColor = vec4(rgb, 1.0) * alpha; @@ -1422,9 +1362,8 @@ FragmentShaderYUVAVideo::FragmentShaderYUVAVideo() yuv_adj_location_(-1) { } -void FragmentShaderYUVAVideo::Init(WebGraphicsContext3D* context, +void FragmentShaderYUVAVideo::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "y_texture", @@ -1442,7 +1381,6 @@ void FragmentShaderYUVAVideo::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); y_texture_location_ = locations[0]; u_texture_location_ = locations[1]; @@ -1454,23 +1392,23 @@ void FragmentShaderYUVAVideo::Init(WebGraphicsContext3D* context, } std::string FragmentShaderYUVAVideo::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; precision mediump int; varying TexCoordPrecision vec2 v_texCoord; - uniform sampler2D y_texture; - uniform sampler2D u_texture; - uniform sampler2D v_texture; - uniform sampler2D a_texture; + uniform SamplerType y_texture; + uniform SamplerType u_texture; + uniform SamplerType v_texture; + uniform SamplerType a_texture; uniform float alpha; uniform vec3 yuv_adj; uniform mat3 yuv_matrix; void main() { - float y_raw = texture2D(y_texture, v_texCoord).x; - float u_unsigned = texture2D(u_texture, v_texCoord).x; - float v_unsigned = texture2D(v_texture, v_texCoord).x; - float a_raw = texture2D(a_texture, v_texCoord).x; + float y_raw = TextureLookup(y_texture, v_texCoord).x; + float u_unsigned = TextureLookup(u_texture, v_texCoord).x; + float v_unsigned = TextureLookup(v_texture, v_texCoord).x; + float a_raw = TextureLookup(a_texture, v_texCoord).x; vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj; vec3 rgb = yuv_matrix * yuv; gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw); @@ -1481,9 +1419,8 @@ std::string FragmentShaderYUVAVideo::GetShaderString( FragmentShaderColor::FragmentShaderColor() : color_location_(-1) {} -void FragmentShaderColor::Init(WebGraphicsContext3D* context, +void FragmentShaderColor::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "color", @@ -1495,13 +1432,12 @@ void FragmentShaderColor::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); color_location_ = locations[0]; } std::string FragmentShaderColor::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; uniform vec4 color; @@ -1514,9 +1450,8 @@ std::string FragmentShaderColor::GetShaderString( FragmentShaderColorAA::FragmentShaderColorAA() : color_location_(-1) {} -void FragmentShaderColorAA::Init(WebGraphicsContext3D* context, +void FragmentShaderColorAA::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "color", @@ -1528,13 +1463,12 @@ void FragmentShaderColorAA::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); color_location_ = locations[0]; } std::string FragmentShaderColorAA::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { return FRAGMENT_SHADER( precision mediump float; uniform vec4 color; @@ -1554,9 +1488,8 @@ FragmentShaderCheckerboard::FragmentShaderCheckerboard() tex_transform_location_(-1), frequency_location_(-1) {} -void FragmentShaderCheckerboard::Init(WebGraphicsContext3D* context, +void FragmentShaderCheckerboard::Init(GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) { static const char* uniforms[] = { "alpha", @@ -1571,7 +1504,6 @@ void FragmentShaderCheckerboard::Init(WebGraphicsContext3D* context, arraysize(uniforms), uniforms, locations, - using_bind_uniform, base_uniform_index); alpha_location_ = locations[0]; tex_transform_location_ = locations[1]; @@ -1580,7 +1512,7 @@ void FragmentShaderCheckerboard::Init(WebGraphicsContext3D* context, } std::string FragmentShaderCheckerboard::GetShaderString( - TexCoordPrecision precision) const { + TexCoordPrecision precision, SamplerType sampler) const { // Shader based on Example 13-17 of "OpenGL ES 2.0 Programming Guide" // by Munshi, Ginsburg, Shreiner. return FRAGMENT_SHADER( diff --git a/chromium/cc/output/shader.h b/chromium/cc/output/shader.h index 7135befd389..9473ce8da38 100644 --- a/chromium/cc/output/shader.h +++ b/chromium/cc/output/shader.h @@ -16,14 +16,27 @@ class Point; class Size; } -namespace WebKit { class WebGraphicsContext3D; } +namespace gpu { +namespace gles2 { +class GLES2Interface; +} +} namespace cc { enum TexCoordPrecision { - TexCoordPrecisionNA, - TexCoordPrecisionMedium, - TexCoordPrecisionHigh, + TexCoordPrecisionNA = 0, + TexCoordPrecisionMedium = 1, + TexCoordPrecisionHigh = 2, + NumTexCoordPrecisions = 3 +}; + +enum SamplerType { + SamplerTypeNA = 0, + SamplerType2D = 1, + SamplerType2DRect = 2, + SamplerTypeExternalOES = 3, + NumSamplerTypes = 4 }; // Note: The highp_threshold_cache must be provided by the caller to make @@ -31,13 +44,13 @@ enum TexCoordPrecision { // The caller must make sure to clear highp_threshold_cache to 0, so it can be // reinitialized, if a new or different context is used. CC_EXPORT TexCoordPrecision TexCoordPrecisionRequired( - WebKit::WebGraphicsContext3D* context, + gpu::gles2::GLES2Interface* context, int *highp_threshold_cache, int highp_threshold_min, gfx::Point max_coordinate); CC_EXPORT TexCoordPrecision TexCoordPrecisionRequired( - WebKit::WebGraphicsContext3D* context, + gpu::gles2::GLES2Interface* context, int *highp_threshold_cache, int highp_threshold_min, gfx::Size max_size); @@ -46,9 +59,8 @@ class VertexShaderPosTex { public: VertexShaderPosTex(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -64,9 +76,8 @@ class VertexShaderPosTexYUVStretch { public: VertexShaderPosTexYUVStretch(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -84,9 +95,8 @@ class VertexShaderPos { public: VertexShaderPos(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -100,9 +110,8 @@ class VertexShaderPos { class VertexShaderPosTexIdentity { public: - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index) {} std::string GetShaderString() const; }; @@ -111,9 +120,8 @@ class VertexShaderPosTexTransform { public: VertexShaderPosTexTransform(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -133,9 +141,8 @@ class VertexShaderQuad { public: VertexShaderQuad(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -155,9 +162,8 @@ class VertexShaderQuadAA { public: VertexShaderQuadAA(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -180,9 +186,8 @@ class VertexShaderQuadTexTransformAA { public: VertexShaderQuadTexTransformAA(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -206,9 +211,8 @@ class VertexShaderTile { public: VertexShaderTile(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -232,9 +236,8 @@ class VertexShaderTileAA { public: VertexShaderTileAA(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -260,9 +263,8 @@ class VertexShaderVideoTransform { public: VertexShaderVideoTransform(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -280,9 +282,8 @@ class FragmentTexAlphaBinding { public: FragmentTexAlphaBinding(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int alpha_location() const { return alpha_location_; } int fragment_tex_transform_location() const { return -1; } @@ -299,10 +300,9 @@ class FragmentTexColorMatrixAlphaBinding { public: FragmentTexColorMatrixAlphaBinding(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool usingBindUniform, - int* baseUniformIndex); + int* base_uniform_index); int alpha_location() const { return alpha_location_; } int color_matrix_location() const { return color_matrix_location_; } int color_offset_location() const { return color_offset_location_; } @@ -320,9 +320,8 @@ class FragmentTexOpaqueBinding { public: FragmentTexOpaqueBinding(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int alpha_location() const { return -1; } int fragment_tex_transform_location() const { return -1; } @@ -339,9 +338,8 @@ class FragmentTexBackgroundBinding { public: FragmentTexBackgroundBinding(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int background_color_location() const { return background_color_location_; } int sampler_location() const { return sampler_location_; } @@ -355,89 +353,78 @@ class FragmentTexBackgroundBinding { class FragmentShaderRGBATexVaryingAlpha : public FragmentTexOpaqueBinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; class FragmentShaderRGBATexPremultiplyAlpha : public FragmentTexOpaqueBinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; class FragmentShaderTexBackgroundVaryingAlpha : public FragmentTexBackgroundBinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; class FragmentShaderTexBackgroundPremultiplyAlpha : public FragmentTexBackgroundBinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; class FragmentShaderRGBATexAlpha : public FragmentTexAlphaBinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; class FragmentShaderRGBATexColorMatrixAlpha : public FragmentTexColorMatrixAlphaBinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; -}; - -class FragmentShaderRGBATexRectVaryingAlpha : public FragmentTexOpaqueBinding { - public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; class FragmentShaderRGBATexOpaque : public FragmentTexOpaqueBinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; class FragmentShaderRGBATex : public FragmentTexOpaqueBinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; // Swizzles the red and blue component of sampled texel with alpha. class FragmentShaderRGBATexSwizzleAlpha : public FragmentTexAlphaBinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; // Swizzles the red and blue component of sampled texel without alpha. class FragmentShaderRGBATexSwizzleOpaque : public FragmentTexOpaqueBinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; -}; - -// Fragment shader for external textures. -class FragmentShaderOESImageExternal : public FragmentTexAlphaBinding { - public: - FragmentShaderOESImageExternal(); - - std::string GetShaderString(TexCoordPrecision precision) const; - void Init(WebKit::WebGraphicsContext3D* context, - unsigned program, - bool using_bind_uniform, - int* base_uniform_index); - private: - int sampler_location_; - - DISALLOW_COPY_AND_ASSIGN(FragmentShaderOESImageExternal); + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; class FragmentShaderRGBATexAlphaAA { public: FragmentShaderRGBATexAlphaAA(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; int alpha_location() const { return alpha_location_; } int sampler_location() const { return sampler_location_; } @@ -453,9 +440,8 @@ class FragmentTexClampAlphaAABinding { public: FragmentTexClampAlphaAABinding(); - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int alpha_location() const { return alpha_location_; } int sampler_location() const { return sampler_location_; } @@ -474,24 +460,26 @@ class FragmentTexClampAlphaAABinding { class FragmentShaderRGBATexClampAlphaAA : public FragmentTexClampAlphaAABinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; // Swizzles the red and blue component of sampled texel. class FragmentShaderRGBATexClampSwizzleAlphaAA : public FragmentTexClampAlphaAABinding { public: - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; }; class FragmentShaderRGBATexAlphaMask { public: FragmentShaderRGBATexAlphaMask(); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int alpha_location() const { return alpha_location_; } int sampler_location() const { return sampler_location_; } @@ -516,11 +504,11 @@ class FragmentShaderRGBATexAlphaMask { class FragmentShaderRGBATexAlphaMaskAA { public: FragmentShaderRGBATexAlphaMaskAA(); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int alpha_location() const { return alpha_location_; } int sampler_location() const { return sampler_location_; } @@ -545,11 +533,11 @@ class FragmentShaderRGBATexAlphaMaskAA { class FragmentShaderRGBATexAlphaMaskColorMatrixAA { public: FragmentShaderRGBATexAlphaMaskColorMatrixAA(); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int alpha_location() const { return alpha_location_; } int sampler_location() const { return sampler_location_; } @@ -576,11 +564,11 @@ class FragmentShaderRGBATexAlphaMaskColorMatrixAA { class FragmentShaderRGBATexAlphaColorMatrixAA { public: FragmentShaderRGBATexAlphaColorMatrixAA(); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int alpha_location() const { return alpha_location_; } int sampler_location() const { return sampler_location_; } @@ -597,11 +585,11 @@ class FragmentShaderRGBATexAlphaColorMatrixAA { class FragmentShaderRGBATexAlphaMaskColorMatrix { public: FragmentShaderRGBATexAlphaMaskColorMatrix(); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int alpha_location() const { return alpha_location_; } int sampler_location() const { return sampler_location_; } @@ -628,11 +616,11 @@ class FragmentShaderRGBATexAlphaMaskColorMatrix { class FragmentShaderYUVVideo { public: FragmentShaderYUVVideo(); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int y_texture_location() const { return y_texture_location_; } int u_texture_location() const { return u_texture_location_; } @@ -656,11 +644,11 @@ class FragmentShaderYUVVideo { class FragmentShaderYUVAVideo { public: FragmentShaderYUVAVideo(); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int y_texture_location() const { return y_texture_location_; } @@ -686,11 +674,11 @@ class FragmentShaderYUVAVideo { class FragmentShaderColor { public: FragmentShaderColor(); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int color_location() const { return color_location_; } @@ -703,11 +691,11 @@ class FragmentShaderColor { class FragmentShaderColorAA { public: FragmentShaderColorAA(); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int color_location() const { return color_location_; } @@ -720,11 +708,11 @@ class FragmentShaderColorAA { class FragmentShaderCheckerboard { public: FragmentShaderCheckerboard(); - std::string GetShaderString(TexCoordPrecision precision) const; + std::string GetShaderString( + TexCoordPrecision precision, SamplerType sampler) const; - void Init(WebKit::WebGraphicsContext3D* context, + void Init(gpu::gles2::GLES2Interface* context, unsigned program, - bool using_bind_uniform, int* base_uniform_index); int alpha_location() const { return alpha_location_; } int tex_transform_location() const { return tex_transform_location_; } diff --git a/chromium/cc/output/shader_unittest.cc b/chromium/cc/output/shader_unittest.cc index 33cc13cd56c..4aacbf7180f 100644 --- a/chromium/cc/output/shader_unittest.cc +++ b/chromium/cc/output/shader_unittest.cc @@ -4,7 +4,8 @@ #include "cc/output/shader.h" -#include "cc/debug/fake_web_graphics_context_3d.h" +#include "cc/test/test_gles2_interface.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/point.h" #include "ui/gfx/size.h" @@ -12,9 +13,11 @@ namespace cc { TEST(ShaderTest, HighpThresholds) { - // The FakeWebGraphicsContext3D always uses a mediump precision of 10 bits - // which corresponds to a native highp threshold of 2^10 = 1024 - FakeWebGraphicsContext3D context; + // The test context always uses a mediump precision of 10 bits which + // corresponds to a native highp threshold of 2^10 = 1024 + scoped_ptr<TestWebGraphicsContext3D> stub_context = + TestWebGraphicsContext3D::Create(); + TestGLES2Interface stub_gl(stub_context.get()); int threshold_cache = 0; int threshold_min; @@ -25,23 +28,23 @@ TEST(ShaderTest, HighpThresholds) { threshold_min = 0; EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired( - &context, &threshold_cache, threshold_min, closePoint)); + &stub_gl, &threshold_cache, threshold_min, closePoint)); EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired( - &context, &threshold_cache, threshold_min, smallSize)); + &stub_gl, &threshold_cache, threshold_min, smallSize)); EXPECT_EQ(TexCoordPrecisionHigh, TexCoordPrecisionRequired( - &context, &threshold_cache, threshold_min, farPoint)); + &stub_gl, &threshold_cache, threshold_min, farPoint)); EXPECT_EQ(TexCoordPrecisionHigh, TexCoordPrecisionRequired( - &context, &threshold_cache, threshold_min, bigSize)); + &stub_gl, &threshold_cache, threshold_min, bigSize)); threshold_min = 3000; EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired( - &context, &threshold_cache, threshold_min, closePoint)); + &stub_gl, &threshold_cache, threshold_min, closePoint)); EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired( - &context, &threshold_cache, threshold_min, smallSize)); + &stub_gl, &threshold_cache, threshold_min, smallSize)); EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired( - &context, &threshold_cache, threshold_min, farPoint)); + &stub_gl, &threshold_cache, threshold_min, farPoint)); EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired( - &context, &threshold_cache, threshold_min, bigSize)); + &stub_gl, &threshold_cache, threshold_min, bigSize)); } } // namespace cc diff --git a/chromium/cc/output/software_output_device.cc b/chromium/cc/output/software_output_device.cc index 03f977e7426..17ef63f6d57 100644 --- a/chromium/cc/output/software_output_device.cc +++ b/chromium/cc/output/software_output_device.cc @@ -9,6 +9,7 @@ #include "third_party/skia/include/core/SkBitmapDevice.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/skia_util.h" +#include "ui/gfx/vsync_provider.h" namespace cc { @@ -56,4 +57,8 @@ void SoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) { NOTIMPLEMENTED(); } +gfx::VSyncProvider* SoftwareOutputDevice::GetVSyncProvider() { + return vsync_provider_.get(); +} + } // namespace cc diff --git a/chromium/cc/output/software_output_device.h b/chromium/cc/output/software_output_device.h index 9e2de88b048..4ecf1fedd8e 100644 --- a/chromium/cc/output/software_output_device.h +++ b/chromium/cc/output/software_output_device.h @@ -6,6 +6,7 @@ #define CC_OUTPUT_SOFTWARE_OUTPUT_DEVICE_H_ #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" #include "skia/ext/refptr.h" // TODO(robertphillips): change this to "class SkBaseDevice;" @@ -17,6 +18,10 @@ class SkBitmap; class SkCanvas; +namespace gfx { +class VSyncProvider; +} + namespace cc { class SoftwareFrameData; @@ -65,11 +70,16 @@ class CC_EXPORT SoftwareOutputDevice { // displayed. virtual void ReclaimSoftwareFrame(unsigned id); + // VSyncProvider used to update the timer used to schedule draws with the + // hardware vsync. Return NULL if a provider doesn't exist. + virtual gfx::VSyncProvider* GetVSyncProvider(); + protected: gfx::Size viewport_size_; gfx::Rect damage_rect_; skia::RefPtr<SkBaseDevice> device_; skia::RefPtr<SkCanvas> canvas_; + scoped_ptr<gfx::VSyncProvider> vsync_provider_; private: DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDevice); diff --git a/chromium/cc/output/software_renderer.cc b/chromium/cc/output/software_renderer.cc index fa8c178df35..421e541da7d 100644 --- a/chromium/cc/output/software_renderer.cc +++ b/chromium/cc/output/software_renderer.cc @@ -11,6 +11,7 @@ #include "cc/output/compositor_frame_metadata.h" #include "cc/output/copy_output_request.h" #include "cc/output/output_surface.h" +#include "cc/output/render_surface_filters.h" #include "cc/output/software_output_device.h" #include "cc/quads/checkerboard_draw_quad.h" #include "cc/quads/debug_border_draw_quad.h" @@ -48,6 +49,17 @@ bool IsScaleAndIntegerTranslate(const SkMatrix& matrix) { SkScalarNearlyZero(matrix[SkMatrix::kMPersp2] - 1.0f); } +static SkShader::TileMode WrapModeToTileMode(GLint wrap_mode) { + switch (wrap_mode) { + case GL_REPEAT: + return SkShader::kRepeat_TileMode; + case GL_CLAMP_TO_EDGE: + return SkShader::kClamp_TileMode; + } + NOTREACHED(); + return SkShader::kClamp_TileMode; +} + } // anonymous namespace scoped_ptr<SoftwareRenderer> SoftwareRenderer::Create( @@ -74,7 +86,6 @@ SoftwareRenderer::SoftwareRenderer(RendererClient* client, capabilities_.best_texture_format = resource_provider_->best_texture_format(); } - capabilities_.using_set_visibility = true; // The updater can access bitmaps while the SoftwareRenderer is using them. capabilities_.allow_partial_texture_updates = true; capabilities_.using_partial_swap = true; @@ -105,9 +116,9 @@ void SoftwareRenderer::FinishDrawingFrame(DrawingFrame* frame) { output_device_->EndPaint(current_frame_data_.get()); } -void SoftwareRenderer::SwapBuffers() { +void SoftwareRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) { CompositorFrame compositor_frame; - compositor_frame.metadata = client_->MakeCompositorFrameMetadata(); + compositor_frame.metadata = metadata; compositor_frame.software_frame_data = current_frame_data_.Pass(); output_surface_->SwapBuffers(&compositor_frame); } @@ -323,7 +334,8 @@ void SoftwareRenderer::DrawPictureQuad(const DrawingFrame* frame, // cases and fall back to a persistent bitmap backing // (http://crbug.com/280374). skia::RefPtr<SkDrawFilter> opacity_filter = - skia::AdoptRef(new skia::OpacityDrawFilter(quad->opacity(), true)); + skia::AdoptRef(new skia::OpacityDrawFilter( + quad->opacity(), frame->disable_picture_quad_image_filtering)); DCHECK(!current_canvas_->getDrawFilter()); current_canvas_->setDrawFilter(opacity_filter.get()); @@ -382,11 +394,23 @@ void SoftwareRenderer::DrawTextureQuad(const DrawingFrame* frame, background_paint.setColor(quad->background_color); current_canvas_->drawRect(quad_rect, background_paint); } - - current_canvas_->drawBitmapRectToRect(*bitmap, - &sk_uv_rect, - quad_rect, - ¤t_paint_); + SkShader::TileMode tile_mode = WrapModeToTileMode(lock.wrap_mode()); + if (tile_mode != SkShader::kClamp_TileMode) { + SkMatrix matrix; + matrix.setRectToRect(sk_uv_rect, quad_rect, SkMatrix::kFill_ScaleToFit); + skia::RefPtr<SkShader> shader = skia::AdoptRef( + SkShader::CreateBitmapShader(*bitmap, tile_mode, tile_mode)); + shader->setLocalMatrix(matrix); + SkPaint paint; + paint.setStyle(SkPaint::kFill_Style); + paint.setShader(shader.get()); + current_canvas_->drawRect(quad_rect, paint); + } else { + current_canvas_->drawBitmapRectToRect(*bitmap, + &sk_uv_rect, + quad_rect, + ¤t_paint_); + } if (needs_layer) current_canvas_->restore(); @@ -396,8 +420,11 @@ void SoftwareRenderer::DrawTileQuad(const DrawingFrame* frame, const TileDrawQuad* quad) { DCHECK(!output_surface_->ForcedDrawToSoftwareDevice()); DCHECK(IsSoftwareResource(quad->resource_id)); + ResourceProvider::ScopedReadLockSoftware lock(resource_provider_, quad->resource_id); + DCHECK_EQ(GL_CLAMP_TO_EDGE, lock.wrap_mode()); + gfx::RectF visible_tex_coord_rect = MathUtil::ScaleRectProportional( quad->tex_coord_rect, quad->rect, quad->visible_rect); gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional( @@ -414,7 +441,7 @@ void SoftwareRenderer::DrawTileQuad(const DrawingFrame* frame, void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, const RenderPassDrawQuad* quad) { - CachedResource* content_texture = + ScopedResource* content_texture = render_pass_textures_.get(quad->render_pass_id); if (!content_texture || !content_texture->id()) return; @@ -422,6 +449,7 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, DCHECK(IsSoftwareResource(content_texture->id())); ResourceProvider::ScopedReadLockSoftware lock(resource_provider_, content_texture->id()); + SkShader::TileMode content_tile_mode = WrapModeToTileMode(lock.wrap_mode()); SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect()); SkRect dest_visible_rect = gfx::RectFToSkRect(MathUtil::ScaleRectProportional( @@ -433,20 +461,51 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, SkMatrix::kFill_ScaleToFit); const SkBitmap* content = lock.sk_bitmap(); - skia::RefPtr<SkShader> shader = skia::AdoptRef( - SkShader::CreateBitmapShader(*content, - SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode)); + + SkBitmap filter_bitmap; + if (!quad->filters.IsEmpty()) { + skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( + quad->filters, content_texture->size()); + // TODO(ajuma): In addition origin translation, the canvas should also be + // scaled to accomodate device pixel ratio and pinch zoom. See + // crbug.com/281516 and crbug.com/281518. + // TODO(ajuma): Apply the filter in the same pass as the content where + // possible (e.g. when there's no origin offset). See crbug.com/308201. + if (filter) { + bool is_opaque = false; + skia::RefPtr<SkBaseDevice> device = + skia::AdoptRef(new SkBitmapDevice(SkBitmap::kARGB_8888_Config, + content_texture->size().width(), + content_texture->size().height(), + is_opaque)); + SkCanvas canvas(device.get()); + SkPaint paint; + paint.setImageFilter(filter.get()); + canvas.clear(SK_ColorTRANSPARENT); + canvas.translate(SkIntToScalar(-quad->rect.origin().x()), + SkIntToScalar(-quad->rect.origin().y())); + canvas.drawSprite(*content, 0, 0, &paint); + bool will_change_pixels = false; + filter_bitmap = device->accessBitmap(will_change_pixels); + } + } + + skia::RefPtr<SkShader> shader; + if (filter_bitmap.isNull()) { + shader = skia::AdoptRef(SkShader::CreateBitmapShader( + *content, content_tile_mode, content_tile_mode)); + } else { + shader = skia::AdoptRef(SkShader::CreateBitmapShader( + filter_bitmap, content_tile_mode, content_tile_mode)); + } shader->setLocalMatrix(content_mat); current_paint_.setShader(shader.get()); - SkImageFilter* filter = quad->filter.get(); - if (filter) - current_paint_.setImageFilter(filter); - if (quad->mask_resource_id) { ResourceProvider::ScopedReadLockSoftware mask_lock(resource_provider_, quad->mask_resource_id); + SkShader::TileMode mask_tile_mode = WrapModeToTileMode( + mask_lock.wrap_mode()); const SkBitmap* mask = mask_lock.sk_bitmap(); @@ -460,9 +519,7 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, mask_mat.setRectToRect(mask_rect, dest_rect, SkMatrix::kFill_ScaleToFit); skia::RefPtr<SkShader> mask_shader = skia::AdoptRef( - SkShader::CreateBitmapShader(*mask, - SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode)); + SkShader::CreateBitmapShader(*mask, mask_tile_mode, mask_tile_mode)); mask_shader->setLocalMatrix(mask_mat); SkPaint mask_paint; @@ -551,8 +608,4 @@ void SoftwareRenderer::SetVisible(bool visible) { DiscardBackbuffer(); } -void SoftwareRenderer::SetDiscardBackBufferWhenNotVisible(bool discard) { - // The software renderer always discards the backbuffer when not visible. -} - } // namespace cc diff --git a/chromium/cc/output/software_renderer.h b/chromium/cc/output/software_renderer.h index 5a8780e043c..18fb2a3fc33 100644 --- a/chromium/cc/output/software_renderer.h +++ b/chromium/cc/output/software_renderer.h @@ -36,7 +36,7 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer { virtual ~SoftwareRenderer(); virtual const RendererCapabilities& Capabilities() const OVERRIDE; virtual void Finish() OVERRIDE; - virtual void SwapBuffers() OVERRIDE; + virtual void SwapBuffers(const CompositorFrameMetadata& metadata) OVERRIDE; virtual void GetFramebufferPixels(void* pixels, gfx::Rect rect) OVERRIDE; virtual void SetVisible(bool visible) OVERRIDE; virtual void SendManagedMemoryStats( @@ -45,7 +45,6 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer { size_t bytes_allocated) OVERRIDE {} virtual void ReceiveSwapBuffersAck( const CompositorFrameAck& ack) OVERRIDE; - virtual void SetDiscardBackBufferWhenNotVisible(bool discard) OVERRIDE; virtual void DiscardBackbuffer() OVERRIDE; virtual void EnsureBackbuffer() OVERRIDE; diff --git a/chromium/cc/output/software_renderer_unittest.cc b/chromium/cc/output/software_renderer_unittest.cc index 03f1635084b..fc1c7070cb4 100644 --- a/chromium/cc/output/software_renderer_unittest.cc +++ b/chromium/cc/output/software_renderer_unittest.cc @@ -34,7 +34,7 @@ class SoftwareRendererTest : public testing::Test, public RendererClient { CHECK(output_surface_->BindToClient(&output_surface_client_)); resource_provider_ = - ResourceProvider::Create(output_surface_.get(), 0, false); + ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1); renderer_ = SoftwareRenderer::Create( this, &settings_, output_surface_.get(), resource_provider()); } @@ -45,19 +45,8 @@ class SoftwareRendererTest : public testing::Test, public RendererClient { SoftwareRenderer* renderer() const { return renderer_.get(); } - void set_viewport(gfx::Rect viewport) { - viewport_ = viewport; - } - // RendererClient implementation. - virtual gfx::Rect DeviceViewport() const OVERRIDE { - return viewport_; - } - virtual gfx::Rect DeviceClip() const OVERRIDE { return DeviceViewport(); } virtual void SetFullRootLayerDamage() OVERRIDE {} - virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const OVERRIDE { - return CompositorFrameMetadata(); - } protected: LayerTreeSettings settings_; @@ -65,7 +54,6 @@ class SoftwareRendererTest : public testing::Test, public RendererClient { scoped_ptr<FakeOutputSurface> output_surface_; scoped_ptr<ResourceProvider> resource_provider_; scoped_ptr<SoftwareRenderer> renderer_; - gfx::Rect viewport_; }; TEST_F(SoftwareRendererTest, SolidColorQuad) { @@ -74,13 +62,17 @@ TEST_F(SoftwareRendererTest, SolidColorQuad) { gfx::Rect outer_rect(outer_size); gfx::Rect inner_rect(gfx::Point(1, 1), inner_size); gfx::Rect visible_rect(gfx::Point(1, 2), gfx::Size(98, 97)); - set_viewport(gfx::Rect(outer_size)); InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create(); - shared_quad_state->SetAll( - gfx::Transform(), outer_size, outer_rect, outer_rect, false, 1.0); + shared_quad_state->SetAll(gfx::Transform(), + outer_size, + outer_rect, + outer_rect, + false, + 1.0, + SkXfermode::kSrcOver_Mode); RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1); scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); root_render_pass->SetNew( @@ -98,12 +90,18 @@ TEST_F(SoftwareRendererTest, SolidColorQuad) { list.push_back(root_render_pass.PassAs<RenderPass>()); float device_scale_factor = 1.f; - renderer()->DrawFrame(&list, NULL, device_scale_factor, true); + gfx::Rect device_viewport_rect(outer_size); + renderer()->DrawFrame(&list, + NULL, + device_scale_factor, + device_viewport_rect, + device_viewport_rect, + true, + false); SkBitmap output; - output.setConfig(SkBitmap::kARGB_8888_Config, - DeviceViewport().width(), - DeviceViewport().height()); + output.setConfig( + SkBitmap::kARGB_8888_Config, outer_rect.width(), outer_rect.height()); output.allocPixels(); renderer()->GetFramebufferPixels(output.getPixels(), outer_rect); @@ -121,7 +119,6 @@ TEST_F(SoftwareRendererTest, TileQuad) { gfx::Size inner_size(98, 98); gfx::Rect outer_rect(outer_size); gfx::Rect inner_rect(gfx::Point(1, 1), inner_size); - set_viewport(gfx::Rect(outer_size)); InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); ResourceProvider::ResourceId resource_yellow = @@ -159,11 +156,16 @@ TEST_F(SoftwareRendererTest, TileQuad) { gfx::Rect(inner_size), gfx::Vector2d()); - gfx::Rect root_rect = DeviceViewport(); + gfx::Rect root_rect = outer_rect; scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create(); - shared_quad_state->SetAll( - gfx::Transform(), outer_size, outer_rect, outer_rect, false, 1.0); + shared_quad_state->SetAll(gfx::Transform(), + outer_size, + outer_rect, + outer_rect, + false, + 1.0, + SkXfermode::kSrcOver_Mode); RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1); scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); root_render_pass->SetNew( @@ -191,12 +193,18 @@ TEST_F(SoftwareRendererTest, TileQuad) { list.push_back(root_render_pass.PassAs<RenderPass>()); float device_scale_factor = 1.f; - renderer()->DrawFrame(&list, NULL, device_scale_factor, true); + gfx::Rect device_viewport_rect(outer_size); + renderer()->DrawFrame(&list, + NULL, + device_scale_factor, + device_viewport_rect, + device_viewport_rect, + true, + false); SkBitmap output; - output.setConfig(SkBitmap::kARGB_8888_Config, - DeviceViewport().width(), - DeviceViewport().height()); + output.setConfig( + SkBitmap::kARGB_8888_Config, outer_size.width(), outer_size.height()); output.allocPixels(); renderer()->GetFramebufferPixels(output.getPixels(), outer_rect); @@ -213,7 +221,6 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) { gfx::Rect tile_rect(tile_size); gfx::Rect visible_rect = tile_rect; visible_rect.Inset(1, 2, 3, 4); - set_viewport(gfx::Rect(tile_size)); InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); ResourceProvider::ResourceId resource_cyan = @@ -238,11 +245,16 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) { gfx::Rect(tile_size), gfx::Vector2d()); - gfx::Rect root_rect = DeviceViewport(); + gfx::Rect root_rect(tile_size); scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create(); - shared_quad_state->SetAll( - gfx::Transform(), tile_size, tile_rect, tile_rect, false, 1.0); + shared_quad_state->SetAll(gfx::Transform(), + tile_size, + tile_rect, + tile_rect, + false, + 1.0, + SkXfermode::kSrcOver_Mode); RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1); scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); root_render_pass->SetNew( @@ -262,12 +274,18 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) { list.push_back(root_render_pass.PassAs<RenderPass>()); float device_scale_factor = 1.f; - renderer()->DrawFrame(&list, NULL, device_scale_factor, true); + gfx::Rect device_viewport_rect(tile_size); + renderer()->DrawFrame(&list, + NULL, + device_scale_factor, + device_viewport_rect, + device_viewport_rect, + true, + false); SkBitmap output; - output.setConfig(SkBitmap::kARGB_8888_Config, - DeviceViewport().width(), - DeviceViewport().height()); + output.setConfig( + SkBitmap::kARGB_8888_Config, tile_size.width(), tile_size.height()); output.allocPixels(); renderer()->GetFramebufferPixels(output.getPixels(), tile_rect); @@ -294,7 +312,6 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) { TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) { float device_scale_factor = 1.f; gfx::Rect viewport_rect(0, 0, 100, 100); - set_viewport(viewport_rect); settings_.should_clear_root_render_pass = false; InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); @@ -314,7 +331,13 @@ TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) { AddQuad(root_clear_pass, viewport_rect, SK_ColorGREEN); renderer()->DecideRenderPassAllocationsForFrame(list); - renderer()->DrawFrame(&list, NULL, device_scale_factor, true); + renderer()->DrawFrame(&list, + NULL, + device_scale_factor, + viewport_rect, + viewport_rect, + true, + false); renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect); EXPECT_EQ(SK_ColorGREEN, output.getColor(0, 0)); @@ -333,7 +356,13 @@ TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) { AddQuad(root_smaller_pass, smaller_rect, SK_ColorMAGENTA); renderer()->DecideRenderPassAllocationsForFrame(list); - renderer()->DrawFrame(&list, NULL, device_scale_factor, true); + renderer()->DrawFrame(&list, + NULL, + device_scale_factor, + viewport_rect, + viewport_rect, + true, + false); renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect); // If we didn't clear, the borders should still be green. @@ -350,7 +379,6 @@ TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) { TEST_F(SoftwareRendererTest, RenderPassVisibleRect) { float device_scale_factor = 1.f; gfx::Rect viewport_rect(0, 0, 100, 100); - set_viewport(viewport_rect); InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); RenderPassList list; @@ -380,7 +408,13 @@ TEST_F(SoftwareRendererTest, RenderPassVisibleRect) { root_clear_pass->quad_list[0]->visible_rect = interior_visible_rect; renderer()->DecideRenderPassAllocationsForFrame(list); - renderer()->DrawFrame(&list, NULL, device_scale_factor, true); + renderer()->DrawFrame(&list, + NULL, + device_scale_factor, + viewport_rect, + viewport_rect, + true, + false); renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect); EXPECT_EQ(SK_ColorGREEN, output.getColor(0, 0)); diff --git a/chromium/cc/quads/draw_quad.cc b/chromium/cc/quads/draw_quad.cc index 0d021d92083..f3cd8189545 100644 --- a/chromium/cc/quads/draw_quad.cc +++ b/chromium/cc/quads/draw_quad.cc @@ -40,6 +40,13 @@ void DrawQuad::SetAll(const SharedQuadState* shared_quad_state, gfx::Rect opaque_rect, gfx::Rect visible_rect, bool needs_blending) { + DCHECK(rect.Contains(visible_rect)) << "rect: " << rect.ToString() + << " visible_rect: " + << visible_rect.ToString(); + DCHECK(opaque_rect.IsEmpty() || rect.Contains(opaque_rect)) + << "rect: " << rect.ToString() << "opaque_rect " + << opaque_rect.ToString(); + this->material = material; this->rect = rect; this->opaque_rect = opaque_rect; diff --git a/chromium/cc/quads/draw_quad_unittest.cc b/chromium/cc/quads/draw_quad_unittest.cc index 5705ce7bf24..876c0461b37 100644 --- a/chromium/cc/quads/draw_quad_unittest.cc +++ b/chromium/cc/quads/draw_quad_unittest.cc @@ -36,6 +36,7 @@ TEST(DrawQuadTest, CopySharedQuadState) { gfx::Rect clip_rect(19, 21, 23, 25); bool is_clipped = true; float opacity = 0.25f; + SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode; scoped_ptr<SharedQuadState> state(SharedQuadState::Create()); state->SetAll(quad_transform, @@ -43,7 +44,8 @@ TEST(DrawQuadTest, CopySharedQuadState) { visible_content_rect, clip_rect, is_clipped, - opacity); + opacity, + blend_mode); scoped_ptr<SharedQuadState> copy(state->Copy()); EXPECT_EQ(quad_transform, copy->content_to_target_transform); @@ -51,6 +53,7 @@ TEST(DrawQuadTest, CopySharedQuadState) { EXPECT_EQ(opacity, copy->opacity); EXPECT_RECT_EQ(clip_rect, copy->clip_rect); EXPECT_EQ(is_clipped, copy->is_clipped); + EXPECT_EQ(blend_mode, copy->blend_mode); } scoped_ptr<SharedQuadState> CreateSharedQuadState() { @@ -60,6 +63,7 @@ scoped_ptr<SharedQuadState> CreateSharedQuadState() { gfx::Rect clip_rect(19, 21, 23, 25); bool is_clipped = false; float opacity = 1.f; + SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode; scoped_ptr<SharedQuadState> state(SharedQuadState::Create()); state->SetAll(quad_transform, @@ -67,7 +71,8 @@ scoped_ptr<SharedQuadState> CreateSharedQuadState() { visible_content_rect, clip_rect, is_clipped, - opacity); + opacity, + blend_mode); return state.Pass(); } @@ -249,6 +254,24 @@ void CompareDrawQuad(DrawQuad* quad, } \ SETUP_AND_COPY_QUAD_ALL(Type, quad_all); +#define CREATE_QUAD_7_NEW_1(Type, a, b, c, d, e, f, g, copy_a) \ + scoped_ptr<Type> quad_new(Type::Create()); \ + { \ + QUAD_DATA \ + quad_new->SetNew(shared_state.get(), quad_rect, a, b, c, d, e, f, g); \ + } \ + SETUP_AND_COPY_QUAD_NEW_1(Type, quad_new, copy_a); + +#define CREATE_QUAD_7_ALL_1(Type, a, b, c, d, e, f, g, copy_a) \ + scoped_ptr<Type> quad_all(Type::Create()); \ + { \ + QUAD_DATA \ + quad_all->SetAll(shared_state.get(), quad_rect, quad_opaque_rect, \ + quad_visible_rect, needs_blending, \ + a, b, c, d, e, f, g); \ + } \ + SETUP_AND_COPY_QUAD_ALL_1(Type, quad_all, copy_a); + #define CREATE_QUAD_8_NEW(Type, a, b, c, d, e, f, g, h) \ scoped_ptr<Type> quad_new(Type::Create()); \ { \ @@ -334,7 +357,7 @@ TEST(DrawQuadTest, CopyDebugBorderDrawQuad) { } TEST(DrawQuadTest, CopyIOSurfaceDrawQuad) { - gfx::Rect opaque_rect(3, 7, 10, 12); + gfx::Rect opaque_rect(33, 47, 10, 12); gfx::Size size(58, 95); ResourceProvider::ResourceId resource_id = 72; IOSurfaceDrawQuad::Orientation orientation = IOSurfaceDrawQuad::UNFLIPPED; @@ -366,20 +389,17 @@ TEST(DrawQuadTest, CopyRenderPassDrawQuad) { FilterOperations background_filters; background_filters.Append( FilterOperation::CreateGrayscaleFilter(1.f)); - skia::RefPtr<SkImageFilter> filter = - skia::AdoptRef(new SkBlurImageFilter(SK_Scalar1, SK_Scalar1)); RenderPass::Id copied_render_pass_id(235, 11); CREATE_SHARED_STATE(); - CREATE_QUAD_8_NEW_1(RenderPassDrawQuad, + CREATE_QUAD_7_NEW_1(RenderPassDrawQuad, render_pass_id, is_replica, mask_resource_id, contents_changed_since_last_frame, mask_u_v_rect, filters, - filter, background_filters, copied_render_pass_id); EXPECT_EQ(DrawQuad::RENDER_PASS, copy_quad->material); @@ -390,17 +410,15 @@ TEST(DrawQuadTest, CopyRenderPassDrawQuad) { copy_quad->contents_changed_since_last_frame); EXPECT_EQ(mask_u_v_rect.ToString(), copy_quad->mask_uv_rect.ToString()); EXPECT_EQ(filters, copy_quad->filters); - EXPECT_EQ(filter, copy_quad->filter); EXPECT_EQ(background_filters, copy_quad->background_filters); - CREATE_QUAD_8_ALL_1(RenderPassDrawQuad, + CREATE_QUAD_7_ALL_1(RenderPassDrawQuad, render_pass_id, is_replica, mask_resource_id, contents_changed_since_last_frame, mask_u_v_rect, filters, - filter, background_filters, copied_render_pass_id); EXPECT_EQ(DrawQuad::RENDER_PASS, copy_quad->material); @@ -411,7 +429,6 @@ TEST(DrawQuadTest, CopyRenderPassDrawQuad) { copy_quad->contents_changed_since_last_frame); EXPECT_EQ(mask_u_v_rect.ToString(), copy_quad->mask_uv_rect.ToString()); EXPECT_EQ(filters, copy_quad->filters); - EXPECT_EQ(filter, copy_quad->filter); EXPECT_EQ(background_filters, copy_quad->background_filters); } @@ -432,7 +449,7 @@ TEST(DrawQuadTest, CopySolidColorDrawQuad) { } TEST(DrawQuadTest, CopyStreamVideoDrawQuad) { - gfx::Rect opaque_rect(3, 7, 10, 12); + gfx::Rect opaque_rect(33, 47, 10, 12); ResourceProvider::ResourceId resource_id = 64; gfx::Transform matrix = gfx::Transform(0.5, 0.25, 1, 0.75, 0, 1); CREATE_SHARED_STATE(); @@ -450,7 +467,7 @@ TEST(DrawQuadTest, CopyStreamVideoDrawQuad) { } TEST(DrawQuadTest, CopyTextureDrawQuad) { - gfx::Rect opaque_rect(3, 7, 10, 12); + gfx::Rect opaque_rect(33, 47, 10, 12); unsigned resource_id = 82; bool premultiplied_alpha = true; gfx::PointF uv_top_left(0.5f, 224.f); @@ -494,102 +511,6 @@ TEST(DrawQuadTest, CopyTextureDrawQuad) { EXPECT_EQ(flipped, copy_quad->flipped); } -TEST(DrawQuadTest, ClipTextureDrawQuad) { - gfx::Rect opaque_rect(3, 7, 10, 12); - unsigned resource_id = 82; - bool premultiplied_alpha = true; - bool flipped = true; - CREATE_SHARED_STATE(); - // The original quad position is (30, 40) its size is 50*60. - shared_state->content_to_target_transform = - gfx::Transform(1.f, 0.f, 0.f, 1.f, 10.f, 20.f); - // After transformation, the quad position is (40, 60) its size is 50*60. - shared_state->clip_rect = gfx::Rect(50, 70, 30, 20); - - // The original quad is 'ABCD', the clipped quad is 'abcd': - // 40 50 90 - // B--:-------C 60 - // | b----c -|-70 - // | | | | - // | a----d -|-90 - // | | - // A----------D 120 - // UV and vertex opacity are stored per vertex on the parent rectangle 'ABCD'. - - // This is the UV value for vertex 'B'. - gfx::PointF uv_top_left(0.1f, 0.2f); - // This is the UV value for vertex 'D'. - gfx::PointF uv_bottom_right(0.9f, 0.8f); - // This the vertex opacity for the vertices 'ABCD'. - const float vertex_opacity[] = { 0.3f, 0.4f, 0.7f, 0.8f }; - { - CREATE_QUAD_8_NEW(TextureDrawQuad, - opaque_rect, - resource_id, - premultiplied_alpha, - uv_top_left, - uv_bottom_right, - SK_ColorTRANSPARENT, - vertex_opacity, - flipped); - CREATE_QUAD_7_ALL(TextureDrawQuad, - resource_id, - premultiplied_alpha, - uv_top_left, - uv_bottom_right, - SK_ColorTRANSPARENT, - vertex_opacity, - flipped); - EXPECT_TRUE(quad_all->PerformClipping()); - - // This is the expected UV value for vertex 'b'. - // uv(b) = uv(B) + (Bb / BD) * (uv(D) - uv(B)) - // 0.3 = 0.2 + (10 / 60) * (0.8 - 0.2) - gfx::PointF uv_top_left_clipped(0.26f, 0.3f); - // This is the expected UV value for vertex 'd'. - // uv(d) = uv(B) + (Bd / BD) * (uv(D) - uv(B)) - gfx::PointF uv_bottom_right_clipped(0.74f, 0.5f); - // This the expected vertex opacity for the vertices 'abcd'. - // They are computed with a bilinear interpolation of the corner values. - const float vertex_opacity_clipped[] = { 0.43f, 0.45f, 0.65f, 0.67f }; - - EXPECT_EQ(uv_top_left_clipped, quad_all->uv_top_left); - EXPECT_EQ(uv_bottom_right_clipped, quad_all->uv_bottom_right); - EXPECT_FLOAT_ARRAY_EQ(vertex_opacity_clipped, quad_all->vertex_opacity, 4); - } - - uv_top_left = gfx::PointF(0.8f, 0.7f); - uv_bottom_right = gfx::PointF(0.2f, 0.1f); - { - CREATE_QUAD_8_NEW(TextureDrawQuad, - opaque_rect, - resource_id, - premultiplied_alpha, - uv_top_left, - uv_bottom_right, - SK_ColorTRANSPARENT, - vertex_opacity, - flipped); - CREATE_QUAD_7_ALL(TextureDrawQuad, - resource_id, - premultiplied_alpha, - uv_top_left, - uv_bottom_right, - SK_ColorTRANSPARENT, - vertex_opacity, - flipped); - EXPECT_TRUE(quad_all->PerformClipping()); - - // This is the expected UV value for vertex 'b'. - gfx::PointF uv_top_left_clipped(0.68f, 0.6f); - // This is the expected UV value for vertex 'd'. - gfx::PointF uv_bottom_right_clipped(0.32f, 0.4f); - - EXPECT_EQ(uv_top_left_clipped, quad_all->uv_top_left); - EXPECT_EQ(uv_bottom_right_clipped, quad_all->uv_bottom_right); - } -} - TEST(DrawQuadTest, CopyTileDrawQuad) { gfx::Rect opaque_rect(33, 44, 22, 33); unsigned resource_id = 104; @@ -624,7 +545,7 @@ TEST(DrawQuadTest, CopyTileDrawQuad) { } TEST(DrawQuadTest, CopyYUVVideoDrawQuad) { - gfx::Rect opaque_rect(3, 7, 10, 12); + gfx::Rect opaque_rect(33, 47, 10, 12); gfx::SizeF tex_scale(0.75f, 0.5f); ResourceProvider::ResourceId y_plane_resource_id = 45; ResourceProvider::ResourceId u_plane_resource_id = 532; @@ -668,18 +589,16 @@ TEST(DrawQuadTest, CopyPictureDrawQuad) { ResourceFormat texture_format = RGBA_8888; gfx::Rect content_rect(30, 40, 20, 30); float contents_scale = 3.141592f; - bool can_draw_direct_to_backbuffer = true; scoped_refptr<PicturePileImpl> picture_pile = PicturePileImpl::Create(); CREATE_SHARED_STATE(); - CREATE_QUAD_8_NEW(PictureDrawQuad, + CREATE_QUAD_7_NEW(PictureDrawQuad, opaque_rect, tex_coord_rect, texture_size, texture_format, content_rect, contents_scale, - can_draw_direct_to_backbuffer, picture_pile); EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material); EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect); @@ -688,17 +607,14 @@ TEST(DrawQuadTest, CopyPictureDrawQuad) { EXPECT_EQ(texture_format, copy_quad->texture_format); EXPECT_RECT_EQ(content_rect, copy_quad->content_rect); EXPECT_EQ(contents_scale, copy_quad->contents_scale); - EXPECT_EQ(can_draw_direct_to_backbuffer, - copy_quad->can_draw_direct_to_backbuffer); EXPECT_EQ(picture_pile, copy_quad->picture_pile); - CREATE_QUAD_7_ALL(PictureDrawQuad, + CREATE_QUAD_6_ALL(PictureDrawQuad, tex_coord_rect, texture_size, texture_format, content_rect, contents_scale, - can_draw_direct_to_backbuffer, picture_pile); EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material); EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect); @@ -706,8 +622,6 @@ TEST(DrawQuadTest, CopyPictureDrawQuad) { EXPECT_EQ(texture_format, copy_quad->texture_format); EXPECT_RECT_EQ(content_rect, copy_quad->content_rect); EXPECT_EQ(contents_scale, copy_quad->contents_scale); - EXPECT_EQ(can_draw_direct_to_backbuffer, - copy_quad->can_draw_direct_to_backbuffer); EXPECT_EQ(picture_pile, copy_quad->picture_pile); } @@ -748,7 +662,7 @@ TEST_F(DrawQuadIteratorTest, DebugBorderDrawQuad) { } TEST_F(DrawQuadIteratorTest, IOSurfaceDrawQuad) { - gfx::Rect opaque_rect(3, 7, 10, 12); + gfx::Rect opaque_rect(33, 47, 10, 12); gfx::Size size(58, 95); ResourceProvider::ResourceId resource_id = 72; IOSurfaceDrawQuad::Orientation orientation = IOSurfaceDrawQuad::UNFLIPPED; @@ -772,20 +686,17 @@ TEST_F(DrawQuadIteratorTest, RenderPassDrawQuad) { FilterOperations background_filters; background_filters.Append( FilterOperation::CreateGrayscaleFilter(1.f)); - skia::RefPtr<SkImageFilter> filter = - skia::AdoptRef(new SkBlurImageFilter(SK_Scalar1, SK_Scalar1)); RenderPass::Id copied_render_pass_id(235, 11); CREATE_SHARED_STATE(); - CREATE_QUAD_8_NEW_1(RenderPassDrawQuad, + CREATE_QUAD_7_NEW_1(RenderPassDrawQuad, render_pass_id, is_replica, mask_resource_id, contents_changed_since_last_frame, mask_u_v_rect, filters, - filter, background_filters, copied_render_pass_id); EXPECT_EQ(mask_resource_id, quad_new->mask_resource_id); @@ -806,7 +717,7 @@ TEST_F(DrawQuadIteratorTest, SolidColorDrawQuad) { } TEST_F(DrawQuadIteratorTest, StreamVideoDrawQuad) { - gfx::Rect opaque_rect(3, 7, 10, 12); + gfx::Rect opaque_rect(33, 47, 10, 12); ResourceProvider::ResourceId resource_id = 64; gfx::Transform matrix = gfx::Transform(0.5, 0.25, 1, 0.75, 0, 1); @@ -818,7 +729,7 @@ TEST_F(DrawQuadIteratorTest, StreamVideoDrawQuad) { } TEST_F(DrawQuadIteratorTest, TextureDrawQuad) { - gfx::Rect opaque_rect(3, 7, 10, 12); + gfx::Rect opaque_rect(33, 47, 10, 12); unsigned resource_id = 82; bool premultiplied_alpha = true; gfx::PointF uv_top_left(0.5f, 224.f); @@ -861,7 +772,7 @@ TEST_F(DrawQuadIteratorTest, TileDrawQuad) { } TEST_F(DrawQuadIteratorTest, YUVVideoDrawQuad) { - gfx::Rect opaque_rect(3, 7, 10, 12); + gfx::Rect opaque_rect(33, 47, 10, 12); gfx::SizeF tex_scale(0.75f, 0.5f); ResourceProvider::ResourceId y_plane_resource_id = 45; ResourceProvider::ResourceId u_plane_resource_id = 532; @@ -896,18 +807,16 @@ TEST_F(DrawQuadIteratorTest, DISABLED_PictureDrawQuad) { ResourceFormat texture_format = RGBA_8888; gfx::Rect content_rect(30, 40, 20, 30); float contents_scale = 3.141592f; - bool can_draw_direct_to_backbuffer = true; scoped_refptr<PicturePileImpl> picture_pile = PicturePileImpl::Create(); CREATE_SHARED_STATE(); - CREATE_QUAD_8_NEW(PictureDrawQuad, + CREATE_QUAD_7_NEW(PictureDrawQuad, opaque_rect, tex_coord_rect, texture_size, texture_format, content_rect, contents_scale, - can_draw_direct_to_backbuffer, picture_pile); EXPECT_EQ(0, IterateAndCount(quad_new.get())); } diff --git a/chromium/cc/quads/picture_draw_quad.cc b/chromium/cc/quads/picture_draw_quad.cc index e566b247f72..bdb12e64d7a 100644 --- a/chromium/cc/quads/picture_draw_quad.cc +++ b/chromium/cc/quads/picture_draw_quad.cc @@ -28,7 +28,6 @@ void PictureDrawQuad::SetNew(const SharedQuadState* shared_quad_state, ResourceFormat texture_format, gfx::Rect content_rect, float contents_scale, - bool can_draw_direct_to_backbuffer, scoped_refptr<PicturePileImpl> picture_pile) { ContentDrawQuadBase::SetNew(shared_quad_state, DrawQuad::PICTURE_CONTENT, @@ -40,7 +39,6 @@ void PictureDrawQuad::SetNew(const SharedQuadState* shared_quad_state, texture_format)); this->content_rect = content_rect; this->contents_scale = contents_scale; - this->can_draw_direct_to_backbuffer = can_draw_direct_to_backbuffer; this->picture_pile = picture_pile; this->texture_format = texture_format; } @@ -55,7 +53,6 @@ void PictureDrawQuad::SetAll(const SharedQuadState* shared_quad_state, ResourceFormat texture_format, gfx::Rect content_rect, float contents_scale, - bool can_draw_direct_to_backbuffer, scoped_refptr<PicturePileImpl> picture_pile) { ContentDrawQuadBase::SetAll(shared_quad_state, DrawQuad::PICTURE_CONTENT, @@ -69,7 +66,6 @@ void PictureDrawQuad::SetAll(const SharedQuadState* shared_quad_state, texture_format)); this->content_rect = content_rect; this->contents_scale = contents_scale; - this->can_draw_direct_to_backbuffer = can_draw_direct_to_backbuffer; this->picture_pile = picture_pile; this->texture_format = texture_format; } @@ -89,8 +85,6 @@ void PictureDrawQuad::ExtendValue(base::DictionaryValue* value) const { ContentDrawQuadBase::ExtendValue(value); value->Set("content_rect", MathUtil::AsValue(content_rect).release()); value->SetDouble("contents_scale", contents_scale); - value->SetBoolean("can_draw_direct_to_backbuffer", - can_draw_direct_to_backbuffer); value->SetInteger("texture_format", texture_format); // TODO(piman): picture_pile? } diff --git a/chromium/cc/quads/picture_draw_quad.h b/chromium/cc/quads/picture_draw_quad.h index 756482a610b..9bea70b4609 100644 --- a/chromium/cc/quads/picture_draw_quad.h +++ b/chromium/cc/quads/picture_draw_quad.h @@ -30,7 +30,6 @@ class CC_EXPORT PictureDrawQuad : public ContentDrawQuadBase { ResourceFormat texture_format, gfx::Rect content_rect, float contents_scale, - bool can_draw_direct_to_backbuffer, scoped_refptr<PicturePileImpl> picture_pile); void SetAll(const SharedQuadState* shared_quad_state, @@ -43,12 +42,10 @@ class CC_EXPORT PictureDrawQuad : public ContentDrawQuadBase { ResourceFormat texture_format, gfx::Rect content_rect, float contents_scale, - bool can_draw_direct_to_backbuffer, scoped_refptr<PicturePileImpl> picture_pile); gfx::Rect content_rect; float contents_scale; - bool can_draw_direct_to_backbuffer; scoped_refptr<PicturePileImpl> picture_pile; ResourceFormat texture_format; diff --git a/chromium/cc/quads/render_pass.cc b/chromium/cc/quads/render_pass.cc index 50d502884b4..53cb83703a3 100644 --- a/chromium/cc/quads/render_pass.cc +++ b/chromium/cc/quads/render_pass.cc @@ -9,23 +9,45 @@ #include "cc/debug/traced_value.h" #include "cc/output/copy_output_request.h" #include "cc/quads/draw_quad.h" +#include "cc/quads/render_pass_draw_quad.h" #include "cc/quads/shared_quad_state.h" +namespace { +const size_t kDefaultNumSharedQuadStatesToReserve = 32; +const size_t kDefaultNumQuadsToReserve = 128; +} + namespace cc { void* RenderPass::Id::AsTracingId() const { - COMPILE_ASSERT(sizeof(size_t) <= sizeof(void*), size_t_bigger_than_pointer); + COMPILE_ASSERT(sizeof(size_t) <= sizeof(void*), // NOLINT(runtime/sizeof) + size_t_bigger_than_pointer); return reinterpret_cast<void*>(base::HashPair(layer_id, index)); } scoped_ptr<RenderPass> RenderPass::Create() { - return make_scoped_ptr(new RenderPass); + return make_scoped_ptr(new RenderPass()); +} + +scoped_ptr<RenderPass> RenderPass::Create(size_t num_layers) { + return make_scoped_ptr(new RenderPass(num_layers)); } RenderPass::RenderPass() : id(Id(-1, -1)), - has_transparent_background(true), - has_occlusion_from_outside_target_surface(false) {} + has_transparent_background(true) { + shared_quad_state_list.reserve(kDefaultNumSharedQuadStatesToReserve); + quad_list.reserve(kDefaultNumQuadsToReserve); +} + +RenderPass::RenderPass(size_t num_layers) + : id(Id(-1, -1)), + has_transparent_background(true) { + // Each layer usually produces one shared quad state, so the number of layers + // is a good hint for what to reserve here. + shared_quad_state_list.reserve(num_layers); + quad_list.reserve(kDefaultNumQuadsToReserve); +} RenderPass::~RenderPass() { TRACE_EVENT_OBJECT_DELETED_WITH_ID( @@ -39,11 +61,56 @@ scoped_ptr<RenderPass> RenderPass::Copy(Id new_id) const { output_rect, damage_rect, transform_to_root_target, - has_transparent_background, - has_occlusion_from_outside_target_surface); + has_transparent_background); return copy_pass.Pass(); } +// static +void RenderPass::CopyAll(const ScopedPtrVector<RenderPass>& in, + ScopedPtrVector<RenderPass>* out) { + for (size_t i = 0; i < in.size(); ++i) { + RenderPass* source = in[i]; + + // Since we can't copy these, it's wrong to use CopyAll in a situation where + // you may have copy_requests present. + DCHECK_EQ(source->copy_requests.size(), 0u); + + scoped_ptr<RenderPass> copy_pass(Create()); + copy_pass->SetAll(source->id, + source->output_rect, + source->damage_rect, + source->transform_to_root_target, + source->has_transparent_background); + for (size_t i = 0; i < source->shared_quad_state_list.size(); ++i) { + copy_pass->shared_quad_state_list.push_back( + source->shared_quad_state_list[i]->Copy()); + } + for (size_t i = 0, sqs_i = 0; i < source->quad_list.size(); ++i) { + while (source->quad_list[i]->shared_quad_state != + source->shared_quad_state_list[sqs_i]) { + ++sqs_i; + DCHECK_LT(sqs_i, source->shared_quad_state_list.size()); + } + DCHECK(source->quad_list[i]->shared_quad_state == + source->shared_quad_state_list[sqs_i]); + + DrawQuad* quad = source->quad_list[i]; + + if (quad->material == DrawQuad::RENDER_PASS) { + const RenderPassDrawQuad* pass_quad = + RenderPassDrawQuad::MaterialCast(quad); + copy_pass->quad_list.push_back( + pass_quad->Copy(copy_pass->shared_quad_state_list[sqs_i], + pass_quad->render_pass_id).PassAs<DrawQuad>()); + } else { + copy_pass->quad_list.push_back(source->quad_list[i]->Copy( + copy_pass->shared_quad_state_list[sqs_i])); + } + } + out->push_back(copy_pass.Pass()); + } +} + void RenderPass::SetNew(Id id, gfx::Rect output_rect, gfx::RectF damage_rect, @@ -64,8 +131,7 @@ void RenderPass::SetAll(Id id, gfx::Rect output_rect, gfx::RectF damage_rect, const gfx::Transform& transform_to_root_target, - bool has_transparent_background, - bool has_occlusion_from_outside_target_surface) { + bool has_transparent_background) { DCHECK_GT(id.layer_id, 0); DCHECK_GE(id.index, 0); @@ -74,8 +140,6 @@ void RenderPass::SetAll(Id id, this->damage_rect = damage_rect; this->transform_to_root_target = transform_to_root_target; this->has_transparent_background = has_transparent_background; - this->has_occlusion_from_outside_target_surface = - has_occlusion_from_outside_target_surface; DCHECK(quad_list.empty()); DCHECK(shared_quad_state_list.empty()); @@ -86,8 +150,6 @@ scoped_ptr<base::Value> RenderPass::AsValue() const { value->Set("output_rect", MathUtil::AsValue(output_rect).release()); value->Set("damage_rect", MathUtil::AsValue(damage_rect).release()); value->SetBoolean("has_transparent_background", has_transparent_background); - value->SetBoolean("has_occlusion_from_outside_target_surface", - has_occlusion_from_outside_target_surface); value->SetInteger("copy_requests", copy_requests.size()); scoped_ptr<base::ListValue> shared_states_value(new base::ListValue()); for (size_t i = 0; i < shared_quad_state_list.size(); ++i) { diff --git a/chromium/cc/quads/render_pass.h b/chromium/cc/quads/render_pass.h index cf2a02d4a3c..407381fb172 100644 --- a/chromium/cc/quads/render_pass.h +++ b/chromium/cc/quads/render_pass.h @@ -65,10 +65,16 @@ class CC_EXPORT RenderPass { ~RenderPass(); static scoped_ptr<RenderPass> Create(); + static scoped_ptr<RenderPass> Create(size_t num_layers); - // A shallow copy of the render pass, which does not include its quads. + // A shallow copy of the render pass, which does not include its quads or copy + // requests. scoped_ptr<RenderPass> Copy(Id new_id) const; + // A deep copy of the render passes in the list including the quads. + static void CopyAll(const ScopedPtrVector<RenderPass>& in, + ScopedPtrVector<RenderPass>* out); + void SetNew(Id id, gfx::Rect output_rect, gfx::RectF damage_rect, @@ -78,8 +84,7 @@ class CC_EXPORT RenderPass { gfx::Rect output_rect, gfx::RectF damage_rect, const gfx::Transform& transform_to_root_target, - bool has_transparent_background, - bool has_occlusion_from_outside_target_surface); + bool has_transparent_background); scoped_ptr<base::Value> AsValue() const; @@ -97,10 +102,6 @@ class CC_EXPORT RenderPass { // If false, the pixels in the render pass' texture are all opaque. bool has_transparent_background; - // If true, then there may be pixels in the render pass' texture that are not - // complete, since they are occluded. - bool has_occlusion_from_outside_target_surface; - // If non-empty, the renderer should produce a copy of the render pass' // contents as a bitmap, and give a copy of the bitmap to each callback in // this list. This property should not be serialized between compositors, as @@ -111,6 +112,7 @@ class CC_EXPORT RenderPass { SharedQuadStateList shared_quad_state_list; protected: + explicit RenderPass(size_t num_layers); RenderPass(); private: diff --git a/chromium/cc/quads/render_pass_draw_quad.cc b/chromium/cc/quads/render_pass_draw_quad.cc index 73b2553e209..af8cd8c492c 100644 --- a/chromium/cc/quads/render_pass_draw_quad.cc +++ b/chromium/cc/quads/render_pass_draw_quad.cc @@ -43,7 +43,6 @@ void RenderPassDrawQuad::SetNew( gfx::Rect contents_changed_since_last_frame, gfx::RectF mask_uv_rect, const FilterOperations& filters, - skia::RefPtr<SkImageFilter> filter, const FilterOperations& background_filters) { DCHECK_GT(render_pass_id.layer_id, 0); DCHECK_GE(render_pass_id.index, 0); @@ -53,7 +52,7 @@ void RenderPassDrawQuad::SetNew( bool needs_blending = false; SetAll(shared_quad_state, rect, opaque_rect, visible_rect, needs_blending, render_pass_id, is_replica, mask_resource_id, - contents_changed_since_last_frame, mask_uv_rect, filters, filter, + contents_changed_since_last_frame, mask_uv_rect, filters, background_filters); } @@ -69,7 +68,6 @@ void RenderPassDrawQuad::SetAll( gfx::Rect contents_changed_since_last_frame, gfx::RectF mask_uv_rect, const FilterOperations& filters, - skia::RefPtr<SkImageFilter> filter, const FilterOperations& background_filters) { DCHECK_GT(render_pass_id.layer_id, 0); DCHECK_GE(render_pass_id.index, 0); @@ -82,7 +80,6 @@ void RenderPassDrawQuad::SetAll( this->contents_changed_since_last_frame = contents_changed_since_last_frame; this->mask_uv_rect = mask_uv_rect; this->filters = filters; - this->filter = filter; this->background_filters = background_filters; } @@ -107,9 +104,6 @@ void RenderPassDrawQuad::ExtendValue(base::DictionaryValue* value) const { MathUtil::AsValue(contents_changed_since_last_frame).release()); value->Set("mask_uv_rect", MathUtil::AsValue(mask_uv_rect).release()); value->Set("filters", filters.AsValue().release()); - // TODO(piman): dump SkImageFilters rather than just indicating if there are - // any or not. - value->SetBoolean("has_filter", !!filter); value->Set("background_filters", background_filters.AsValue().release()); } diff --git a/chromium/cc/quads/render_pass_draw_quad.h b/chromium/cc/quads/render_pass_draw_quad.h index e253dec430b..8546c45621c 100644 --- a/chromium/cc/quads/render_pass_draw_quad.h +++ b/chromium/cc/quads/render_pass_draw_quad.h @@ -28,7 +28,6 @@ class CC_EXPORT RenderPassDrawQuad : public DrawQuad { gfx::Rect contents_changed_since_last_frame, gfx::RectF mask_uv_rect, const FilterOperations& filters, - skia::RefPtr<SkImageFilter> filter, const FilterOperations& background_filters); void SetAll(const SharedQuadState* shared_quad_state, @@ -42,7 +41,6 @@ class CC_EXPORT RenderPassDrawQuad : public DrawQuad { gfx::Rect contents_changed_since_last_frame, gfx::RectF mask_uv_rect, const FilterOperations& filters, - skia::RefPtr<SkImageFilter> filter, const FilterOperations& background_filters); scoped_ptr<RenderPassDrawQuad> Copy( @@ -55,11 +53,8 @@ class CC_EXPORT RenderPassDrawQuad : public DrawQuad { gfx::Rect contents_changed_since_last_frame; gfx::RectF mask_uv_rect; - // Deprecated post-processing filters, applied to the pixels in the render - // pass' texture. + // Post-processing filters, applied to the pixels in the render pass' texture. FilterOperations filters; - // Post-processing filter applied to the pixels in the render pass' texture. - skia::RefPtr<SkImageFilter> filter; // Post-processing filters, applied to the pixels showing through the // background of the render pass, from behind it. diff --git a/chromium/cc/quads/render_pass_unittest.cc b/chromium/cc/quads/render_pass_unittest.cc index b12faa89840..e70a33dd685 100644 --- a/chromium/cc/quads/render_pass_unittest.cc +++ b/chromium/cc/quads/render_pass_unittest.cc @@ -8,6 +8,7 @@ #include "cc/base/scoped_ptr_vector.h" #include "cc/output/copy_output_request.h" #include "cc/quads/checkerboard_draw_quad.h" +#include "cc/quads/render_pass_draw_quad.h" #include "cc/test/geometry_test_utils.h" #include "cc/test/render_pass_test_common.h" #include "testing/gtest/include/gtest/gtest.h" @@ -29,10 +30,38 @@ struct RenderPassSize { gfx::Rect output_rect; gfx::RectF damage_rect; bool has_transparent_background; - bool has_occlusion_from_outside_target_surface; ScopedPtrVector<CopyOutputRequest> copy_callbacks; }; +static void CompareRenderPassLists(const RenderPassList& expected_list, + const RenderPassList& actual_list) { + EXPECT_EQ(expected_list.size(), actual_list.size()); + for (size_t i = 0; i < actual_list.size(); ++i) { + RenderPass* expected = expected_list[i]; + RenderPass* actual = actual_list[i]; + + EXPECT_EQ(expected->id, actual->id); + EXPECT_RECT_EQ(expected->output_rect, actual->output_rect); + EXPECT_EQ(expected->transform_to_root_target, + actual->transform_to_root_target); + EXPECT_RECT_EQ(expected->damage_rect, actual->damage_rect); + EXPECT_EQ(expected->has_transparent_background, + actual->has_transparent_background); + + EXPECT_EQ(expected->shared_quad_state_list.size(), + actual->shared_quad_state_list.size()); + EXPECT_EQ(expected->quad_list.size(), actual->quad_list.size()); + + for (size_t i = 0; i < expected->quad_list.size(); ++i) { + EXPECT_EQ(expected->quad_list[i]->rect.ToString(), + actual->quad_list[i]->rect.ToString()); + EXPECT_EQ( + expected->quad_list[i]->shared_quad_state->content_bounds.ToString(), + actual->quad_list[i]->shared_quad_state->content_bounds.ToString()); + } + } +} + TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) { RenderPass::Id id(3, 2); gfx::Rect output_rect(45, 22, 120, 13); @@ -40,21 +69,24 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) { gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0); gfx::Rect damage_rect(56, 123, 19, 43); bool has_transparent_background = true; - bool has_occlusion_from_outside_target_surface = true; scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); pass->SetAll(id, output_rect, damage_rect, transform_to_root, - has_transparent_background, - has_occlusion_from_outside_target_surface); + has_transparent_background); pass->copy_requests.push_back(CopyOutputRequest::CreateEmptyRequest()); // Stick a quad in the pass, this should not get copied. scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create(); - shared_state->SetAll( - gfx::Transform(), gfx::Size(), gfx::Rect(), gfx::Rect(), false, 1); + shared_state->SetAll(gfx::Transform(), + gfx::Size(), + gfx::Rect(), + gfx::Rect(), + false, + 1, + SkXfermode::kSrcOver_Mode); pass->AppendSharedQuadState(shared_state.Pass()); scoped_ptr<CheckerboardDrawQuad> checkerboard_quad = @@ -71,8 +103,6 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) { EXPECT_EQ(pass->transform_to_root_target, copy->transform_to_root_target); EXPECT_RECT_EQ(pass->damage_rect, copy->damage_rect); EXPECT_EQ(pass->has_transparent_background, copy->has_transparent_background); - EXPECT_EQ(pass->has_occlusion_from_outside_target_surface, - copy->has_occlusion_from_outside_target_surface); EXPECT_EQ(0u, copy->quad_list.size()); // The copy request should not be copied/duplicated. @@ -82,5 +112,204 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) { EXPECT_EQ(sizeof(RenderPassSize), sizeof(RenderPass)); } +TEST(RenderPassTest, CopyAllShouldBeIdentical) { + RenderPassList pass_list; + + RenderPass::Id id(3, 2); + gfx::Rect output_rect(45, 22, 120, 13); + gfx::Transform transform_to_root = + gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0); + gfx::Rect damage_rect(56, 123, 19, 43); + bool has_transparent_background = true; + + scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); + pass->SetAll(id, + output_rect, + damage_rect, + transform_to_root, + has_transparent_background); + + // Two quads using one shared state. + scoped_ptr<SharedQuadState> shared_state1 = SharedQuadState::Create(); + shared_state1->SetAll(gfx::Transform(), + gfx::Size(1, 1), + gfx::Rect(), + gfx::Rect(), + false, + 1, + SkXfermode::kSrcOver_Mode); + pass->AppendSharedQuadState(shared_state1.Pass()); + + scoped_ptr<CheckerboardDrawQuad> checkerboard_quad1 = + CheckerboardDrawQuad::Create(); + checkerboard_quad1->SetNew( + pass->shared_quad_state_list.back(), gfx::Rect(1, 1, 1, 1), SkColor()); + pass->quad_list.push_back(checkerboard_quad1.PassAs<DrawQuad>()); + + scoped_ptr<CheckerboardDrawQuad> checkerboard_quad2 = + CheckerboardDrawQuad::Create(); + checkerboard_quad2->SetNew( + pass->shared_quad_state_list.back(), gfx::Rect(2, 2, 2, 2), SkColor()); + pass->quad_list.push_back(checkerboard_quad2.PassAs<DrawQuad>()); + + // And two quads using another shared state. + scoped_ptr<SharedQuadState> shared_state2 = SharedQuadState::Create(); + shared_state2->SetAll(gfx::Transform(), + gfx::Size(2, 2), + gfx::Rect(), + gfx::Rect(), + false, + 1, + SkXfermode::kSrcOver_Mode); + pass->AppendSharedQuadState(shared_state2.Pass()); + + scoped_ptr<CheckerboardDrawQuad> checkerboard_quad3 = + CheckerboardDrawQuad::Create(); + checkerboard_quad3->SetNew( + pass->shared_quad_state_list.back(), gfx::Rect(3, 3, 3, 3), SkColor()); + pass->quad_list.push_back(checkerboard_quad3.PassAs<DrawQuad>()); + + scoped_ptr<CheckerboardDrawQuad> checkerboard_quad4 = + CheckerboardDrawQuad::Create(); + checkerboard_quad4->SetNew( + pass->shared_quad_state_list.back(), gfx::Rect(4, 4, 4, 4), SkColor()); + pass->quad_list.push_back(checkerboard_quad4.PassAs<DrawQuad>()); + + // A second render pass with a quad. + RenderPass::Id contrib_id(4, 1); + gfx::Rect contrib_output_rect(10, 15, 12, 17); + gfx::Transform contrib_transform_to_root = + gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0); + gfx::Rect contrib_damage_rect(11, 16, 10, 15); + bool contrib_has_transparent_background = true; + + scoped_ptr<TestRenderPass> contrib = TestRenderPass::Create(); + contrib->SetAll(contrib_id, + contrib_output_rect, + contrib_damage_rect, + contrib_transform_to_root, + contrib_has_transparent_background); + + scoped_ptr<SharedQuadState> contrib_shared_state = SharedQuadState::Create(); + contrib_shared_state->SetAll(gfx::Transform(), + gfx::Size(2, 2), + gfx::Rect(), + gfx::Rect(), + false, + 1, + SkXfermode::kSrcOver_Mode); + contrib->AppendSharedQuadState(contrib_shared_state.Pass()); + + scoped_ptr<CheckerboardDrawQuad> contrib_quad = + CheckerboardDrawQuad::Create(); + contrib_quad->SetNew( + contrib->shared_quad_state_list.back(), gfx::Rect(3, 3, 3, 3), SkColor()); + contrib->quad_list.push_back(contrib_quad.PassAs<DrawQuad>()); + + // And a RenderPassDrawQuad for the contributing pass. + scoped_ptr<RenderPassDrawQuad> pass_quad = RenderPassDrawQuad::Create(); + pass_quad->SetNew(pass->shared_quad_state_list.back(), + contrib_output_rect, + contrib_id, + false, // is_replica + 0, // mask_resource_id + contrib_damage_rect, + gfx::RectF(), // mask_uv_rect + FilterOperations(), + FilterOperations()); + pass->quad_list.push_back(pass_quad.PassAs<DrawQuad>()); + + pass_list.push_back(pass.PassAs<RenderPass>()); + pass_list.push_back(contrib.PassAs<RenderPass>()); + + // Make a copy with CopyAll(). + RenderPassList copy_list; + RenderPass::CopyAll(pass_list, ©_list); + + CompareRenderPassLists(pass_list, copy_list); +} + +TEST(RenderPassTest, CopyAllWithCulledQuads) { + RenderPassList pass_list; + + RenderPass::Id id(3, 2); + gfx::Rect output_rect(45, 22, 120, 13); + gfx::Transform transform_to_root = + gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0); + gfx::Rect damage_rect(56, 123, 19, 43); + bool has_transparent_background = true; + + scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); + pass->SetAll(id, + output_rect, + damage_rect, + transform_to_root, + has_transparent_background); + + // A shared state with a quad. + scoped_ptr<SharedQuadState> shared_state1 = SharedQuadState::Create(); + shared_state1->SetAll(gfx::Transform(), + gfx::Size(1, 1), + gfx::Rect(), + gfx::Rect(), + false, + 1, + SkXfermode::kSrcOver_Mode); + pass->AppendSharedQuadState(shared_state1.Pass()); + + scoped_ptr<CheckerboardDrawQuad> checkerboard_quad1 = + CheckerboardDrawQuad::Create(); + checkerboard_quad1->SetNew( + pass->shared_quad_state_list.back(), gfx::Rect(1, 1, 1, 1), SkColor()); + pass->quad_list.push_back(checkerboard_quad1.PassAs<DrawQuad>()); + + // A shared state with no quads, they were culled. + scoped_ptr<SharedQuadState> shared_state2 = SharedQuadState::Create(); + shared_state2->SetAll(gfx::Transform(), + gfx::Size(2, 2), + gfx::Rect(), + gfx::Rect(), + false, + 1, + SkXfermode::kSrcOver_Mode); + pass->AppendSharedQuadState(shared_state2.Pass()); + + // A second shared state with no quads. + scoped_ptr<SharedQuadState> shared_state3 = SharedQuadState::Create(); + shared_state3->SetAll(gfx::Transform(), + gfx::Size(2, 2), + gfx::Rect(), + gfx::Rect(), + false, + 1, + SkXfermode::kSrcOver_Mode); + pass->AppendSharedQuadState(shared_state3.Pass()); + + // A last shared state with a quad again. + scoped_ptr<SharedQuadState> shared_state4 = SharedQuadState::Create(); + shared_state4->SetAll(gfx::Transform(), + gfx::Size(2, 2), + gfx::Rect(), + gfx::Rect(), + false, + 1, + SkXfermode::kSrcOver_Mode); + pass->AppendSharedQuadState(shared_state4.Pass()); + + scoped_ptr<CheckerboardDrawQuad> checkerboard_quad2 = + CheckerboardDrawQuad::Create(); + checkerboard_quad2->SetNew( + pass->shared_quad_state_list.back(), gfx::Rect(3, 3, 3, 3), SkColor()); + pass->quad_list.push_back(checkerboard_quad2.PassAs<DrawQuad>()); + + pass_list.push_back(pass.PassAs<RenderPass>()); + + // Make a copy with CopyAll(). + RenderPassList copy_list; + RenderPass::CopyAll(pass_list, ©_list); + + CompareRenderPassLists(pass_list, copy_list); +} + } // namespace } // namespace cc diff --git a/chromium/cc/quads/shared_quad_state.cc b/chromium/cc/quads/shared_quad_state.cc index 6a53d9f6a9f..56584577917 100644 --- a/chromium/cc/quads/shared_quad_state.cc +++ b/chromium/cc/quads/shared_quad_state.cc @@ -10,7 +10,8 @@ namespace cc { -SharedQuadState::SharedQuadState() : is_clipped(false), opacity(0.f) {} +SharedQuadState::SharedQuadState() + : is_clipped(false), opacity(0.f), blend_mode(SkXfermode::kSrcOver_Mode) {} SharedQuadState::~SharedQuadState() { TRACE_EVENT_OBJECT_DELETED_WITH_ID( @@ -26,19 +27,20 @@ scoped_ptr<SharedQuadState> SharedQuadState::Copy() const { return make_scoped_ptr(new SharedQuadState(*this)); } -void SharedQuadState::SetAll( - const gfx::Transform& content_to_target_transform, - gfx::Size content_bounds, - gfx::Rect visible_content_rect, - gfx::Rect clip_rect, - bool is_clipped, - float opacity) { +void SharedQuadState::SetAll(const gfx::Transform& content_to_target_transform, + gfx::Size content_bounds, + gfx::Rect visible_content_rect, + gfx::Rect clip_rect, + bool is_clipped, + float opacity, + SkXfermode::Mode blend_mode) { this->content_to_target_transform = content_to_target_transform; this->content_bounds = content_bounds; this->visible_content_rect = visible_content_rect; this->clip_rect = clip_rect; this->is_clipped = is_clipped; this->opacity = opacity; + this->blend_mode = blend_mode; } scoped_ptr<base::Value> SharedQuadState::AsValue() const { @@ -52,6 +54,7 @@ scoped_ptr<base::Value> SharedQuadState::AsValue() const { value->SetBoolean("is_clipped", is_clipped); value->Set("clip_rect", MathUtil::AsValue(clip_rect).release()); value->SetDouble("opacity", opacity); + value->SetString("blend_mode", SkXfermode::ModeName(blend_mode)); TracedValue::MakeDictIntoImplicitSnapshotWithCategory( TRACE_DISABLED_BY_DEFAULT("cc.debug.quads"), value.get(), "cc::SharedQuadState", this); diff --git a/chromium/cc/quads/shared_quad_state.h b/chromium/cc/quads/shared_quad_state.h index 79bd09b60f7..b70d4a11fb9 100644 --- a/chromium/cc/quads/shared_quad_state.h +++ b/chromium/cc/quads/shared_quad_state.h @@ -7,6 +7,7 @@ #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" +#include "third_party/skia/include/core/SkXfermode.h" #include "ui/gfx/rect.h" #include "ui/gfx/transform.h" @@ -28,7 +29,8 @@ class CC_EXPORT SharedQuadState { gfx::Rect visible_content_rect, gfx::Rect clip_rect, bool is_clipped, - float opacity); + float opacity, + SkXfermode::Mode blend_mode); scoped_ptr<base::Value> AsValue() const; // Transforms from quad's original content space to its target content space. @@ -41,6 +43,7 @@ class CC_EXPORT SharedQuadState { gfx::Rect clip_rect; bool is_clipped; float opacity; + SkXfermode::Mode blend_mode; private: SharedQuadState(); diff --git a/chromium/cc/quads/texture_draw_quad.cc b/chromium/cc/quads/texture_draw_quad.cc index ae7cfd6e238..191dcc43e7f 100644 --- a/chromium/cc/quads/texture_draw_quad.cc +++ b/chromium/cc/quads/texture_draw_quad.cc @@ -84,80 +84,6 @@ const TextureDrawQuad* TextureDrawQuad::MaterialCast(const DrawQuad* quad) { return static_cast<const TextureDrawQuad*>(quad); } -bool TextureDrawQuad::PerformClipping() { - // This only occurs if the rect is only scaled and translated (and thus still - // axis aligned). - if (!quadTransform().IsPositiveScaleOrTranslation()) - return false; - - // Grab our scale and make sure it's positive. - float x_scale = static_cast<float>(quadTransform().matrix().getDouble(0, 0)); - float y_scale = static_cast<float>(quadTransform().matrix().getDouble(1, 1)); - - // Grab our offset. - gfx::Vector2dF offset( - static_cast<float>(quadTransform().matrix().getDouble(0, 3)), - static_cast<float>(quadTransform().matrix().getDouble(1, 3))); - - // Transform the rect by the scale and offset. - gfx::RectF rect_f = rect; - rect_f.Scale(x_scale, y_scale); - rect_f += offset; - - // Perform clipping and check to see if the result is empty. - gfx::RectF clipped_rect = IntersectRects(rect_f, clipRect()); - if (clipped_rect.IsEmpty()) { - rect = gfx::Rect(); - uv_top_left = gfx::PointF(); - uv_bottom_right = gfx::PointF(); - return true; - } - - // Create a new uv-rect by clipping the old one to the new bounds. - gfx::Vector2dF uv_scale(uv_bottom_right - uv_top_left); - uv_scale.Scale(1.f / rect_f.width(), 1.f / rect_f.height()); - uv_bottom_right = uv_top_left + - gfx::ScaleVector2d( - clipped_rect.bottom_right() - rect_f.origin(), - uv_scale.x(), - uv_scale.y()); - uv_top_left = uv_top_left + - gfx::ScaleVector2d( - clipped_rect.origin() - rect_f.origin(), - uv_scale.x(), - uv_scale.y()); - - // Indexing according to the quad vertex generation: - // 1--2 - // | | - // 0--3 - if (vertex_opacity[0] != vertex_opacity[1] - || vertex_opacity[0] != vertex_opacity[2] - || vertex_opacity[0] != vertex_opacity[3]) { - const float x1 = (clipped_rect.x() - rect_f.x()) / rect_f.width(); - const float y1 = (clipped_rect.y() - rect_f.y()) / rect_f.height(); - const float x3 = (clipped_rect.right() - rect_f.x()) / rect_f.width(); - const float y3 = (clipped_rect.bottom() - rect_f.y()) / rect_f.height(); - const float x1y1 = x1 * vertex_opacity[2] + (1.0f - x1) * vertex_opacity[1]; - const float x1y3 = x1 * vertex_opacity[3] + (1.0f - x1) * vertex_opacity[0]; - const float x3y1 = x3 * vertex_opacity[2] + (1.0f - x3) * vertex_opacity[1]; - const float x3y3 = x3 * vertex_opacity[3] + (1.0f - x3) * vertex_opacity[0]; - vertex_opacity[0] = y3 * x1y3 + (1.0f - y3) * x1y1; - vertex_opacity[1] = y1 * x1y3 + (1.0f - y1) * x1y1; - vertex_opacity[2] = y1 * x3y3 + (1.0f - y1) * x3y1; - vertex_opacity[3] = y3 * x3y3 + (1.0f - y3) * x3y1; - } - - // Move the clipped rectangle back into its space. - clipped_rect -= offset; - clipped_rect.Scale(1.0f / x_scale, 1.0f / y_scale); - rect = gfx::Rect(static_cast<int>(clipped_rect.x() + 0.5f), - static_cast<int>(clipped_rect.y() + 0.5f), - static_cast<int>(clipped_rect.width() + 0.5f), - static_cast<int>(clipped_rect.height() + 0.5f)); - return true; -} - void TextureDrawQuad::ExtendValue(base::DictionaryValue* value) const { value->SetInteger("resource_id", resource_id); value->SetBoolean("premultiplied_alpha", premultiplied_alpha); diff --git a/chromium/cc/quads/texture_draw_quad.h b/chromium/cc/quads/texture_draw_quad.h index 7f066188484..4aa4d7a1642 100644 --- a/chromium/cc/quads/texture_draw_quad.h +++ b/chromium/cc/quads/texture_draw_quad.h @@ -53,8 +53,6 @@ class CC_EXPORT TextureDrawQuad : public DrawQuad { static const TextureDrawQuad* MaterialCast(const DrawQuad*); - bool PerformClipping(); - private: TextureDrawQuad(); virtual void ExtendValue(base::DictionaryValue* value) const OVERRIDE; diff --git a/chromium/cc/resources/bitmap_content_layer_updater.cc b/chromium/cc/resources/bitmap_content_layer_updater.cc index 75b99c54b81..fd0fbdaf597 100644 --- a/chromium/cc/resources/bitmap_content_layer_updater.cc +++ b/chromium/cc/resources/bitmap_content_layer_updater.cc @@ -59,14 +59,16 @@ void BitmapContentLayerUpdater::PrepareToUpdate( float contents_width_scale, float contents_height_scale, gfx::Rect* resulting_opaque_rect) { - devtools_instrumentation::ScopedLayerTask paint_layer( - devtools_instrumentation::kPaintLayer, layer_id_); if (canvas_size_ != content_rect.size()) { devtools_instrumentation::ScopedLayerTask paint_setup( devtools_instrumentation::kPaintSetup, layer_id_); canvas_size_ = content_rect.size(); - canvas_ = skia::AdoptRef(skia::CreateBitmapCanvas( - canvas_size_.width(), canvas_size_.height(), layer_is_opaque_)); + bitmap_backing_.setConfig( + SkBitmap::kARGB_8888_Config, + canvas_size_.width(), canvas_size_.height(), + 0, layer_is_opaque_ ? kOpaque_SkAlphaType : kPremul_SkAlphaType); + bitmap_backing_.allocPixels(); + canvas_ = skia::AdoptRef(new SkCanvas(bitmap_backing_)); } base::TimeTicks start_time = diff --git a/chromium/cc/resources/bitmap_content_layer_updater.h b/chromium/cc/resources/bitmap_content_layer_updater.h index 2a417f06dfa..ecc0c153b7f 100644 --- a/chromium/cc/resources/bitmap_content_layer_updater.h +++ b/chromium/cc/resources/bitmap_content_layer_updater.h @@ -8,6 +8,7 @@ #include "cc/base/cc_export.h" #include "cc/resources/content_layer_updater.h" #include "skia/ext/refptr.h" +#include "third_party/skia/include/core/SkBitmap.h" class SkCanvas; @@ -65,6 +66,7 @@ class CC_EXPORT BitmapContentLayerUpdater : public ContentLayerUpdater { int layer_id); virtual ~BitmapContentLayerUpdater(); + SkBitmap bitmap_backing_; skia::RefPtr<SkCanvas> canvas_; gfx::Size canvas_size_; bool opaque_; diff --git a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc index 2db3f417a97..cc839a60eee 100644 --- a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc +++ b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc @@ -25,9 +25,9 @@ void BitmapSkPictureContentLayerUpdater::Resource::Update( gfx::Vector2d dest_offset, bool partial_update) { bitmap_.setConfig( - SkBitmap::kARGB_8888_Config, source_rect.width(), source_rect.height()); + SkBitmap::kARGB_8888_Config, source_rect.width(), source_rect.height(), 0, + updater_->layer_is_opaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType); bitmap_.allocPixels(); - bitmap_.setIsOpaque(updater_->layer_is_opaque()); SkBitmapDevice device(bitmap_); SkCanvas canvas(&device); updater_->PaintContentsRect(&canvas, source_rect); @@ -81,9 +81,7 @@ void BitmapSkPictureContentLayerUpdater::PaintContentsRect( rendering_stats_instrumentation_->EndRecording(start_time); rendering_stats_instrumentation_->AddRaster( duration, - duration, - source_rect.width() * source_rect.height(), - false); + source_rect.width() * source_rect.height()); } } // namespace cc diff --git a/chromium/cc/resources/content_layer_updater.cc b/chromium/cc/resources/content_layer_updater.cc index 2e73c4bb904..bc6c635dbd0 100644 --- a/chromium/cc/resources/content_layer_updater.cc +++ b/chromium/cc/resources/content_layer_updater.cc @@ -60,12 +60,14 @@ void ContentLayerUpdater::PaintContents(SkCanvas* canvas, SkRect layer_sk_rect = SkRect::MakeXYWH( layer_rect.x(), layer_rect.y(), layer_rect.width(), layer_rect.height()); + canvas->clipRect(layer_sk_rect); + // If the layer has opaque contents then there is no need to // clear the canvas before painting. - if (!layer_is_opaque_) - canvas->clear(SK_ColorTRANSPARENT); - - canvas->clipRect(layer_sk_rect); + if (!layer_is_opaque_) { + TRACE_EVENT0("cc", "Clear"); + canvas->drawColor(SK_ColorTRANSPARENT, SkXfermode::kSrc_Mode); + } gfx::RectF opaque_layer_rect; painter_->Paint(canvas, layer_rect, &opaque_layer_rect); diff --git a/chromium/cc/resources/etc1_pixel_ref.cc b/chromium/cc/resources/etc1_pixel_ref.cc new file mode 100644 index 00000000000..7176562317b --- /dev/null +++ b/chromium/cc/resources/etc1_pixel_ref.cc @@ -0,0 +1,38 @@ +// Copyright 2013 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 "cc/resources/etc1_pixel_ref.h" + +#include "base/memory/scoped_ptr.h" +#include "third_party/skia/include/core/SkPixelRef.h" + +namespace cc { + +#ifdef SK_SUPPORT_LEGACY_PIXELREF_CONSTRUCTOR +// Takes ownership of pixels. +ETC1PixelRef::ETC1PixelRef(scoped_ptr<uint8_t[]> pixels) + : pixels_(pixels.Pass()) { + setImmutable(); +} +#endif + +// Takes ownership of pixels. +ETC1PixelRef::ETC1PixelRef(const SkImageInfo& info, + scoped_ptr<uint8_t[]> pixels) + : SkPixelRef(info), pixels_(pixels.Pass()) { + setImmutable(); +} + +ETC1PixelRef::~ETC1PixelRef() {} + +void* ETC1PixelRef::onLockPixels(SkColorTable** color_table) { + *color_table = NULL; + return static_cast<void*>(pixels_.get()); +} + +void ETC1PixelRef::onUnlockPixels() {} + +SkFlattenable::Factory ETC1PixelRef::getFactory() const { return NULL; } + +} // namespace cc diff --git a/chromium/cc/resources/etc1_pixel_ref.h b/chromium/cc/resources/etc1_pixel_ref.h new file mode 100644 index 00000000000..166e185f533 --- /dev/null +++ b/chromium/cc/resources/etc1_pixel_ref.h @@ -0,0 +1,44 @@ +// Copyright 2013 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 CC_RESOURCES_ETC1_PIXEL_REF_H_ +#define CC_RESOURCES_ETC1_PIXEL_REF_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "third_party/skia/include/core/SkPixelRef.h" + +namespace cc { + +class CC_EXPORT ETC1PixelRef : public SkPixelRef { + public: +#ifdef SK_SUPPORT_LEGACY_PIXELREF_CONSTRUCTOR + // DEPRECATED -- will remove once blink updates to pass info + // TODO(reed) + explicit ETC1PixelRef(scoped_ptr<uint8_t[]> pixels); +#endif + + // Takes ownership of pixels. + ETC1PixelRef(const SkImageInfo& info, scoped_ptr<uint8_t[]> pixels); + virtual ~ETC1PixelRef(); + + // SK_DECLARE_UNFLATTENABLE_OBJECT + virtual Factory getFactory() const OVERRIDE; + + protected: + // Implementation of SkPixelRef. + virtual void* onLockPixels(SkColorTable** color_table) OVERRIDE; + virtual void onUnlockPixels() OVERRIDE; + + private: + scoped_ptr<uint8_t[]> pixels_; + + DISALLOW_COPY_AND_ASSIGN(ETC1PixelRef); +}; + +} // namespace cc + +#endif // CC_RESOURCES_ETC1_PIXEL_REF_H_ diff --git a/chromium/cc/resources/image_raster_worker_pool.cc b/chromium/cc/resources/image_raster_worker_pool.cc index 30add2ad2ea..90572ab417d 100644 --- a/chromium/cc/resources/image_raster_worker_pool.cc +++ b/chromium/cc/resources/image_raster_worker_pool.cc @@ -57,8 +57,11 @@ class ImageWorkerPoolTaskImpl : public internal::WorkerPoolTask { } // namespace ImageRasterWorkerPool::ImageRasterWorkerPool( - ResourceProvider* resource_provider, size_t num_threads) + ResourceProvider* resource_provider, + size_t num_threads, + GLenum texture_target) : RasterWorkerPool(resource_provider, num_threads), + texture_target_(texture_target), raster_tasks_pending_(false), raster_tasks_required_for_activation_pending_(false) { } @@ -149,14 +152,17 @@ void ImageRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) { set_raster_required_for_activation_finished_task( new_raster_required_for_activation_finished_task); - TRACE_EVENT_ASYNC_STEP1( + TRACE_EVENT_ASYNC_STEP_INTO1( "cc", "ScheduledTasks", this, "rasterizing", "state", TracedValue::FromValue(StateAsValue().release())); } +GLenum ImageRasterWorkerPool::GetResourceTarget() const { + return texture_target_; +} + ResourceFormat ImageRasterWorkerPool::GetResourceFormat() const { - // Only format supported by CHROMIUM_map_image - return RGBA_8888; + return resource_provider()->best_texture_format(); } void ImageRasterWorkerPool::OnRasterTasksFinished() { @@ -169,7 +175,7 @@ void ImageRasterWorkerPool::OnRasterTasksFinished() { void ImageRasterWorkerPool::OnRasterTasksRequiredForActivationFinished() { DCHECK(raster_tasks_required_for_activation_pending_); raster_tasks_required_for_activation_pending_ = false; - TRACE_EVENT_ASYNC_STEP1( + TRACE_EVENT_ASYNC_STEP_INTO1( "cc", "ScheduledTasks", this, "rasterizing", "state", TracedValue::FromValue(StateAsValue().release())); client()->DidFinishRunningTasksRequiredForActivation(); diff --git a/chromium/cc/resources/image_raster_worker_pool.h b/chromium/cc/resources/image_raster_worker_pool.h index 63526493350..38fe04238e1 100644 --- a/chromium/cc/resources/image_raster_worker_pool.h +++ b/chromium/cc/resources/image_raster_worker_pool.h @@ -14,20 +14,26 @@ class CC_EXPORT ImageRasterWorkerPool : public RasterWorkerPool { virtual ~ImageRasterWorkerPool(); static scoped_ptr<RasterWorkerPool> Create( - ResourceProvider* resource_provider, size_t num_threads) { + ResourceProvider* resource_provider, + size_t num_threads, + GLenum texture_target) { return make_scoped_ptr<RasterWorkerPool>( - new ImageRasterWorkerPool(resource_provider, num_threads)); + new ImageRasterWorkerPool(resource_provider, + num_threads, + texture_target)); } // Overridden from RasterWorkerPool: virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE; + virtual GLenum GetResourceTarget() const OVERRIDE; virtual ResourceFormat GetResourceFormat() const OVERRIDE; virtual void OnRasterTasksFinished() OVERRIDE; virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE; private: ImageRasterWorkerPool(ResourceProvider* resource_provider, - size_t num_threads); + size_t num_threads, + GLenum texture_target); void OnRasterTaskCompleted( scoped_refptr<internal::RasterWorkerPoolTask> task, bool was_canceled); @@ -43,6 +49,8 @@ class CC_EXPORT ImageRasterWorkerPool : public RasterWorkerPool { internal::GraphNode* raster_finished_node, TaskGraph* graph); + const GLenum texture_target_; + TaskMap image_tasks_; bool raster_tasks_pending_; diff --git a/chromium/cc/resources/managed_tile_state.cc b/chromium/cc/resources/managed_tile_state.cc index 8856d4f5168..b453bd6d95f 100644 --- a/chromium/cc/resources/managed_tile_state.cc +++ b/chromium/cc/resources/managed_tile_state.cc @@ -54,8 +54,6 @@ ManagedTileState::ManagedTileState() distance_to_visible_in_pixels(std::numeric_limits<float>::infinity()), visible_and_ready_to_draw(false), scheduled_priority(0) { - for (int i = 0; i < NUM_TREES; ++i) - tree_bin[i] = NEVER_BIN; } ManagedTileState::TileVersion::TileVersion() @@ -89,13 +87,19 @@ ManagedTileState::~ManagedTileState() { } scoped_ptr<base::Value> ManagedTileState::AsValue() const { + bool has_resource = false; + bool has_active_task = false; + for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { + has_resource |= (tile_versions[mode].resource_.get() != 0); + has_active_task |= !tile_versions[mode].raster_task_.is_null(); + } + + bool is_using_gpu_memory = has_resource || has_active_task; + scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); - state->SetBoolean("has_resource", - tile_versions[raster_mode].resource_.get() != 0); - state->Set("tree_bin.0", - ManagedTileBinAsValue(tree_bin[ACTIVE_TREE]).release()); - state->Set("tree_bin.1", - ManagedTileBinAsValue(tree_bin[PENDING_TREE]).release()); + state->SetBoolean("has_resource", has_resource); + state->SetBoolean("is_using_gpu_memory", is_using_gpu_memory); + state->Set("bin", ManagedTileBinAsValue(bin).release()); state->Set("resolution", TileResolutionAsValue(resolution).release()); state->Set("time_to_needed_in_seconds", MathUtil::AsValueSafely(time_to_needed_in_seconds).release()); @@ -114,4 +118,3 @@ scoped_ptr<base::Value> ManagedTileState::AsValue() const { } } // namespace cc - diff --git a/chromium/cc/resources/managed_tile_state.h b/chromium/cc/resources/managed_tile_state.h index 35e4415dd9e..dc6f6d62cb6 100644 --- a/chromium/cc/resources/managed_tile_state.h +++ b/chromium/cc/resources/managed_tile_state.h @@ -10,6 +10,7 @@ #include "cc/resources/raster_worker_pool.h" #include "cc/resources/resource_pool.h" #include "cc/resources/resource_provider.h" +#include "cc/resources/scoped_resource.h" namespace cc { @@ -111,7 +112,7 @@ class CC_EXPORT ManagedTileState { Mode mode_; SkColor solid_color_; bool has_text_; - scoped_ptr<ResourcePool::Resource> resource_; + scoped_ptr<ScopedResource> resource_; RasterWorkerPool::RasterTask raster_task_; }; @@ -125,7 +126,6 @@ class CC_EXPORT ManagedTileState { RasterMode raster_mode; ManagedTileBin bin; - ManagedTileBin tree_bin[NUM_TREES]; TileResolution resolution; bool required_for_activation; diff --git a/chromium/cc/resources/picture.cc b/chromium/cc/resources/picture.cc index f9afca9ee3d..8c3be9c3bca 100644 --- a/chromium/cc/resources/picture.cc +++ b/chromium/cc/resources/picture.cc @@ -13,8 +13,6 @@ #include "base/values.h" #include "cc/base/math_util.h" #include "cc/base/util.h" -#include "cc/debug/benchmark_instrumentation.h" -#include "cc/debug/rendering_stats_instrumentation.h" #include "cc/debug/traced_picture.h" #include "cc/debug/traced_value.h" #include "cc/layers/content_layer_client.h" @@ -88,7 +86,8 @@ scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) { } Picture::Picture(gfx::Rect layer_rect) - : layer_rect_(layer_rect) { + : layer_rect_(layer_rect), + cell_size_(layer_rect.size()) { // Instead of recording a trace event for object creation here, we wait for // the picture to be recorded in Picture::Record. } @@ -157,7 +156,8 @@ Picture::Picture(SkPicture* picture, gfx::Rect opaque_rect) : layer_rect_(layer_rect), opaque_rect_(opaque_rect), - picture_(skia::AdoptRef(picture)) { + picture_(skia::AdoptRef(picture)), + cell_size_(layer_rect.size()) { } Picture::Picture(const skia::RefPtr<SkPicture>& picture, @@ -167,7 +167,8 @@ Picture::Picture(const skia::RefPtr<SkPicture>& picture, layer_rect_(layer_rect), opaque_rect_(opaque_rect), picture_(picture), - pixel_refs_(pixel_refs) { + pixel_refs_(pixel_refs), + cell_size_(layer_rect.size()) { } Picture::~Picture() { @@ -204,11 +205,9 @@ void Picture::CloneForDrawing(int num_threads) { } void Picture::Record(ContentLayerClient* painter, - const SkTileGridPicture::TileGridInfo& tile_grid_info, - RenderingStatsInstrumentation* stats_instrumentation) { - TRACE_EVENT1(benchmark_instrumentation::kCategory, - benchmark_instrumentation::kPictureRecord, - benchmark_instrumentation::kData, AsTraceableRecordData()); + const SkTileGridPicture::TileGridInfo& tile_grid_info) { + TRACE_EVENT1("cc", "Picture::Record", + "data", AsTraceableRecordData()); DCHECK(!tile_grid_info.fTileInterval.isEmpty()); picture_ = skia::AdoptRef(new SkTileGridPicture( @@ -231,14 +230,9 @@ void Picture::Record(ContentLayerClient* painter, canvas->clipRect(layer_skrect); gfx::RectF opaque_layer_rect; - base::TimeTicks start_time = stats_instrumentation->StartRecording(); painter->PaintContents(canvas, layer_rect_, &opaque_layer_rect); - base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); - stats_instrumentation->AddRecord(duration, - layer_rect_.width() * layer_rect_.height()); - canvas->restore(); picture_->endRecording(); @@ -248,13 +242,14 @@ void Picture::Record(ContentLayerClient* painter, } void Picture::GatherPixelRefs( - const SkTileGridPicture::TileGridInfo& tile_grid_info, - RenderingStatsInstrumentation* stats_instrumentation) { + const SkTileGridPicture::TileGridInfo& tile_grid_info) { TRACE_EVENT2("cc", "Picture::GatherPixelRefs", "width", layer_rect_.width(), "height", layer_rect_.height()); DCHECK(picture_); + if (!WillPlayBackBitmaps()) + return; cell_size_ = gfx::Size( tile_grid_info.fTileInterval.width() + 2 * tile_grid_info.fMargin.width(), @@ -268,8 +263,6 @@ void Picture::GatherPixelRefs( int max_x = 0; int max_y = 0; - base::TimeTicks start_time = stats_instrumentation->StartRecording(); - skia::LazyPixelRefList pixel_refs; skia::LazyPixelRefUtils::GatherPixelRefs(picture_.get(), &pixel_refs); for (skia::LazyPixelRefList::const_iterator it = pixel_refs.begin(); @@ -299,37 +292,38 @@ void Picture::GatherPixelRefs( max_y = std::max(max_y, max.y()); } - base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); - stats_instrumentation->AddImageGathering(duration); - min_pixel_cell_ = gfx::Point(min_x, min_y); max_pixel_cell_ = gfx::Point(max_x, max_y); } -void Picture::Raster( +int Picture::Raster( SkCanvas* canvas, SkDrawPictureCallback* callback, - gfx::Rect content_rect, + const Region& negated_content_region, float contents_scale) { - TRACE_EVENT_BEGIN1(benchmark_instrumentation::kCategory, - benchmark_instrumentation::kPictureRaster, - "data", - AsTraceableRasterData(content_rect, contents_scale)); + TRACE_EVENT_BEGIN1( + "cc", + "Picture::Raster", + "data", + AsTraceableRasterData(contents_scale)); DCHECK(picture_); canvas->save(); - canvas->clipRect(gfx::RectToSkRect(content_rect)); + + for (Region::Iterator it(negated_content_region); it.has_rect(); it.next()) + canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op); + canvas->scale(contents_scale, contents_scale); canvas->translate(layer_rect_.x(), layer_rect_.y()); picture_->draw(canvas, callback); SkIRect bounds; canvas->getClipDeviceBounds(&bounds); canvas->restore(); - TRACE_EVENT_END1(benchmark_instrumentation::kCategory, - benchmark_instrumentation::kPictureRaster, - benchmark_instrumentation::kNumPixelsRasterized, - bounds.width() * bounds.height()); + TRACE_EVENT_END1( + "cc", "Picture::Raster", + "num_pixels_rasterized", bounds.width() * bounds.height()); + return bounds.width() * bounds.height(); } void Picture::Replay(SkCanvas* canvas) { @@ -398,8 +392,9 @@ Picture::PixelRefIterator::PixelRefIterator( current_index_(0) { gfx::Rect layer_rect = picture->layer_rect_; gfx::Size cell_size = picture->cell_size_; + DCHECK(!cell_size.IsEmpty()); - // Early out if the query rect doesn't intersect this picture + // Early out if the query rect doesn't intersect this picture. if (!query_rect.Intersects(layer_rect)) { min_point_ = gfx::Point(0, 0); max_point_ = gfx::Point(0, 0); @@ -475,26 +470,20 @@ Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() { return *this; } -scoped_ptr<base::debug::ConvertableToTraceFormat> - Picture::AsTraceableRasterData(gfx::Rect rect, float scale) const { +scoped_refptr<base::debug::ConvertableToTraceFormat> + Picture::AsTraceableRasterData(float scale) const { scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue()); raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release()); raster_data->SetDouble("scale", scale); - raster_data->SetDouble("rect_x", rect.x()); - raster_data->SetDouble("rect_y", rect.y()); - raster_data->SetDouble("rect_width", rect.width()); - raster_data->SetDouble("rect_height", rect.height()); return TracedValue::FromValue(raster_data.release()); } -scoped_ptr<base::debug::ConvertableToTraceFormat> +scoped_refptr<base::debug::ConvertableToTraceFormat> Picture::AsTraceableRecordData() const { scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue()); record_data->Set("picture_id", TracedValue::CreateIDRef(this).release()); - record_data->SetInteger(benchmark_instrumentation::kWidth, - layer_rect_.width()); - record_data->SetInteger(benchmark_instrumentation::kHeight, - layer_rect_.height()); + record_data->SetInteger("width", layer_rect_.width()); + record_data->SetInteger("height", layer_rect_.height()); return TracedValue::FromValue(record_data.release()); } diff --git a/chromium/cc/resources/picture.h b/chromium/cc/resources/picture.h index 238647772fc..085fb6a4531 100644 --- a/chromium/cc/resources/picture.h +++ b/chromium/cc/resources/picture.h @@ -17,6 +17,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" +#include "cc/base/region.h" #include "skia/ext/lazy_pixel_ref.h" #include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkPixelRef.h" @@ -34,7 +35,6 @@ class AnalysisCanvas; namespace cc { class ContentLayerClient; -class RenderingStatsInstrumentation; class CC_EXPORT Picture : public base::RefCountedThreadSafe<Picture> { @@ -60,21 +60,20 @@ class CC_EXPORT Picture // Record a paint operation. To be able to safely use this SkPicture for // playback on a different thread this can only be called once. void Record(ContentLayerClient* client, - const SkTileGridPicture::TileGridInfo& tile_grid_info, - RenderingStatsInstrumentation* stats_instrumentation); + const SkTileGridPicture::TileGridInfo& tile_grid_info); // Gather pixel refs from recording. - void GatherPixelRefs(const SkTileGridPicture::TileGridInfo& tile_grid_info, - RenderingStatsInstrumentation* stats_instrumentation); + void GatherPixelRefs(const SkTileGridPicture::TileGridInfo& tile_grid_info); // Has Record() been called yet? bool HasRecording() const { return picture_.get() != NULL; } - // Apply this contents scale and raster the content rect into the canvas. - void Raster(SkCanvas* canvas, - SkDrawPictureCallback* callback, - gfx::Rect content_rect, - float contents_scale); + // Apply this scale and raster the negated region into the canvas. See comment + // in PicturePileImpl::RasterCommon for explanation on negated content region. + int Raster(SkCanvas* canvas, + SkDrawPictureCallback* callback, + const Region& negated_content_region, + float contents_scale); // Draw the picture directly into the given canvas, without applying any // clip/scale/layer transformations. @@ -118,6 +117,8 @@ class CC_EXPORT Picture void EmitTraceSnapshot(); void EmitTraceSnapshotAlias(Picture* original); + bool WillPlayBackBitmaps() const { return picture_->willPlayBackBitmaps(); } + private: explicit Picture(gfx::Rect layer_rect); // This constructor assumes SkPicture is already ref'd and transfers @@ -144,9 +145,9 @@ class CC_EXPORT Picture gfx::Point max_pixel_cell_; gfx::Size cell_size_; - scoped_ptr<base::debug::ConvertableToTraceFormat> - AsTraceableRasterData(gfx::Rect rect, float scale) const; - scoped_ptr<base::debug::ConvertableToTraceFormat> + scoped_refptr<base::debug::ConvertableToTraceFormat> + AsTraceableRasterData(float scale) const; + scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableRecordData() const; friend class base::RefCountedThreadSafe<Picture>; diff --git a/chromium/cc/resources/picture_layer_tiling.cc b/chromium/cc/resources/picture_layer_tiling.cc index 12bfb18b441..1aa3567e0a3 100644 --- a/chromium/cc/resources/picture_layer_tiling.cc +++ b/chromium/cc/resources/picture_layer_tiling.cc @@ -339,35 +339,6 @@ void PictureLayerTiling::Reset() { tiles_.clear(); } -namespace { - -bool NearlyOne(SkMScalar lhs) { - return std::abs(lhs-1.0) < std::numeric_limits<float>::epsilon(); -} - -bool NearlyZero(SkMScalar lhs) { - return std::abs(lhs) < std::numeric_limits<float>::epsilon(); -} - -bool ApproximatelyTranslation(const SkMatrix44& matrix) { - return - NearlyOne(matrix.get(0, 0)) && - NearlyZero(matrix.get(1, 0)) && - NearlyZero(matrix.get(2, 0)) && - matrix.get(3, 0) == 0 && - NearlyZero(matrix.get(0, 1)) && - NearlyOne(matrix.get(1, 1)) && - NearlyZero(matrix.get(2, 1)) && - matrix.get(3, 1) == 0 && - NearlyZero(matrix.get(0, 2)) && - NearlyZero(matrix.get(1, 2)) && - NearlyOne(matrix.get(2, 2)) && - matrix.get(3, 2) == 0 && - matrix.get(3, 3) == 1; -} - -} // namespace - void PictureLayerTiling::UpdateTilePriorities( WhichTree tree, gfx::Size device_viewport, @@ -406,7 +377,8 @@ void PictureLayerTiling::UpdateTilePriorities( gfx::Rect interest_rect = ExpandRectEquallyToAreaBoundedBy( starting_rect, interest_rect_area, - ContentRect()); + ContentRect(), + &expansion_cache_); DCHECK(interest_rect.IsEmpty() || ContentRect().Contains(interest_rect)); @@ -419,17 +391,15 @@ void PictureLayerTiling::UpdateTilePriorities( current_frame_time_in_seconds - last_impl_frame_time_in_seconds_; } - gfx::Rect view_rect(device_viewport); + gfx::RectF view_rect(device_viewport); float current_scale = current_layer_contents_scale / contents_scale_; float last_scale = last_layer_contents_scale / contents_scale_; - bool store_screen_space_quads_on_tiles; - TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - &store_screen_space_quads_on_tiles); - // Fast path tile priority calculation when both transforms are translations. - if (ApproximatelyTranslation(last_screen_transform.matrix()) && - ApproximatelyTranslation(current_screen_transform.matrix())) { + if (last_screen_transform.IsApproximatelyIdentityOrTranslation( + std::numeric_limits<float>::epsilon()) && + current_screen_transform.IsApproximatelyIdentityOrTranslation( + std::numeric_limits<float>::epsilon())) { gfx::Vector2dF current_offset( current_screen_transform.matrix().get(0, 3), current_screen_transform.matrix().get(1, 3)); @@ -456,7 +426,7 @@ void PictureLayerTiling::UpdateTilePriorities( last_scale) + last_offset; float distance_to_visible_in_pixels = - TilePriority::manhattanDistance(current_screen_rect, view_rect); + current_screen_rect.ManhattanInternalDistance(view_rect); float time_to_visible_in_seconds = TilePriority::TimeForBoundsToIntersect( @@ -465,8 +435,6 @@ void PictureLayerTiling::UpdateTilePriorities( resolution_, time_to_visible_in_seconds, distance_to_visible_in_pixels); - if (store_screen_space_quads_on_tiles) - priority.set_current_screen_quad(gfx::QuadF(current_screen_rect)); tile->SetPriority(tree, priority); } } else if (!last_screen_transform.HasPerspective() && @@ -538,7 +506,7 @@ void PictureLayerTiling::UpdateTilePriorities( last_tile_origin + last_vertical).BoundingBox(); float distance_to_visible_in_pixels = - TilePriority::manhattanDistance(current_screen_rect, view_rect); + current_screen_rect.ManhattanInternalDistance(view_rect); float time_to_visible_in_seconds = TilePriority::TimeForBoundsToIntersect( @@ -547,21 +515,6 @@ void PictureLayerTiling::UpdateTilePriorities( resolution_, time_to_visible_in_seconds, distance_to_visible_in_pixels); - - if (store_screen_space_quads_on_tiles) { - // This overhead is only triggered when logging event tracing data. - gfx::Rect tile_bounds = - tiling_data_.TileBounds(iter.index_x(), iter.index_y()); - gfx::RectF current_layer_content_rect = gfx::ScaleRect( - tile_bounds, - current_scale, - current_scale); - bool clipped; - priority.set_current_screen_quad( - MathUtil::MapQuad(current_screen_transform, - gfx::QuadF(current_layer_content_rect), - &clipped)); - } tile->SetPriority(tree, priority); } } else { @@ -588,7 +541,7 @@ void PictureLayerTiling::UpdateTilePriorities( last_screen_transform, last_layer_content_rect); float distance_to_visible_in_pixels = - TilePriority::manhattanDistance(current_screen_rect, view_rect); + current_screen_rect.ManhattanInternalDistance(view_rect); float time_to_visible_in_seconds = TilePriority::TimeForBoundsToIntersect( @@ -598,13 +551,6 @@ void PictureLayerTiling::UpdateTilePriorities( resolution_, time_to_visible_in_seconds, distance_to_visible_in_pixels); - if (store_screen_space_quads_on_tiles) { - bool clipped; - priority.set_current_screen_quad( - MathUtil::MapQuad(current_screen_transform, - gfx::QuadF(current_layer_content_rect), - &clipped)); - } tile->SetPriority(tree, priority); } } @@ -648,6 +594,16 @@ void PictureLayerTiling::SetLiveTilesRect( live_tiles_rect_ = new_live_tiles_rect; } +void PictureLayerTiling::DidBecomeRecycled() { + // DidBecomeActive below will set the active priority for tiles that are + // still in the tree. Calling this first on an active tiling that is becoming + // recycled takes care of tiles that are no longer in the active tree (eg. + // due to a pending invalidation). + for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { + it->second->SetPriority(ACTIVE_TREE, TilePriority()); + } +} + void PictureLayerTiling::DidBecomeActive() { for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { it->second->SetPriority(ACTIVE_TREE, it->second->priority(PENDING_TREE)); @@ -687,6 +643,10 @@ size_t PictureLayerTiling::GPUMemoryUsageInBytes() const { return amount; } +PictureLayerTiling::RectExpansionCache::RectExpansionCache() + : previous_target(0) { +} + namespace { // This struct represents an event at which the expending rect intersects @@ -718,10 +678,23 @@ int ComputeExpansionDelta(int num_x_edges, int num_y_edges, gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( gfx::Rect starting_rect, int64 target_area, - gfx::Rect bounding_rect) { + gfx::Rect bounding_rect, + RectExpansionCache* cache) { if (starting_rect.IsEmpty()) return starting_rect; + if (cache && + cache->previous_start == starting_rect && + cache->previous_bounds == bounding_rect && + cache->previous_target == target_area) + return cache->previous_result; + + if (cache) { + cache->previous_start = starting_rect; + cache->previous_bounds = bounding_rect; + cache->previous_target = target_area; + } + DCHECK(!bounding_rect.IsEmpty()); DCHECK_GT(target_area, 0); @@ -735,11 +708,15 @@ gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( gfx::Rect rect = IntersectRects(expanded_starting_rect, bounding_rect); if (rect.IsEmpty()) { // The starting_rect and bounding_rect are far away. + if (cache) + cache->previous_result = rect; return rect; } if (delta >= 0 && rect == expanded_starting_rect) { // The starting rect already covers the entire bounding_rect and isn't too // large for the target_area. + if (cache) + cache->previous_result = rect; return rect; } @@ -809,7 +786,10 @@ gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( break; } - return gfx::Rect(origin_x, origin_y, width, height); + gfx::Rect result(origin_x, origin_y, width, height); + if (cache) + cache->previous_result = result; + return result; } } // namespace cc diff --git a/chromium/cc/resources/picture_layer_tiling.h b/chromium/cc/resources/picture_layer_tiling.h index 973fa50b73f..dae62723711 100644 --- a/chromium/cc/resources/picture_layer_tiling.h +++ b/chromium/cc/resources/picture_layer_tiling.h @@ -34,7 +34,7 @@ class CC_EXPORT PictureLayerTilingClient { gfx::Size content_bounds) const = 0; virtual const Region* GetInvalidation() = 0; virtual const PictureLayerTiling* GetTwinTiling( - const PictureLayerTiling* tiling) = 0; + const PictureLayerTiling* tiling) const = 0; protected: virtual ~PictureLayerTilingClient() {} @@ -78,6 +78,8 @@ class CC_EXPORT PictureLayerTiling { return all_tiles; } + Tile* TileAt(int i, int j) const; + // Iterate over all tiles to fill content_rect. Even if tiles are invalid // (i.e. no valid resource) this tiling should still iterate over them. // The union of all geometry_rect calls for each element iterated over should @@ -107,6 +109,9 @@ class CC_EXPORT PictureLayerTiling { CoverageIterator& operator++(); operator bool() const { return tile_j_ <= bottom_; } + int i() const { return tile_i_; } + int j() const { return tile_j_; } + private: const PictureLayerTiling* tiling_; gfx::Rect dest_rect_; @@ -147,6 +152,13 @@ class CC_EXPORT PictureLayerTiling { // also updates the pile on each tile to be the current client's pile. void DidBecomeActive(); + // Resets the active priority for all tiles in a tiling, when an active + // tiling is becoming recycled. This may include some tiles which are + // not in the the pending tiling (due to invalidations). This must + // be called before DidBecomeActive, as it resets the active priority + // while DidBecomeActive promotes pending priority on a similar set of tiles. + void DidBecomeRecycled(); + void UpdateTilesToCurrentPile(); bool NeedsUpdateForFrameAtTime(double frame_time_in_seconds) { @@ -156,10 +168,21 @@ class CC_EXPORT PictureLayerTiling { scoped_ptr<base::Value> AsValue() const; size_t GPUMemoryUsageInBytes() const; - static gfx::Rect ExpandRectEquallyToAreaBoundedBy( + struct RectExpansionCache { + RectExpansionCache(); + + gfx::Rect previous_start; + gfx::Rect previous_bounds; + gfx::Rect previous_result; + int64 previous_target; + }; + + static + gfx::Rect ExpandRectEquallyToAreaBoundedBy( gfx::Rect starting_rect, int64 target_area, - gfx::Rect bounding_rect); + gfx::Rect bounding_rect, + RectExpansionCache* cache); bool has_ever_been_updated() const { return last_impl_frame_time_in_seconds_ != 0.0; @@ -174,7 +197,6 @@ class CC_EXPORT PictureLayerTiling { PictureLayerTilingClient* client); void SetLiveTilesRect(gfx::Rect live_tiles_rect); void CreateTile(int i, int j, const PictureLayerTiling* twin_tiling); - Tile* TileAt(int, int) const; // Given properties. float contents_scale_; @@ -194,6 +216,8 @@ class CC_EXPORT PictureLayerTiling { private: DISALLOW_ASSIGN(PictureLayerTiling); + + RectExpansionCache expansion_cache_; }; } // namespace cc diff --git a/chromium/cc/resources/picture_layer_tiling_perftest.cc b/chromium/cc/resources/picture_layer_tiling_perftest.cc index 655603d2e85..7a9b8dff4b4 100644 --- a/chromium/cc/resources/picture_layer_tiling_perftest.cc +++ b/chromium/cc/resources/picture_layer_tiling_perftest.cc @@ -153,7 +153,12 @@ TEST_F(PictureLayerTilingPerfTest, Invalidate) { RunInvalidateTest("50x50", full_region); } +#if defined(OS_ANDROID) +// TODO(vmpstr): Investigate why this is noisy (crbug.com/310220). +TEST_F(PictureLayerTilingPerfTest, DISABLED_UpdateTilePriorities) { +#else TEST_F(PictureLayerTilingPerfTest, UpdateTilePriorities) { +#endif // defined(OS_ANDROID) gfx::Transform transform; RunUpdateTilePrioritiesStationaryTest("no_transform", transform); RunUpdateTilePrioritiesScrollingTest("no_transform", transform); diff --git a/chromium/cc/resources/picture_layer_tiling_set.cc b/chromium/cc/resources/picture_layer_tiling_set.cc index 14c9cc87a30..5ad26506fd7 100644 --- a/chromium/cc/resources/picture_layer_tiling_set.cc +++ b/chromium/cc/resources/picture_layer_tiling_set.cc @@ -343,6 +343,11 @@ void PictureLayerTilingSet::DidBecomeActive() { tilings_[i]->DidBecomeActive(); } +void PictureLayerTilingSet::DidBecomeRecycled() { + for (size_t i = 0; i < tilings_.size(); ++i) + tilings_[i]->DidBecomeRecycled(); +} + scoped_ptr<base::Value> PictureLayerTilingSet::AsValue() const { scoped_ptr<base::ListValue> state(new base::ListValue()); for (size_t i = 0; i < tilings_.size(); ++i) diff --git a/chromium/cc/resources/picture_layer_tiling_set.h b/chromium/cc/resources/picture_layer_tiling_set.h index 9a3f00db61f..29e6bf453f5 100644 --- a/chromium/cc/resources/picture_layer_tiling_set.h +++ b/chromium/cc/resources/picture_layer_tiling_set.h @@ -69,6 +69,7 @@ class CC_EXPORT PictureLayerTilingSet { size_t max_tiles_for_interest_area); void DidBecomeActive(); + void DidBecomeRecycled(); // For a given rect, iterates through tiles that can fill it. If no // set of tiles with resources can fill the rect, then it will iterate diff --git a/chromium/cc/resources/picture_layer_tiling_set_unittest.cc b/chromium/cc/resources/picture_layer_tiling_set_unittest.cc index 231e378fbd0..96129c64fe5 100644 --- a/chromium/cc/resources/picture_layer_tiling_set_unittest.cc +++ b/chromium/cc/resources/picture_layer_tiling_set_unittest.cc @@ -66,9 +66,9 @@ class PictureLayerTilingSetTestWithResources : public testing::Test { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider = - ResourceProvider::Create(output_surface.get(), 0, false); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1); - FakePictureLayerTilingClient client; + FakePictureLayerTilingClient client(resource_provider.get()); client.SetTileSize(gfx::Size(256, 256)); gfx::Size layer_bounds(1000, 800); PictureLayerTilingSet set(&client, layer_bounds); diff --git a/chromium/cc/resources/picture_layer_tiling_unittest.cc b/chromium/cc/resources/picture_layer_tiling_unittest.cc index af70f297ed2..6adc6116454 100644 --- a/chromium/cc/resources/picture_layer_tiling_unittest.cc +++ b/chromium/cc/resources/picture_layer_tiling_unittest.cc @@ -266,7 +266,7 @@ TEST(PictureLayerTilingTest, ExpandRectEqual) { gfx::Rect bounds(-1000, -1000, 10000, 10000); int64 target_area = 100 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(in.ToString(), out.ToString()); } @@ -275,7 +275,7 @@ TEST(PictureLayerTilingTest, ExpandRectSmaller) { gfx::Rect bounds(-1000, -1000, 10000, 10000); int64 target_area = 100 * 100; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); EXPECT_EQ(out.width() - in.width(), out.height() - in.height()); @@ -288,7 +288,7 @@ TEST(PictureLayerTilingTest, ExpandRectUnbounded) { gfx::Rect bounds(-1000, -1000, 10000, 10000); int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); EXPECT_EQ(out.width() - in.width(), out.height() - in.height()); @@ -301,7 +301,7 @@ TEST(PictureLayerTilingTest, ExpandRectBoundedSmaller) { gfx::Rect bounds(50, 60, 40, 30); int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(bounds.ToString(), out.ToString()); } @@ -310,7 +310,7 @@ TEST(PictureLayerTilingTest, ExpandRectBoundedEqual) { gfx::Rect bounds = in; int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(bounds.ToString(), out.ToString()); } @@ -319,7 +319,7 @@ TEST(PictureLayerTilingTest, ExpandRectBoundedSmallerStretchVertical) { gfx::Rect bounds(45, 0, 90, 300); int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(bounds.ToString(), out.ToString()); } @@ -328,7 +328,7 @@ TEST(PictureLayerTilingTest, ExpandRectBoundedEqualStretchVertical) { gfx::Rect bounds(40, 0, 100, 300); int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(bounds.ToString(), out.ToString()); } @@ -337,7 +337,7 @@ TEST(PictureLayerTilingTest, ExpandRectBoundedSmallerStretchHorizontal) { gfx::Rect bounds(0, 55, 180, 190); int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(bounds.ToString(), out.ToString()); } @@ -346,7 +346,7 @@ TEST(PictureLayerTilingTest, ExpandRectBoundedEqualStretchHorizontal) { gfx::Rect bounds(0, 50, 180, 200); int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(bounds.ToString(), out.ToString()); } @@ -355,7 +355,7 @@ TEST(PictureLayerTilingTest, ExpandRectBoundedLeft) { gfx::Rect bounds(20, -1000, 10000, 10000); int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); EXPECT_EQ(out.bottom() - in.bottom(), out.right() - in.right()); EXPECT_LE(out.width() * out.height(), target_area); @@ -369,7 +369,7 @@ TEST(PictureLayerTilingTest, ExpandRectBoundedRight) { gfx::Rect bounds(-1000, -1000, 1000+120, 10000); int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); EXPECT_EQ(out.bottom() - in.bottom(), in.x() - out.x()); EXPECT_LE(out.width() * out.height(), target_area); @@ -383,7 +383,7 @@ TEST(PictureLayerTilingTest, ExpandRectBoundedTop) { gfx::Rect bounds(-1000, 30, 10000, 10000); int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); EXPECT_EQ(out.right() - in.right(), out.bottom() - in.bottom()); EXPECT_LE(out.width() * out.height(), target_area); @@ -397,7 +397,7 @@ TEST(PictureLayerTilingTest, ExpandRectBoundedBottom) { gfx::Rect bounds(-1000, -1000, 10000, 1000 + 220); int64 target_area = 200 * 200; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); EXPECT_EQ(out.right() - in.right(), in.y() - out.y()); EXPECT_LE(out.width() * out.height(), target_area); @@ -411,7 +411,7 @@ TEST(PictureLayerTilingTest, ExpandRectSquishedHorizontally) { gfx::Rect bounds(0, -4000, 100+40+20, 100000); int64 target_area = 400 * 400; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(20, out.right() - in.right()); EXPECT_EQ(40, in.x() - out.x()); EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); @@ -426,7 +426,7 @@ TEST(PictureLayerTilingTest, ExpandRectSquishedVertically) { gfx::Rect bounds(-4000, 0, 100000, 200+50+30); int64 target_area = 400 * 400; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(30, out.bottom() - in.bottom()); EXPECT_EQ(50, in.y() - out.y()); EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); @@ -441,7 +441,7 @@ TEST(PictureLayerTilingTest, ExpandRectOutOfBoundsFarAway) { gfx::Rect bounds(0, 0, 10, 10); int64 target_area = 400 * 400; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_TRUE(out.IsEmpty()); } @@ -450,7 +450,7 @@ TEST(PictureLayerTilingTest, ExpandRectOutOfBoundsExpandedFullyCover) { gfx::Rect bounds(0, 0, 10, 10); int64 target_area = 400 * 400; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(bounds.ToString(), out.ToString()); } @@ -459,7 +459,7 @@ TEST(PictureLayerTilingTest, ExpandRectOutOfBoundsExpandedPartlyCover) { gfx::Rect bounds(0, 0, 500, 500); int64 target_area = 400 * 400; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_EQ(bounds.right(), out.right()); EXPECT_EQ(bounds.bottom(), out.bottom()); EXPECT_LE(out.width() * out.height(), target_area); @@ -475,7 +475,7 @@ TEST(PictureLayerTilingTest, EmptyStartingRect) { gfx::Rect bounds(0, 0, 10, 10); int64 target_area = 400 * 400; gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds); + in, target_area, bounds, NULL); EXPECT_TRUE(out.IsEmpty()); } diff --git a/chromium/cc/resources/picture_pile.cc b/chromium/cc/resources/picture_pile.cc index 17283ddd263..68d75d7aea1 100644 --- a/chromium/cc/resources/picture_pile.cc +++ b/chromium/cc/resources/picture_pile.cc @@ -5,23 +5,137 @@ #include "cc/resources/picture_pile.h" #include <algorithm> +#include <limits> #include <vector> #include "cc/base/region.h" -#include "cc/debug/benchmark_instrumentation.h" +#include "cc/debug/rendering_stats_instrumentation.h" #include "cc/resources/picture_pile_impl.h" +#include "cc/resources/tile_priority.h" namespace { -// Maximum number of pictures that can overlap before we collapse them into -// a larger one. -const size_t kMaxOverlapping = 2; -// Maximum percentage area of the base picture another picture in the picture -// list can be. If higher, we destroy the list and recreate from scratch. -const float kResetThreshold = 0.7f; // Layout pixel buffer around the visible layer rect to record. Any base // picture that intersects the visible layer rect expanded by this distance // will be recorded. const int kPixelDistanceToRecord = 8000; + +// TODO(humper): The density threshold here is somewhat arbitrary; need a +// way to set // this from the command line so we can write a benchmark +// script and find a sweet spot. +const float kDensityThreshold = 0.5f; + +bool rect_sort_y(const gfx::Rect &r1, const gfx::Rect &r2) { + return r1.y() < r2.y() || (r1.y() == r2.y() && r1.x() < r2.x()); +} + +bool rect_sort_x(const gfx::Rect &r1, const gfx::Rect &r2) { + return r1.x() < r2.x() || (r1.x() == r2.x() && r1.y() < r2.y()); +} + +float do_clustering(const std::vector<gfx::Rect>& tiles, + std::vector<gfx::Rect>* clustered_rects) { + // These variables track the record area and invalid area + // for the entire clustering + int total_record_area = 0; + int total_invalid_area = 0; + + // These variables track the record area and invalid area + // for the current cluster being constructed. + gfx::Rect cur_record_rect; + int cluster_record_area = 0, cluster_invalid_area = 0; + + for (std::vector<gfx::Rect>::const_iterator it = tiles.begin(); + it != tiles.end(); + it++) { + gfx::Rect invalid_tile = *it; + + // For each tile, we consider adding the invalid tile to the + // current record rectangle. Only add it if the amount of empty + // space created is below a density threshold. + int tile_area = invalid_tile.width() * invalid_tile.height(); + + gfx::Rect proposed_union = cur_record_rect; + proposed_union.Union(invalid_tile); + int proposed_area = proposed_union.width() * proposed_union.height(); + float proposed_density = + static_cast<float>(cluster_invalid_area + tile_area) / + static_cast<float>(proposed_area); + + if (proposed_density >= kDensityThreshold) { + // It's okay to add this invalid tile to the + // current recording rectangle. + cur_record_rect = proposed_union; + cluster_record_area = proposed_area; + cluster_invalid_area += tile_area; + total_invalid_area += tile_area; + } else { + // Adding this invalid tile to the current recording rectangle + // would exceed our badness threshold, so put the current rectangle + // in the list of recording rects, and start a new one. + clustered_rects->push_back(cur_record_rect); + total_record_area += cluster_record_area; + cur_record_rect = invalid_tile; + cluster_invalid_area = tile_area; + cluster_record_area = tile_area; + } + } + + DCHECK(!cur_record_rect.IsEmpty()); + clustered_rects->push_back(cur_record_rect); + total_record_area += cluster_record_area;; + + DCHECK_NE(total_record_area, 0); + + return static_cast<float>(total_invalid_area) / + static_cast<float>(total_record_area); + } + +float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, + std::vector<gfx::Rect>* record_rects) { + TRACE_EVENT1("cc", "ClusterTiles", + "count", + invalid_tiles.size()); + + if (invalid_tiles.size() <= 1) { + // Quickly handle the special case for common + // single-invalidation update, and also the less common + // case of no tiles passed in. + *record_rects = invalid_tiles; + return 1; + } + + // Sort the invalid tiles by y coordinate. + std::vector<gfx::Rect> invalid_tiles_vertical = invalid_tiles; + std::sort(invalid_tiles_vertical.begin(), + invalid_tiles_vertical.end(), + rect_sort_y); + + float vertical_density; + std::vector<gfx::Rect> vertical_clustering; + vertical_density = do_clustering(invalid_tiles_vertical, + &vertical_clustering); + + // Now try again with a horizontal sort, see which one is best + // TODO(humper): Heuristics for skipping this step? + std::vector<gfx::Rect> invalid_tiles_horizontal = invalid_tiles; + std::sort(invalid_tiles_vertical.begin(), + invalid_tiles_vertical.end(), + rect_sort_x); + + float horizontal_density; + std::vector<gfx::Rect> horizontal_clustering; + horizontal_density = do_clustering(invalid_tiles_vertical, + &horizontal_clustering); + + if (vertical_density < horizontal_density) { + *record_rects = horizontal_clustering; + return horizontal_density; + } + + *record_rects = vertical_clustering; + return vertical_density; +} + } // namespace namespace cc { @@ -38,6 +152,7 @@ bool PicturePile::Update( bool contents_opaque, const Region& invalidation, gfx::Rect visible_layer_rect, + int frame_number, RenderingStatsInstrumentation* stats_instrumentation) { background_color_ = background_color; contents_opaque_ = contents_opaque; @@ -48,130 +163,93 @@ bool PicturePile::Update( -kPixelDistanceToRecord, -kPixelDistanceToRecord, -kPixelDistanceToRecord); - bool modified_pile = false; + + bool invalidated = false; for (Region::Iterator i(invalidation); i.has_rect(); i.next()) { gfx::Rect invalidation = i.rect(); // Split this inflated invalidation across tile boundaries and apply it // to all tiles that it touches. for (TilingData::Iterator iter(&tiling_, invalidation); iter; ++iter) { - gfx::Rect tile = - tiling_.TileBoundsWithBorder(iter.index_x(), iter.index_y()); - if (!tile.Intersects(interest_rect)) { - // This invalidation touches a tile outside the interest rect, so - // just remove the entire picture list. - picture_list_map_.erase(iter.index()); - modified_pile = true; - continue; - } + const PictureMapKey& key = iter.index(); - gfx::Rect tile_invalidation = gfx::IntersectRects(invalidation, tile); - if (tile_invalidation.IsEmpty()) - continue; - PictureListMap::iterator find = picture_list_map_.find(iter.index()); - if (find == picture_list_map_.end()) + PictureMap::iterator picture_it = picture_map_.find(key); + if (picture_it == picture_map_.end()) continue; - PictureList& pic_list = find->second; - // Leave empty pic_lists empty in case there are multiple invalidations. - if (!pic_list.empty()) { - // Inflate all recordings from invalidations with a margin so that when - // scaled down to at least min_contents_scale, any final pixel touched - // by an invalidation can be fully rasterized by this picture. - tile_invalidation.Inset(-buffer_pixels(), -buffer_pixels()); - - DCHECK_GE(tile_invalidation.width(), buffer_pixels() * 2 + 1); - DCHECK_GE(tile_invalidation.height(), buffer_pixels() * 2 + 1); - - InvalidateRect(pic_list, tile_invalidation); - modified_pile = true; - } + + // Inform the grid cell that it has been invalidated in this frame. + invalidated = picture_it->second.Invalidate(frame_number) || invalidated; } } - int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); - - // Walk through all pictures in the rect of interest and record. - for (TilingData::Iterator iter(&tiling_, interest_rect); iter; ++iter) { - // Create a picture in this list if it doesn't exist. - PictureList& pic_list = picture_list_map_[iter.index()]; - if (pic_list.empty()) { - // Inflate the base picture with a margin, similar to invalidations, so - // that when scaled down to at least min_contents_scale, the enclosed - // rect still includes content all the way to the edge of the layer. - gfx::Rect tile = tiling_.TileBounds(iter.index_x(), iter.index_y()); - tile.Inset( - -buffer_pixels(), - -buffer_pixels(), - -buffer_pixels(), - -buffer_pixels()); - scoped_refptr<Picture> base_picture = Picture::Create(tile); - pic_list.push_back(base_picture); - } + // Make a list of all invalid tiles; we will attempt to + // cluster these into multiple invalidation regions. + std::vector<gfx::Rect> invalid_tiles; - for (PictureList::iterator pic = pic_list.begin(); - pic != pic_list.end(); ++pic) { - if (!(*pic)->HasRecording()) { - modified_pile = true; - TRACE_EVENT0(benchmark_instrumentation::kCategory, - benchmark_instrumentation::kRecordLoop); - for (int i = 0; i < repeat_count; i++) - (*pic)->Record(painter, tile_grid_info_, stats_instrumentation); - (*pic)->GatherPixelRefs(tile_grid_info_, stats_instrumentation); - (*pic)->CloneForDrawing(num_raster_threads_); - } + for (TilingData::Iterator it(&tiling_, interest_rect); + it; ++it) { + const PictureMapKey& key = it.index(); + PictureInfo& info = picture_map_[key]; + + gfx::Rect rect = PaddedRect(key); + int distance_to_visible = + rect.ManhattanInternalDistance(visible_layer_rect); + + if (info.NeedsRecording(frame_number, distance_to_visible)) { + gfx::Rect tile = tiling_.TileBounds(key.first, key.second); + invalid_tiles.push_back(tile); } } - UpdateRecordedRegion(); + std::vector<gfx::Rect> record_rects; + ClusterTiles(invalid_tiles, &record_rects); - return modified_pile; -} - -class FullyContainedPredicate { - public: - explicit FullyContainedPredicate(gfx::Rect rect) : layer_rect_(rect) {} - bool operator()(const scoped_refptr<Picture>& picture) { - return picture->LayerRect().IsEmpty() || - layer_rect_.Contains(picture->LayerRect()); - } - gfx::Rect layer_rect_; -}; - -void PicturePile::InvalidateRect( - PictureList& picture_list, - gfx::Rect invalidation) { - DCHECK(!picture_list.empty()); - DCHECK(!invalidation.IsEmpty()); - - std::vector<PictureList::iterator> overlaps; - for (PictureList::iterator i = picture_list.begin(); - i != picture_list.end(); ++i) { - if ((*i)->LayerRect().Contains(invalidation) && !(*i)->HasRecording()) - return; - if ((*i)->LayerRect().Intersects(invalidation) && i != picture_list.begin()) - overlaps.push_back(i); + if (record_rects.empty()) { + if (invalidated) + UpdateRecordedRegion(); + return invalidated; } - gfx::Rect picture_rect = invalidation; - if (overlaps.size() >= kMaxOverlapping) { - for (size_t j = 0; j < overlaps.size(); j++) - picture_rect.Union((*overlaps[j])->LayerRect()); - } + for (std::vector<gfx::Rect>::iterator it = record_rects.begin(); + it != record_rects.end(); + it++) { + gfx::Rect record_rect = *it; + record_rect = PadRect(record_rect); + + int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); + scoped_refptr<Picture> picture = Picture::Create(record_rect); + + { + base::TimeDelta best_duration = base::TimeDelta::FromInternalValue( + std::numeric_limits<int64>::max()); + for (int i = 0; i < repeat_count; i++) { + base::TimeTicks start_time = stats_instrumentation->StartRecording(); + picture->Record(painter, tile_grid_info_); + base::TimeDelta duration = + stats_instrumentation->EndRecording(start_time); + best_duration = std::min(duration, best_duration); + } + int recorded_pixel_count = + picture->LayerRect().width() * picture->LayerRect().height(); + stats_instrumentation->AddRecord(best_duration, recorded_pixel_count); + if (num_raster_threads_ > 1) + picture->GatherPixelRefs(tile_grid_info_); + picture->CloneForDrawing(num_raster_threads_); + } - Picture* base_picture = picture_list.front().get(); - int max_pixels = kResetThreshold * base_picture->LayerRect().size().GetArea(); - if (picture_rect.size().GetArea() > max_pixels) { - // This picture list will be entirely recreated, so clear it. - picture_list.clear(); - return; + for (TilingData::Iterator it(&tiling_, record_rect); + it; ++it) { + const PictureMapKey& key = it.index(); + gfx::Rect tile = PaddedRect(key); + if (record_rect.Contains(tile)) { + PictureInfo& info = picture_map_[key]; + info.SetPicture(picture); + } + } } - FullyContainedPredicate pred(picture_rect); - picture_list.erase(std::remove_if(picture_list.begin(), - picture_list.end(), - pred), - picture_list.end()); - picture_list.push_back(Picture::Create(picture_rect)); + UpdateRecordedRegion(); + return true; } } // namespace cc diff --git a/chromium/cc/resources/picture_pile.h b/chromium/cc/resources/picture_pile.h index 7830a9e62c4..7860e7f831f 100644 --- a/chromium/cc/resources/picture_pile.h +++ b/chromium/cc/resources/picture_pile.h @@ -26,6 +26,7 @@ class CC_EXPORT PicturePile : public PicturePileBase { bool contents_opaque, const Region& invalidation, gfx::Rect visible_layer_rect, + int frame_number, RenderingStatsInstrumentation* stats_instrumentation); void set_num_raster_threads(int num_raster_threads) { @@ -46,12 +47,6 @@ class CC_EXPORT PicturePile : public PicturePileBase { private: friend class PicturePileImpl; - // Add an invalidation to this picture list. If the list needs to be - // entirely recreated, leave it empty. Do not call this on an empty list. - void InvalidateRect( - PictureList& picture_list, - gfx::Rect invalidation); - DISALLOW_COPY_AND_ASSIGN(PicturePile); }; diff --git a/chromium/cc/resources/picture_pile_base.cc b/chromium/cc/resources/picture_pile_base.cc index 0352d30816c..7d60dcafc6b 100644 --- a/chromium/cc/resources/picture_pile_base.cc +++ b/chromium/cc/resources/picture_pile_base.cc @@ -5,6 +5,7 @@ #include "cc/resources/picture_pile_base.h" #include <algorithm> +#include <set> #include <vector> #include "base/logging.h" @@ -17,18 +18,33 @@ namespace { // Dimensions of the tiles in this picture pile as well as the dimensions of // the base picture in each tile. -const int kBasePictureSize = 3000; +const int kBasePictureSize = 512; const int kTileGridBorderPixels = 1; -} +#ifdef NDEBUG +const bool kDefaultClearCanvasSetting = false; +#else +const bool kDefaultClearCanvasSetting = true; +#endif + +// Invalidation frequency settings. kInvalidationFrequencyThreshold is a value +// between 0 and 1 meaning invalidation frequency between 0% and 100% that +// indicates when to stop invalidating offscreen regions. +// kFrequentInvalidationDistanceThreshold defines what it means to be +// "offscreen" in terms of distance to visible in css pixels. +const float kInvalidationFrequencyThreshold = 0.75f; +const int kFrequentInvalidationDistanceThreshold = 512; + +} // namespace namespace cc { PicturePileBase::PicturePileBase() : min_contents_scale_(0), background_color_(SkColorSetARGBInline(0, 0, 0, 0)), - contents_opaque_(false), slow_down_raster_scale_factor_for_debug_(0), + contents_opaque_(false), show_debug_picture_borders_(false), + clear_canvas_with_debug_color_(kDefaultClearCanvasSetting), num_raster_threads_(0) { tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize)); tile_grid_info_.fTileInterval.setEmpty(); @@ -37,16 +53,17 @@ PicturePileBase::PicturePileBase() } PicturePileBase::PicturePileBase(const PicturePileBase* other) - : picture_list_map_(other->picture_list_map_), + : picture_map_(other->picture_map_), tiling_(other->tiling_), recorded_region_(other->recorded_region_), min_contents_scale_(other->min_contents_scale_), tile_grid_info_(other->tile_grid_info_), background_color_(other->background_color_), - contents_opaque_(other->contents_opaque_), slow_down_raster_scale_factor_for_debug_( other->slow_down_raster_scale_factor_for_debug_), + contents_opaque_(other->contents_opaque_), show_debug_picture_borders_(other->show_debug_picture_borders_), + clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), num_raster_threads_(other->num_raster_threads_) { } @@ -57,21 +74,16 @@ PicturePileBase::PicturePileBase( min_contents_scale_(other->min_contents_scale_), tile_grid_info_(other->tile_grid_info_), background_color_(other->background_color_), - contents_opaque_(other->contents_opaque_), slow_down_raster_scale_factor_for_debug_( other->slow_down_raster_scale_factor_for_debug_), + contents_opaque_(other->contents_opaque_), show_debug_picture_borders_(other->show_debug_picture_borders_), + clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), num_raster_threads_(other->num_raster_threads_) { - const PictureListMap& other_pic_list_map = other->picture_list_map_; - for (PictureListMap::const_iterator map_iter = other_pic_list_map.begin(); - map_iter != other_pic_list_map.end(); ++map_iter) { - PictureList& pic_list = picture_list_map_[map_iter->first]; - const PictureList& other_pic_list = map_iter->second; - for (PictureList::const_iterator pic_iter = other_pic_list.begin(); - pic_iter != other_pic_list.end(); ++pic_iter) { - pic_list.push_back( - (*pic_iter)->GetCloneForDrawingOnThread(thread_index)); - } + for (PictureMap::const_iterator it = other->picture_map_.begin(); + it != other->picture_map_.end(); + ++it) { + picture_map_[it->first] = it->second.CloneForThread(thread_index); } } @@ -86,20 +98,22 @@ void PicturePileBase::Resize(gfx::Size new_size) { tiling_.SetTotalSize(new_size); // Find all tiles that contain any pixels outside the new size. - std::vector<PictureListMapKey> to_erase; + std::vector<PictureMapKey> to_erase; int min_toss_x = tiling_.FirstBorderTileXIndexFromSrcCoord( std::min(old_size.width(), new_size.width())); int min_toss_y = tiling_.FirstBorderTileYIndexFromSrcCoord( std::min(old_size.height(), new_size.height())); - for (PictureListMap::iterator iter = picture_list_map_.begin(); - iter != picture_list_map_.end(); ++iter) { - if (iter->first.first < min_toss_x && iter->first.second < min_toss_y) + for (PictureMap::const_iterator it = picture_map_.begin(); + it != picture_map_.end(); + ++it) { + const PictureMapKey& key = it->first; + if (key.first < min_toss_x && key.second < min_toss_y) continue; - to_erase.push_back(iter->first); + to_erase.push_back(key); } for (size_t i = 0; i < to_erase.size(); ++i) - picture_list_map_.erase(to_erase[i]); + picture_map_.erase(to_erase[i]); } void PicturePileBase::SetMinContentsScale(float min_contents_scale) { @@ -123,19 +137,24 @@ void PicturePileBase::SetMinContentsScale(float min_contents_scale) { min_contents_scale_ = min_contents_scale; } -void PicturePileBase::SetTileGridSize(gfx::Size tile_grid_size) { - tile_grid_info_.fTileInterval.set( - tile_grid_size.width() - 2 * kTileGridBorderPixels, - tile_grid_size.height() - 2 * kTileGridBorderPixels); - DCHECK_GT(tile_grid_info_.fTileInterval.width(), 0); - DCHECK_GT(tile_grid_info_.fTileInterval.height(), 0); - tile_grid_info_.fMargin.set(kTileGridBorderPixels, - kTileGridBorderPixels); +// static +void PicturePileBase::ComputeTileGridInfo( + gfx::Size tile_grid_size, + SkTileGridPicture::TileGridInfo* info) { + DCHECK(info); + info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels, + tile_grid_size.height() - 2 * kTileGridBorderPixels); + DCHECK_GT(info->fTileInterval.width(), 0); + DCHECK_GT(info->fTileInterval.height(), 0); + info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels); // Offset the tile grid coordinate space to take into account the fact // that the top-most and left-most tiles do not have top and left borders // respectively. - tile_grid_info_.fOffset.set(-kTileGridBorderPixels, - -kTileGridBorderPixels); + info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels); +} + +void PicturePileBase::SetTileGridSize(gfx::Size tile_grid_size) { + ComputeTileGridInfo(tile_grid_size, &tile_grid_info_); } void PicturePileBase::SetBufferPixels(int new_buffer_pixels) { @@ -147,25 +166,26 @@ void PicturePileBase::SetBufferPixels(int new_buffer_pixels) { } void PicturePileBase::Clear() { - picture_list_map_.clear(); + picture_map_.clear(); } void PicturePileBase::UpdateRecordedRegion() { recorded_region_.Clear(); - for (PictureListMap::iterator it = picture_list_map_.begin(); - it != picture_list_map_.end(); ++it) { - const PictureListMapKey& key = it->first; - recorded_region_.Union(tile_bounds(key.first, key.second)); + for (PictureMap::const_iterator it = picture_map_.begin(); + it != picture_map_.end(); + ++it) { + if (it->second.GetPicture()) { + const PictureMapKey& key = it->first; + recorded_region_.Union(tile_bounds(key.first, key.second)); + } } } bool PicturePileBase::HasRecordingAt(int x, int y) { - PictureListMap::iterator found = - picture_list_map_.find(PictureListMapKey(x, y)); - if (found == picture_list_map_.end()) + PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y)); + if (found == picture_map_.end()) return false; - DCHECK(!found->second.empty()); - return true; + return !!found->second.GetPicture(); } bool PicturePileBase::CanRaster(float contents_scale, gfx::Rect content_rect) { @@ -177,25 +197,92 @@ bool PicturePileBase::CanRaster(float contents_scale, gfx::Rect content_rect) { return recorded_region_.Contains(layer_rect); } +gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) { + gfx::Rect tile = tiling_.TileBounds(key.first, key.second); + return PadRect(tile); +} + +gfx::Rect PicturePileBase::PadRect(gfx::Rect rect) { + gfx::Rect padded_rect = rect; + padded_rect.Inset( + -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels()); + return padded_rect; +} + scoped_ptr<base::Value> PicturePileBase::AsValue() const { scoped_ptr<base::ListValue> pictures(new base::ListValue()); gfx::Rect layer_rect(tiling_.total_size()); + std::set<void*> appended_pictures; for (TilingData::Iterator tile_iter(&tiling_, layer_rect); tile_iter; ++tile_iter) { - PictureListMap::const_iterator map_iter = - picture_list_map_.find(tile_iter.index()); - if (map_iter == picture_list_map_.end()) + PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); + if (map_iter == picture_map_.end()) continue; - const PictureList& pic_list= map_iter->second; - if (pic_list.empty()) - continue; - for (PictureList::const_reverse_iterator i = pic_list.rbegin(); - i != pic_list.rend(); ++i) { - Picture* picture = (*i).get(); + + Picture* picture = map_iter->second.GetPicture(); + if (picture && (appended_pictures.count(picture) == 0)) { + appended_pictures.insert(picture); pictures->Append(TracedValue::CreateIDRef(picture).release()); } } return pictures.PassAs<base::Value>(); } +PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {} + +PicturePileBase::PictureInfo::~PictureInfo() {} + +void PicturePileBase::PictureInfo::AdvanceInvalidationHistory( + int frame_number) { + DCHECK_GE(frame_number, last_frame_number_); + if (frame_number == last_frame_number_) + return; + + invalidation_history_ <<= (frame_number - last_frame_number_); + last_frame_number_ = frame_number; +} + +bool PicturePileBase::PictureInfo::Invalidate(int frame_number) { + AdvanceInvalidationHistory(frame_number); + invalidation_history_.set(0); + + bool did_invalidate = !!picture_; + picture_ = NULL; + return did_invalidate; +} + +bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number, + int distance_to_visible) { + AdvanceInvalidationHistory(frame_number); + + // We only need recording if we don't have a picture. Furthermore, we only + // need a recording if we're within frequent invalidation distance threshold + // or the invalidation is not frequent enough (below invalidation frequency + // threshold). + return !picture_ && + ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) || + (GetInvalidationFrequency() < kInvalidationFrequencyThreshold)); +} + +void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) { + picture_ = picture; +} + +Picture* PicturePileBase::PictureInfo::GetPicture() const { + return picture_.get(); +} + +PicturePileBase::PictureInfo PicturePileBase::PictureInfo::CloneForThread( + int thread_index) const { + PictureInfo info = *this; + if (picture_.get()) + info.picture_ = picture_->GetCloneForDrawingOnThread(thread_index); + return info; +} + +float PicturePileBase::PictureInfo::GetInvalidationFrequency() const { + return invalidation_history_.count() / + static_cast<float>(INVALIDATION_FRAMES_TRACKED); +} + } // namespace cc diff --git a/chromium/cc/resources/picture_pile_base.h b/chromium/cc/resources/picture_pile_base.h index fdb593fa81a..274c865ad3f 100644 --- a/chromium/cc/resources/picture_pile_base.h +++ b/chromium/cc/resources/picture_pile_base.h @@ -5,6 +5,7 @@ #ifndef CC_RESOURCES_PICTURE_PILE_BASE_H_ #define CC_RESOURCES_PICTURE_PILE_BASE_H_ +#include <bitset> #include <list> #include <utility> @@ -41,33 +42,71 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { bool HasRecordingAt(int x, int y); bool CanRaster(float contents_scale, gfx::Rect content_rect); + static void ComputeTileGridInfo(gfx::Size tile_grid_size, + SkTileGridPicture::TileGridInfo* info); + void SetTileGridSize(gfx::Size tile_grid_size); TilingData& tiling() { return tiling_; } scoped_ptr<base::Value> AsValue() const; protected: + class CC_EXPORT PictureInfo { + public: + enum { + INVALIDATION_FRAMES_TRACKED = 32 + }; + + PictureInfo(); + ~PictureInfo(); + + bool Invalidate(int frame_number); + bool NeedsRecording(int frame_number, int distance_to_visible); + PictureInfo CloneForThread(int thread_index) const; + void SetPicture(scoped_refptr<Picture> picture); + Picture* GetPicture() const; + + float GetInvalidationFrequencyForTesting() const { + return GetInvalidationFrequency(); + } + + private: + void AdvanceInvalidationHistory(int frame_number); + float GetInvalidationFrequency() const; + + int last_frame_number_; + scoped_refptr<Picture> picture_; + std::bitset<INVALIDATION_FRAMES_TRACKED> invalidation_history_; + }; + + typedef std::pair<int, int> PictureMapKey; + typedef base::hash_map<PictureMapKey, PictureInfo> PictureMap; + virtual ~PicturePileBase(); + void SetRecordedRegionForTesting(const Region& recorded_region) { + recorded_region_ = recorded_region; + } + int num_raster_threads() { return num_raster_threads_; } int buffer_pixels() const { return tiling_.border_texels(); } void Clear(); - typedef std::pair<int, int> PictureListMapKey; - typedef std::list<scoped_refptr<Picture> > PictureList; - typedef base::hash_map<PictureListMapKey, PictureList> PictureListMap; + gfx::Rect PaddedRect(const PictureMapKey& key); + gfx::Rect PadRect(gfx::Rect rect); - // A picture pile is a tiled set of picture lists. The picture list map - // is a map of tile indices to picture lists. - PictureListMap picture_list_map_; + // A picture pile is a tiled set of pictures. The picture map is a map of tile + // indices to picture infos. + PictureMap picture_map_; TilingData tiling_; Region recorded_region_; float min_contents_scale_; SkTileGridPicture::TileGridInfo tile_grid_info_; SkColor background_color_; - bool contents_opaque_; int slow_down_raster_scale_factor_for_debug_; + bool contents_opaque_; bool show_debug_picture_borders_; + bool clear_canvas_with_debug_color_; int num_raster_threads_; private: diff --git a/chromium/cc/resources/picture_pile_impl.cc b/chromium/cc/resources/picture_pile_impl.cc index 3a4020e072b..b6f4d77156f 100644 --- a/chromium/cc/resources/picture_pile_impl.cc +++ b/chromium/cc/resources/picture_pile_impl.cc @@ -7,7 +7,6 @@ #include "base/debug/trace_event.h" #include "cc/base/region.h" -#include "cc/debug/benchmark_instrumentation.h" #include "cc/debug/debug_colors.h" #include "cc/resources/picture_pile_impl.h" #include "skia/ext/analysis_canvas.h" @@ -73,26 +72,33 @@ void PicturePileImpl::RasterDirect( SkCanvas* canvas, gfx::Rect canvas_rect, float contents_scale, - RasterStats* raster_stats) { - RasterCommon(canvas, NULL, canvas_rect, contents_scale, raster_stats); + RenderingStatsInstrumentation* rendering_stats_instrumentation) { + RasterCommon(canvas, + NULL, + canvas_rect, + contents_scale, + rendering_stats_instrumentation, + false); } void PicturePileImpl::RasterForAnalysis( skia::AnalysisCanvas* canvas, gfx::Rect canvas_rect, - float contents_scale) { - RasterCommon(canvas, canvas, canvas_rect, contents_scale, NULL); + float contents_scale, + RenderingStatsInstrumentation* stats_instrumentation) { + RasterCommon( + canvas, canvas, canvas_rect, contents_scale, stats_instrumentation, true); } void PicturePileImpl::RasterToBitmap( SkCanvas* canvas, gfx::Rect canvas_rect, float contents_scale, - RasterStats* raster_stats) { -#ifndef NDEBUG - // Any non-painted areas will be left in this color. - canvas->clear(DebugColors::NonPaintedFillColor()); -#endif // NDEBUG + RenderingStatsInstrumentation* rendering_stats_instrumentation) { + if (clear_canvas_with_debug_color_) { + // Any non-painted areas will be left in this color. + canvas->clear(DebugColors::NonPaintedFillColor()); + } // If this picture has opaque contents, it is guaranteeing that it will // draw an opaque rect the size of the layer. If it is not, then we must @@ -109,18 +115,17 @@ void PicturePileImpl::RasterToBitmap( gfx::SizeF total_content_size = gfx::ScaleSize(tiling_.total_size(), contents_scale); gfx::Rect content_rect(gfx::ToCeiledSize(total_content_size)); - gfx::Rect deflated_content_rect = content_rect; - content_rect.Intersect(canvas_rect); // The final texel of content may only be partially covered by a // rasterization; this rect represents the content rect that is fully // covered by content. + gfx::Rect deflated_content_rect = content_rect; deflated_content_rect.Inset(0, 0, 1, 1); - deflated_content_rect.Intersect(canvas_rect); if (!deflated_content_rect.Contains(canvas_rect)) { // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X // faster than clearing, so special case this. canvas->save(); + canvas->translate(-canvas_rect.x(), -canvas_rect.y()); gfx::Rect inflated_content_rect = content_rect; inflated_content_rect.Inset(0, 0, -1, -1); canvas->clipRect(gfx::RectToSkRect(inflated_content_rect), @@ -132,7 +137,71 @@ void PicturePileImpl::RasterToBitmap( } } - RasterCommon(canvas, NULL, canvas_rect, contents_scale, raster_stats); + RasterCommon(canvas, + NULL, + canvas_rect, + contents_scale, + rendering_stats_instrumentation, + false); +} + +void PicturePileImpl::CoalesceRasters(gfx::Rect canvas_rect, + gfx::Rect content_rect, + float contents_scale, + PictureRegionMap* results) { + DCHECK(results); + // Rasterize the collection of relevant picture piles. + gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( + content_rect, 1.f / contents_scale); + + // Coalesce rasters of the same picture into different rects: + // - Compute the clip of each of the pile chunks, + // - Subtract it from the canvas rect to get difference region + // - Later, use the difference region to subtract each of the comprising + // rects from the canvas. + // Note that in essence, we're trying to mimic clipRegion with intersect op + // that also respects the current canvas transform and clip. In order to use + // the canvas transform, we must stick to clipRect operations (clipRegion + // ignores the transform). Intersect then can be written as subtracting the + // negation of the region we're trying to intersect. Luckily, we know that all + // of the rects will have to fit into |content_rect|, so we can start with + // that and subtract chunk rects to get the region that we need to subtract + // from the canvas. Then, we can use clipRect with difference op to subtract + // each rect in the region. + for (TilingData::Iterator tile_iter(&tiling_, layer_rect); + tile_iter; ++tile_iter) { + PictureMap::iterator map_iter = picture_map_.find(tile_iter.index()); + if (map_iter == picture_map_.end()) + continue; + PictureInfo& info = map_iter->second; + Picture* picture = info.GetPicture(); + if (!picture) + continue; + + // This is intentionally *enclosed* rect, so that the clip is aligned on + // integral post-scale content pixels and does not extend past the edges + // of the picture chunk's layer rect. The min_contents_scale enforces that + // enough buffer pixels have been added such that the enclosed rect + // encompasses all invalidated pixels at any larger scale level. + gfx::Rect chunk_rect = PaddedRect(tile_iter.index()); + gfx::Rect content_clip = + gfx::ScaleToEnclosedRect(chunk_rect, contents_scale); + DCHECK(!content_clip.IsEmpty()) << "Layer rect: " + << picture->LayerRect().ToString() + << "Contents scale: " << contents_scale; + content_clip.Intersect(canvas_rect); + + PictureRegionMap::iterator it = results->find(picture); + if (it == results->end()) { + Region& region = (*results)[picture]; + region = content_rect; + region.Subtract(content_clip); + continue; + } + + Region& region = it->second; + region.Subtract(content_clip); + } } void PicturePileImpl::RasterCommon( @@ -140,128 +209,84 @@ void PicturePileImpl::RasterCommon( SkDrawPictureCallback* callback, gfx::Rect canvas_rect, float contents_scale, - RasterStats* raster_stats) { + RenderingStatsInstrumentation* rendering_stats_instrumentation, + bool is_analysis) { DCHECK(contents_scale >= min_contents_scale_); canvas->translate(-canvas_rect.x(), -canvas_rect.y()); - gfx::SizeF total_content_size = gfx::ScaleSize(tiling_.total_size(), contents_scale); gfx::Rect total_content_rect(gfx::ToCeiledSize(total_content_size)); gfx::Rect content_rect = total_content_rect; content_rect.Intersect(canvas_rect); - // Rasterize the collection of relevant picture piles. - gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( - content_rect, 1.f / contents_scale); - canvas->clipRect(gfx::RectToSkRect(content_rect), SkRegion::kIntersect_Op); - Region unclipped(content_rect); - if (raster_stats) { - raster_stats->total_pixels_rasterized = 0; - raster_stats->total_rasterize_time = base::TimeDelta::FromSeconds(0); - raster_stats->best_rasterize_time = base::TimeDelta::FromSeconds(0); - } + PictureRegionMap picture_region_map; + CoalesceRasters( + canvas_rect, content_rect, contents_scale, &picture_region_map); - for (TilingData::Iterator tile_iter(&tiling_, layer_rect); - tile_iter; ++tile_iter) { - PictureListMap::iterator map_iter = - picture_list_map_.find(tile_iter.index()); - if (map_iter == picture_list_map_.end()) - continue; - PictureList& pic_list= map_iter->second; - if (pic_list.empty()) - continue; +#ifndef NDEBUG + Region total_clip; +#endif // NDEBUG - // Raster through the picture list top down, using clips to make sure that - // pictures on top are not overdrawn by pictures on the bottom. - for (PictureList::reverse_iterator i = pic_list.rbegin(); - i != pic_list.rend(); ++i) { - // This is intentionally *enclosed* rect, so that the clip is aligned on - // integral post-scale content pixels and does not extend past the edges - // of the picture's layer rect. The min_contents_scale enforces that - // enough buffer pixels have been added such that the enclosed rect - // encompasses all invalidated pixels at any larger scale level. - gfx::Rect content_clip = gfx::ScaleToEnclosedRect( - (*i)->LayerRect(), contents_scale); - - DCHECK(!content_clip.IsEmpty()) << - "Layer rect: " << (*i)->LayerRect().ToString() << - "Contents scale: " << contents_scale; - - content_clip.Intersect(canvas_rect); - - if (!unclipped.Intersects(content_clip)) - continue; - - base::TimeDelta total_duration = - base::TimeDelta::FromInternalValue(0); - base::TimeDelta best_duration = - base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max()); - int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); - - TRACE_EVENT0(benchmark_instrumentation::kCategory, - benchmark_instrumentation::kRasterLoop); - for (int j = 0; j < repeat_count; ++j) { - base::TimeTicks start_time; - if (raster_stats) - start_time = base::TimeTicks::HighResNow(); - - (*i)->Raster(canvas, callback, content_clip, contents_scale); - - if (raster_stats) { - base::TimeDelta duration = base::TimeTicks::HighResNow() - start_time; - total_duration += duration; - best_duration = std::min(best_duration, duration); - } - } + // Iterate the coalesced map and use each picture's region + // to clip the canvas. + for (PictureRegionMap::iterator it = picture_region_map.begin(); + it != picture_region_map.end(); + ++it) { + Picture* picture = it->first; + Region negated_clip_region = it->second; - if (raster_stats) { - raster_stats->total_pixels_rasterized += - repeat_count * content_clip.width() * content_clip.height(); - raster_stats->total_rasterize_time += total_duration; - raster_stats->best_rasterize_time += best_duration; - } +#ifndef NDEBUG + Region positive_clip = content_rect; + positive_clip.Subtract(negated_clip_region); + total_clip.Union(positive_clip); +#endif // NDEBUG + + base::TimeDelta best_duration = + base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max()); + int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); + int rasterized_pixel_count = 0; + + for (int j = 0; j < repeat_count; ++j) { + base::TimeTicks start_time; + if (rendering_stats_instrumentation) + start_time = rendering_stats_instrumentation->StartRecording(); - if (show_debug_picture_borders_) { - gfx::Rect border = gfx::ScaleToEnclosedRect( - (*i)->LayerRect(), contents_scale); - border.Inset(0, 0, 1, 1); - - SkPaint picture_border_paint; - picture_border_paint.setColor(DebugColors::PictureBorderColor()); - canvas->drawLine(border.x(), border.y(), border.right(), border.y(), - picture_border_paint); - canvas->drawLine(border.right(), border.y(), border.right(), - border.bottom(), picture_border_paint); - canvas->drawLine(border.right(), border.bottom(), border.x(), - border.bottom(), picture_border_paint); - canvas->drawLine(border.x(), border.bottom(), border.x(), border.y(), - picture_border_paint); + rasterized_pixel_count = picture->Raster( + canvas, callback, negated_clip_region, contents_scale); + + if (rendering_stats_instrumentation) { + base::TimeDelta duration = + rendering_stats_instrumentation->EndRecording(start_time); + best_duration = std::min(best_duration, duration); } + } - // Don't allow pictures underneath to draw where this picture did. - canvas->clipRect( - gfx::RectToSkRect(content_clip), - SkRegion::kDifference_Op); - unclipped.Subtract(content_clip); + if (rendering_stats_instrumentation) { + if (is_analysis) { + rendering_stats_instrumentation->AddAnalysis(best_duration, + rasterized_pixel_count); + } else { + rendering_stats_instrumentation->AddRaster(best_duration, + rasterized_pixel_count); + } } } #ifndef NDEBUG - // Fill the remaining clip with debug color. This allows us to + // Fill the clip with debug color. This allows us to // distinguish between non painted areas and problems with missing // pictures. SkPaint paint; + for (Region::Iterator it(total_clip); it.has_rect(); it.next()) + canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op); paint.setColor(DebugColors::MissingPictureFillColor()); paint.setXfermodeMode(SkXfermode::kSrc_Mode); canvas->drawPaint(paint); #endif // NDEBUG - - // We should always paint some part of |content_rect|. - DCHECK(!unclipped.Contains(content_rect)); } skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() { @@ -283,9 +308,18 @@ skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() { return picture; } -void PicturePileImpl::AnalyzeInRect(gfx::Rect content_rect, - float contents_scale, - PicturePileImpl::Analysis* analysis) { +void PicturePileImpl::AnalyzeInRect( + gfx::Rect content_rect, + float contents_scale, + PicturePileImpl::Analysis* analysis) { + AnalyzeInRect(content_rect, contents_scale, analysis, NULL); +} + +void PicturePileImpl::AnalyzeInRect( + gfx::Rect content_rect, + float contents_scale, + PicturePileImpl::Analysis* analysis, + RenderingStatsInstrumentation* stats_instrumentation) { DCHECK(analysis); TRACE_EVENT0("cc", "PicturePileImpl::AnalyzeInRect"); @@ -301,7 +335,7 @@ void PicturePileImpl::AnalyzeInRect(gfx::Rect content_rect, skia::AnalysisDevice device(empty_bitmap); skia::AnalysisCanvas canvas(&device); - RasterForAnalysis(&canvas, layer_rect, 1.0f); + RasterForAnalysis(&canvas, layer_rect, 1.0f, stats_instrumentation); analysis->is_solid_color = canvas.GetColorIfSolid(&analysis->solid_color); analysis->has_text = canvas.HasText(); @@ -322,14 +356,12 @@ PicturePileImpl::PixelRefIterator::PixelRefIterator( : picture_pile_(picture_pile), layer_rect_(gfx::ScaleToEnclosingRect( content_rect, 1.f / contents_scale)), - tile_iterator_(&picture_pile_->tiling_, layer_rect_), - picture_list_(NULL) { + tile_iterator_(&picture_pile_->tiling_, layer_rect_) { // Early out if there isn't a single tile. if (!tile_iterator_) return; - if (AdvanceToTileWithPictures()) - AdvanceToPictureWithPixelRefs(); + AdvanceToTilePictureWithPixelRefs(); } PicturePileImpl::PixelRefIterator::~PixelRefIterator() { @@ -341,50 +373,40 @@ PicturePileImpl::PixelRefIterator& if (pixel_ref_iterator_) return *this; - ++picture_list_iterator_; - AdvanceToPictureWithPixelRefs(); + ++tile_iterator_; + AdvanceToTilePictureWithPixelRefs(); return *this; } -bool PicturePileImpl::PixelRefIterator::AdvanceToTileWithPictures() { +void PicturePileImpl::PixelRefIterator::AdvanceToTilePictureWithPixelRefs() { for (; tile_iterator_; ++tile_iterator_) { - PictureListMap::const_iterator map_iterator = - picture_pile_->picture_list_map_.find(tile_iterator_.index()); - if (map_iterator != picture_pile_->picture_list_map_.end()) { - picture_list_ = &map_iterator->second; - picture_list_iterator_ = picture_list_->begin(); - return true; - } - } + PictureMap::const_iterator it = + picture_pile_->picture_map_.find(tile_iterator_.index()); + if (it == picture_pile_->picture_map_.end()) + continue; - return false; -} + const Picture* picture = it->second.GetPicture(); + if (!picture || (processed_pictures_.count(picture) != 0) || + !picture->WillPlayBackBitmaps()) + continue; -void PicturePileImpl::PixelRefIterator::AdvanceToPictureWithPixelRefs() { - DCHECK(tile_iterator_); - do { - for (; - picture_list_iterator_ != picture_list_->end(); - ++picture_list_iterator_) { - pixel_ref_iterator_ = - Picture::PixelRefIterator(layer_rect_, picture_list_iterator_->get()); - if (pixel_ref_iterator_) - return; - } - ++tile_iterator_; - } while (AdvanceToTileWithPictures()); + processed_pictures_.insert(picture); + pixel_ref_iterator_ = Picture::PixelRefIterator(layer_rect_, picture); + if (pixel_ref_iterator_) + break; + } } void PicturePileImpl::DidBeginTracing() { gfx::Rect layer_rect(tiling_.total_size()); - for (PictureListMap::iterator pli = picture_list_map_.begin(); - pli != picture_list_map_.end(); - pli++) { - PictureList& picture_list = (*pli).second; - for (PictureList::iterator picture = picture_list.begin(); - picture != picture_list.end(); - picture++) { - (*picture)->EmitTraceSnapshot(); + std::set<void*> processed_pictures; + for (PictureMap::iterator it = picture_map_.begin(); + it != picture_map_.end(); + ++it) { + Picture* picture = it->second.GetPicture(); + if (picture && (processed_pictures.count(picture) == 0)) { + picture->EmitTraceSnapshot(); + processed_pictures.insert(picture); } } } diff --git a/chromium/cc/resources/picture_pile_impl.h b/chromium/cc/resources/picture_pile_impl.h index c6c3ab3fbe4..180dba258ee 100644 --- a/chromium/cc/resources/picture_pile_impl.h +++ b/chromium/cc/resources/picture_pile_impl.h @@ -7,10 +7,12 @@ #include <list> #include <map> +#include <set> #include <vector> #include "base/time/time.h" #include "cc/base/cc_export.h" +#include "cc/debug/rendering_stats_instrumentation.h" #include "cc/resources/picture_pile_base.h" #include "skia/ext/analysis_canvas.h" #include "skia/ext/refptr.h" @@ -27,16 +29,6 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase { // Get paint-safe version of this picture for a specific thread. PicturePileImpl* GetCloneForDrawingOnThread(unsigned thread_index) const; - struct CC_EXPORT RasterStats { - // Minimum rasterize time from N runs - // N=max(1,slow-down-raster-scale-factor) - base::TimeDelta best_rasterize_time; - // Total rasterize time for all N runs - base::TimeDelta total_rasterize_time; - // Total number of pixels rasterize in all N runs - int64 total_pixels_rasterized; - }; - // Raster a subrect of this PicturePileImpl into the given canvas. // It's only safe to call paint on a cloned version. It is assumed // that contents_scale has already been applied to this canvas. @@ -49,7 +41,7 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase { SkCanvas* canvas, gfx::Rect canvas_rect, float contents_scale, - RasterStats* raster_stats); + RenderingStatsInstrumentation* rendering_stats_instrumentation); // Similar to the above RasterDirect method, but this is a convenience method // for when it is known that the raster is going to an intermediate bitmap @@ -58,15 +50,15 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase { SkCanvas* canvas, gfx::Rect canvas_rect, float contents_scale, - RasterStats* raster_stats); + RenderingStatsInstrumentation* stats_instrumentation); // Called when analyzing a tile. We can use AnalysisCanvas as // SkDrawPictureCallback, which allows us to early out from analysis. void RasterForAnalysis( skia::AnalysisCanvas* canvas, gfx::Rect canvas_rect, - float contents_scale); - + float contents_scale, + RenderingStatsInstrumentation* stats_instrumentation); skia::RefPtr<SkPicture> GetFlattenedPicture(); @@ -83,6 +75,11 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase { float contents_scale, Analysis* analysis); + void AnalyzeInRect(gfx::Rect content_rect, + float contents_scale, + Analysis* analysis, + RenderingStatsInstrumentation* stats_instrumentation); + class CC_EXPORT PixelRefIterator { public: PixelRefIterator(gfx::Rect content_rect, @@ -96,15 +93,13 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase { operator bool() const { return pixel_ref_iterator_; } private: - bool AdvanceToTileWithPictures(); - void AdvanceToPictureWithPixelRefs(); + void AdvanceToTilePictureWithPixelRefs(); const PicturePileImpl* picture_pile_; gfx::Rect layer_rect_; TilingData::Iterator tile_iterator_; Picture::PixelRefIterator pixel_ref_iterator_; - const PictureList* picture_list_; - PictureList::const_iterator picture_list_iterator_; + std::set<const void*> processed_pictures_; }; void DidBeginTracing(); @@ -132,12 +127,20 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase { PicturePileImpl(const PicturePileImpl* other, unsigned thread_index); + private: + typedef std::map<Picture*, Region> PictureRegionMap; + void CoalesceRasters(gfx::Rect canvas_rect, + gfx::Rect content_rect, + float contents_scale, + PictureRegionMap* result); + void RasterCommon( SkCanvas* canvas, SkDrawPictureCallback* callback, gfx::Rect canvas_rect, float contents_scale, - RasterStats* raster_stats); + RenderingStatsInstrumentation* rendering_stats_instrumentation, + bool is_analysis); // Once instantiated, |clones_for_drawing_| can't be modified. This // guarantees thread-safe access during the life time of a PicturePileImpl diff --git a/chromium/cc/resources/picture_pile_impl_unittest.cc b/chromium/cc/resources/picture_pile_impl_unittest.cc index 6f33691b5da..e5691e39301 100644 --- a/chromium/cc/resources/picture_pile_impl_unittest.cc +++ b/chromium/cc/resources/picture_pile_impl_unittest.cc @@ -635,128 +635,75 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefsBaseNonLazy) { } } -TEST(PicturePileImplTest, PixelRefIteratorMultiplePictures) { - gfx::Size tile_size(256, 256); - gfx::Size layer_bounds(256, 256); - - SkTileGridPicture::TileGridInfo tile_grid_info; - tile_grid_info.fTileInterval = SkISize::Make(256, 256); - tile_grid_info.fMargin.setEmpty(); - tile_grid_info.fOffset.setZero(); - - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - - SkBitmap lazy_bitmap[2][2]; - CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][0]); - CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][1]); - CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[1][1]); - SkBitmap non_lazy_bitmap; - CreateBitmap(gfx::Size(256, 256), "notlazy", &non_lazy_bitmap); - - // Each bitmap goes into its own picture, the final layout - // has lazy pixel refs in the following regions: - // ||=======|| - // ||x| |x|| - // ||-- --|| - // || |x|| - // ||=======|| - pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(0, 0)); - pile->RerecordPile(); - - FakeContentLayerClient content_layer_clients[2][2]; - FakeRenderingStatsInstrumentation stats_instrumentation; - scoped_refptr<Picture> pictures[2][2]; - for (int y = 0; y < 2; ++y) { - for (int x = 0; x < 2; ++x) { - if (x == 0 && y == 1) - continue; - content_layer_clients[y][x].add_draw_bitmap( - lazy_bitmap[y][x], - gfx::Point(x * 128 + 10, y * 128 + 10)); - pictures[y][x] = Picture::Create( - gfx::Rect(x * 128 + 10, y * 128 + 10, 64, 64)); - pictures[y][x]->Record( - &content_layer_clients[y][x], - tile_grid_info, - &stats_instrumentation); - pictures[y][x]->GatherPixelRefs(tile_grid_info, &stats_instrumentation); - pile->AddPictureToRecording(0, 0, pictures[y][x]); - } - } - - // These should find only one pixel ref. - { - PicturePileImpl::PixelRefIterator iterator( - gfx::Rect(0, 0, 128, 128), 1.0, pile.get()); - EXPECT_TRUE(iterator); - EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); - EXPECT_FALSE(++iterator); - } - { - PicturePileImpl::PixelRefIterator iterator( - gfx::Rect(128, 0, 128, 128), 1.0, pile.get()); - EXPECT_TRUE(iterator); - EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef()); - EXPECT_FALSE(++iterator); - } - { - PicturePileImpl::PixelRefIterator iterator( - gfx::Rect(128, 128, 128, 128), 1.0, pile.get()); - EXPECT_TRUE(iterator); - EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); - EXPECT_FALSE(++iterator); - } - // This one should not find any refs - { - PicturePileImpl::PixelRefIterator iterator( - gfx::Rect(0, 128, 128, 128), 1.0, pile.get()); - EXPECT_FALSE(iterator); - } -} - TEST(PicturePileImpl, RasterContentsOpaque) { gfx::Size tile_size(1000, 1000); gfx::Size layer_bounds(3, 5); float contents_scale = 1.5f; + float raster_divisions = 2.f; scoped_refptr<FakePicturePileImpl> pile = FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); // Because the caller sets content opaque, it also promises that it // has at least filled in layer_bounds opaquely. - SkPaint red_paint; - red_paint.setColor(SK_ColorRED); - pile->add_draw_rect_with_paint(gfx::Rect(layer_bounds), red_paint); + SkPaint white_paint; + white_paint.setColor(SK_ColorWHITE); + pile->add_draw_rect_with_paint(gfx::Rect(layer_bounds), white_paint); pile->SetMinContentsScale(contents_scale); - pile->set_background_color(SK_ColorRED); + pile->set_background_color(SK_ColorBLACK); pile->set_contents_opaque(true); + pile->set_clear_canvas_with_debug_color(false); pile->RerecordPile(); gfx::Size content_bounds( gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale))); - // Simulate a canvas rect larger than the content bounds. Every pixel - // up to one pixel outside the content bounds is guaranteed to be opaque. - // Outside of that is undefined. - gfx::Rect canvas_rect(content_bounds); - canvas_rect.Inset(0, 0, -1, -1); - - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, - canvas_rect.width(), - canvas_rect.height()); - bitmap.allocPixels(); - SkCanvas canvas(bitmap); - - PicturePileImpl::RasterStats raster_stats; - pile->RasterToBitmap( - &canvas, canvas_rect, contents_scale, &raster_stats); - - SkColor* pixels = reinterpret_cast<SkColor*>(bitmap.getPixels()); - int num_pixels = bitmap.width() * bitmap.height(); - for (int i = 0; i < num_pixels; ++i) { - EXPECT_EQ(SkColorGetA(pixels[i]), 255u); + // Simulate drawing into different tiles at different offsets. + int step_x = std::ceil(content_bounds.width() / raster_divisions); + int step_y = std::ceil(content_bounds.height() / raster_divisions); + for (int offset_x = 0; offset_x < content_bounds.width(); + offset_x += step_x) { + for (int offset_y = 0; offset_y < content_bounds.height(); + offset_y += step_y) { + gfx::Rect content_rect(offset_x, offset_y, step_x, step_y); + content_rect.Intersect(gfx::Rect(content_bounds)); + + // Simulate a canvas rect larger than the content rect. Every pixel + // up to one pixel outside the content rect is guaranteed to be opaque. + // Outside of that is undefined. + gfx::Rect canvas_rect(content_rect); + canvas_rect.Inset(0, 0, -1, -1); + + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, + canvas_rect.width(), + canvas_rect.height()); + bitmap.allocPixels(); + SkCanvas canvas(bitmap); + canvas.clear(SK_ColorTRANSPARENT); + + FakeRenderingStatsInstrumentation rendering_stats_instrumentation; + + pile->RasterToBitmap(&canvas, + canvas_rect, + contents_scale, + &rendering_stats_instrumentation); + + SkColor* pixels = reinterpret_cast<SkColor*>(bitmap.getPixels()); + int num_pixels = bitmap.width() * bitmap.height(); + bool all_white = true; + for (int i = 0; i < num_pixels; ++i) { + EXPECT_EQ(SkColorGetA(pixels[i]), 255u); + all_white &= (SkColorGetR(pixels[i]) == 255); + all_white &= (SkColorGetG(pixels[i]) == 255); + all_white &= (SkColorGetB(pixels[i]) == 255); + } + + // If the canvas doesn't extend past the edge of the content, + // it should be entirely white. Otherwise, the edge of the content + // will be non-white. + EXPECT_EQ(all_white, gfx::Rect(content_bounds).Contains(canvas_rect)); + } } } @@ -770,6 +717,7 @@ TEST(PicturePileImpl, RasterContentsTransparent) { pile->set_background_color(SK_ColorTRANSPARENT); pile->set_contents_opaque(false); pile->SetMinContentsScale(contents_scale); + pile->set_clear_canvas_with_debug_color(false); pile->RerecordPile(); gfx::Size content_bounds( @@ -785,9 +733,9 @@ TEST(PicturePileImpl, RasterContentsTransparent) { bitmap.allocPixels(); SkCanvas canvas(bitmap); - PicturePileImpl::RasterStats raster_stats; + FakeRenderingStatsInstrumentation rendering_stats_instrumentation; pile->RasterToBitmap( - &canvas, canvas_rect, contents_scale, &raster_stats); + &canvas, canvas_rect, contents_scale, &rendering_stats_instrumentation); SkColor* pixels = reinterpret_cast<SkColor*>(bitmap.getPixels()); int num_pixels = bitmap.width() * bitmap.height(); diff --git a/chromium/cc/resources/picture_pile_unittest.cc b/chromium/cc/resources/picture_pile_unittest.cc index 1eeb5ad5fe5..91ec355424e 100644 --- a/chromium/cc/resources/picture_pile_unittest.cc +++ b/chromium/cc/resources/picture_pile_unittest.cc @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <map> +#include <utility> + #include "cc/resources/picture_pile.h" #include "cc/test/fake_content_layer_client.h" #include "cc/test/fake_rendering_stats_instrumentation.h" @@ -16,11 +19,11 @@ class TestPicturePile : public PicturePile { public: using PicturePile::buffer_pixels; - PictureListMap& picture_list_map() { return picture_list_map_; } + PictureMap& picture_map() { return picture_map_; } - typedef PicturePile::PictureList PictureList; - typedef PicturePile::PictureListMapKey PictureListMapKey; - typedef PicturePile::PictureListMap PictureListMap; + typedef PicturePile::PictureInfo PictureInfo; + typedef PicturePile::PictureMapKey PictureMapKey; + typedef PicturePile::PictureMap PictureMap; protected: virtual ~TestPicturePile() {} @@ -46,6 +49,7 @@ TEST(PicturePileTest, SmallInvalidateInflated) { false, gfx::Rect(layer_size), gfx::Rect(layer_size), + 1, &stats_instrumentation); // Invalidate something inside a tile. @@ -55,27 +59,23 @@ TEST(PicturePileTest, SmallInvalidateInflated) { false, invalidate_rect, gfx::Rect(layer_size), + 2, &stats_instrumentation); EXPECT_EQ(1, pile->tiling().num_tiles_x()); EXPECT_EQ(1, pile->tiling().num_tiles_y()); - TestPicturePile::PictureList& picture_list = - pile->picture_list_map().find( - TestPicturePile::PictureListMapKey(0, 0))->second; - EXPECT_EQ(2u, picture_list.size()); - for (TestPicturePile::PictureList::iterator it = picture_list.begin(); - it != picture_list.end(); - ++it) { - scoped_refptr<Picture> picture = *it; - gfx::Rect picture_rect = - gfx::ScaleToEnclosedRect(picture->LayerRect(), min_scale); - - // The invalidation in each tile should have been made large enough - // that scaling it never makes a rect smaller than 1 px wide or tall. - EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect " << - picture_rect.ToString(); - } + TestPicturePile::PictureInfo& picture_info = + pile->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second; + // We should have a picture. + EXPECT_TRUE(!!picture_info.GetPicture()); + gfx::Rect picture_rect = gfx::ScaleToEnclosedRect( + picture_info.GetPicture()->LayerRect(), min_scale); + + // The the picture should be large enough that scaling it never makes a rect + // smaller than 1 px wide or tall. + EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect " << + picture_rect.ToString(); } TEST(PicturePileTest, LargeInvalidateInflated) { @@ -98,6 +98,7 @@ TEST(PicturePileTest, LargeInvalidateInflated) { false, gfx::Rect(layer_size), gfx::Rect(layer_size), + 1, &stats_instrumentation); // Invalidate something inside a tile. @@ -107,29 +108,23 @@ TEST(PicturePileTest, LargeInvalidateInflated) { false, invalidate_rect, gfx::Rect(layer_size), + 2, &stats_instrumentation); EXPECT_EQ(1, pile->tiling().num_tiles_x()); EXPECT_EQ(1, pile->tiling().num_tiles_y()); - TestPicturePile::PictureList& picture_list = - pile->picture_list_map().find( - TestPicturePile::PictureListMapKey(0, 0))->second; - EXPECT_EQ(2u, picture_list.size()); + TestPicturePile::PictureInfo& picture_info = + pile->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second; + EXPECT_TRUE(!!picture_info.GetPicture()); int expected_inflation = pile->buffer_pixels(); - scoped_refptr<Picture> base_picture = *picture_list.begin(); + Picture* base_picture = picture_info.GetPicture(); gfx::Rect base_picture_rect(layer_size); base_picture_rect.Inset(-expected_inflation, -expected_inflation); EXPECT_EQ(base_picture_rect.ToString(), base_picture->LayerRect().ToString()); - - scoped_refptr<Picture> picture = *(++picture_list.begin()); - gfx::Rect picture_rect(invalidate_rect); - picture_rect.Inset(-expected_inflation, -expected_inflation); - EXPECT_EQ(picture_rect.ToString(), - picture->LayerRect().ToString()); } TEST(PicturePileTest, InvalidateOnTileBoundaryInflated) { @@ -155,12 +150,23 @@ TEST(PicturePileTest, InvalidateOnTileBoundaryInflated) { EXPECT_EQ(7, pile->buffer_pixels()); EXPECT_EQ(7, pile->tiling().border_texels()); - // Update the whole layer. + // Update the whole layer to create initial pictures. + pile->Update(&client, + background_color, + false, + gfx::Rect(layer_size), + gfx::Rect(layer_size), + 0, + &stats_instrumentation); + + // Invalidate everything again to have a non zero invalidation + // frequency. pile->Update(&client, background_color, false, gfx::Rect(layer_size), gfx::Rect(layer_size), + 1, &stats_instrumentation); // Invalidate something just over a tile boundary by a single pixel. @@ -175,34 +181,120 @@ TEST(PicturePileTest, InvalidateOnTileBoundaryInflated) { false, invalidate_rect, gfx::Rect(layer_size), + 2, &stats_instrumentation); for (int i = 0; i < pile->tiling().num_tiles_x(); ++i) { for (int j = 0; j < pile->tiling().num_tiles_y(); ++j) { - // (1, 0) and (1, 1) should be invalidated partially. - bool expect_invalidated = i == 1 && (j == 0 || j == 1); - - TestPicturePile::PictureList& picture_list = - pile->picture_list_map().find( - TestPicturePile::PictureListMapKey(i, j))->second; - if (!expect_invalidated) { - EXPECT_EQ(1u, picture_list.size()) << "For i,j " << i << "," << j; - continue; + TestPicturePile::PictureInfo& picture_info = + pile->picture_map().find( + TestPicturePile::PictureMapKey(i, j))->second; + + // Expect (1, 1) and (1, 0) to be invalidated once more + // than the rest of the tiles. + if (i == 1 && (j == 0 || j == 1)) { + EXPECT_FLOAT_EQ( + 2.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED, + picture_info.GetInvalidationFrequencyForTesting()); + } else { + EXPECT_FLOAT_EQ( + 1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED, + picture_info.GetInvalidationFrequencyForTesting()); } + } + } +} - EXPECT_EQ(2u, picture_list.size()) << "For i,j " << i << "," << j; - for (TestPicturePile::PictureList::iterator it = picture_list.begin(); - it != picture_list.end(); - ++it) { - scoped_refptr<Picture> picture = *it; - gfx::Rect picture_rect = - gfx::ScaleToEnclosedRect(picture->LayerRect(), min_scale); - - // The invalidation in each tile should have been made large enough - // that scaling it never makes a rect smaller than 1 px wide or tall. - EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect " << - picture_rect.ToString(); - } +TEST(PicturePileTest, StopRecordingOffscreenInvalidations) { + FakeContentLayerClient client; + FakeRenderingStatsInstrumentation stats_instrumentation; + scoped_refptr<TestPicturePile> pile = new TestPicturePile; + SkColor background_color = SK_ColorBLUE; + + float min_scale = 0.125; + gfx::Size base_picture_size = pile->tiling().max_texture_size(); + + gfx::Size layer_size = + gfx::ToFlooredSize(gfx::ScaleSize(base_picture_size, 4.f)); + pile->Resize(layer_size); + pile->SetTileGridSize(gfx::Size(1000, 1000)); + pile->SetMinContentsScale(min_scale); + + gfx::Rect viewport(0, 0, layer_size.width(), 1); + + // Update the whole layer until the invalidation frequency is high. + int frame; + for (frame = 0; frame < 33; ++frame) { + pile->Update(&client, + background_color, + false, + gfx::Rect(layer_size), + viewport, + frame, + &stats_instrumentation); + } + + // Make sure we have a high invalidation frequency. + for (int i = 0; i < pile->tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile->tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureInfo& picture_info = + pile->picture_map().find( + TestPicturePile::PictureMapKey(i, j))->second; + EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting()) + << "i " << i << " j " << j; + } + } + + // Update once more with a small viewport 0,0 layer_width by 1 + pile->Update(&client, + background_color, + false, + gfx::Rect(layer_size), + viewport, + frame, + &stats_instrumentation); + + for (int i = 0; i < pile->tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile->tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureInfo& picture_info = + pile->picture_map().find( + TestPicturePile::PictureMapKey(i, j))->second; + EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting()); + + // If the y far enough away we expect to find no picture (no re-recording + // happened). For close y, the picture should change. + if (j >= 2) + EXPECT_FALSE(picture_info.GetPicture()) << "i " << i << " j " << j; + else + EXPECT_TRUE(picture_info.GetPicture()) << "i " << i << " j " << j; + } + } + + // Now update with no invalidation and full viewport + pile->Update(&client, + background_color, + false, + gfx::Rect(), + gfx::Rect(layer_size), + frame+1, + &stats_instrumentation); + + for (int i = 0; i < pile->tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile->tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureInfo& picture_info = + pile->picture_map().find( + TestPicturePile::PictureMapKey(i, j))->second; + // Expect the invalidation frequency to be less than 1, since we just + // updated with no invalidations. + float expected_frequency = + 1.0f - + 1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED; + + EXPECT_FLOAT_EQ(expected_frequency, + picture_info.GetInvalidationFrequencyForTesting()); + + // We expect that there are pictures everywhere now. + EXPECT_TRUE(picture_info.GetPicture()) << "i " << i << " j " << j; } } } diff --git a/chromium/cc/resources/picture_unittest.cc b/chromium/cc/resources/picture_unittest.cc index aa20ebb6381..f279a99b281 100644 --- a/chromium/cc/resources/picture_unittest.cc +++ b/chromium/cc/resources/picture_unittest.cc @@ -8,7 +8,6 @@ #include "base/memory/scoped_ptr.h" #include "base/values.h" #include "cc/test/fake_content_layer_client.h" -#include "cc/test/fake_rendering_stats_instrumentation.h" #include "cc/test/skia_common.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -33,7 +32,6 @@ TEST(PictureTest, AsBase64String) { tile_grid_info.fOffset.setZero(); FakeContentLayerClient content_layer_client; - FakeRenderingStatsInstrumentation stats_instrumentation; scoped_ptr<base::Value> tmp; @@ -52,8 +50,7 @@ TEST(PictureTest, AsBase64String) { content_layer_client.add_draw_rect(layer_rect, red_paint); scoped_refptr<Picture> one_rect_picture = Picture::Create(layer_rect); one_rect_picture->Record(&content_layer_client, - tile_grid_info, - &stats_instrumentation); + tile_grid_info); scoped_ptr<base::Value> serialized_one_rect( one_rect_picture->AsValue()); @@ -79,8 +76,7 @@ TEST(PictureTest, AsBase64String) { content_layer_client.add_draw_rect(gfx::Rect(25, 25, 50, 50), green_paint); scoped_refptr<Picture> two_rect_picture = Picture::Create(layer_rect); two_rect_picture->Record(&content_layer_client, - tile_grid_info, - &stats_instrumentation); + tile_grid_info); scoped_ptr<base::Value> serialized_two_rect( two_rect_picture->AsValue()); @@ -113,7 +109,6 @@ TEST(PictureTest, PixelRefIterator) { tile_grid_info.fOffset.setZero(); FakeContentLayerClient content_layer_client; - FakeRenderingStatsInstrumentation stats_instrumentation; // Lazy pixel refs are found in the following grids: // |---|---|---|---| @@ -130,18 +125,18 @@ TEST(PictureTest, PixelRefIterator) { for (int x = 0; x < 4; ++x) { if ((x + y) & 1) { CreateBitmap(gfx::Size(500, 500), "lazy", &lazy_bitmap[y][x]); + SkPaint paint; content_layer_client.add_draw_bitmap( lazy_bitmap[y][x], - gfx::Point(x * 512 + 6, y * 512 + 6)); + gfx::Point(x * 512 + 6, y * 512 + 6), paint); } } } scoped_refptr<Picture> picture = Picture::Create(layer_rect); picture->Record(&content_layer_client, - tile_grid_info, - &stats_instrumentation); - picture->GatherPixelRefs(tile_grid_info, &stats_instrumentation); + tile_grid_info); + picture->GatherPixelRefs(tile_grid_info); // Default iterator does not have any pixel refs { @@ -211,7 +206,6 @@ TEST(PictureTest, PixelRefIteratorNonZeroLayer) { tile_grid_info.fOffset.setZero(); FakeContentLayerClient content_layer_client; - FakeRenderingStatsInstrumentation stats_instrumentation; // Lazy pixel refs are found in the following grids: // |---|---|---|---| @@ -228,18 +222,18 @@ TEST(PictureTest, PixelRefIteratorNonZeroLayer) { for (int x = 0; x < 4; ++x) { if ((x + y) & 1) { CreateBitmap(gfx::Size(500, 500), "lazy", &lazy_bitmap[y][x]); + SkPaint paint; content_layer_client.add_draw_bitmap( lazy_bitmap[y][x], - gfx::Point(1024 + x * 512 + 6, y * 512 + 6)); + gfx::Point(1024 + x * 512 + 6, y * 512 + 6), paint); } } } scoped_refptr<Picture> picture = Picture::Create(layer_rect); picture->Record(&content_layer_client, - tile_grid_info, - &stats_instrumentation); - picture->GatherPixelRefs(tile_grid_info, &stats_instrumentation); + tile_grid_info); + picture->GatherPixelRefs(tile_grid_info); // Default iterator does not have any pixel refs { @@ -333,7 +327,6 @@ TEST(PictureTest, PixelRefIteratorOnePixelQuery) { tile_grid_info.fOffset.setZero(); FakeContentLayerClient content_layer_client; - FakeRenderingStatsInstrumentation stats_instrumentation; // Lazy pixel refs are found in the following grids: // |---|---|---|---| @@ -350,18 +343,18 @@ TEST(PictureTest, PixelRefIteratorOnePixelQuery) { for (int x = 0; x < 4; ++x) { if ((x + y) & 1) { CreateBitmap(gfx::Size(500, 500), "lazy", &lazy_bitmap[y][x]); + SkPaint paint; content_layer_client.add_draw_bitmap( lazy_bitmap[y][x], - gfx::Point(x * 512 + 6, y * 512 + 6)); + gfx::Point(x * 512 + 6, y * 512 + 6), paint); } } } scoped_refptr<Picture> picture = Picture::Create(layer_rect); picture->Record(&content_layer_client, - tile_grid_info, - &stats_instrumentation); - picture->GatherPixelRefs(tile_grid_info, &stats_instrumentation); + tile_grid_info); + picture->GatherPixelRefs(tile_grid_info); for (int y = 0; y < 4; ++y) { for (int x = 0; x < 4; ++x) { @@ -389,7 +382,6 @@ TEST(PictureTest, CreateFromSkpValue) { tile_grid_info.fOffset.setZero(); FakeContentLayerClient content_layer_client; - FakeRenderingStatsInstrumentation stats_instrumentation; scoped_ptr<base::Value> tmp; @@ -408,8 +400,7 @@ TEST(PictureTest, CreateFromSkpValue) { content_layer_client.add_draw_rect(layer_rect, red_paint); scoped_refptr<Picture> one_rect_picture = Picture::Create(layer_rect); one_rect_picture->Record(&content_layer_client, - tile_grid_info, - &stats_instrumentation); + tile_grid_info); scoped_ptr<base::Value> serialized_one_rect( one_rect_picture->AsValue()); diff --git a/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc b/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc index a555e581540..011e5147e06 100644 --- a/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc +++ b/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc @@ -212,11 +212,15 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) { check_for_completed_raster_tasks_pending_ = false; ScheduleCheckForCompletedRasterTasks(); - TRACE_EVENT_ASYNC_STEP1( + TRACE_EVENT_ASYNC_STEP_INTO1( "cc", "ScheduledTasks", this, StateName(), "state", TracedValue::FromValue(StateAsValue().release())); } +GLenum PixelBufferRasterWorkerPool::GetResourceTarget() const { + return GL_TEXTURE_2D; +} + ResourceFormat PixelBufferRasterWorkerPool::GetResourceFormat() const { return resource_provider()->memory_efficient_texture_format(); } @@ -397,7 +401,7 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() { if (PendingRasterTaskCount()) ScheduleMoreTasks(); - TRACE_EVENT_ASYNC_STEP1( + TRACE_EVENT_ASYNC_STEP_INTO1( "cc", "ScheduledTasks", this, StateName(), "state", TracedValue::FromValue(StateAsValue().release())); diff --git a/chromium/cc/resources/pixel_buffer_raster_worker_pool.h b/chromium/cc/resources/pixel_buffer_raster_worker_pool.h index a856d8ae5a9..88be2c02a7f 100644 --- a/chromium/cc/resources/pixel_buffer_raster_worker_pool.h +++ b/chromium/cc/resources/pixel_buffer_raster_worker_pool.h @@ -34,6 +34,7 @@ class CC_EXPORT PixelBufferRasterWorkerPool : public RasterWorkerPool { // Overridden from RasterWorkerPool: virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE; + virtual GLenum GetResourceTarget() const OVERRIDE; virtual ResourceFormat GetResourceFormat() const OVERRIDE; virtual void OnRasterTasksFinished() OVERRIDE; virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE; diff --git a/chromium/cc/resources/prioritized_resource.cc b/chromium/cc/resources/prioritized_resource.cc index 313b275a3ab..f62ee40b0cb 100644 --- a/chromium/cc/resources/prioritized_resource.cc +++ b/chromium/cc/resources/prioritized_resource.cc @@ -124,6 +124,7 @@ PrioritizedResource::Backing::Backing(unsigned id, priority_at_last_priority_update_(PriorityCalculator::LowestPriority()), was_above_priority_cutoff_at_last_priority_update_(false), in_drawing_impl_tree_(false), + in_parent_compositor_(false), #ifdef NDEBUG resource_has_been_deleted_(false) {} #else @@ -154,7 +155,7 @@ bool PrioritizedResource::Backing::ResourceHasBeenDeleted() const { return resource_has_been_deleted_; } -bool PrioritizedResource::Backing::CanBeRecycled() const { +bool PrioritizedResource::Backing::CanBeRecycledIfNotInExternalUse() const { DCHECK(!proxy() || proxy()->IsImplThread()); return !was_above_priority_cutoff_at_last_priority_update_ && !in_drawing_impl_tree_; @@ -173,10 +174,12 @@ void PrioritizedResource::Backing::UpdatePriority() { } } -void PrioritizedResource::Backing::UpdateInDrawingImplTree() { +void PrioritizedResource::Backing::UpdateState( + ResourceProvider* resource_provider) { DCHECK(!proxy() || (proxy()->IsImplThread() && proxy()->IsMainThreadBlocked())); in_drawing_impl_tree_ = !!owner(); + in_parent_compositor_ = resource_provider->InUseByConsumer(id()); if (!in_drawing_impl_tree_) { DCHECK_EQ(priority_at_last_priority_update_, PriorityCalculator::LowestPriority()); diff --git a/chromium/cc/resources/prioritized_resource.h b/chromium/cc/resources/prioritized_resource.h index a3d5d89cf64..ee90024fd5c 100644 --- a/chromium/cc/resources/prioritized_resource.h +++ b/chromium/cc/resources/prioritized_resource.h @@ -111,10 +111,10 @@ class CC_EXPORT PrioritizedResource { ResourceFormat format); ~Backing(); void UpdatePriority(); - void UpdateInDrawingImplTree(); + void UpdateState(ResourceProvider* resource_provider); PrioritizedResource* owner() { return owner_; } - bool CanBeRecycled() const; + bool CanBeRecycledIfNotInExternalUse() const; int request_priority_at_last_priority_update() const { return priority_at_last_priority_update_; } @@ -122,6 +122,7 @@ class CC_EXPORT PrioritizedResource { return was_above_priority_cutoff_at_last_priority_update_; } bool in_drawing_impl_tree() const { return in_drawing_impl_tree_; } + bool in_parent_compositor() const { return in_parent_compositor_; } void DeleteResource(ResourceProvider* resource_provider); bool ResourceHasBeenDeleted() const; @@ -137,6 +138,8 @@ class CC_EXPORT PrioritizedResource { // Set if this is currently-drawing impl tree. bool in_drawing_impl_tree_; + // Set if this is in the parent compositor. + bool in_parent_compositor_; bool resource_has_been_deleted_; diff --git a/chromium/cc/resources/prioritized_resource_manager.cc b/chromium/cc/resources/prioritized_resource_manager.cc index 1a6e545a1a5..da8f0555124 100644 --- a/chromium/cc/resources/prioritized_resource_manager.cc +++ b/chromium/cc/resources/prioritized_resource_manager.cc @@ -160,7 +160,8 @@ void PrioritizedResourceManager::PushTexturePrioritiesToBackings() { memory_visible_and_nearby_bytes_; } -void PrioritizedResourceManager::UpdateBackingsInDrawingImplTree() { +void PrioritizedResourceManager::UpdateBackingsState( + ResourceProvider* resource_provider) { TRACE_EVENT0("cc", "PrioritizedResourceManager::UpdateBackingsInDrawingImplTree"); DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked()); @@ -169,7 +170,7 @@ void PrioritizedResourceManager::UpdateBackingsInDrawingImplTree() { for (BackingList::iterator it = backings_.begin(); it != backings_.end(); ++it) { PrioritizedResource::Backing* backing = (*it); - backing->UpdateInDrawingImplTree(); + backing->UpdateState(resource_provider); } SortBackings(); AssertInvariants(); @@ -240,7 +241,7 @@ void PrioritizedResourceManager::AcquireBackingTextureIfNeeded( // First try to recycle for (BackingList::iterator it = backings_.begin(); it != backings_.end(); ++it) { - if (!(*it)->CanBeRecycled()) + if (!(*it)->CanBeRecycledIfNotInExternalUse()) break; if (resource_provider->InUseByConsumer((*it)->id())) continue; @@ -298,7 +299,8 @@ bool PrioritizedResourceManager::EvictBackingsToReduceMemory( backing->request_priority_at_last_priority_update(), priority_cutoff)) break; - if (eviction_policy == EVICT_ONLY_RECYCLABLE && !backing->CanBeRecycled()) + if (eviction_policy == EVICT_ONLY_RECYCLABLE && + !backing->CanBeRecycledIfNotInExternalUse()) break; if (unlink_policy == UNLINK_BACKINGS && backing->owner()) backing->owner()->Unlink(); @@ -320,12 +322,18 @@ void PrioritizedResourceManager::ReduceWastedMemory( ++it) { if ((*it)->owner()) break; + if ((*it)->in_parent_compositor()) + continue; wasted_memory += (*it)->bytes(); } - size_t ten_percent_of_memory = memory_available_bytes_ / 10; - if (wasted_memory > ten_percent_of_memory) + size_t wasted_memory_to_allow = memory_available_bytes_ / 10; + // If the external priority cutoff indicates that unused memory should be + // freed, then do not allow any memory for texture recycling. + if (external_priority_cutoff_ != PriorityCalculator::AllowEverythingCutoff()) + wasted_memory_to_allow = 0; + if (wasted_memory > wasted_memory_to_allow) EvictBackingsToReduceMemory(MemoryUseBytes() - - (wasted_memory - ten_percent_of_memory), + (wasted_memory - wasted_memory_to_allow), PriorityCalculator::AllowEverythingCutoff(), EVICT_ONLY_RECYCLABLE, DO_NOT_UNLINK_BACKINGS, @@ -365,6 +373,7 @@ bool PrioritizedResourceManager::ReduceMemoryOnImplThread( ResourceProvider* resource_provider) { DCHECK(proxy_->IsImplThread()); DCHECK(resource_provider); + // If we are in the process of uploading a new frame then the backings at the // very end of the list are not sorted by priority. Sort them before doing the // eviction. @@ -377,18 +386,6 @@ bool PrioritizedResourceManager::ReduceMemoryOnImplThread( resource_provider); } -void PrioritizedResourceManager::ReduceWastedMemoryOnImplThread( - ResourceProvider* resource_provider) { - DCHECK(proxy_->IsImplThread()); - DCHECK(resource_provider); - // If we are in the process of uploading a new frame then the backings at the - // very end of the list are not sorted by priority. Sort them before doing the - // eviction. - if (backings_tail_not_sorted_) - SortBackings(); - ReduceWastedMemory(resource_provider); -} - void PrioritizedResourceManager::UnlinkAndClearEvictedBackings() { DCHECK(proxy_->IsMainThread()); base::AutoLock scoped_lock(evicted_backings_lock_); @@ -456,6 +453,7 @@ PrioritizedResource::Backing* PrioritizedResourceManager::CreateBacking( ResourceProvider::ResourceId resource_id = resource_provider->CreateManagedResource( size, + GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); @@ -535,12 +533,12 @@ void PrioritizedResourceManager::AssertInvariants() { (!backings_tail_not_sorted_ || !backing->was_above_priority_cutoff_at_last_priority_update())) DCHECK(CompareBackings(previous_backing, backing)); - if (!backing->CanBeRecycled()) + if (!backing->CanBeRecycledIfNotInExternalUse()) reached_unrecyclable = true; if (reached_unrecyclable) - DCHECK(!backing->CanBeRecycled()); + DCHECK(!backing->CanBeRecycledIfNotInExternalUse()); else - DCHECK(backing->CanBeRecycled()); + DCHECK(backing->CanBeRecycledIfNotInExternalUse()); previous_backing = backing; } #endif diff --git a/chromium/cc/resources/prioritized_resource_manager.h b/chromium/cc/resources/prioritized_resource_manager.h index 07cc7cf39a6..9b558a45b8f 100644 --- a/chromium/cc/resources/prioritized_resource_manager.h +++ b/chromium/cc/resources/prioritized_resource_manager.h @@ -96,10 +96,6 @@ class CC_EXPORT PrioritizedResourceManager { int priority_cutoff, ResourceProvider* resource_provider); - // Delete contents textures' backing resources that can be recycled. This - // may be called on the impl thread while the main thread is running. - void ReduceWastedMemoryOnImplThread(ResourceProvider* resource_provider); - // Returns true if there exist any textures that are linked to backings that // have had their resources evicted. Only when we commit a tree that has no // textures linked to evicted backings may we allow drawing. After an @@ -129,7 +125,7 @@ class CC_EXPORT PrioritizedResourceManager { void PushTexturePrioritiesToBackings(); // Mark all textures' backings as being in the drawing impl tree. - void UpdateBackingsInDrawingImplTree(); + void UpdateBackingsState(ResourceProvider* resource_provider); const Proxy* ProxyForDebug() const; @@ -156,25 +152,32 @@ class CC_EXPORT PrioritizedResourceManager { // Compare backings. Lowest priority first. static inline bool CompareBackings(PrioritizedResource::Backing* a, PrioritizedResource::Backing* b) { - // Make textures that can be recycled appear first - if (a->CanBeRecycled() != b->CanBeRecycled()) - return (a->CanBeRecycled() > b->CanBeRecycled()); + // Make textures that can be recycled appear first. + if (a->CanBeRecycledIfNotInExternalUse() != + b->CanBeRecycledIfNotInExternalUse()) + return (a->CanBeRecycledIfNotInExternalUse() > + b->CanBeRecycledIfNotInExternalUse()); // Then sort by being above or below the priority cutoff. if (a->was_above_priority_cutoff_at_last_priority_update() != b->was_above_priority_cutoff_at_last_priority_update()) return (a->was_above_priority_cutoff_at_last_priority_update() < b->was_above_priority_cutoff_at_last_priority_update()); // Then sort by priority (note that backings that no longer have owners will - // always have the lowest priority) + // always have the lowest priority). if (a->request_priority_at_last_priority_update() != b->request_priority_at_last_priority_update()) return PriorityCalculator::priority_is_lower( a->request_priority_at_last_priority_update(), b->request_priority_at_last_priority_update()); - // Finally sort by being in the impl tree versus being completely - // unreferenced + // Then sort by being in the impl tree versus being completely + // unreferenced. if (a->in_drawing_impl_tree() != b->in_drawing_impl_tree()) return (a->in_drawing_impl_tree() < b->in_drawing_impl_tree()); + // Finally, prefer to evict textures in the parent compositor because + // they will otherwise take another roundtrip to the parent compositor + // before they are evicted. + if (a->in_parent_compositor() != b->in_parent_compositor()) + return (a->in_parent_compositor() > b->in_parent_compositor()); return a < b; } diff --git a/chromium/cc/resources/prioritized_resource_unittest.cc b/chromium/cc/resources/prioritized_resource_unittest.cc index 181498c5a34..7619dcc75e3 100644 --- a/chromium/cc/resources/prioritized_resource_unittest.cc +++ b/chromium/cc/resources/prioritized_resource_unittest.cc @@ -4,8 +4,11 @@ #include "cc/resources/prioritized_resource.h" +#include <vector> + #include "cc/resources/prioritized_resource_manager.h" #include "cc/resources/resource.h" +#include "cc/resources/resource_provider.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_proxy.h" @@ -24,7 +27,7 @@ class PrioritizedResourceTest : public testing::Test { DebugScopedSetImplThread impl_thread(&proxy_); CHECK(output_surface_->BindToClient(&output_surface_client_)); resource_provider_ = - cc::ResourceProvider::Create(output_surface_.get(), 0, false); + ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1); } virtual ~PrioritizedResourceTest() { @@ -51,10 +54,10 @@ class PrioritizedResourceTest : public testing::Test { texture->RequestLate(); ResourceManagerAssertInvariants(texture->resource_manager()); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); + impl_thread_and_main_thread_blocked(&proxy_); bool success = texture->can_acquire_backing_texture(); if (success) - texture->AcquireBackingTexture(ResourceProvider()); + texture->AcquireBackingTexture(resource_provider()); return success; } @@ -67,17 +70,17 @@ class PrioritizedResourceTest : public testing::Test { void ResourceManagerUpdateBackingsPriorities( PrioritizedResourceManager* resource_manager) { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); + impl_thread_and_main_thread_blocked(&proxy_); resource_manager->PushTexturePrioritiesToBackings(); } - cc::ResourceProvider* ResourceProvider() { return resource_provider_.get(); } + ResourceProvider* resource_provider() { return resource_provider_.get(); } void ResourceManagerAssertInvariants( PrioritizedResourceManager* resource_manager) { #ifndef NDEBUG DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); + impl_thread_and_main_thread_blocked(&proxy_); resource_manager->AssertInvariants(); #endif } @@ -91,13 +94,24 @@ class PrioritizedResourceTest : public testing::Test { return resource_manager->evicted_backings_.size(); } + std::vector<unsigned> BackingResources( + PrioritizedResourceManager* resource_manager) { + std::vector<unsigned> resources; + for (PrioritizedResourceManager::BackingList::iterator it = + resource_manager->backings_.begin(); + it != resource_manager->backings_.end(); + ++it) + resources.push_back((*it)->id()); + return resources; + } + protected: FakeProxy proxy_; const gfx::Size texture_size_; const ResourceFormat texture_format_; FakeOutputSurfaceClient output_surface_client_; scoped_ptr<OutputSurface> output_surface_; - scoped_ptr<cc::ResourceProvider> resource_provider_; + scoped_ptr<ResourceProvider> resource_provider_; }; namespace { @@ -144,8 +158,8 @@ TEST_F(PrioritizedResourceTest, RequestTextureExceedingMaxLimit) { resource_manager->MaxMemoryNeededBytes()); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } TEST_F(PrioritizedResourceTest, ChangeMemoryLimits) { @@ -168,8 +182,8 @@ TEST_F(PrioritizedResourceTest, ChangeMemoryLimits) { ValidateTexture(textures[i].get(), false); { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ReduceMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemory(resource_provider()); } EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); @@ -183,8 +197,8 @@ TEST_F(PrioritizedResourceTest, ChangeMemoryLimits) { EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 5); { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ReduceMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemory(resource_provider()); } EXPECT_EQ(TexturesMemorySize(5), resource_manager->MemoryAboveCutoffBytes()); @@ -200,8 +214,8 @@ TEST_F(PrioritizedResourceTest, ChangeMemoryLimits) { EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ReduceMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemory(resource_provider()); } EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); @@ -211,8 +225,158 @@ TEST_F(PrioritizedResourceTest, ChangeMemoryLimits) { resource_manager->MaxMemoryNeededBytes()); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); +} + +TEST_F(PrioritizedResourceTest, ReduceWastedMemory) { + const size_t kMaxTextures = 20; + scoped_ptr<PrioritizedResourceManager> resource_manager = + CreateManager(kMaxTextures); + scoped_ptr<PrioritizedResource> textures[kMaxTextures]; + + for (size_t i = 0; i < kMaxTextures; ++i) { + textures[i] = + resource_manager->CreateTexture(texture_size_, texture_format_); + } + for (size_t i = 0; i < kMaxTextures; ++i) + textures[i]->set_request_priority(100 + i); + + // Set the memory limit to the max number of textures. + resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); + PrioritizeTexturesAndBackings(resource_manager.get()); + + // Create backings and textures for all of the textures. + for (size_t i = 0; i < kMaxTextures; ++i) { + ValidateTexture(textures[i].get(), false); + + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + uint8_t image[4] = {0}; + textures[i]->SetPixels(resource_provider_.get(), + image, + gfx::Rect(1, 1), + gfx::Rect(1, 1), + gfx::Vector2d()); + } + } + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemory(resource_provider()); + } + + // 20 textures have backings allocated. + EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); + + // Destroy one texture, not enough is wasted to cause cleanup. + textures[0] = scoped_ptr<PrioritizedResource>(); + PrioritizeTexturesAndBackings(resource_manager.get()); + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->UpdateBackingsState(resource_provider()); + resource_manager->ReduceWastedMemory(resource_provider()); + } + EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); + + // Destroy half the textures, leaving behind the backings. Now a cleanup + // should happen. + for (size_t i = 0; i < kMaxTextures / 2; ++i) + textures[i] = scoped_ptr<PrioritizedResource>(); + PrioritizeTexturesAndBackings(resource_manager.get()); + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->UpdateBackingsState(resource_provider()); + resource_manager->ReduceWastedMemory(resource_provider()); + } + EXPECT_GT(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); + + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); +} + +TEST_F(PrioritizedResourceTest, InUseNotWastedMemory) { + const size_t kMaxTextures = 20; + scoped_ptr<PrioritizedResourceManager> resource_manager = + CreateManager(kMaxTextures); + scoped_ptr<PrioritizedResource> textures[kMaxTextures]; + + for (size_t i = 0; i < kMaxTextures; ++i) { + textures[i] = + resource_manager->CreateTexture(texture_size_, texture_format_); + } + for (size_t i = 0; i < kMaxTextures; ++i) + textures[i]->set_request_priority(100 + i); + + // Set the memory limit to the max number of textures. + resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); + PrioritizeTexturesAndBackings(resource_manager.get()); + + // Create backings and textures for all of the textures. + for (size_t i = 0; i < kMaxTextures; ++i) { + ValidateTexture(textures[i].get(), false); + + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + uint8_t image[4] = {0}; + textures[i]->SetPixels(resource_provider_.get(), + image, + gfx::Rect(1, 1), + gfx::Rect(1, 1), + gfx::Vector2d()); + } + } + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemory(resource_provider()); + } + + // 20 textures have backings allocated. + EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); + + // Send half the textures to a parent compositor. + ResourceProvider::ResourceIdArray to_send; + TransferableResourceArray transferable; + for (size_t i = 0; i < kMaxTextures / 2; ++i) + to_send.push_back(textures[i]->resource_id()); + resource_provider_->PrepareSendToParent(to_send, &transferable); + + // Destroy half the textures, leaving behind the backings. The backings are + // sent to a parent compositor though, so they should not be considered wasted + // and a cleanup should not happen. + for (size_t i = 0; i < kMaxTextures / 2; ++i) + textures[i] = scoped_ptr<PrioritizedResource>(); + PrioritizeTexturesAndBackings(resource_manager.get()); + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->UpdateBackingsState(resource_provider()); + resource_manager->ReduceWastedMemory(resource_provider()); + } + EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); + + // Receive the textures back from the parent compositor. Now a cleanup should + // happen. + ReturnedResourceArray returns; + TransferableResource::ReturnResources(transferable, &returns); + resource_provider_->ReceiveReturnsFromParent(returns); + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->UpdateBackingsState(resource_provider()); + resource_manager->ReduceWastedMemory(resource_provider()); + } + EXPECT_GT(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); + + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } TEST_F(PrioritizedResourceTest, ChangePriorityCutoff) { @@ -238,8 +402,8 @@ TEST_F(PrioritizedResourceTest, ChangePriorityCutoff) { EXPECT_EQ(ValidateTexture(textures[i].get(), true), i < 6); { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ReduceMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemory(resource_provider()); } EXPECT_EQ(TexturesMemorySize(6), resource_manager->MemoryAboveCutoffBytes()); EXPECT_LE(resource_manager->MemoryUseBytes(), @@ -252,22 +416,21 @@ TEST_F(PrioritizedResourceTest, ChangePriorityCutoff) { EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ReduceMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemory(resource_provider()); } EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); // Do a one-time eviction for one more texture based on priority cutoff - PrioritizedResourceManager::BackingList evicted_backings; resource_manager->UnlinkAndClearEvictedBackings(); { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); + impl_thread_and_main_thread_blocked(&proxy_); resource_manager->ReduceMemoryOnImplThread( - TexturesMemorySize(8), 104, ResourceProvider()); + TexturesMemorySize(8), 104, resource_provider()); EXPECT_EQ(0u, EvictedBackingCount(resource_manager.get())); resource_manager->ReduceMemoryOnImplThread( - TexturesMemorySize(8), 103, ResourceProvider()); + TexturesMemorySize(8), 103, resource_provider()); EXPECT_EQ(1u, EvictedBackingCount(resource_manager.get())); } resource_manager->UnlinkAndClearEvictedBackings(); @@ -279,14 +442,157 @@ TEST_F(PrioritizedResourceTest, ChangePriorityCutoff) { EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ReduceMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemory(resource_provider()); } EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); +} + +TEST_F(PrioritizedResourceTest, EvictingTexturesInParent) { + const size_t kMaxTextures = 8; + scoped_ptr<PrioritizedResourceManager> resource_manager = + CreateManager(kMaxTextures); + scoped_ptr<PrioritizedResource> textures[kMaxTextures]; + unsigned texture_resource_ids[kMaxTextures]; + + for (size_t i = 0; i < kMaxTextures; ++i) { + textures[i] = + resource_manager->CreateTexture(texture_size_, texture_format_); + textures[i]->set_request_priority(100 + i); + } + + PrioritizeTexturesAndBackings(resource_manager.get()); + for (size_t i = 0; i < kMaxTextures; ++i) { + EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); + + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + uint8_t image[4] = {0}; + textures[i]->SetPixels(resource_provider_.get(), + image, + gfx::Rect(1, 1), + gfx::Rect(1, 1), + gfx::Vector2d()); + } + } + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemory(resource_provider()); + } + EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); + + for (size_t i = 0; i < 8; ++i) + texture_resource_ids[i] = textures[i]->resource_id(); + + // Evict four textures. It will be the last four. + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemoryOnImplThread( + TexturesMemorySize(4), 200, resource_provider()); + + EXPECT_EQ(4u, EvictedBackingCount(resource_manager.get())); + + // The last four backings are evicted. + std::vector<unsigned> remaining = BackingResources(resource_manager.get()); + EXPECT_TRUE(std::find(remaining.begin(), + remaining.end(), + texture_resource_ids[0]) != remaining.end()); + EXPECT_TRUE(std::find(remaining.begin(), + remaining.end(), + texture_resource_ids[1]) != remaining.end()); + EXPECT_TRUE(std::find(remaining.begin(), + remaining.end(), + texture_resource_ids[2]) != remaining.end()); + EXPECT_TRUE(std::find(remaining.begin(), + remaining.end(), + texture_resource_ids[3]) != remaining.end()); + } + resource_manager->UnlinkAndClearEvictedBackings(); + EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryUseBytes()); + + // Re-allocate the the texture after the eviction. + PrioritizeTexturesAndBackings(resource_manager.get()); + for (size_t i = 0; i < kMaxTextures; ++i) { + EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); + + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + uint8_t image[4] = {0}; + textures[i]->SetPixels(resource_provider_.get(), + image, + gfx::Rect(1, 1), + gfx::Rect(1, 1), + gfx::Vector2d()); + } + } + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemory(resource_provider()); + } + EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); + + // Send the last two of the textures to a parent compositor. + ResourceProvider::ResourceIdArray to_send; + TransferableResourceArray transferable; + for (size_t i = 6; i < 8; ++i) + to_send.push_back(textures[i]->resource_id()); + resource_provider_->PrepareSendToParent(to_send, &transferable); + + // Set the last two textures to be tied for prioity with the two + // before them. Being sent to the parent will break the tie. + textures[4]->set_request_priority(100 + 4); + textures[5]->set_request_priority(100 + 5); + textures[6]->set_request_priority(100 + 4); + textures[7]->set_request_priority(100 + 5); + + for (size_t i = 0; i < 8; ++i) + texture_resource_ids[i] = textures[i]->resource_id(); + + // Drop all the textures. Now we have backings that can be recycled. + for (size_t i = 0; i < 8; ++i) + textures[0].reset(); + PrioritizeTexturesAndBackings(resource_manager.get()); + + // The next commit finishes. + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->UpdateBackingsState(resource_provider()); + } + + // Evict four textures. It would be the last four again, except that 2 of them + // are sent to the parent, so they are evicted last. + { + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ReduceMemoryOnImplThread( + TexturesMemorySize(4), 200, resource_provider()); + + EXPECT_EQ(4u, EvictedBackingCount(resource_manager.get())); + // The last 2 backings remain this time. + std::vector<unsigned> remaining = BackingResources(resource_manager.get()); + EXPECT_TRUE(std::find(remaining.begin(), + remaining.end(), + texture_resource_ids[6]) == remaining.end()); + EXPECT_TRUE(std::find(remaining.begin(), + remaining.end(), + texture_resource_ids[7]) == remaining.end()); + } + resource_manager->UnlinkAndClearEvictedBackings(); + EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryUseBytes()); + + DebugScopedSetImplThreadAndMainThreadBlocked + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } TEST_F(PrioritizedResourceTest, ResourceManagerPartialUpdateTextures) { @@ -348,8 +654,8 @@ TEST_F(PrioritizedResourceTest, ResourceManagerPartialUpdateTextures) { EXPECT_FALSE(textures[3]->have_backing_texture()); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } TEST_F(PrioritizedResourceTest, ResourceManagerPrioritiesAreEqual) { @@ -393,8 +699,8 @@ TEST_F(PrioritizedResourceTest, ResourceManagerPrioritiesAreEqual) { resource_manager->MemoryAboveCutoffBytes()); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } TEST_F(PrioritizedResourceTest, ResourceManagerDestroyedFirst) { @@ -413,8 +719,8 @@ TEST_F(PrioritizedResourceTest, ResourceManagerDestroyedFirst) { EXPECT_TRUE(texture->have_backing_texture()); { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } resource_manager.reset(); @@ -443,8 +749,8 @@ TEST_F(PrioritizedResourceTest, TextureMovedToNewManager) { texture->SetTextureManager(NULL); { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager_one->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager_one->ClearAllMemory(resource_provider()); } resource_manager_one.reset(); @@ -460,8 +766,8 @@ TEST_F(PrioritizedResourceTest, TextureMovedToNewManager) { EXPECT_TRUE(texture->have_backing_texture()); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager_two->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager_two->ClearAllMemory(resource_provider()); } TEST_F(PrioritizedResourceTest, @@ -517,8 +823,8 @@ TEST_F(PrioritizedResourceTest, resource_manager->MaxMemoryNeededBytes()); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } TEST_F(PrioritizedResourceTest, @@ -565,8 +871,8 @@ TEST_F(PrioritizedResourceTest, resource_manager->MaxMemoryNeededBytes()); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } TEST_F(PrioritizedResourceTest, @@ -617,8 +923,8 @@ TEST_F(PrioritizedResourceTest, resource_manager->MemoryAboveCutoffBytes()); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } TEST_F(PrioritizedResourceTest, RequestLateBackingsSorting) { @@ -669,8 +975,8 @@ TEST_F(PrioritizedResourceTest, RequestLateBackingsSorting) { EXPECT_FALSE(TextureBackingIsAbovePriorityCutoff(textures[i].get())); DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } TEST_F(PrioritizedResourceTest, ClearUploadsToEvictedResources) { @@ -695,7 +1001,7 @@ TEST_F(PrioritizedResourceTest, ClearUploadsToEvictedResources) { ResourceUpdateQueue queue; DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); + impl_thread_and_main_thread_blocked(&proxy_); for (size_t i = 0; i < kMaxTextures; ++i) { const ResourceUpdate upload = ResourceUpdate::Create( textures[i].get(), NULL, gfx::Rect(), gfx::Rect(), gfx::Vector2d()); @@ -712,12 +1018,12 @@ TEST_F(PrioritizedResourceTest, ClearUploadsToEvictedResources) { resource_manager->ReduceMemoryOnImplThread( TexturesMemorySize(1), PriorityCalculator::AllowEverythingCutoff(), - ResourceProvider()); + resource_provider()); queue.ClearUploadsToEvictedResources(); EXPECT_EQ(1u, queue.FullUploadSize()); resource_manager->ReduceMemoryOnImplThread( - 0, PriorityCalculator::AllowEverythingCutoff(), ResourceProvider()); + 0, PriorityCalculator::AllowEverythingCutoff(), resource_provider()); queue.ClearUploadsToEvictedResources(); EXPECT_EQ(0u, queue.FullUploadSize()); } @@ -788,7 +1094,7 @@ TEST_F(PrioritizedResourceTest, UsageStatistics) { // Push priorities to backings, and verify we see the new values. { DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); + impl_thread_and_main_thread_blocked(&proxy_); resource_manager->PushTexturePrioritiesToBackings(); EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes()); EXPECT_EQ(TexturesMemorySize(3), resource_manager->MemoryVisibleBytes()); @@ -797,8 +1103,8 @@ TEST_F(PrioritizedResourceTest, UsageStatistics) { } DebugScopedSetImplThreadAndMainThreadBlocked - impl_thread_and_main_thread_blocked(&proxy_); - resource_manager->ClearAllMemory(ResourceProvider()); + impl_thread_and_main_thread_blocked(&proxy_); + resource_manager->ClearAllMemory(resource_provider()); } } // namespace diff --git a/chromium/cc/resources/prioritized_tile_set_unittest.cc b/chromium/cc/resources/prioritized_tile_set_unittest.cc index 7de1032523c..b51eb0063fb 100644 --- a/chromium/cc/resources/prioritized_tile_set_unittest.cc +++ b/chromium/cc/resources/prioritized_tile_set_unittest.cc @@ -57,22 +57,25 @@ class PrioritizedTileSetTest : public testing::Test { CHECK(output_surface_->BindToClient(&output_surface_client_)); resource_provider_ = - ResourceProvider::Create(output_surface_.get(), 0, false).Pass(); - tile_manager_.reset(new FakeTileManager(&tile_manager_client_, - resource_provider_.get())); + ResourceProvider::Create(output_surface_.get(), + NULL, + 0, + false, + 1).Pass(); + tile_manager_.reset( + new FakeTileManager(&tile_manager_client_, resource_provider_.get())); picture_pile_ = FakePicturePileImpl::CreatePile(); } scoped_refptr<Tile> CreateTile() { - return make_scoped_refptr(new Tile(tile_manager_.get(), - picture_pile_.get(), - settings_.default_tile_size, - gfx::Rect(), - gfx::Rect(), - 1.0, - 0, - 0, - true)); + return tile_manager_->CreateTile(picture_pile_.get(), + settings_.default_tile_size, + gfx::Rect(), + gfx::Rect(), + 1.0, + 0, + 0, + Tile::USE_LCD_TEXT); } private: diff --git a/chromium/cc/resources/priority_calculator.cc b/chromium/cc/resources/priority_calculator.cc index 4e828207ff1..fe5741c30e9 100644 --- a/chromium/cc/resources/priority_calculator.cc +++ b/chromium/cc/resources/priority_calculator.cc @@ -68,20 +68,11 @@ int PriorityCalculator::LingeringPriority(int previous_priority) { std::max(kLingeringBasePriority, previous_priority + 1)); } -namespace { -int ManhattanDistance(gfx::Rect a, gfx::Rect b) { - gfx::Rect c = gfx::UnionRects(a, b); - int x = std::max(0, c.width() - a.width() - b.width() + 1); - int y = std::max(0, c.height() - a.height() - b.height() + 1); - return (x + y); -} -} - // static int PriorityCalculator::PriorityFromDistance(gfx::Rect visible_rect, gfx::Rect texture_rect, bool draws_to_root_surface) { - int distance = ManhattanDistance(visible_rect, texture_rect); + int distance = visible_rect.ManhattanInternalDistance(texture_rect); if (!distance) return VisiblePriority(draws_to_root_surface); return std::min(kNotVisibleLimitPriority, kNotVisibleBasePriority + distance); diff --git a/chromium/cc/resources/raster_worker_pool.cc b/chromium/cc/resources/raster_worker_pool.cc index 5aaf0b66540..06fd18e62e0 100644 --- a/chromium/cc/resources/raster_worker_pool.cc +++ b/chromium/cc/resources/raster_worker_pool.cc @@ -7,7 +7,6 @@ #include "base/json/json_writer.h" #include "base/metrics/histogram.h" #include "base/values.h" -#include "cc/debug/benchmark_instrumentation.h" #include "cc/debug/devtools_instrumentation.h" #include "cc/debug/traced_value.h" #include "cc/resources/picture_pile_impl.h" @@ -55,7 +54,6 @@ class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask { gfx::Rect content_rect, float contents_scale, RasterMode raster_mode, - bool is_tile_in_pending_tree_now_bin, TileResolution tile_resolution, int layer_id, const void* tile_id, @@ -68,7 +66,6 @@ class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask { content_rect_(content_rect), contents_scale_(contents_scale), raster_mode_(raster_mode), - is_tile_in_pending_tree_now_bin_(is_tile_in_pending_tree_now_bin), tile_resolution_(tile_resolution), layer_id_(layer_id), tile_id_(tile_id), @@ -90,14 +87,12 @@ class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask { DCHECK(picture_clone); - base::TimeTicks start_time = rendering_stats_->StartRecording(); - picture_clone->AnalyzeInRect(content_rect_, contents_scale_, &analysis_); - base::TimeDelta duration = rendering_stats_->EndRecording(start_time); + picture_clone->AnalyzeInRect( + content_rect_, contents_scale_, &analysis_, rendering_stats_); // Record the solid color prediction. UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed", analysis_.is_solid_color); - rendering_stats_->AddAnalysisResult(duration, analysis_.is_solid_color); // Clear the flag if we're not using the estimator. analysis_.is_solid_color &= kUseColorEstimator; @@ -108,9 +103,8 @@ class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask { gfx::Size size, int stride) { TRACE_EVENT2( - benchmark_instrumentation::kCategory, - benchmark_instrumentation::kRunRasterOnThread, - benchmark_instrumentation::kData, + "cc", "RasterWorkerPoolTaskImpl::RunRasterOnThread", + "data", TracedValue::FromValue(DataAsValue().release()), "raster_mode", TracedValue::FromValue(RasterModeAsValue(raster_mode_).release())); @@ -147,6 +141,7 @@ class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask { break; case LUMINANCE_8: case RGB_565: + case ETC1: NOTREACHED(); break; } @@ -170,25 +165,30 @@ class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask { canvas.setDrawFilter(draw_filter.get()); - if (rendering_stats_->record_rendering_stats()) { - PicturePileImpl::RasterStats raster_stats; + base::TimeDelta prev_rasterize_time = + rendering_stats_->impl_thread_rendering_stats().rasterize_time; + + // Only record rasterization time for highres tiles, because + // lowres tiles are not required for activation and therefore + // introduce noise in the measurement (sometimes they get rasterized + // before we draw and sometimes they aren't) + if (tile_resolution_ == HIGH_RESOLUTION) { picture_clone->RasterToBitmap( - &canvas, content_rect_, contents_scale_, &raster_stats); - rendering_stats_->AddRaster( - raster_stats.total_rasterize_time, - raster_stats.best_rasterize_time, - raster_stats.total_pixels_rasterized, - is_tile_in_pending_tree_now_bin_); + &canvas, content_rect_, contents_scale_, rendering_stats_); + } else { + picture_clone->RasterToBitmap( + &canvas, content_rect_, contents_scale_, NULL); + } + if (rendering_stats_->record_rendering_stats()) { + base::TimeDelta current_rasterize_time = + rendering_stats_->impl_thread_rendering_stats().rasterize_time; HISTOGRAM_CUSTOM_COUNTS( "Renderer4.PictureRasterTimeUS", - raster_stats.total_rasterize_time.InMicroseconds(), + (current_rasterize_time - prev_rasterize_time).InMicroseconds(), 0, 100000, 100); - } else { - picture_clone->RasterToBitmap( - &canvas, content_rect_, contents_scale_, NULL); } ChangeBitmapConfigIfNeeded(bitmap, buffer); @@ -216,8 +216,6 @@ class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask { scoped_ptr<base::Value> DataAsValue() const { scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); res->Set("tile_id", TracedValue::CreateIDRef(tile_id_).release()); - res->SetBoolean("is_tile_in_pending_tree_now_bin", - is_tile_in_pending_tree_now_bin_); res->Set("resolution", TileResolutionAsValue(tile_resolution_).release()); res->SetInteger("source_frame_number", source_frame_number_); res->SetInteger("layer_id", layer_id_); @@ -227,8 +225,7 @@ class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask { void ChangeBitmapConfigIfNeeded(const SkBitmap& bitmap, void* buffer) { TRACE_EVENT0("cc", "RasterWorkerPoolTaskImpl::ChangeBitmapConfigIfNeeded"); - SkBitmap::Config config = SkBitmapConfigFromFormat( - resource()->format()); + SkBitmap::Config config = SkBitmapConfig(resource()->format()); if (bitmap.getConfig() != config) { SkBitmap bitmap_dest; IdentityAllocator allocator(buffer); @@ -244,7 +241,6 @@ class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask { gfx::Rect content_rect_; float contents_scale_; RasterMode raster_mode_; - bool is_tile_in_pending_tree_now_bin_; TileResolution tile_resolution_; int layer_id_; const void* tile_id_; @@ -271,10 +267,7 @@ class ImageDecodeWorkerPoolTaskImpl : public internal::WorkerPoolTask { TRACE_EVENT0("cc", "ImageDecodeWorkerPoolTaskImpl::RunOnWorkerThread"); devtools_instrumentation::ScopedImageDecodeTask image_decode_task( pixel_ref_.get()); - base::TimeTicks start_time = rendering_stats_->StartRecording(); pixel_ref_->Decode(); - base::TimeDelta duration = rendering_stats_->EndRecording(start_time); - rendering_stats_->AddDeferredImageDecode(duration); } virtual void CompleteOnOriginThread() OVERRIDE { reply_.Run(!HasFinishedRunning()); @@ -434,7 +427,6 @@ RasterWorkerPool::RasterTask RasterWorkerPool::CreateRasterTask( gfx::Rect content_rect, float contents_scale, RasterMode raster_mode, - bool is_tile_in_pending_tree_now_bin, TileResolution tile_resolution, int layer_id, const void* tile_id, @@ -448,7 +440,6 @@ RasterWorkerPool::RasterTask RasterWorkerPool::CreateRasterTask( content_rect, contents_scale, raster_mode, - is_tile_in_pending_tree_now_bin, tile_resolution, layer_id, tile_id, diff --git a/chromium/cc/resources/raster_worker_pool.h b/chromium/cc/resources/raster_worker_pool.h index b12a1b43c23..fac2fd845ce 100644 --- a/chromium/cc/resources/raster_worker_pool.h +++ b/chromium/cc/resources/raster_worker_pool.h @@ -22,10 +22,6 @@ class LazyPixelRef; } namespace cc { -class PicturePileImpl; -class PixelBufferRasterWorkerPool; -class ResourceProvider; - namespace internal { class CC_EXPORT RasterWorkerPoolTask @@ -186,6 +182,9 @@ class CC_EXPORT RasterWorkerPool : public WorkerPool { // even if they later get canceled by another call to ScheduleTasks(). virtual void ScheduleTasks(RasterTask::Queue* queue) = 0; + // Returns the target that needs to be used for raster task resources. + virtual GLenum GetResourceTarget() const = 0; + // Returns the format that needs to be used for raster task resources. virtual ResourceFormat GetResourceFormat() const = 0; @@ -196,7 +195,6 @@ class CC_EXPORT RasterWorkerPool : public WorkerPool { gfx::Rect content_rect, float contents_scale, RasterMode raster_mode, - bool is_tile_in_pending_tree_now_bin, TileResolution tile_resolution, int layer_id, const void* tile_id, @@ -273,10 +271,10 @@ class CC_EXPORT RasterWorkerPool : public WorkerPool { RasterTask::Queue::TaskVector raster_tasks_; RasterTask::Queue::TaskSet raster_tasks_required_for_activation_; - base::WeakPtrFactory<RasterWorkerPool> weak_ptr_factory_; scoped_refptr<internal::WorkerPoolTask> raster_finished_task_; scoped_refptr<internal::WorkerPoolTask> raster_required_for_activation_finished_task_; + base::WeakPtrFactory<RasterWorkerPool> weak_ptr_factory_; }; } // namespace cc diff --git a/chromium/cc/resources/raster_worker_pool_perftest.cc b/chromium/cc/resources/raster_worker_pool_perftest.cc index cec9c4820d1..8b9c8e0b5f5 100644 --- a/chromium/cc/resources/raster_worker_pool_perftest.cc +++ b/chromium/cc/resources/raster_worker_pool_perftest.cc @@ -40,6 +40,10 @@ class PerfRasterWorkerPool : public RasterWorkerPool { virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE { NOTREACHED(); } + virtual GLenum GetResourceTarget() const OVERRIDE { + NOTREACHED(); + return GL_TEXTURE_2D; + } virtual ResourceFormat GetResourceFormat() const OVERRIDE { NOTREACHED(); return RGBA_8888; @@ -164,7 +168,6 @@ class RasterWorkerPoolPerfTest : public testing::Test { gfx::Rect(), 1.0, HIGH_QUALITY_RASTER_MODE, - false, TileResolution(), 1, NULL, diff --git a/chromium/cc/resources/raster_worker_pool_unittest.cc b/chromium/cc/resources/raster_worker_pool_unittest.cc index 61cb324f772..716edf6c526 100644 --- a/chromium/cc/resources/raster_worker_pool_unittest.cc +++ b/chromium/cc/resources/raster_worker_pool_unittest.cc @@ -7,7 +7,6 @@ #include <limits> #include <vector> -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/resources/image_raster_worker_pool.h" #include "cc/resources/picture_pile.h" #include "cc/resources/picture_pile_impl.h" @@ -16,6 +15,7 @@ #include "cc/resources/scoped_resource.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { @@ -67,8 +67,8 @@ class RasterWorkerPoolTest : public testing::Test, output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass(); CHECK(output_surface_->BindToClient(&output_surface_client_)); - resource_provider_ = - ResourceProvider::Create(output_surface_.get(), 0, false).Pass(); + resource_provider_ = ResourceProvider::Create( + output_surface_.get(), NULL, 0, false, 1).Pass(); } virtual ~RasterWorkerPoolTest() { resource_provider_.reset(); @@ -104,7 +104,7 @@ class RasterWorkerPoolTest : public testing::Test, void RunTest(bool use_map_image) { if (use_map_image) { raster_worker_pool_ = ImageRasterWorkerPool::Create( - resource_provider(), 1); + resource_provider(), 1, GL_TEXTURE_2D); } else { raster_worker_pool_ = PixelBufferRasterWorkerPool::Create( @@ -159,7 +159,7 @@ class RasterWorkerPoolTest : public testing::Test, const gfx::Size size(1, 1); scoped_ptr<ScopedResource> resource( - ScopedResource::create(resource_provider())); + ScopedResource::Create(resource_provider())); resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888); const Resource* const_resource = resource.get(); diff --git a/chromium/cc/resources/resource.cc b/chromium/cc/resources/resource.cc index c97db7fb872..9bbcd4f498b 100644 --- a/chromium/cc/resources/resource.cc +++ b/chromium/cc/resources/resource.cc @@ -13,8 +13,5 @@ size_t Resource::bytes() const { return MemorySizeBytes(size_, format_); } -size_t Resource::MemorySizeBytes(gfx::Size size, ResourceFormat format) { - return ResourceProvider::BytesPerPixel(format) * size.width() * size.height(); -} } // namespace cc diff --git a/chromium/cc/resources/resource.h b/chromium/cc/resources/resource.h index d2d104c1370..e9dd393a6a4 100644 --- a/chromium/cc/resources/resource.h +++ b/chromium/cc/resources/resource.h @@ -25,7 +25,10 @@ class CC_EXPORT Resource { ResourceFormat format() const { return format_; } size_t bytes() const; - static size_t MemorySizeBytes(gfx::Size size, ResourceFormat format); + inline static size_t MemorySizeBytes(gfx::Size size, ResourceFormat format) { + DCHECK_EQ(0u, (BitsPerPixel(format) * size.width() * size.height()) % 8); + return (BitsPerPixel(format) * size.width() * size.height()) / 8; + } protected: void set_id(ResourceProvider::ResourceId id) { id_ = id; } diff --git a/chromium/cc/resources/resource_format.cc b/chromium/cc/resources/resource_format.cc index 5ea3df12598..35617174cb5 100644 --- a/chromium/cc/resources/resource_format.cc +++ b/chromium/cc/resources/resource_format.cc @@ -6,13 +6,14 @@ namespace cc { -SkBitmap::Config SkBitmapConfigFromFormat(ResourceFormat format) { +SkBitmap::Config SkBitmapConfig(ResourceFormat format) { switch (format) { case RGBA_4444: return SkBitmap::kARGB_4444_Config; case RGBA_8888: case BGRA_8888: return SkBitmap::kARGB_8888_Config; + case ETC1: case LUMINANCE_8: case RGB_565: NOTREACHED(); diff --git a/chromium/cc/resources/resource_format.h b/chromium/cc/resources/resource_format.h index ef83cc02eb7..54061394ff7 100644 --- a/chromium/cc/resources/resource_format.h +++ b/chromium/cc/resources/resource_format.h @@ -10,16 +10,18 @@ namespace cc { +// Keep in sync with arrays below. enum ResourceFormat { RGBA_8888, RGBA_4444, BGRA_8888, LUMINANCE_8, RGB_565, - RESOURCE_FORMAT_MAX = RGB_565, + ETC1, + RESOURCE_FORMAT_MAX = ETC1, }; -SkBitmap::Config SkBitmapConfigFromFormat(ResourceFormat format); +SkBitmap::Config SkBitmapConfig(ResourceFormat format); } // namespace cc diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc index cef86ded178..6abfd7c4a3d 100644 --- a/chromium/cc/resources/resource_pool.cc +++ b/chromium/cc/resources/resource_pool.cc @@ -5,31 +5,16 @@ #include "cc/resources/resource_pool.h" #include "cc/resources/resource_provider.h" +#include "cc/resources/scoped_resource.h" namespace cc { -ResourcePool::Resource::Resource(cc::ResourceProvider* resource_provider, - gfx::Size size, - ResourceFormat format) - : cc::Resource(resource_provider->CreateManagedResource( - size, - GL_CLAMP_TO_EDGE, - ResourceProvider::TextureUsageAny, - format), - size, - format), - resource_provider_(resource_provider) { - DCHECK(id()); -} - -ResourcePool::Resource::~Resource() { - DCHECK(id()); - DCHECK(resource_provider_); - resource_provider_->DeleteResource(id()); -} - -ResourcePool::ResourcePool(ResourceProvider* resource_provider) +ResourcePool::ResourcePool(ResourceProvider* resource_provider, + GLenum target, + ResourceFormat format) : resource_provider_(resource_provider), + target_(target), + format_(format), max_memory_usage_bytes_(0), max_unused_memory_usage_bytes_(0), max_resource_count_(0), @@ -39,21 +24,26 @@ ResourcePool::ResourcePool(ResourceProvider* resource_provider) } ResourcePool::~ResourcePool() { + while (!busy_resources_.empty()) { + DidFinishUsingResource(busy_resources_.front()); + busy_resources_.pop_front(); + } + SetResourceUsageLimits(0, 0, 0); + DCHECK_EQ(0u, unused_resources_.size()); + DCHECK_EQ(0u, memory_usage_bytes_); + DCHECK_EQ(0u, unused_memory_usage_bytes_); + DCHECK_EQ(0u, resource_count_); } -scoped_ptr<ResourcePool::Resource> ResourcePool::AcquireResource( - gfx::Size size, ResourceFormat format) { +scoped_ptr<ScopedResource> ResourcePool::AcquireResource(gfx::Size size) { for (ResourceList::iterator it = unused_resources_.begin(); it != unused_resources_.end(); ++it) { - Resource* resource = *it; + ScopedResource* resource = *it; + DCHECK(resource_provider_->CanLockForWrite(resource->id())); - if (!resource_provider_->CanLockForWrite(resource->id())) - continue; if (resource->size() != size) continue; - if (resource->format() != format) - continue; unused_resources_.erase(it); unused_memory_usage_bytes_ -= resource->bytes(); @@ -61,7 +51,9 @@ scoped_ptr<ResourcePool::Resource> ResourcePool::AcquireResource( } // Create new resource. - Resource* resource = new Resource(resource_provider_, size, format); + scoped_ptr<ScopedResource> resource = + ScopedResource::Create(resource_provider_); + resource->AllocateManaged(size, target_, format_); // Extend all read locks on all resources until the resource is // finished being used, such that we know when resources are @@ -70,19 +62,11 @@ scoped_ptr<ResourcePool::Resource> ResourcePool::AcquireResource( memory_usage_bytes_ += resource->bytes(); ++resource_count_; - return make_scoped_ptr(resource); + return resource.Pass(); } -void ResourcePool::ReleaseResource( - scoped_ptr<ResourcePool::Resource> resource) { - if (ResourceUsageTooHigh()) { - memory_usage_bytes_ -= resource->bytes(); - --resource_count_; - return; - } - - unused_memory_usage_bytes_ += resource->bytes(); - unused_resources_.push_back(resource.release()); +void ResourcePool::ReleaseResource(scoped_ptr<ScopedResource> resource) { + busy_resources_.push_back(resource.release()); } void ResourcePool::SetResourceUsageLimits( @@ -108,7 +92,7 @@ void ResourcePool::ReduceResourceUsage() { // can't be locked for write might also not be truly free-able. // We can free the resource here but it doesn't mean that the // memory is necessarily returned to the OS. - Resource* resource = unused_resources_.front(); + ScopedResource* resource = unused_resources_.front(); unused_resources_.pop_front(); memory_usage_bytes_ -= resource->bytes(); unused_memory_usage_bytes_ -= resource->bytes(); @@ -127,4 +111,24 @@ bool ResourcePool::ResourceUsageTooHigh() { return false; } +void ResourcePool::CheckBusyResources() { + ResourceList::iterator it = busy_resources_.begin(); + + while (it != busy_resources_.end()) { + ScopedResource* resource = *it; + + if (resource_provider_->CanLockForWrite(resource->id())) { + DidFinishUsingResource(resource); + it = busy_resources_.erase(it); + } else { + ++it; + } + } +} + +void ResourcePool::DidFinishUsingResource(ScopedResource* resource) { + unused_memory_usage_bytes_ += resource->bytes(); + unused_resources_.push_back(resource); +} + } // namespace cc diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h index 21bbb0a70d0..3c6b23f642a 100644 --- a/chromium/cc/resources/resource_pool.h +++ b/chromium/cc/resources/resource_pool.h @@ -14,37 +14,29 @@ #include "cc/resources/resource_format.h" namespace cc { +class ScopedResource; class CC_EXPORT ResourcePool { public: - class CC_EXPORT Resource : public cc::Resource { - public: - Resource(ResourceProvider* resource_provider, - gfx::Size size, - ResourceFormat format); - ~Resource(); - - private: - ResourceProvider* resource_provider_; - - DISALLOW_COPY_AND_ASSIGN(Resource); - }; - - static scoped_ptr<ResourcePool> Create(ResourceProvider* resource_provider) { - return make_scoped_ptr(new ResourcePool(resource_provider)); + static scoped_ptr<ResourcePool> Create(ResourceProvider* resource_provider, + GLenum target, + ResourceFormat format) { + return make_scoped_ptr(new ResourcePool(resource_provider, + target, + format)); } virtual ~ResourcePool(); - scoped_ptr<ResourcePool::Resource> AcquireResource( - gfx::Size size, ResourceFormat format); - void ReleaseResource(scoped_ptr<ResourcePool::Resource>); + scoped_ptr<ScopedResource> AcquireResource(gfx::Size size); + void ReleaseResource(scoped_ptr<ScopedResource>); void SetResourceUsageLimits(size_t max_memory_usage_bytes, size_t max_unused_memory_usage_bytes, size_t max_resource_count); void ReduceResourceUsage(); + void CheckBusyResources(); size_t total_memory_usage_bytes() const { return memory_usage_bytes_; @@ -57,12 +49,18 @@ class CC_EXPORT ResourcePool { } protected: - explicit ResourcePool(ResourceProvider* resource_provider); + ResourcePool(ResourceProvider* resource_provider, + GLenum target, + ResourceFormat format); bool ResourceUsageTooHigh(); private: + void DidFinishUsingResource(ScopedResource* resource); + ResourceProvider* resource_provider_; + const GLenum target_; + const ResourceFormat format_; size_t max_memory_usage_bytes_; size_t max_unused_memory_usage_bytes_; size_t max_resource_count_; @@ -70,8 +68,9 @@ class CC_EXPORT ResourcePool { size_t unused_memory_usage_bytes_; size_t resource_count_; - typedef std::list<Resource*> ResourceList; + typedef std::list<ScopedResource*> ResourceList; ResourceList unused_resources_; + ResourceList busy_resources_; DISALLOW_COPY_AND_ASSIGN(ResourcePool); }; diff --git a/chromium/cc/resources/resource_provider.cc b/chromium/cc/resources/resource_provider.cc index ee761d17564..1331ca2f1cf 100644 --- a/chromium/cc/resources/resource_provider.cc +++ b/chromium/cc/resources/resource_provider.cc @@ -8,6 +8,7 @@ #include <limits> #include "base/containers/hash_tables.h" +#include "base/debug/trace_event.h" #include "base/stl_util.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -15,19 +16,42 @@ #include "cc/output/gl_renderer.h" // For the GLC() macro. #include "cc/resources/platform_color.h" #include "cc/resources/returned_resource.h" +#include "cc/resources/shared_bitmap_manager.h" #include "cc/resources/transferable_resource.h" #include "cc/scheduler/texture_uploader.h" #include "gpu/GLES2/gl2extchromium.h" -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" +#include "gpu/command_buffer/client/gles2_interface.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" +#include "ui/gfx/frame_time.h" #include "ui/gfx/rect.h" #include "ui/gfx/vector2d.h" -using WebKit::WebGraphicsContext3D; +using gpu::gles2::GLES2Interface; namespace cc { +class IdAllocator { + public: + virtual ~IdAllocator() {} + + virtual GLuint NextId() = 0; + + protected: + IdAllocator(GLES2Interface* gl, size_t id_allocation_chunk_size) + : gl_(gl), + id_allocation_chunk_size_(id_allocation_chunk_size), + ids_(new GLuint[id_allocation_chunk_size]), + next_id_index_(id_allocation_chunk_size) { + DCHECK(id_allocation_chunk_size_); + } + + GLES2Interface* gl_; + const size_t id_allocation_chunk_size_; + scoped_ptr<GLuint[]> ids_; + size_t next_id_index_; +}; + namespace { // Measured in seconds. @@ -45,6 +69,7 @@ GLenum TextureToStorageFormat(ResourceFormat format) { case RGBA_4444: case LUMINANCE_8: case RGB_565: + case ETC1: NOTREACHED(); break; } @@ -60,6 +85,7 @@ bool IsFormatSupportedForStorage(ResourceFormat format) { case RGBA_4444: case LUMINANCE_8: case RGB_565: + case ETC1: return false; } return false; @@ -67,25 +93,72 @@ bool IsFormatSupportedForStorage(ResourceFormat format) { class ScopedSetActiveTexture { public: - ScopedSetActiveTexture(WebGraphicsContext3D* context3d, GLenum unit) - : context3d_(context3d), unit_(unit) { - DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(context3d_)); + ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit) + : gl_(gl), unit_(unit) { + DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_)); if (unit_ != GL_TEXTURE0) - GLC(context3d_, context3d_->activeTexture(unit_)); + GLC(gl_, gl_->ActiveTexture(unit_)); } ~ScopedSetActiveTexture() { // Active unit being GL_TEXTURE0 is effectively the ground state. if (unit_ != GL_TEXTURE0) - GLC(context3d_, context3d_->activeTexture(GL_TEXTURE0)); + GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0)); } private: - WebGraphicsContext3D* context3d_; + GLES2Interface* gl_; GLenum unit_; }; +class TextureIdAllocator : public IdAllocator { + public: + TextureIdAllocator(GLES2Interface* gl, + size_t texture_id_allocation_chunk_size) + : IdAllocator(gl, texture_id_allocation_chunk_size) {} + virtual ~TextureIdAllocator() { + gl_->DeleteTextures(id_allocation_chunk_size_ - next_id_index_, + ids_.get() + next_id_index_); + } + + // Overridden from IdAllocator: + virtual GLuint NextId() OVERRIDE { + if (next_id_index_ == id_allocation_chunk_size_) { + gl_->GenTextures(id_allocation_chunk_size_, ids_.get()); + next_id_index_ = 0; + } + + return ids_[next_id_index_++]; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator); +}; + +class BufferIdAllocator : public IdAllocator { + public: + BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size) + : IdAllocator(gl, buffer_id_allocation_chunk_size) {} + virtual ~BufferIdAllocator() { + gl_->DeleteBuffers(id_allocation_chunk_size_ - next_id_index_, + ids_.get() + next_id_index_); + } + + // Overridden from IdAllocator: + virtual GLuint NextId() OVERRIDE { + if (next_id_index_ == id_allocation_chunk_size_) { + gl_->GenBuffers(id_allocation_chunk_size_, ids_.get()); + next_id_index_ = 0; + } + + return ids_[next_id_index_++]; + } + + private: + DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator); +}; + } // namespace ResourceProvider::Resource::Resource() @@ -107,21 +180,25 @@ ResourceProvider::Resource::Resource() enable_read_lock_fences(false), read_lock_fence(NULL), size(), + target(0), original_filter(0), filter(0), - target(0), image_id(0), + bound_image_id(0), + dirty_image(false), texture_pool(0), wrap_mode(0), lost(false), hint(TextureUsageAny), type(static_cast<ResourceType>(0)), - format(RGBA_8888) {} + format(RGBA_8888), + shared_bitmap(NULL) {} ResourceProvider::Resource::~Resource() {} -ResourceProvider::Resource::Resource(unsigned texture_id, +ResourceProvider::Resource::Resource(GLuint texture_id, gfx::Size size, + GLenum target, GLenum filter, GLenum texture_pool, GLint wrap_mode, @@ -145,20 +222,24 @@ ResourceProvider::Resource::Resource(unsigned texture_id, enable_read_lock_fences(false), read_lock_fence(NULL), size(size), + target(target), original_filter(filter), filter(filter), - target(0), image_id(0), + bound_image_id(0), + dirty_image(false), texture_pool(texture_pool), wrap_mode(wrap_mode), lost(false), hint(hint), type(GLTexture), - format(format) { + format(format), + shared_bitmap(NULL) { DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); } ResourceProvider::Resource::Resource(uint8_t* pixels, + SharedBitmap* bitmap, gfx::Size size, GLenum filter, GLint wrap_mode) @@ -180,34 +261,41 @@ ResourceProvider::Resource::Resource(uint8_t* pixels, enable_read_lock_fences(false), read_lock_fence(NULL), size(size), + target(0), original_filter(filter), filter(filter), - target(0), image_id(0), + bound_image_id(0), + dirty_image(false), texture_pool(0), wrap_mode(wrap_mode), lost(false), hint(TextureUsageAny), type(Bitmap), - format(RGBA_8888) { + format(RGBA_8888), + shared_bitmap(bitmap) { DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); } -ResourceProvider::Child::Child() {} +ResourceProvider::Child::Child() : marked_for_deletion(false) {} ResourceProvider::Child::~Child() {} scoped_ptr<ResourceProvider> ResourceProvider::Create( OutputSurface* output_surface, + SharedBitmapManager* shared_bitmap_manager, int highp_threshold_min, - bool use_rgba_4444_texture_format) { + bool use_rgba_4444_texture_format, + size_t id_allocation_chunk_size) { scoped_ptr<ResourceProvider> resource_provider( new ResourceProvider(output_surface, + shared_bitmap_manager, highp_threshold_min, - use_rgba_4444_texture_format)); + use_rgba_4444_texture_format, + id_allocation_chunk_size)); bool success = false; - if (resource_provider->Context3d()) { + if (resource_provider->ContextGL()) { success = resource_provider->InitializeGL(); } else { resource_provider->InitializeSoftware(); @@ -223,7 +311,7 @@ scoped_ptr<ResourceProvider> ResourceProvider::Create( ResourceProvider::~ResourceProvider() { while (!children_.empty()) - DestroyChild(children_.begin()->first); + DestroyChildInternal(children_.begin(), ForShutdown); while (!resources_.empty()) DeleteResourceInternal(resources_.begin(), ForShutdown); @@ -250,13 +338,14 @@ ResourceProvider::ResourceId ResourceProvider::CreateResource( switch (default_resource_type_) { case GLTexture: return CreateGLTexture(size, + GL_TEXTURE_2D, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, wrap_mode, hint, format); case Bitmap: DCHECK_EQ(RGBA_8888, format); - return CreateBitmap(size); + return CreateBitmap(size, wrap_mode); case InvalidType: break; } @@ -267,6 +356,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateResource( ResourceProvider::ResourceId ResourceProvider::CreateManagedResource( gfx::Size size, + GLenum target, GLint wrap_mode, TextureUsageHint hint, ResourceFormat format) { @@ -274,13 +364,14 @@ ResourceProvider::ResourceId ResourceProvider::CreateManagedResource( switch (default_resource_type_) { case GLTexture: return CreateGLTexture(size, + target, GL_TEXTURE_POOL_MANAGED_CHROMIUM, wrap_mode, hint, format); case Bitmap: DCHECK_EQ(RGBA_8888, format); - return CreateBitmap(size); + return CreateBitmap(size, wrap_mode); case InvalidType: break; } @@ -291,6 +382,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateManagedResource( ResourceProvider::ResourceId ResourceProvider::CreateGLTexture( gfx::Size size, + GLenum target, GLenum texture_pool, GLint wrap_mode, TextureUsageHint hint, @@ -300,19 +392,30 @@ ResourceProvider::ResourceId ResourceProvider::CreateGLTexture( DCHECK(thread_checker_.CalledOnValidThread()); ResourceId id = next_id_++; - Resource resource(0, size, GL_LINEAR, texture_pool, wrap_mode, hint, format); + Resource resource( + 0, size, target, GL_LINEAR, texture_pool, wrap_mode, hint, format); resource.allocated = false; resources_[id] = resource; return id; } -ResourceProvider::ResourceId ResourceProvider::CreateBitmap(gfx::Size size) { +ResourceProvider::ResourceId ResourceProvider::CreateBitmap( + gfx::Size size, GLint wrap_mode) { DCHECK(thread_checker_.CalledOnValidThread()); - uint8_t* pixels = new uint8_t[4 * size.GetArea()]; + scoped_ptr<SharedBitmap> bitmap; + if (shared_bitmap_manager_) + bitmap = shared_bitmap_manager_->AllocateSharedBitmap(size); + + uint8_t* pixels; + if (bitmap) + pixels = bitmap->pixels(); + else + pixels = new uint8_t[4 * size.GetArea()]; ResourceId id = next_id_++; - Resource resource(pixels, size, GL_LINEAR, GL_CLAMP_TO_EDGE); + Resource resource( + pixels, bitmap.release(), size, GL_LINEAR, wrap_mode); resource.allocated = true; resources_[id] = resource; return id; @@ -320,25 +423,24 @@ ResourceProvider::ResourceId ResourceProvider::CreateBitmap(gfx::Size size) { ResourceProvider::ResourceId ResourceProvider::CreateResourceFromExternalTexture( - unsigned texture_target, - unsigned texture_id) { + GLuint texture_target, + GLuint texture_id) { DCHECK(thread_checker_.CalledOnValidThread()); - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - GLC(context3d, context3d->bindTexture(texture_target, texture_id)); - GLC(context3d, context3d->texParameteri( - texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GLC(context3d, context3d->texParameteri( - texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GLC(context3d, context3d->texParameteri( - texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GLC(context3d, context3d->texParameteri( - texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + GLC(gl, gl->BindTexture(texture_target, texture_id)); + GLC(gl, gl->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GLC(gl, gl->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GLC(gl, + gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLC(gl, + gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); ResourceId id = next_id_++; Resource resource(texture_id, gfx::Size(), + texture_target, GL_LINEAR, 0, GL_CLAMP_TO_EDGE, @@ -361,6 +463,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( if (mailbox.IsTexture()) { resource = Resource(0, gfx::Size(), + mailbox.target(), GL_LINEAR, 0, GL_CLAMP_TO_EDGE, @@ -371,8 +474,16 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( base::SharedMemory* shared_memory = mailbox.shared_memory(); DCHECK(shared_memory->memory()); uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory()); - resource = Resource( - pixels, mailbox.shared_memory_size(), GL_LINEAR, GL_CLAMP_TO_EDGE); + scoped_ptr<SharedBitmap> shared_bitmap; + if (shared_bitmap_manager_) { + shared_bitmap = + shared_bitmap_manager_->GetBitmapForSharedMemory(shared_memory); + } + resource = Resource(pixels, + shared_bitmap.release(), + mailbox.shared_memory_size(), + GL_LINEAR, + GL_CLAMP_TO_EDGE); } resource.external = true; resource.allocated = true; @@ -403,53 +514,61 @@ void ResourceProvider::DeleteResource(ResourceId id) { void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style) { + TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal"); Resource* resource = &it->second; - bool lost_resource = lost_output_surface_ || resource->lost; + bool lost_resource = resource->lost; DCHECK(resource->exported_count == 0 || style != Normal); if (style == ForShutdown && resource->exported_count > 0) lost_resource = true; if (resource->image_id) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - GLC(context3d, context3d->destroyImageCHROMIUM(resource->image_id)); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + GLC(gl, gl->DestroyImageCHROMIUM(resource->image_id)); } if (resource->gl_id && !resource->external) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - GLC(context3d, context3d->deleteTexture(resource->gl_id)); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + GLC(gl, gl->DeleteTextures(1, &resource->gl_id)); } if (resource->gl_upload_query_id) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - GLC(context3d, context3d->deleteQueryEXT(resource->gl_upload_query_id)); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id)); } if (resource->gl_pixel_buffer_id) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - GLC(context3d, context3d->deleteBuffer(resource->gl_pixel_buffer_id)); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + GLC(gl, gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id)); } if (resource->mailbox.IsValid() && resource->external) { - unsigned sync_point = resource->mailbox.sync_point(); + GLuint sync_point = resource->mailbox.sync_point(); if (resource->mailbox.IsTexture()) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); + lost_resource |= lost_output_surface_; + GLES2Interface* gl = ContextGL(); + DCHECK(gl); if (resource->gl_id) - GLC(context3d, context3d->deleteTexture(resource->gl_id)); + GLC(gl, gl->DeleteTextures(1, &resource->gl_id)); if (!lost_resource && resource->gl_id) - sync_point = context3d->insertSyncPoint(); + sync_point = gl->InsertSyncPointCHROMIUM(); } else { DCHECK(resource->mailbox.IsSharedMemory()); base::SharedMemory* shared_memory = resource->mailbox.shared_memory(); if (resource->pixels && shared_memory) { DCHECK(shared_memory->memory() == resource->pixels); resource->pixels = NULL; + delete resource->shared_bitmap; + resource->shared_bitmap = NULL; } } resource->release_callback.Run(sync_point, lost_resource); } + if (resource->shared_bitmap) { + delete resource->shared_bitmap; + resource->pixels = NULL; + } if (resource->pixels) delete[] resource->pixels; if (resource->pixel_buffer) @@ -478,10 +597,11 @@ void ResourceProvider::SetPixels(ResourceId id, if (resource->gl_id) { DCHECK(!resource->pending_set_pixels); - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); + DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); DCHECK(texture_uploader_.get()); - context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id); + gl->BindTexture(GL_TEXTURE_2D, resource->gl_id); texture_uploader_->Upload(image, image_rect, source_rect, @@ -525,11 +645,14 @@ void ResourceProvider::MarkPendingUploadsAsNonBlocking() { texture_uploader_->MarkPendingUploadsAsNonBlocking(); } -double ResourceProvider::EstimatedUploadsPerSecond() { +size_t ResourceProvider::EstimatedUploadsPerTick() { if (!texture_uploader_) - return 0.0; + return 1u; - return texture_uploader_->EstimatedTexturesPerSecond(); + double textures_per_second = texture_uploader_->EstimatedTexturesPerSecond(); + size_t textures_per_tick = floor( + kTextureUploadTickRate * textures_per_second); + return textures_per_tick ? textures_per_tick : 1u; } void ResourceProvider::FlushUploads() { @@ -546,36 +669,48 @@ void ResourceProvider::ReleaseCachedData() { texture_uploader_->ReleaseCachedQueries(); } -base::TimeDelta ResourceProvider::TextureUpdateTickRate() { +base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime( + size_t uploads_per_tick) { + if (lost_output_surface_) + return base::TimeTicks(); + // Software resource uploads happen on impl thread, so don't bother batching // them up and trying to wait for them to complete. - double rate = - texture_uploader_ ? kTextureUploadTickRate : kSoftwareUploadTickRate; - return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond * - rate); + if (!texture_uploader_) { + return gfx::FrameTime::Now() + base::TimeDelta::FromMicroseconds( + base::Time::kMicrosecondsPerSecond * kSoftwareUploadTickRate); + } + + base::TimeDelta upload_one_texture_time = + base::TimeDelta::FromMicroseconds( + base::Time::kMicrosecondsPerSecond * kTextureUploadTickRate) / + uploads_per_tick; + + size_t total_uploads = NumBlockingUploads() + uploads_per_tick; + return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads; } void ResourceProvider::Flush() { DCHECK(thread_checker_.CalledOnValidThread()); - WebGraphicsContext3D* context3d = Context3d(); - if (context3d) - context3d->flush(); + GLES2Interface* gl = ContextGL(); + if (gl) + gl->Flush(); } void ResourceProvider::Finish() { DCHECK(thread_checker_.CalledOnValidThread()); - WebGraphicsContext3D* context3d = Context3d(); - if (context3d) - context3d->finish(); + GLES2Interface* gl = ContextGL(); + if (gl) + gl->Finish(); } bool ResourceProvider::ShallowFlushIfSupported() { DCHECK(thread_checker_.CalledOnValidThread()); - WebGraphicsContext3D* context3d = Context3d(); - if (!context3d || !use_shallow_flush_) + GLES2Interface* gl = ContextGL(); + if (!gl) return false; - context3d->shallowFlushCHROMIUM(); + gl->ShallowFlushCHROMIUM(); return true; } @@ -600,18 +735,17 @@ const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) { if (resource->external) { if (!resource->gl_id && resource->mailbox.IsTexture()) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); if (resource->mailbox.sync_point()) { - GLC(context3d, - context3d->waitSyncPoint(resource->mailbox.sync_point())); + GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point())); resource->mailbox.ResetSyncPoint(); } - resource->gl_id = context3d->createTexture(); - GLC(context3d, context3d->bindTexture( - resource->mailbox.target(), resource->gl_id)); - GLC(context3d, context3d->consumeTextureCHROMIUM( - resource->mailbox.target(), resource->mailbox.data())); + resource->gl_id = texture_id_allocator_->NextId(); + GLC(gl, gl->BindTexture(resource->target, resource->gl_id)); + GLC(gl, + gl->ConsumeTextureCHROMIUM(resource->target, + resource->mailbox.data())); } } @@ -675,28 +809,23 @@ ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() { ResourceProvider::ScopedSamplerGL::ScopedSamplerGL( ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id, - GLenum target, GLenum filter) : ScopedReadLockGL(resource_provider, resource_id), - target_(target), - unit_(GL_TEXTURE0) { - resource_provider->BindForSampling(resource_id, target, unit_, filter); + unit_(GL_TEXTURE0), + target_(resource_provider->BindForSampling(resource_id, unit_, filter)) { } ResourceProvider::ScopedSamplerGL::ScopedSamplerGL( ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id, - GLenum target, GLenum unit, GLenum filter) : ScopedReadLockGL(resource_provider, resource_id), - target_(target), - unit_(unit) { - resource_provider->BindForSampling(resource_id, target, unit, filter); + unit_(unit), + target_(resource_provider->BindForSampling(resource_id, unit_, filter)) { } ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() { - resource_provider_->UnbindForSampling(resource_id_, target_, unit_); } ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL( @@ -727,8 +856,9 @@ ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware( ResourceProvider::ResourceId resource_id) : resource_provider_(resource_provider), resource_id_(resource_id) { - ResourceProvider::PopulateSkBitmapWithResource( - &sk_bitmap_, resource_provider->LockForRead(resource_id)); + const Resource* resource = resource_provider->LockForRead(resource_id); + wrap_mode_ = resource->wrap_mode; + ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource); } ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() { @@ -750,9 +880,12 @@ ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() { } ResourceProvider::ResourceProvider(OutputSurface* output_surface, + SharedBitmapManager* shared_bitmap_manager, int highp_threshold_min, - bool use_rgba_4444_texture_format) + bool use_rgba_4444_texture_format, + size_t id_allocation_chunk_size) : output_surface_(output_surface), + shared_bitmap_manager_(shared_bitmap_manager), lost_output_surface_(false), highp_threshold_min_(highp_threshold_min), next_id_(1), @@ -760,11 +893,13 @@ ResourceProvider::ResourceProvider(OutputSurface* output_surface, default_resource_type_(InvalidType), use_texture_storage_ext_(false), use_texture_usage_hint_(false), - use_shallow_flush_(false), + use_compressed_texture_etc1_(false), max_texture_size_(0), best_texture_format_(RGBA_8888), - use_rgba_4444_texture_format_(use_rgba_4444_texture_format) { + use_rgba_4444_texture_format_(use_rgba_4444_texture_format), + id_allocation_chunk_size_(id_allocation_chunk_size) { DCHECK(output_surface_->HasClient()); + DCHECK(id_allocation_chunk_size_); } void ResourceProvider::InitializeSoftware() { @@ -774,7 +909,8 @@ void ResourceProvider::InitializeSoftware() { CleanUpGLIfNeeded(); default_resource_type_ = Bitmap; - max_texture_size_ = INT_MAX / 2; + // Pick an arbitrary limit here similar to what hardware might. + max_texture_size_ = 16 * 1024; best_texture_format_ = RGBA_8888; } @@ -782,45 +918,48 @@ bool ResourceProvider::InitializeGL() { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(!texture_uploader_); DCHECK_NE(GLTexture, default_resource_type_); - - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - - if (!context3d->makeContextCurrent()) - return false; + DCHECK(!texture_id_allocator_); + DCHECK(!buffer_id_allocator_); default_resource_type_ = GLTexture; const ContextProvider::Capabilities& caps = output_surface_->context_provider()->ContextCapabilities(); - bool use_map_sub = caps.map_sub; bool use_bgra = caps.texture_format_bgra8888; use_texture_storage_ext_ = caps.texture_storage; - use_shallow_flush_ = caps.shallow_flush; use_texture_usage_hint_ = caps.texture_usage; + use_compressed_texture_etc1_ = caps.texture_format_etc1; + + GLES2Interface* gl = ContextGL(); + DCHECK(gl); - texture_uploader_ = - TextureUploader::Create(context3d, use_map_sub, use_shallow_flush_); - GLC(context3d, context3d->getIntegerv(GL_MAX_TEXTURE_SIZE, - &max_texture_size_)); + texture_uploader_ = TextureUploader::Create(gl); + max_texture_size_ = 0; // Context expects cleared value. + GLC(gl, gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_)); best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra); + texture_id_allocator_.reset( + new TextureIdAllocator(gl, id_allocation_chunk_size_)); + buffer_id_allocator_.reset( + new BufferIdAllocator(gl, id_allocation_chunk_size_)); + return true; } void ResourceProvider::CleanUpGLIfNeeded() { - WebGraphicsContext3D* context3d = Context3d(); + GLES2Interface* gl = ContextGL(); if (default_resource_type_ != GLTexture) { // We are not in GL mode, but double check before returning. - DCHECK(!context3d); + DCHECK(!gl); DCHECK(!texture_uploader_); return; } - DCHECK(context3d); - context3d->makeContextCurrent(); + DCHECK(gl); texture_uploader_.reset(); + texture_id_allocator_.reset(); + buffer_id_allocator_.reset(); Finish(); } @@ -836,11 +975,17 @@ int ResourceProvider::CreateChild(const ReturnCallback& return_callback) { } void ResourceProvider::DestroyChild(int child_id) { - DCHECK(thread_checker_.CalledOnValidThread()); - ChildMap::iterator it = children_.find(child_id); DCHECK(it != children_.end()); + DestroyChildInternal(it, Normal); +} + +void ResourceProvider::DestroyChildInternal(ChildMap::iterator it, + DeleteStyle style) { + DCHECK(thread_checker_.CalledOnValidThread()); + Child& child = it->second; + DCHECK(style == ForShutdown || !child.marked_for_deletion); ResourceIdArray resources_for_child; @@ -853,11 +998,9 @@ void ResourceProvider::DestroyChild(int child_id) { // If the child is going away, don't consider any resources in use. child.in_use_resources.clear(); + child.marked_for_deletion = true; - DeleteAndReturnUnusedResourcesToChild( - &child, ForShutdown, resources_for_child); - - children_.erase(it); + DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child); } const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap( @@ -865,30 +1008,27 @@ const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap( DCHECK(thread_checker_.CalledOnValidThread()); ChildMap::const_iterator it = children_.find(child); DCHECK(it != children_.end()); + DCHECK(!it->second.marked_for_deletion); return it->second.child_to_parent_map; } void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources, TransferableResourceArray* list) { DCHECK(thread_checker_.CalledOnValidThread()); - WebGraphicsContext3D* context3d = Context3d(); - if (!context3d || !context3d->makeContextCurrent()) { - // TODO(skaslev): Implement this path for software compositing. - return; - } + GLES2Interface* gl = ContextGL(); bool need_sync_point = false; for (ResourceIdArray::const_iterator it = resources.begin(); it != resources.end(); ++it) { TransferableResource resource; - TransferResource(context3d, *it, &resource); - if (!resource.sync_point) + TransferResource(gl, *it, &resource); + if (!resource.sync_point && !resource.is_software) need_sync_point = true; ++resources_.find(*it)->second.exported_count; list->push_back(resource); } if (need_sync_point) { - unsigned int sync_point = context3d->insertSyncPoint(); + GLuint sync_point = gl->InsertSyncPointCHROMIUM(); for (TransferableResourceArray::iterator it = list->begin(); it != list->end(); ++it) { @@ -901,12 +1041,9 @@ void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources, void ResourceProvider::ReceiveFromChild( int child, const TransferableResourceArray& resources) { DCHECK(thread_checker_.CalledOnValidThread()); - WebGraphicsContext3D* context3d = Context3d(); - if (!context3d || !context3d->makeContextCurrent()) { - // TODO(skaslev): Implement this path for software compositing. - return; - } + GLES2Interface* gl = ContextGL(); Child& child_info = children_.find(child)->second; + DCHECK(!child_info.marked_for_deletion); for (TransferableResourceArray::const_iterator it = resources.begin(); it != resources.end(); ++it) { @@ -916,33 +1053,57 @@ void ResourceProvider::ReceiveFromChild( resources_[resource_in_map_it->second].imported_count++; continue; } - unsigned texture_id; - // NOTE: If the parent is a browser and the child a renderer, the parent - // is not supposed to have its context wait, because that could induce - // deadlocks and/or security issues. The caller is responsible for - // waiting asynchronously, and resetting sync_point before calling this. - // However if the parent is a renderer (e.g. browser tag), it may be ok - // (and is simpler) to wait. - if (it->sync_point) - GLC(context3d, context3d->waitSyncPoint(it->sync_point)); - GLC(context3d, texture_id = context3d->createTexture()); - GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, texture_id)); - GLC(context3d, context3d->consumeTextureCHROMIUM(GL_TEXTURE_2D, - it->mailbox.name)); + + scoped_ptr<SharedBitmap> bitmap; + uint8_t* pixels = NULL; + if (it->is_software) { + if (shared_bitmap_manager_) + bitmap = shared_bitmap_manager_->GetSharedBitmapFromId(it->size, + it->mailbox); + if (bitmap) + pixels = bitmap->pixels(); + } + + if ((!it->is_software && !gl) || (it->is_software && !pixels)) { + TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid"); + ReturnedResourceArray to_return; + to_return.push_back(it->ToReturnedResource()); + child_info.return_callback.Run(to_return); + continue; + } + ResourceId local_id = next_id_++; - Resource resource(texture_id, - it->size, - it->filter, - 0, - GL_CLAMP_TO_EDGE, - TextureUsageAny, - it->format); - resource.mailbox.SetName(it->mailbox); + Resource& resource = resources_[local_id]; + if (it->is_software) { + resource = Resource( + pixels, bitmap.release(), it->size, GL_LINEAR, GL_CLAMP_TO_EDGE); + } else { + GLuint texture_id; + // NOTE: If the parent is a browser and the child a renderer, the parent + // is not supposed to have its context wait, because that could induce + // deadlocks and/or security issues. The caller is responsible for + // waiting asynchronously, and resetting sync_point before calling this. + // However if the parent is a renderer (e.g. browser tag), it may be ok + // (and is simpler) to wait. + if (it->sync_point) + GLC(gl, gl->WaitSyncPointCHROMIUM(it->sync_point)); + texture_id = texture_id_allocator_->NextId(); + GLC(gl, gl->BindTexture(it->target, texture_id)); + GLC(gl, gl->ConsumeTextureCHROMIUM(it->target, it->mailbox.name)); + resource = Resource(texture_id, + it->size, + it->target, + it->filter, + 0, + GL_CLAMP_TO_EDGE, + TextureUsageAny, + it->format); + resource.mailbox.SetName(it->mailbox); + } resource.child_id = child; // Don't allocate a texture for a child. resource.allocated = true; resource.imported_count = 1; - resources_[local_id] = resource; child_info.parent_to_child_map[local_id] = it->id; child_info.child_to_parent_map[it->id] = local_id; } @@ -953,7 +1114,10 @@ void ResourceProvider::DeclareUsedResourcesFromChild( const ResourceIdArray& resources_from_child) { DCHECK(thread_checker_.CalledOnValidThread()); - Child& child_info = children_.find(child)->second; + ChildMap::iterator child_it = children_.find(child); + DCHECK(child_it != children_.end()); + Child& child_info = child_it->second; + DCHECK(!child_info.marked_for_deletion); child_info.in_use_resources.clear(); for (size_t i = 0; i < resources_from_child.size(); ++i) { @@ -974,7 +1138,7 @@ void ResourceProvider::DeclareUsedResourcesFromChild( if (!resource_is_in_use) unused.push_back(local_id); } - DeleteAndReturnUnusedResourcesToChild(&child_info, Normal, unused); + DeleteAndReturnUnusedResourcesToChild(child_it, Normal, unused); } // static @@ -991,14 +1155,9 @@ bool ResourceProvider::CompareResourceMapIteratorsByChildId( void ResourceProvider::ReceiveReturnsFromParent( const ReturnedResourceArray& resources) { DCHECK(thread_checker_.CalledOnValidThread()); - WebGraphicsContext3D* context3d = Context3d(); - if (!context3d || !context3d->makeContextCurrent()) { - // TODO(skaslev): Implement this path for software compositing. - return; - } + GLES2Interface* gl = ContextGL(); int child_id = 0; - Child* child_info = NULL; ResourceIdArray resources_for_child; std::vector<std::pair<ReturnedResource, ResourceMap::iterator> > @@ -1023,6 +1182,7 @@ void ResourceProvider::ReceiveReturnsFromParent( sorted_resources.end(), CompareResourceMapIteratorsByChildId); + ChildMap::iterator child_it = children_.end(); for (size_t i = 0; i < sorted_resources.size(); ++i) { ReturnedResource& returned = sorted_resources[i].first; ResourceMap::iterator& map_iterator = sorted_resources[i].second; @@ -1037,8 +1197,8 @@ void ResourceProvider::ReceiveReturnsFromParent( if (resource->gl_id) { if (returned.sync_point) - GLC(context3d, context3d->waitSyncPoint(returned.sync_point)); - } else { + GLC(gl, gl->WaitSyncPointCHROMIUM(returned.sync_point)); + } else if (!resource->shared_bitmap) { resource->mailbox = TextureMailbox(resource->mailbox.name(), returned.sync_point); } @@ -1054,17 +1214,16 @@ void ResourceProvider::ReceiveReturnsFromParent( // Delete the resource and return it to the child it came from one. if (resource->child_id != child_id) { - ChildMap::iterator child_it = children_.find(resource->child_id); - DCHECK(child_it != children_.end()); - if (child_id) { DCHECK_NE(resources_for_child.size(), 0u); + DCHECK(child_it != children_.end()); DeleteAndReturnUnusedResourcesToChild( - child_info, Normal, resources_for_child); + child_it, Normal, resources_for_child); resources_for_child.clear(); } - child_info = &child_it->second; + child_it = children_.find(resource->child_id); + DCHECK(child_it != children_.end()); child_id = resource->child_id; } resources_for_child.push_back(local_id); @@ -1072,12 +1231,13 @@ void ResourceProvider::ReceiveReturnsFromParent( if (child_id) { DCHECK_NE(resources_for_child.size(), 0u); + DCHECK(child_it != children_.end()); DeleteAndReturnUnusedResourcesToChild( - child_info, Normal, resources_for_child); + child_it, Normal, resources_for_child); } } -void ResourceProvider::TransferResource(WebGraphicsContext3D* context, +void ResourceProvider::TransferResource(GLES2Interface* gl, ResourceId id, TransferableResource* resource) { Resource* source = GetResource(id); @@ -1085,24 +1245,27 @@ void ResourceProvider::TransferResource(WebGraphicsContext3D* context, DCHECK(!source->lock_for_read_count); DCHECK(!source->external || (source->external && source->mailbox.IsValid())); DCHECK(source->allocated); + DCHECK_EQ(source->wrap_mode, GL_CLAMP_TO_EDGE); resource->id = id; resource->format = source->format; + resource->target = source->target; resource->filter = source->filter; resource->size = source->size; - // TODO(skaslev) Implement this path for shared memory resources. - DCHECK(!source->mailbox.IsSharedMemory()); - - if (!source->mailbox.IsTexture()) { + if (source->shared_bitmap) { + resource->mailbox = source->shared_bitmap->id(); + resource->is_software = true; + } else if (!source->mailbox.IsValid()) { // This is a resource allocated by the compositor, we need to produce it. // Don't set a sync point, the caller will do it. DCHECK(source->gl_id); - GLC(context, context->bindTexture(GL_TEXTURE_2D, source->gl_id)); - GLC(context, context->genMailboxCHROMIUM(resource->mailbox.name)); - GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D, - resource->mailbox.name)); + GLC(gl, gl->BindTexture(resource->target, source->gl_id)); + GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox.name)); + GLC(gl, + gl->ProduceTextureCHROMIUM(resource->target, resource->mailbox.name)); source->mailbox.SetName(resource->mailbox); } else { + DCHECK(source->mailbox.IsTexture()); // This is either an external resource, or a compositor resource that we // already exported. Make sure to forward the sync point that we were given. resource->mailbox = source->mailbox.name(); @@ -1112,23 +1275,19 @@ void ResourceProvider::TransferResource(WebGraphicsContext3D* context, } void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( - Child* child_info, + ChildMap::iterator child_it, DeleteStyle style, const ResourceIdArray& unused) { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(child_info); - - if (unused.empty()) - return; + DCHECK(child_it != children_.end()); + Child* child_info = &child_it->second; - WebGraphicsContext3D* context3d = Context3d(); - if (!context3d || !context3d->makeContextCurrent()) { - // TODO(skaslev): Implement this path for software compositing. + if (unused.empty() && !child_info->marked_for_deletion) return; - } ReturnedResourceArray to_return; + GLES2Interface* gl = ContextGL(); bool need_sync_point = false; for (size_t i = 0; i < unused.size(); ++i) { ResourceId local_id = unused[i]; @@ -1145,7 +1304,8 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( ResourceId child_id = child_info->parent_to_child_map[local_id]; DCHECK(child_info->child_to_parent_map.count(child_id)); - bool is_lost = resource.lost || lost_output_surface_; + bool is_lost = + resource.lost || (!resource.shared_bitmap && lost_output_surface_); if (resource.exported_count > 0) { if (style != ForShutdown) { // Defer this until we receive the resource back from the parent. @@ -1157,25 +1317,25 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( is_lost = true; } - if (resource.filter != resource.original_filter) { + if (gl && resource.filter != resource.original_filter) { DCHECK(resource.target); DCHECK(resource.gl_id); - GLC(context3d, context3d->bindTexture(resource.target, resource.gl_id)); - GLC(context3d, - context3d->texParameteri(resource.target, - GL_TEXTURE_MIN_FILTER, - resource.original_filter)); - GLC(context3d, - context3d->texParameteri(resource.target, - GL_TEXTURE_MAG_FILTER, - resource.original_filter)); + GLC(gl, gl->BindTexture(resource.target, resource.gl_id)); + GLC(gl, + gl->TexParameteri(resource.target, + GL_TEXTURE_MIN_FILTER, + resource.original_filter)); + GLC(gl, + gl->TexParameteri(resource.target, + GL_TEXTURE_MAG_FILTER, + resource.original_filter)); } ReturnedResource returned; returned.id = child_id; returned.sync_point = resource.mailbox.sync_point(); - if (!returned.sync_point) + if (!returned.sync_point && !resource.shared_bitmap) need_sync_point = true; returned.count = resource.imported_count; returned.lost = is_lost; @@ -1187,7 +1347,8 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( DeleteResourceInternal(it, style); } if (need_sync_point) { - unsigned int sync_point = context3d->insertSyncPoint(); + DCHECK(gl); + GLuint sync_point = gl->InsertSyncPointCHROMIUM(); for (size_t i = 0; i < to_return.size(); ++i) { if (!to_return[i].sync_point) to_return[i].sync_point = sync_point; @@ -1196,6 +1357,12 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( if (!to_return.empty()) child_info->return_callback.Run(to_return); + + if (child_info->marked_for_deletion && + child_info->parent_to_child_map.empty()) { + DCHECK(child_info->child_to_parent_map.empty()); + children_.erase(child_it); + } } void ResourceProvider::AcquirePixelBuffer(ResourceId id) { @@ -1203,23 +1370,22 @@ void ResourceProvider::AcquirePixelBuffer(ResourceId id) { DCHECK(!resource->external); DCHECK_EQ(resource->exported_count, 0); DCHECK(!resource->image_id); + DCHECK_NE(ETC1, resource->format); if (resource->type == GLTexture) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); if (!resource->gl_pixel_buffer_id) - resource->gl_pixel_buffer_id = context3d->createBuffer(); - context3d->bindBuffer( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->gl_pixel_buffer_id); - unsigned bytes_per_pixel = BytesPerPixel(resource->format); - context3d->bufferData( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->size.height() * RoundUp(bytes_per_pixel - * resource->size.width(), 4u), - NULL, - GL_DYNAMIC_DRAW); - context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); + resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId(); + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, + resource->gl_pixel_buffer_id); + unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8; + gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, + resource->size.height() * + RoundUp(bytes_per_pixel * resource->size.width(), 4u), + NULL, + GL_DYNAMIC_DRAW); + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); } if (resource->pixels) { @@ -1251,17 +1417,13 @@ void ResourceProvider::ReleasePixelBuffer(ResourceId id) { if (resource->type == GLTexture) { if (!resource->gl_pixel_buffer_id) return; - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - context3d->bindBuffer( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->gl_pixel_buffer_id); - context3d->bufferData( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - 0, - NULL, - GL_DYNAMIC_DRAW); - context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, + resource->gl_pixel_buffer_id); + gl->BufferData( + GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW); + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); } if (resource->pixels) { @@ -1279,16 +1441,14 @@ uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id) { DCHECK(!resource->image_id); if (resource->type == GLTexture) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); DCHECK(resource->gl_pixel_buffer_id); - context3d->bindBuffer( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->gl_pixel_buffer_id); - uint8_t* image = static_cast<uint8_t*>( - context3d->mapBufferCHROMIUM( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY)); - context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, + resource->gl_pixel_buffer_id); + uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM( + GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY)); + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); // Buffer is required to be 4-byte aligned. CHECK(!(reinterpret_cast<intptr_t>(image) & 3)); return image; @@ -1307,62 +1467,47 @@ void ResourceProvider::UnmapPixelBuffer(ResourceId id) { DCHECK(!resource->image_id); if (resource->type == GLTexture) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); DCHECK(resource->gl_pixel_buffer_id); - context3d->bindBuffer( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->gl_pixel_buffer_id); - context3d->unmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM); - context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, + resource->gl_pixel_buffer_id); + gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM); + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); } } -void ResourceProvider::BindForSampling(ResourceProvider::ResourceId resource_id, - GLenum target, - GLenum unit, - GLenum filter) { +GLenum ResourceProvider::BindForSampling( + ResourceProvider::ResourceId resource_id, + GLenum unit, + GLenum filter) { DCHECK(thread_checker_.CalledOnValidThread()); - WebGraphicsContext3D* context3d = Context3d(); + GLES2Interface* gl = ContextGL(); ResourceMap::iterator it = resources_.find(resource_id); DCHECK(it != resources_.end()); Resource* resource = &it->second; DCHECK(resource->lock_for_read_count); DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced); - ScopedSetActiveTexture scoped_active_tex(context3d, unit); - GLC(context3d, context3d->bindTexture(target, resource->gl_id)); + ScopedSetActiveTexture scoped_active_tex(gl, unit); + GLenum target = resource->target; + GLC(gl, gl->BindTexture(target, resource->gl_id)); if (filter != resource->filter) { - GLC(context3d, context3d->texParameteri(target, - GL_TEXTURE_MIN_FILTER, - filter)); - GLC(context3d, context3d->texParameteri(target, - GL_TEXTURE_MAG_FILTER, - filter)); + GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter)); + GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter)); resource->filter = filter; - if (resource->target == 0) - resource->target = target; - else - DCHECK_EQ(resource->target, target); } - if (resource->image_id) - context3d->bindTexImage2DCHROMIUM(target, resource->image_id); -} - -void ResourceProvider::UnbindForSampling( - ResourceProvider::ResourceId resource_id, GLenum target, GLenum unit) { - DCHECK(thread_checker_.CalledOnValidThread()); - ResourceMap::iterator it = resources_.find(resource_id); - DCHECK(it != resources_.end()); - Resource* resource = &it->second; - - if (!resource->image_id) - return; + if (resource->image_id && resource->dirty_image) { + // Release image currently bound to texture. + if (resource->bound_image_id) + gl->ReleaseTexImage2DCHROMIUM(target, resource->bound_image_id); + gl->BindTexImage2DCHROMIUM(target, resource->image_id); + resource->bound_image_id = resource->image_id; + resource->dirty_image = false; + } - WebGraphicsContext3D* context3d = Context3d(); - ScopedSetActiveTexture scoped_active_tex(context3d, unit); - context3d->releaseTexImage2DCHROMIUM(target, resource->image_id); + return target; } void ResourceProvider::BeginSetPixels(ResourceId id) { @@ -1379,43 +1524,40 @@ void ResourceProvider::BeginSetPixels(ResourceId id) { LockForWrite(id); if (resource->gl_id) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); DCHECK(resource->gl_pixel_buffer_id); - context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id); - context3d->bindBuffer( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->gl_pixel_buffer_id); + DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); + gl->BindTexture(GL_TEXTURE_2D, resource->gl_id); + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, + resource->gl_pixel_buffer_id); if (!resource->gl_upload_query_id) - resource->gl_upload_query_id = context3d->createQueryEXT(); - context3d->beginQueryEXT( - GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM, - resource->gl_upload_query_id); + gl->GenQueriesEXT(1, &resource->gl_upload_query_id); + gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM, + resource->gl_upload_query_id); if (allocate) { - context3d->asyncTexImage2DCHROMIUM( - GL_TEXTURE_2D, - 0, /* level */ - GetGLInternalFormat(resource->format), - resource->size.width(), - resource->size.height(), - 0, /* border */ - GetGLDataFormat(resource->format), - GetGLDataType(resource->format), - NULL); + gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D, + 0, /* level */ + GLInternalFormat(resource->format), + resource->size.width(), + resource->size.height(), + 0, /* border */ + GLDataFormat(resource->format), + GLDataType(resource->format), + NULL); } else { - context3d->asyncTexSubImage2DCHROMIUM( - GL_TEXTURE_2D, - 0, /* level */ - 0, /* x */ - 0, /* y */ - resource->size.width(), - resource->size.height(), - GetGLDataFormat(resource->format), - GetGLDataType(resource->format), - NULL); + gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D, + 0, /* level */ + 0, /* x */ + 0, /* y */ + resource->size.width(), + resource->size.height(), + GLDataFormat(resource->format), + GLDataType(resource->format), + NULL); } - context3d->endQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM); - context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); + gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM); + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); } if (resource->pixels) { @@ -1439,10 +1581,10 @@ void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) { DCHECK(!resource->set_pixels_completion_forced); if (resource->gl_id) { - WebGraphicsContext3D* context3d = Context3d(); - GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id)); - GLC(context3d, context3d->waitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D)); - GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, 0)); + GLES2Interface* gl = ContextGL(); + GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id)); + GLC(gl, gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D)); + GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0)); } resource->set_pixels_completion_forced = true; @@ -1454,14 +1596,12 @@ bool ResourceProvider::DidSetPixelsComplete(ResourceId id) { DCHECK(resource->pending_set_pixels); if (resource->gl_id) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); DCHECK(resource->gl_upload_query_id); - unsigned complete = 1; - context3d->getQueryObjectuivEXT( - resource->gl_upload_query_id, - GL_QUERY_RESULT_AVAILABLE_EXT, - &complete); + GLuint complete = 1; + gl->GetQueryObjectuivEXT( + resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete); if (!complete) return false; } @@ -1476,9 +1616,9 @@ void ResourceProvider::CreateForTesting(ResourceId id) { LazyCreate(GetResource(id)); } -GLint ResourceProvider::WrapModeForTesting(ResourceId id) { +GLenum ResourceProvider::TargetForTesting(ResourceId id) { Resource* resource = GetResource(id); - return resource->wrap_mode; + return resource->target; } void ResourceProvider::LazyCreate(Resource* resource) { @@ -1489,27 +1629,31 @@ void ResourceProvider::LazyCreate(Resource* resource) { if (resource->texture_pool == 0) return; - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); + resource->gl_id = texture_id_allocator_->NextId(); + + GLES2Interface* gl = ContextGL(); + DCHECK(gl); // Create and set texture properties. Allocation is delayed until needed. - GLC(context3d, resource->gl_id = context3d->createTexture()); - GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id)); - GLC(context3d, context3d->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GLC(context3d, context3d->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GLC(context3d, context3d->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, resource->wrap_mode)); - GLC(context3d, context3d->texParameteri( - GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, resource->wrap_mode)); - GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, - GL_TEXTURE_POOL_CHROMIUM, - resource->texture_pool)); + GLC(gl, gl->BindTexture(resource->target, resource->gl_id)); + GLC(gl, + gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GLC(gl, + gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GLC(gl, + gl->TexParameteri( + resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode)); + GLC(gl, + gl->TexParameteri( + resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode)); + GLC(gl, + gl->TexParameteri( + resource->target, GL_TEXTURE_POOL_CHROMIUM, resource->texture_pool)); if (use_texture_usage_hint_ && resource->hint == TextureUsageFramebuffer) { - GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, - GL_TEXTURE_USAGE_ANGLE, - GL_FRAMEBUFFER_ATTACHMENT_ANGLE)); + GLC(gl, + gl->TexParameteri(resource->target, + GL_TEXTURE_USAGE_ANGLE, + GL_FRAMEBUFFER_ATTACHMENT_ANGLE)); } } @@ -1525,27 +1669,31 @@ void ResourceProvider::LazyAllocate(Resource* resource) { if (resource->allocated || !resource->gl_id) return; resource->allocated = true; - WebGraphicsContext3D* context3d = Context3d(); + GLES2Interface* gl = ContextGL(); gfx::Size& size = resource->size; + DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); ResourceFormat format = resource->format; - GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id)); - if (use_texture_storage_ext_ && IsFormatSupportedForStorage(format)) { + GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id)); + if (use_texture_storage_ext_ && IsFormatSupportedForStorage(format) && + resource->hint != TextureUsageFramebuffer) { GLenum storage_format = TextureToStorageFormat(format); - GLC(context3d, context3d->texStorage2DEXT(GL_TEXTURE_2D, - 1, - storage_format, - size.width(), - size.height())); + GLC(gl, + gl->TexStorage2DEXT( + GL_TEXTURE_2D, 1, storage_format, size.width(), size.height())); } else { - GLC(context3d, context3d->texImage2D(GL_TEXTURE_2D, - 0, - GetGLInternalFormat(format), - size.width(), - size.height(), - 0, - GetGLDataFormat(format), - GetGLDataType(format), - NULL)); + // ETC1 does not support preallocation. + if (format != ETC1) { + GLC(gl, + gl->TexImage2D(GL_TEXTURE_2D, + 0, + GLInternalFormat(format), + size.width(), + size.height(), + 0, + GLDataFormat(format), + GLDataType(format), + NULL)); + } } } @@ -1567,11 +1715,12 @@ void ResourceProvider::AcquireImage(ResourceId id) { return; resource->allocated = true; - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - DCHECK_EQ(RGBA_8888, resource->format); - resource->image_id = context3d->createImageCHROMIUM( - resource->size.width(), resource->size.height(), GL_RGBA8_OES); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + resource->image_id = + gl->CreateImageCHROMIUM(resource->size.width(), + resource->size.height(), + TextureToStorageFormat(resource->format)); DCHECK(resource->image_id); } @@ -1583,10 +1732,12 @@ void ResourceProvider::ReleaseImage(ResourceId id) { if (!resource->image_id) return; - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - context3d->destroyImageCHROMIUM(resource->image_id); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + gl->DestroyImageCHROMIUM(resource->image_id); resource->image_id = 0; + resource->bound_image_id = 0; + resource->dirty_image = false; resource->allocated = false; } @@ -1597,10 +1748,10 @@ uint8_t* ResourceProvider::MapImage(ResourceId id) { DCHECK_EQ(resource->exported_count, 0); if (resource->image_id) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); return static_cast<uint8_t*>( - context3d->mapImageCHROMIUM(resource->image_id, GL_READ_WRITE)); + gl->MapImageCHROMIUM(resource->image_id, GL_READ_WRITE)); } if (resource->pixels) @@ -1615,9 +1766,10 @@ void ResourceProvider::UnmapImage(ResourceId id) { DCHECK_EQ(resource->exported_count, 0); if (resource->image_id) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - context3d->unmapImageCHROMIUM(resource->image_id); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + gl->UnmapImageCHROMIUM(resource->image_id); + resource->dirty_image = true; } } @@ -1629,74 +1781,34 @@ int ResourceProvider::GetImageStride(ResourceId id) { int stride = 0; if (resource->image_id) { - WebGraphicsContext3D* context3d = Context3d(); - DCHECK(context3d); - context3d->getImageParameterivCHROMIUM( + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + gl->GetImageParameterivCHROMIUM( resource->image_id, GL_IMAGE_ROWBYTES_CHROMIUM, &stride); } return stride; } -GLint ResourceProvider::GetActiveTextureUnit(WebGraphicsContext3D* context) { - GLint active_unit = 0; - context->getIntegerv(GL_ACTIVE_TEXTURE, &active_unit); - return active_unit; -} - -WebKit::WebGraphicsContext3D* ResourceProvider::Context3d() const { - ContextProvider* context_provider = output_surface_->context_provider(); - return context_provider ? context_provider->Context3d() : NULL; -} +base::SharedMemory* ResourceProvider::GetSharedMemory(ResourceId id) { + Resource* resource = GetResource(id); + DCHECK(!resource->external); + DCHECK_EQ(resource->exported_count, 0); -size_t ResourceProvider::BytesPerPixel(ResourceFormat format) { - switch (format) { - case RGBA_8888: - case BGRA_8888: - return 4; - case RGBA_4444: - case RGB_565: - return 2; - case LUMINANCE_8: - return 1; - } - NOTREACHED(); - return 4; + if (!resource->shared_bitmap) + return NULL; + return resource->shared_bitmap->memory(); } -GLenum ResourceProvider::GetGLDataType(ResourceFormat format) { - switch (format) { - case RGBA_4444: - return GL_UNSIGNED_SHORT_4_4_4_4; - case RGBA_8888: - case BGRA_8888: - case LUMINANCE_8: - return GL_UNSIGNED_BYTE; - case RGB_565: - return GL_UNSIGNED_SHORT_5_6_5; - } - NOTREACHED(); - return GL_UNSIGNED_BYTE; -} - -GLenum ResourceProvider::GetGLDataFormat(ResourceFormat format) { - switch (format) { - case RGBA_8888: - case RGBA_4444: - return GL_RGBA; - case BGRA_8888: - return GL_BGRA_EXT; - case LUMINANCE_8: - return GL_LUMINANCE; - case RGB_565: - return GL_RGB; - } - NOTREACHED(); - return GL_RGBA; +GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) { + GLint active_unit = 0; + gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit); + return active_unit; } -GLenum ResourceProvider::GetGLInternalFormat(ResourceFormat format) { - return GetGLDataFormat(format); +GLES2Interface* ResourceProvider::ContextGL() const { + ContextProvider* context_provider = output_surface_->context_provider(); + return context_provider ? context_provider->ContextGL() : NULL; } } // namespace cc diff --git a/chromium/cc/resources/resource_provider.h b/chromium/cc/resources/resource_provider.h index 928d4f9aa2a..2478661d62c 100644 --- a/chromium/cc/resources/resource_provider.h +++ b/chromium/cc/resources/resource_provider.h @@ -29,18 +29,24 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/size.h" +namespace gpu { +namespace gles { +class GLES2Interface; +} +} // A correct fix would be not to use GL types in this interal API file. typedef unsigned int GLenum; typedef int GLint; -namespace WebKit { class WebGraphicsContext3D; } - namespace gfx { class Rect; class Vector2d; } namespace cc { +class IdAllocator; +class SharedBitmap; +class SharedBitmapManager; class TextureUploader; // This class is not thread-safe and can only be called from the thread it was @@ -61,9 +67,12 @@ class CC_EXPORT ResourceProvider { Bitmap, }; - static scoped_ptr<ResourceProvider> Create(OutputSurface* output_surface, - int highp_threshold_min, - bool use_rgba_4444_texture_format); + static scoped_ptr<ResourceProvider> Create( + OutputSurface* output_surface, + SharedBitmapManager* shared_bitmap_manager, + int highp_threshold_min, + bool use_rgba_4444_texture_format, + size_t id_allocation_chunk_size); virtual ~ResourceProvider(); void InitializeSoftware(); @@ -97,18 +106,20 @@ class CC_EXPORT ResourceProvider { // Creates a resource which is tagged as being managed for GPU memory // accounting purposes. ResourceId CreateManagedResource(gfx::Size size, + GLenum target, GLint wrap_mode, TextureUsageHint hint, ResourceFormat format); // You can also explicitly create a specific resource type. ResourceId CreateGLTexture(gfx::Size size, + GLenum target, GLenum texture_pool, GLint wrap_mode, TextureUsageHint hint, ResourceFormat format); - ResourceId CreateBitmap(gfx::Size size); + ResourceId CreateBitmap(gfx::Size size, GLint wrap_mode); // Wraps an external texture into a GL resource. ResourceId CreateResourceFromExternalTexture( unsigned texture_target, @@ -132,10 +143,10 @@ class CC_EXPORT ResourceProvider { // Check upload status. size_t NumBlockingUploads(); void MarkPendingUploadsAsNonBlocking(); - double EstimatedUploadsPerSecond(); + size_t EstimatedUploadsPerTick(); void FlushUploads(); void ReleaseCachedData(); - base::TimeDelta TextureUpdateTickRate(); + base::TimeTicks EstimatedUploadCompletionTime(size_t uploads_per_tick); // Flush all context operations, kicking uploads and ensuring ordering with // respect to other contexts. @@ -217,18 +228,18 @@ class CC_EXPORT ResourceProvider { public: ScopedSamplerGL(ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id, - GLenum target, GLenum filter); ScopedSamplerGL(ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id, - GLenum target, GLenum unit, GLenum filter); virtual ~ScopedSamplerGL(); + GLenum target() const { return target_; } + private: - GLenum target_; GLenum unit_; + GLenum target_; DISALLOW_COPY_AND_ASSIGN(ScopedSamplerGL); }; @@ -256,11 +267,13 @@ class CC_EXPORT ResourceProvider { ~ScopedReadLockSoftware(); const SkBitmap* sk_bitmap() const { return &sk_bitmap_; } + GLint wrap_mode() const { return wrap_mode_; } private: ResourceProvider* resource_provider_; ResourceProvider::ResourceId resource_id_; SkBitmap sk_bitmap_; + GLint wrap_mode_; DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSoftware); }; @@ -322,6 +335,8 @@ class CC_EXPORT ResourceProvider { // Returns the stride for the image. int GetImageStride(ResourceId id); + base::SharedMemory* GetSharedMemory(ResourceId id); + // For tests only! This prevents detecting uninitialized reads. // Use SetPixels or LockForWrite to allocate implicitly. void AllocateForTesting(ResourceId id); @@ -329,7 +344,7 @@ class CC_EXPORT ResourceProvider { // For tests only! void CreateForTesting(ResourceId id); - GLint WrapModeForTesting(ResourceId id); + GLenum TargetForTesting(ResourceId id); // Sets the current read fence. If a resource is locked for read // and has read fences enabled, the resource will not allow writes @@ -345,11 +360,7 @@ class CC_EXPORT ResourceProvider { // Indicates if we can currently lock this resource for write. bool CanLockForWrite(ResourceId id); - static GLint GetActiveTextureUnit(WebKit::WebGraphicsContext3D* context); - static size_t BytesPerPixel(ResourceFormat format); - static GLenum GetGLDataType(ResourceFormat format); - static GLenum GetGLDataFormat(ResourceFormat format); - static GLenum GetGLInternalFormat(ResourceFormat format); + static GLint GetActiveTextureUnit(gpu::gles2::GLES2Interface* gl); private: struct Resource { @@ -357,12 +368,14 @@ class CC_EXPORT ResourceProvider { ~Resource(); Resource(unsigned texture_id, gfx::Size size, + GLenum target, GLenum filter, GLenum texture_pool, GLint wrap_mode, TextureUsageHint hint, ResourceFormat format); Resource(uint8_t* pixels, + SharedBitmap* bitmap, gfx::Size size, GLenum filter, GLint wrap_mode); @@ -389,17 +402,20 @@ class CC_EXPORT ResourceProvider { bool enable_read_lock_fences; scoped_refptr<Fence> read_lock_fence; gfx::Size size; + GLenum target; // TODO(skyostil): Use a separate sampler object for filter state. GLenum original_filter; GLenum filter; - GLenum target; unsigned image_id; + unsigned bound_image_id; + bool dirty_image; GLenum texture_pool; GLint wrap_mode; bool lost; TextureUsageHint hint; ResourceType type; ResourceFormat format; + SharedBitmap* shared_bitmap; }; typedef base::hash_map<ResourceId, Resource> ResourceMap; @@ -415,6 +431,7 @@ class CC_EXPORT ResourceProvider { ResourceIdMap parent_to_child_map; ReturnCallback return_callback; ResourceIdSet in_use_resources; + bool marked_for_deletion; }; typedef base::hash_map<int, Child> ChildMap; @@ -424,8 +441,10 @@ class CC_EXPORT ResourceProvider { } ResourceProvider(OutputSurface* output_surface, + SharedBitmapManager* shared_bitmap_manager, int highp_threshold_min, - bool use_rgba_4444_texture_format); + bool use_rgba_4444_texture_format, + size_t id_allocation_chunk_size); void CleanUpGLIfNeeded(); @@ -437,7 +456,7 @@ class CC_EXPORT ResourceProvider { static void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap, const Resource* resource); - void TransferResource(WebKit::WebGraphicsContext3D* context, + void TransferResource(gpu::gles2::GLES2Interface* gl, ResourceId id, TransferableResource* resource); enum DeleteStyle { @@ -445,27 +464,25 @@ class CC_EXPORT ResourceProvider { ForShutdown, }; void DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style); - void DeleteAndReturnUnusedResourcesToChild(Child* child_info, + void DeleteAndReturnUnusedResourcesToChild(ChildMap::iterator child_it, DeleteStyle style, const ResourceIdArray& unused); + void DestroyChildInternal(ChildMap::iterator it, DeleteStyle style); void LazyCreate(Resource* resource); void LazyAllocate(Resource* resource); // Binds the given GL resource to a texture target for sampling using the - // specified filter for both minification and magnification. The resource - // must be locked for reading. - void BindForSampling(ResourceProvider::ResourceId resource_id, - GLenum target, - GLenum unit, - GLenum filter); - void UnbindForSampling(ResourceProvider::ResourceId resource_id, - GLenum target, - GLenum unit); + // specified filter for both minification and magnification. Returns the + // texture target used. The resource must be locked for reading. + GLenum BindForSampling(ResourceProvider::ResourceId resource_id, + GLenum unit, + GLenum filter); // Returns NULL if the output_surface_ does not have a ContextProvider. - WebKit::WebGraphicsContext3D* Context3d() const; + gpu::gles2::GLES2Interface* ContextGL() const; OutputSurface* output_surface_; + SharedBitmapManager* shared_bitmap_manager_; bool lost_output_surface_; int highp_threshold_min_; ResourceId next_id_; @@ -476,7 +493,7 @@ class CC_EXPORT ResourceProvider { ResourceType default_resource_type_; bool use_texture_storage_ext_; bool use_texture_usage_hint_; - bool use_shallow_flush_; + bool use_compressed_texture_etc1_; scoped_ptr<TextureUploader> texture_uploader_; int max_texture_size_; ResourceFormat best_texture_format_; @@ -486,9 +503,29 @@ class CC_EXPORT ResourceProvider { scoped_refptr<Fence> current_read_lock_fence_; bool use_rgba_4444_texture_format_; + const size_t id_allocation_chunk_size_; + scoped_ptr<IdAllocator> texture_id_allocator_; + scoped_ptr<IdAllocator> buffer_id_allocator_; + DISALLOW_COPY_AND_ASSIGN(ResourceProvider); }; + +// TODO(epenner): Move these format conversions to resource_format.h +// once that builds on mac (npapi.h currently #includes OpenGL.h). +inline unsigned BitsPerPixel(ResourceFormat format) { + DCHECK_LE(format, RESOURCE_FORMAT_MAX); + static const unsigned format_bits_per_pixel[RESOURCE_FORMAT_MAX + 1] = { + 32, // RGBA_8888 + 16, // RGBA_4444 + 32, // BGRA_8888 + 8, // LUMINANCE_8 + 16, // RGB_565, + 4 // ETC1 + }; + return format_bits_per_pixel[format]; +} + } // namespace cc #endif // CC_RESOURCES_RESOURCE_PROVIDER_H_ diff --git a/chromium/cc/resources/resource_provider_unittest.cc b/chromium/cc/resources/resource_provider_unittest.cc index fed3016e2e5..e40c9a7e6fe 100644 --- a/chromium/cc/resources/resource_provider_unittest.cc +++ b/chromium/cc/resources/resource_provider_unittest.cc @@ -5,22 +5,24 @@ #include "cc/resources/resource_provider.h" #include <algorithm> +#include <map> #include "base/bind.h" #include "base/containers/hash_tables.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "cc/base/scoped_ptr_deque.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/output/output_surface.h" #include "cc/resources/returned_resource.h" +#include "cc/resources/shared_bitmap_manager.h" #include "cc/resources/single_release_callback.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" +#include "cc/test/test_texture.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "gpu/GLES2/gl2extchromium.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "ui/gfx/rect.h" @@ -31,57 +33,65 @@ using testing::Return; using testing::SetArgPointee; using testing::StrictMock; using testing::_; -using WebKit::WGC3Dbyte; -using WebKit::WGC3Denum; -using WebKit::WGC3Dint; -using WebKit::WGC3Dsizei; -using WebKit::WGC3Duint; -using WebKit::WebGLId; namespace cc { namespace { -size_t TextureSize(gfx::Size size, ResourceFormat format) { - unsigned int components_per_pixel = 4; - unsigned int bytes_per_component = 1; - return size.width() * size.height() * components_per_pixel * - bytes_per_component; +static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {} + +static void SharedMemoryReleaseCallback(scoped_ptr<base::SharedMemory> memory, + unsigned sync_point, + bool lost_resource) {} + +static void ReleaseTextureMailbox(unsigned* release_sync_point, + bool* release_lost_resource, + unsigned sync_point, + bool lost_resource) { + *release_sync_point = sync_point; + *release_lost_resource = lost_resource; +} + +static void ReleaseSharedMemoryCallback( + scoped_ptr<base::SharedMemory> shared_memory, + bool* release_called, + unsigned* release_sync_point, + bool* lost_resource_result, + unsigned sync_point, + bool lost_resource) { + *release_called = true; + *release_sync_point = sync_point; + *lost_resource_result = lost_resource; +} + +static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory( + gfx::Size size, + uint32_t value) { + scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory); + CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea())); + uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_memory->memory()); + CHECK(pixels); + std::fill_n(pixels, size.GetArea(), value); + return shared_memory.Pass(); } class TextureStateTrackingContext : public TestWebGraphicsContext3D { public: - MOCK_METHOD2(bindTexture, void(WGC3Denum target, WebGLId texture)); - MOCK_METHOD3(texParameteri, - void(WGC3Denum target, WGC3Denum pname, WGC3Dint param)); + MOCK_METHOD2(bindTexture, void(GLenum target, GLuint texture)); + MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param)); MOCK_METHOD1(waitSyncPoint, void(unsigned sync_point)); MOCK_METHOD0(insertSyncPoint, unsigned(void)); - MOCK_METHOD2(produceTextureCHROMIUM, void(WGC3Denum target, - const WGC3Dbyte* mailbox)); - MOCK_METHOD2(consumeTextureCHROMIUM, void(WGC3Denum target, - const WGC3Dbyte* mailbox)); - - // Force all textures to be "1" so we can test for them. - virtual WebKit::WebGLId NextTextureId() OVERRIDE { return 1; } -}; - -struct Texture : public base::RefCounted<Texture> { - Texture() : format(RGBA_8888), - filter(GL_NEAREST_MIPMAP_LINEAR) {} - - void Reallocate(gfx::Size size, ResourceFormat format) { - this->size = size; - this->format = format; - this->data.reset(new uint8_t[TextureSize(size, format)]); - } - - gfx::Size size; - ResourceFormat format; - WGC3Denum filter; - scoped_ptr<uint8_t[]> data; - - private: - friend class base::RefCounted<Texture>; - ~Texture() {} + MOCK_METHOD2(produceTextureCHROMIUM, + void(GLenum target, const GLbyte* mailbox)); + MOCK_METHOD2(consumeTextureCHROMIUM, + void(GLenum target, const GLbyte* mailbox)); + + // Force all textures to be consecutive numbers starting at "1", + // so we easily can test for them. + virtual GLuint NextTextureId() OVERRIDE { + base::AutoLock lock(namespace_->lock); + return namespace_->next_texture_id++; + } + virtual void RetireTextureId(GLuint) OVERRIDE {} }; // Shared data between multiple ResourceProviderContext. This contains mailbox @@ -94,15 +104,15 @@ class ContextSharedData { unsigned InsertSyncPoint() { return next_sync_point_++; } - void GenMailbox(WGC3Dbyte* mailbox) { - memset(mailbox, 0, sizeof(WGC3Dbyte[64])); + void GenMailbox(GLbyte* mailbox) { + memset(mailbox, 0, sizeof(GLbyte[64])); memcpy(mailbox, &next_mailbox_, sizeof(next_mailbox_)); ++next_mailbox_; } - void ProduceTexture(const WGC3Dbyte* mailbox_name, + void ProduceTexture(const GLbyte* mailbox_name, unsigned sync_point, - scoped_refptr<Texture> texture) { + scoped_refptr<TestTexture> texture) { unsigned mailbox = 0; memcpy(&mailbox, mailbox_name, sizeof(mailbox)); ASSERT_TRUE(mailbox && mailbox < next_mailbox_); @@ -111,8 +121,8 @@ class ContextSharedData { sync_point_for_mailbox_[mailbox] = sync_point; } - scoped_refptr<Texture> ConsumeTexture(const WGC3Dbyte* mailbox_name, - unsigned sync_point) { + scoped_refptr<TestTexture> ConsumeTexture(const GLbyte* mailbox_name, + unsigned sync_point) { unsigned mailbox = 0; memcpy(&mailbox, mailbox_name, sizeof(mailbox)); DCHECK(mailbox && mailbox < next_mailbox_); @@ -122,7 +132,7 @@ class ContextSharedData { // ProduceTexture. if (sync_point_for_mailbox_[mailbox] > sync_point) { NOTREACHED(); - return scoped_refptr<Texture>(); + return scoped_refptr<TestTexture>(); } return textures_[mailbox]; } @@ -132,7 +142,7 @@ class ContextSharedData { unsigned next_sync_point_; unsigned next_mailbox_; - typedef base::hash_map<unsigned, scoped_refptr<Texture> > TextureMap; + typedef base::hash_map<unsigned, scoped_refptr<TestTexture> > TextureMap; TextureMap textures_; base::hash_map<unsigned, unsigned> sync_point_for_mailbox_; }; @@ -141,8 +151,7 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { public: static scoped_ptr<ResourceProviderContext> Create( ContextSharedData* shared_data) { - return make_scoped_ptr( - new ResourceProviderContext(Attributes(), shared_data)); + return make_scoped_ptr(new ResourceProviderContext(shared_data)); } virtual unsigned insertSyncPoint() OVERRIDE { @@ -164,35 +173,15 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { last_waited_sync_point_ = std::max(sync_point, last_waited_sync_point_); } - virtual void bindTexture(WGC3Denum target, WebGLId texture) OVERRIDE { - ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); - ASSERT_TRUE(!texture || textures_.find(texture) != textures_.end()); - current_texture_ = texture; - } - - virtual WebGLId createTexture() OVERRIDE { - WebGLId id = TestWebGraphicsContext3D::createTexture(); - textures_[id] = new Texture; - return id; - } - - virtual void deleteTexture(WebGLId id) OVERRIDE { - TextureMap::iterator it = textures_.find(id); - ASSERT_FALSE(it == textures_.end()); - textures_.erase(it); - if (current_texture_ == id) - current_texture_ = 0; - } - - virtual void texStorage2DEXT(WGC3Denum target, - WGC3Dint levels, - WGC3Duint internalformat, - WGC3Dint width, - WGC3Dint height) OVERRIDE { - ASSERT_TRUE(current_texture_); + virtual void texStorage2DEXT(GLenum target, + GLint levels, + GLuint internalformat, + GLint width, + GLint height) OVERRIDE { + CheckTextureIsBound(target); ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); ASSERT_EQ(1, levels); - WGC3Denum format = GL_RGBA; + GLenum format = GL_RGBA; switch (internalformat) { case GL_RGBA8_OES: break; @@ -205,16 +194,16 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { AllocateTexture(gfx::Size(width, height), format); } - virtual void texImage2D(WGC3Denum target, - WGC3Dint level, - WGC3Denum internalformat, - WGC3Dsizei width, - WGC3Dsizei height, - WGC3Dint border, - WGC3Denum format, - WGC3Denum type, + virtual void texImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, const void* pixels) OVERRIDE { - ASSERT_TRUE(current_texture_); + CheckTextureIsBound(target); ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); ASSERT_FALSE(level); ASSERT_EQ(internalformat, format); @@ -225,95 +214,71 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { SetPixels(0, 0, width, height, pixels); } - virtual void texSubImage2D(WGC3Denum target, - WGC3Dint level, - WGC3Dint xoffset, - WGC3Dint yoffset, - WGC3Dsizei width, - WGC3Dsizei height, - WGC3Denum format, - WGC3Denum type, + virtual void texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, const void* pixels) OVERRIDE { - ASSERT_TRUE(current_texture_); + CheckTextureIsBound(target); ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); ASSERT_FALSE(level); - ASSERT_TRUE(textures_[current_texture_].get()); - ASSERT_EQ( - ResourceProvider::GetGLDataFormat(textures_[current_texture_]->format), - format); ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); + { + base::AutoLock lock_for_texture_access(namespace_->lock); + ASSERT_EQ(GLDataFormat(BoundTexture(target)->format), format); + } ASSERT_TRUE(pixels); SetPixels(xoffset, yoffset, width, height, pixels); } - virtual void texParameteri(WGC3Denum target, WGC3Denum param, WGC3Dint value) - OVERRIDE { - ASSERT_TRUE(current_texture_); - ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); - scoped_refptr<Texture> texture = textures_[current_texture_]; - ASSERT_TRUE(texture.get()); - if (param != GL_TEXTURE_MIN_FILTER) - return; - texture->filter = value; - } - - virtual void genMailboxCHROMIUM(WGC3Dbyte* mailbox) OVERRIDE { + virtual void genMailboxCHROMIUM(GLbyte* mailbox) OVERRIDE { return shared_data_->GenMailbox(mailbox); } - virtual void produceTextureCHROMIUM(WGC3Denum target, - const WGC3Dbyte* mailbox) OVERRIDE { - ASSERT_TRUE(current_texture_); - ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); + virtual void produceTextureCHROMIUM(GLenum target, + const GLbyte* mailbox) OVERRIDE { + CheckTextureIsBound(target); // Delay moving the texture into the mailbox until the next // InsertSyncPoint, so that it is not visible to other contexts that // haven't waited on that sync point. scoped_ptr<PendingProduceTexture> pending(new PendingProduceTexture); memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox)); - pending->texture = textures_[current_texture_]; + base::AutoLock lock_for_texture_access(namespace_->lock); + pending->texture = BoundTexture(target); pending_produce_textures_.push_back(pending.Pass()); } - virtual void consumeTextureCHROMIUM(WGC3Denum target, - const WGC3Dbyte* mailbox) OVERRIDE { - ASSERT_TRUE(current_texture_); - ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); - textures_[current_texture_] = shared_data_->ConsumeTexture( - mailbox, last_waited_sync_point_); + virtual void consumeTextureCHROMIUM(GLenum target, + const GLbyte* mailbox) OVERRIDE { + CheckTextureIsBound(target); + base::AutoLock lock_for_texture_access(namespace_->lock); + scoped_refptr<TestTexture> texture = + shared_data_->ConsumeTexture(mailbox, last_waited_sync_point_); + namespace_->textures.Replace(BoundTextureId(target), texture); } void GetPixels(gfx::Size size, ResourceFormat format, uint8_t* pixels) { - ASSERT_TRUE(current_texture_); - scoped_refptr<Texture> texture = textures_[current_texture_]; - ASSERT_TRUE(texture.get()); + CheckTextureIsBound(GL_TEXTURE_2D); + base::AutoLock lock_for_texture_access(namespace_->lock); + scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D); ASSERT_EQ(texture->size, size); ASSERT_EQ(texture->format, format); - memcpy(pixels, texture->data.get(), TextureSize(size, format)); + memcpy(pixels, texture->data.get(), TextureSizeBytes(size, format)); } - WGC3Denum GetTextureFilter() { - DCHECK(current_texture_); - scoped_refptr<Texture> texture = textures_[current_texture_]; - DCHECK(texture.get()); - return texture->filter; - } - - int texture_count() { return textures_.size(); } - protected: - ResourceProviderContext(const Attributes& attrs, - ContextSharedData* shared_data) - : TestWebGraphicsContext3D(attrs), - shared_data_(shared_data), - current_texture_(0), + explicit ResourceProviderContext(ContextSharedData* shared_data) + : shared_data_(shared_data), last_waited_sync_point_(0) {} private: - void AllocateTexture(gfx::Size size, WGC3Denum format) { - ASSERT_TRUE(current_texture_); - scoped_refptr<Texture> texture = textures_[current_texture_]; - ASSERT_TRUE(texture.get()); + void AllocateTexture(gfx::Size size, GLenum format) { + CheckTextureIsBound(GL_TEXTURE_2D); ResourceFormat texture_format = RGBA_8888; switch (format) { case GL_RGBA: @@ -323,7 +288,8 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { texture_format = BGRA_8888; break; } - texture->Reallocate(size, texture_format); + base::AutoLock lock_for_texture_access(namespace_->lock); + BoundTexture(GL_TEXTURE_2D)->Reallocate(size, texture_format); } void SetPixels(int xoffset, @@ -331,18 +297,18 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { int width, int height, const void* pixels) { - ASSERT_TRUE(current_texture_); - scoped_refptr<Texture> texture = textures_[current_texture_]; - ASSERT_TRUE(texture.get()); + CheckTextureIsBound(GL_TEXTURE_2D); + base::AutoLock lock_for_texture_access(namespace_->lock); + scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D); ASSERT_TRUE(texture->data.get()); ASSERT_TRUE(xoffset >= 0 && xoffset + width <= texture->size.width()); ASSERT_TRUE(yoffset >= 0 && yoffset + height <= texture->size.height()); ASSERT_TRUE(pixels); - size_t in_pitch = TextureSize(gfx::Size(width, 1), texture->format); + size_t in_pitch = TextureSizeBytes(gfx::Size(width, 1), texture->format); size_t out_pitch = - TextureSize(gfx::Size(texture->size.width(), 1), texture->format); + TextureSizeBytes(gfx::Size(texture->size.width(), 1), texture->format); uint8_t* dest = texture->data.get() + yoffset * out_pitch + - TextureSize(gfx::Size(xoffset, 1), texture->format); + TextureSizeBytes(gfx::Size(xoffset, 1), texture->format); const uint8_t* src = static_cast<const uint8_t*>(pixels); for (int i = 0; i < height; ++i) { memcpy(dest, src, in_pitch); @@ -351,19 +317,65 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { } } - typedef base::hash_map<WebGLId, scoped_refptr<Texture> > TextureMap; struct PendingProduceTexture { - WGC3Dbyte mailbox[64]; - scoped_refptr<Texture> texture; + GLbyte mailbox[64]; + scoped_refptr<TestTexture> texture; }; typedef ScopedPtrDeque<PendingProduceTexture> PendingProduceTextureList; ContextSharedData* shared_data_; - WebGLId current_texture_; - TextureMap textures_; unsigned last_waited_sync_point_; PendingProduceTextureList pending_produce_textures_; }; +void FreeSharedBitmap(SharedBitmap* shared_bitmap) { + delete shared_bitmap->memory(); +} + +void IgnoreSharedBitmap(SharedBitmap* shared_bitmap) {} + +class TestSharedBitmapManager : public SharedBitmapManager { + public: + TestSharedBitmapManager() : count_(0) {} + virtual ~TestSharedBitmapManager() {} + + virtual scoped_ptr<SharedBitmap> AllocateSharedBitmap(gfx::Size size) + OVERRIDE { + scoped_ptr<base::SharedMemory> memory(new base::SharedMemory); + memory->CreateAndMapAnonymous(size.GetArea() * 4); + int8 name[64] = { 0 }; + name[0] = count_++; + SharedBitmapId id; + id.SetName(name); + bitmap_map_[id] = memory.get(); + return scoped_ptr<SharedBitmap>( + new SharedBitmap(memory.release(), id, base::Bind(&FreeSharedBitmap))); + } + + virtual scoped_ptr<SharedBitmap> GetSharedBitmapFromId( + gfx::Size, + const SharedBitmapId& id) OVERRIDE { + if (bitmap_map_.find(id) == bitmap_map_.end()) + return scoped_ptr<SharedBitmap>(); + return scoped_ptr<SharedBitmap>( + new SharedBitmap(bitmap_map_[id], id, base::Bind(&IgnoreSharedBitmap))); + } + + virtual scoped_ptr<SharedBitmap> GetBitmapForSharedMemory( + base::SharedMemory* memory) OVERRIDE { + int8 name[64] = { 0 }; + name[0] = count_++; + SharedBitmapId id; + id.SetName(name); + bitmap_map_[id] = memory; + return scoped_ptr<SharedBitmap>( + new SharedBitmap(memory, id, base::Bind(&IgnoreSharedBitmap))); + } + + private: + int count_; + std::map<SharedBitmapId, base::SharedMemory*> bitmap_map_; +}; + void GetResourcePixels(ResourceProvider* resource_provider, ResourceProviderContext* context, ResourceProvider::ResourceId id, @@ -397,7 +409,8 @@ class ResourceProviderTest public: ResourceProviderTest() : shared_data_(ContextSharedData::Create()), - context3d_(NULL) { + context3d_(NULL), + child_context_(NULL) { switch (GetParam()) { case ResourceProvider::GLTexture: { scoped_ptr<ResourceProviderContext> context3d( @@ -409,19 +422,37 @@ class ResourceProviderTest context3d.PassAs<TestWebGraphicsContext3D>()); output_surface_ = FakeOutputSurface::Create3d(context_provider); + + scoped_ptr<ResourceProviderContext> child_context_owned = + ResourceProviderContext::Create(shared_data_.get()); + child_context_ = child_context_owned.get(); + child_output_surface_ = FakeOutputSurface::Create3d( + child_context_owned.PassAs<TestWebGraphicsContext3D>()); break; } case ResourceProvider::Bitmap: output_surface_ = FakeOutputSurface::CreateSoftware( make_scoped_ptr(new SoftwareOutputDevice)); + child_output_surface_ = FakeOutputSurface::CreateSoftware( + make_scoped_ptr(new SoftwareOutputDevice)); break; case ResourceProvider::InvalidType: NOTREACHED(); break; } CHECK(output_surface_->BindToClient(&output_surface_client_)); + CHECK(child_output_surface_->BindToClient(&child_output_surface_client_)); + + shared_bitmap_manager_.reset(new TestSharedBitmapManager()); + resource_provider_ = ResourceProvider::Create( - output_surface_.get(), 0, false); + output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1); + child_resource_provider_ = ResourceProvider::Create( + child_output_surface_.get(), + shared_bitmap_manager_.get(), + 0, + false, + 1); } static void CollectResources(ReturnedResourceArray* array, @@ -435,19 +466,63 @@ class ResourceProviderTest static void SetResourceFilter(ResourceProvider* resource_provider, ResourceProvider::ResourceId id, - WGC3Denum filter) { + GLenum filter) { ResourceProvider::ScopedSamplerGL sampler( resource_provider, id, GL_TEXTURE_2D, filter); } ResourceProviderContext* context() { return context3d_; } + ResourceProvider::ResourceId CreateChildMailbox(unsigned* release_sync_point, + bool* lost_resource, + bool* release_called, + unsigned* sync_point) { + if (GetParam() == ResourceProvider::GLTexture) { + unsigned texture = child_context_->createTexture(); + gpu::Mailbox gpu_mailbox; + child_context_->bindTexture(GL_TEXTURE_2D, texture); + child_context_->genMailboxCHROMIUM(gpu_mailbox.name); + child_context_->produceTextureCHROMIUM(GL_TEXTURE_2D, gpu_mailbox.name); + *sync_point = child_context_->insertSyncPoint(); + EXPECT_LT(0u, *sync_point); + + scoped_ptr<base::SharedMemory> shared_memory; + scoped_ptr<SingleReleaseCallback> callback = + SingleReleaseCallback::Create(base::Bind(ReleaseSharedMemoryCallback, + base::Passed(&shared_memory), + release_called, + release_sync_point, + lost_resource)); + return child_resource_provider_->CreateResourceFromTextureMailbox( + TextureMailbox(gpu_mailbox, *sync_point), callback.Pass()); + } else { + gfx::Size size(64, 64); + scoped_ptr<base::SharedMemory> shared_memory( + CreateAndFillSharedMemory(size, 0)); + + base::SharedMemory* shared_memory_ptr = shared_memory.get(); + scoped_ptr<SingleReleaseCallback> callback = + SingleReleaseCallback::Create(base::Bind(ReleaseSharedMemoryCallback, + base::Passed(&shared_memory), + release_called, + release_sync_point, + lost_resource)); + return child_resource_provider_->CreateResourceFromTextureMailbox( + TextureMailbox(shared_memory_ptr, size), callback.Pass()); + } + } + protected: scoped_ptr<ContextSharedData> shared_data_; ResourceProviderContext* context3d_; + ResourceProviderContext* child_context_; FakeOutputSurfaceClient output_surface_client_; + FakeOutputSurfaceClient child_output_surface_client_; scoped_ptr<OutputSurface> output_surface_; + scoped_ptr<OutputSurface> child_output_surface_; scoped_ptr<ResourceProvider> resource_provider_; + scoped_ptr<ResourceProvider> child_resource_provider_; + scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_; }; void CheckCreateResource(ResourceProvider::ResourceType expected_default_type, @@ -457,20 +532,20 @@ void CheckCreateResource(ResourceProvider::ResourceType expected_default_type, gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; - size_t pixel_size = TextureSize(size, format); + size_t pixel_size = TextureSizeBytes(size, format); ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); EXPECT_EQ(1, static_cast<int>(resource_provider->num_resources())); if (expected_default_type == ResourceProvider::GLTexture) - EXPECT_EQ(0, context->texture_count()); + EXPECT_EQ(0u, context->NumTextures()); uint8_t data[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d()); if (expected_default_type == ResourceProvider::GLTexture) - EXPECT_EQ(1, context->texture_count()); + EXPECT_EQ(1u, context->NumTextures()); uint8_t result[4] = { 0 }; GetResourcePixels(resource_provider, context, id, size, format, result); @@ -479,7 +554,7 @@ void CheckCreateResource(ResourceProvider::ResourceType expected_default_type, resource_provider->DeleteResource(id); EXPECT_EQ(0, static_cast<int>(resource_provider->num_resources())); if (expected_default_type == ResourceProvider::GLTexture) - EXPECT_EQ(0, context->texture_count()); + EXPECT_EQ(0u, context->NumTextures()); } TEST_P(ResourceProviderTest, Basic) { @@ -489,7 +564,7 @@ TEST_P(ResourceProviderTest, Basic) { TEST_P(ResourceProviderTest, Upload) { gfx::Size size(2, 2); ResourceFormat format = RGBA_8888; - size_t pixel_size = TextureSize(size, format); + size_t pixel_size = TextureSizeBytes(size, format); ASSERT_EQ(16U, pixel_size); ResourceProvider::ResourceId id = resource_provider_->CreateResource( @@ -553,39 +628,38 @@ TEST_P(ResourceProviderTest, Upload) { resource_provider_->DeleteResource(id); } -TEST_P(ResourceProviderTest, TransferResources) { - // Resource transfer is only supported with GL textures for now. +TEST_P(ResourceProviderTest, TransferGLResources) { if (GetParam() != ResourceProvider::GLTexture) return; - - scoped_ptr<ResourceProviderContext> child_context_owned( - ResourceProviderContext::Create(shared_data_.get())); - ResourceProviderContext* child_context = child_context_owned.get(); - - FakeOutputSurfaceClient child_output_surface_client; - scoped_ptr<OutputSurface> child_output_surface( - FakeOutputSurface::Create3d( - child_context_owned.PassAs<TestWebGraphicsContext3D>())); - CHECK(child_output_surface->BindToClient(&child_output_surface_client)); - - scoped_ptr<ResourceProvider> child_resource_provider( - ResourceProvider::Create(child_output_surface.get(), 0, false)); - gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; - size_t pixel_size = TextureSize(size, format); + size_t pixel_size = TextureSizeBytes(size, format); ASSERT_EQ(4U, pixel_size); - ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource( + ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); uint8_t data1[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); - child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); + child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); - ResourceProvider::ResourceId id2 = child_resource_provider->CreateResource( + ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); uint8_t data2[4] = { 5, 5, 5, 5 }; - child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); + child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); + + GLuint external_texture_id = child_context_->createExternalTexture(); + child_context_->bindTexture(GL_TEXTURE_EXTERNAL_OES, external_texture_id); + + gpu::Mailbox external_mailbox; + child_context_->genMailboxCHROMIUM(external_mailbox.name); + child_context_->produceTextureCHROMIUM(GL_TEXTURE_EXTERNAL_OES, + external_mailbox.name); + const unsigned external_sync_point = child_context_->insertSyncPoint(); + ResourceProvider::ResourceId id3 = + child_resource_provider_->CreateResourceFromTextureMailbox( + TextureMailbox( + external_mailbox, GL_TEXTURE_EXTERNAL_OES, external_sync_point), + SingleReleaseCallback::Create(base::Bind(&EmptyReleaseCallback))); ReturnedResourceArray returned_to_child; int child_id = @@ -595,28 +669,37 @@ TEST_P(ResourceProviderTest, TransferResources) { ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(id1); resource_ids_to_transfer.push_back(id2); + resource_ids_to_transfer.push_back(id3); TransferableResourceArray list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, - &list); - ASSERT_EQ(2u, list.size()); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); + ASSERT_EQ(3u, list.size()); EXPECT_NE(0u, list[0].sync_point); EXPECT_NE(0u, list[1].sync_point); - EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); - EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2)); + EXPECT_EQ(external_sync_point, list[2].sync_point); + EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target); + EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[1].target); + EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), list[2].target); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3)); resource_provider_->ReceiveFromChild(child_id, list); resource_provider_->DeclareUsedResourcesFromChild(child_id, resource_ids_to_transfer); } - EXPECT_EQ(2u, resource_provider_->num_resources()); + EXPECT_EQ(3u, resource_provider_->num_resources()); ResourceProvider::ResourceIdMap resource_map = resource_provider_->GetChildToParentMap(child_id); ResourceProvider::ResourceId mapped_id1 = resource_map[id1]; ResourceProvider::ResourceId mapped_id2 = resource_map[id2]; + ResourceProvider::ResourceId mapped_id3 = resource_map[id3]; EXPECT_NE(0u, mapped_id1); EXPECT_NE(0u, mapped_id2); + EXPECT_NE(0u, mapped_id3); EXPECT_FALSE(resource_provider_->InUseByConsumer(id1)); EXPECT_FALSE(resource_provider_->InUseByConsumer(id2)); + EXPECT_FALSE(resource_provider_->InUseByConsumer(id3)); uint8_t result[4] = { 0 }; GetResourcePixels( @@ -626,22 +709,24 @@ TEST_P(ResourceProviderTest, TransferResources) { GetResourcePixels( resource_provider_.get(), context(), mapped_id2, size, format, result); EXPECT_EQ(0, memcmp(data2, result, pixel_size)); + { // Check that transfering again the same resource from the child to the // parent works. ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(id1); TransferableResourceArray list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, - &list); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); EXPECT_EQ(1u, list.size()); EXPECT_EQ(id1, list[0].id); + EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target); ReturnedResourceArray returned; TransferableResource::ReturnResources(list, &returned); - child_resource_provider->ReceiveReturnsFromParent(returned); + child_resource_provider_->ReceiveReturnsFromParent(returned); // id1 was exported twice, we returned it only once, it should still be // in-use. - EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); } { EXPECT_EQ(0u, returned_to_child.size()); @@ -651,29 +736,34 @@ TEST_P(ResourceProviderTest, TransferResources) { ResourceProvider::ResourceIdArray no_resources; resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); - ASSERT_EQ(2u, returned_to_child.size()); + ASSERT_EQ(3u, returned_to_child.size()); EXPECT_NE(0u, returned_to_child[0].sync_point); EXPECT_NE(0u, returned_to_child[1].sync_point); + EXPECT_NE(0u, returned_to_child[2].sync_point); EXPECT_FALSE(returned_to_child[0].lost); EXPECT_FALSE(returned_to_child[1].lost); - child_resource_provider->ReceiveReturnsFromParent(returned_to_child); + EXPECT_FALSE(returned_to_child[2].lost); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); returned_to_child.clear(); } - EXPECT_FALSE(child_resource_provider->InUseByConsumer(id1)); - EXPECT_FALSE(child_resource_provider->InUseByConsumer(id2)); + EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id2)); + EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id3)); { - ResourceProvider::ScopedReadLockGL lock(child_resource_provider.get(), id1); + ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(), + id1); ASSERT_NE(0U, lock.texture_id()); - child_context->bindTexture(GL_TEXTURE_2D, lock.texture_id()); - child_context->GetPixels(size, format, result); + child_context_->bindTexture(GL_TEXTURE_2D, lock.texture_id()); + child_context_->GetPixels(size, format, result); EXPECT_EQ(0, memcmp(data1, result, pixel_size)); } { - ResourceProvider::ScopedReadLockGL lock(child_resource_provider.get(), id2); + ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(), + id2); ASSERT_NE(0U, lock.texture_id()); - child_context->bindTexture(GL_TEXTURE_2D, lock.texture_id()); - child_context->GetPixels(size, format, result); + child_context_->bindTexture(GL_TEXTURE_2D, lock.texture_id()); + child_context_->GetPixels(size, format, result); EXPECT_EQ(0, memcmp(data2, result, pixel_size)); } { @@ -681,14 +771,23 @@ TEST_P(ResourceProviderTest, TransferResources) { ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(id1); resource_ids_to_transfer.push_back(id2); + resource_ids_to_transfer.push_back(id3); TransferableResourceArray list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, - &list); - ASSERT_EQ(2u, list.size()); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); + ASSERT_EQ(3u, list.size()); + EXPECT_EQ(id1, list[0].id); + EXPECT_EQ(id2, list[1].id); + EXPECT_EQ(id3, list[2].id); EXPECT_NE(0u, list[0].sync_point); EXPECT_NE(0u, list[1].sync_point); - EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); - EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2)); + EXPECT_NE(0u, list[2].sync_point); + EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target); + EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[1].target); + EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), list[2].target); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3)); resource_provider_->ReceiveFromChild(child_id, list); resource_provider_->DeclareUsedResourcesFromChild(child_id, resource_ids_to_transfer); @@ -696,20 +795,251 @@ TEST_P(ResourceProviderTest, TransferResources) { EXPECT_EQ(0u, returned_to_child.size()); - EXPECT_EQ(2u, resource_provider_->num_resources()); + EXPECT_EQ(3u, resource_provider_->num_resources()); resource_provider_->DestroyChild(child_id); EXPECT_EQ(0u, resource_provider_->num_resources()); - ASSERT_EQ(2u, returned_to_child.size()); + ASSERT_EQ(3u, returned_to_child.size()); EXPECT_NE(0u, returned_to_child[0].sync_point); EXPECT_NE(0u, returned_to_child[1].sync_point); + EXPECT_NE(0u, returned_to_child[2].sync_point); EXPECT_FALSE(returned_to_child[0].lost); EXPECT_FALSE(returned_to_child[1].lost); + EXPECT_FALSE(returned_to_child[2].lost); } -TEST_P(ResourceProviderTest, DeleteExportedResources) { - // Resource transfer is only supported with GL textures for now. - if (GetParam() != ResourceProvider::GLTexture) +TEST_P(ResourceProviderTest, TransferSoftwareResources) { + if (GetParam() != ResourceProvider::Bitmap) + return; + + gfx::Size size(1, 1); + ResourceFormat format = RGBA_8888; + size_t pixel_size = TextureSizeBytes(size, format); + ASSERT_EQ(4U, pixel_size); + + ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + uint8_t data1[4] = { 1, 2, 3, 4 }; + gfx::Rect rect(size); + child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); + + ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + uint8_t data2[4] = { 5, 5, 5, 5 }; + child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); + + scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); + shared_memory->CreateAndMapAnonymous(1); + base::SharedMemory* shared_memory_ptr = shared_memory.get(); + ResourceProvider::ResourceId id3 = + child_resource_provider_->CreateResourceFromTextureMailbox( + TextureMailbox(shared_memory_ptr, gfx::Size(1, 1)), + SingleReleaseCallback::Create(base::Bind( + &SharedMemoryReleaseCallback, base::Passed(&shared_memory)))); + + ReturnedResourceArray returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + { + // Transfer some resources to the parent. + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(id1); + resource_ids_to_transfer.push_back(id2); + resource_ids_to_transfer.push_back(id3); + TransferableResourceArray list; + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); + ASSERT_EQ(3u, list.size()); + EXPECT_EQ(0u, list[0].sync_point); + EXPECT_EQ(0u, list[1].sync_point); + EXPECT_EQ(0u, list[2].sync_point); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3)); + resource_provider_->ReceiveFromChild(child_id, list); + resource_provider_->DeclareUsedResourcesFromChild(child_id, + resource_ids_to_transfer); + } + + EXPECT_EQ(3u, resource_provider_->num_resources()); + ResourceProvider::ResourceIdMap resource_map = + resource_provider_->GetChildToParentMap(child_id); + ResourceProvider::ResourceId mapped_id1 = resource_map[id1]; + ResourceProvider::ResourceId mapped_id2 = resource_map[id2]; + ResourceProvider::ResourceId mapped_id3 = resource_map[id3]; + EXPECT_NE(0u, mapped_id1); + EXPECT_NE(0u, mapped_id2); + EXPECT_NE(0u, mapped_id3); + EXPECT_FALSE(resource_provider_->InUseByConsumer(id1)); + EXPECT_FALSE(resource_provider_->InUseByConsumer(id2)); + EXPECT_FALSE(resource_provider_->InUseByConsumer(id3)); + + uint8_t result[4] = { 0 }; + GetResourcePixels( + resource_provider_.get(), context(), mapped_id1, size, format, result); + EXPECT_EQ(0, memcmp(data1, result, pixel_size)); + + GetResourcePixels( + resource_provider_.get(), context(), mapped_id2, size, format, result); + EXPECT_EQ(0, memcmp(data2, result, pixel_size)); + + { + // Check that transfering again the same resource from the child to the + // parent works. + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(id1); + TransferableResourceArray list; + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); + EXPECT_EQ(1u, list.size()); + EXPECT_EQ(id1, list[0].id); + ReturnedResourceArray returned; + TransferableResource::ReturnResources(list, &returned); + child_resource_provider_->ReceiveReturnsFromParent(returned); + // id1 was exported twice, we returned it only once, it should still be + // in-use. + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + } + { + EXPECT_EQ(0u, returned_to_child.size()); + + // Transfer resources back from the parent to the child. Set no resources as + // being in use. + ResourceProvider::ResourceIdArray no_resources; + resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); + + ASSERT_EQ(3u, returned_to_child.size()); + EXPECT_EQ(0u, returned_to_child[0].sync_point); + EXPECT_EQ(0u, returned_to_child[1].sync_point); + EXPECT_EQ(0u, returned_to_child[2].sync_point); + EXPECT_EQ(id1, returned_to_child[0].id); + EXPECT_EQ(id2, returned_to_child[1].id); + EXPECT_EQ(id3, returned_to_child[2].id); + EXPECT_FALSE(returned_to_child[0].lost); + EXPECT_FALSE(returned_to_child[1].lost); + EXPECT_FALSE(returned_to_child[2].lost); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + returned_to_child.clear(); + } + EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id2)); + EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id3)); + + { + ResourceProvider::ScopedReadLockSoftware lock( + child_resource_provider_.get(), id1); + const SkBitmap* sk_bitmap = lock.sk_bitmap(); + EXPECT_EQ(sk_bitmap->width(), size.width()); + EXPECT_EQ(sk_bitmap->height(), size.height()); + EXPECT_EQ(0, memcmp(data1, sk_bitmap->getPixels(), pixel_size)); + } + { + ResourceProvider::ScopedReadLockSoftware lock( + child_resource_provider_.get(), id2); + const SkBitmap* sk_bitmap = lock.sk_bitmap(); + EXPECT_EQ(sk_bitmap->width(), size.width()); + EXPECT_EQ(sk_bitmap->height(), size.height()); + EXPECT_EQ(0, memcmp(data2, sk_bitmap->getPixels(), pixel_size)); + } + { + // Transfer resources to the parent again. + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(id1); + resource_ids_to_transfer.push_back(id2); + resource_ids_to_transfer.push_back(id3); + TransferableResourceArray list; + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); + ASSERT_EQ(3u, list.size()); + EXPECT_EQ(id1, list[0].id); + EXPECT_EQ(id2, list[1].id); + EXPECT_EQ(id3, list[2].id); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3)); + resource_provider_->ReceiveFromChild(child_id, list); + resource_provider_->DeclareUsedResourcesFromChild(child_id, + resource_ids_to_transfer); + } + + EXPECT_EQ(0u, returned_to_child.size()); + + EXPECT_EQ(3u, resource_provider_->num_resources()); + resource_provider_->DestroyChild(child_id); + EXPECT_EQ(0u, resource_provider_->num_resources()); + + ASSERT_EQ(3u, returned_to_child.size()); + EXPECT_EQ(0u, returned_to_child[0].sync_point); + EXPECT_EQ(0u, returned_to_child[1].sync_point); + EXPECT_EQ(0u, returned_to_child[2].sync_point); + EXPECT_EQ(id1, returned_to_child[0].id); + EXPECT_EQ(id2, returned_to_child[1].id); + EXPECT_EQ(id3, returned_to_child[2].id); + EXPECT_FALSE(returned_to_child[0].lost); + EXPECT_FALSE(returned_to_child[1].lost); + EXPECT_FALSE(returned_to_child[2].lost); +} + +TEST_P(ResourceProviderTest, TransferSoftwareToNonUber) { + // TODO(jbauman): Remove test when shared bitmap manager available + // everywhere. + if (GetParam() != ResourceProvider::Bitmap) + return; + + scoped_ptr<FakeOutputSurface> parent_output_surface = + FakeOutputSurface::CreateSoftware( + make_scoped_ptr(new SoftwareOutputDevice)); + FakeOutputSurfaceClient parent_output_surface_client; + CHECK(parent_output_surface->BindToClient(&parent_output_surface_client)); + + scoped_ptr<ResourceProvider> parent_resource_provider( + ResourceProvider::Create(parent_output_surface.get(), + NULL, + 0, + false, + 1)); + + gfx::Size size(1, 1); + ResourceFormat format = RGBA_8888; + size_t pixel_size = TextureSizeBytes(size, format); + ASSERT_EQ(4U, pixel_size); + + ResourceProvider::ResourceId id1 = resource_provider_->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + uint8_t data1[4] = { 1, 2, 3, 4 }; + gfx::Rect rect(size); + resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); + + ReturnedResourceArray returned_to_child; + int child_id = parent_resource_provider->CreateChild( + GetReturnCallback(&returned_to_child)); + { + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(id1); + TransferableResourceArray list; + resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); + ASSERT_EQ(1u, list.size()); + EXPECT_TRUE(resource_provider_->InUseByConsumer(id1)); + parent_resource_provider->ReceiveFromChild(child_id, list); + } + + EXPECT_EQ(0u, parent_resource_provider->num_resources()); + ASSERT_EQ(1u, returned_to_child.size()); + EXPECT_EQ(returned_to_child[0].id, id1); + ResourceProvider::ResourceIdMap resource_map = + parent_resource_provider->GetChildToParentMap(child_id); + ResourceProvider::ResourceId mapped_id1 = resource_map[id1]; + EXPECT_EQ(0u, mapped_id1); + + parent_resource_provider->DestroyChild(child_id); + EXPECT_EQ(0u, parent_resource_provider->num_resources()); + + ASSERT_EQ(1u, returned_to_child.size()); + EXPECT_FALSE(returned_to_child[0].lost); +} + +TEST_P(ResourceProviderTest, TransferGLToSoftware) { + if (GetParam() != ResourceProvider::Bitmap) return; scoped_ptr<ResourceProviderContext> child_context_owned( @@ -721,23 +1051,116 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) { CHECK(child_output_surface->BindToClient(&child_output_surface_client)); scoped_ptr<ResourceProvider> child_resource_provider( - ResourceProvider::Create(child_output_surface.get(), 0, false)); + ResourceProvider::Create(child_output_surface.get(), + NULL, + 0, + false, + 1)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; - size_t pixel_size = TextureSize(size, format); + size_t pixel_size = TextureSizeBytes(size, format); ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - uint8_t data1[4] = {1, 2, 3, 4}; + uint8_t data1[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); - ResourceProvider::ResourceId id2 = child_resource_provider->CreateResource( + ReturnedResourceArray returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + { + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(id1); + TransferableResourceArray list; + child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, + &list); + ASSERT_EQ(1u, list.size()); + EXPECT_NE(0u, list[0].sync_point); + EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target); + EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); + resource_provider_->ReceiveFromChild(child_id, list); + } + + EXPECT_EQ(0u, resource_provider_->num_resources()); + ASSERT_EQ(1u, returned_to_child.size()); + EXPECT_EQ(returned_to_child[0].id, id1); + ResourceProvider::ResourceIdMap resource_map = + resource_provider_->GetChildToParentMap(child_id); + ResourceProvider::ResourceId mapped_id1 = resource_map[id1]; + EXPECT_EQ(0u, mapped_id1); + + resource_provider_->DestroyChild(child_id); + EXPECT_EQ(0u, resource_provider_->num_resources()); + + ASSERT_EQ(1u, returned_to_child.size()); + EXPECT_FALSE(returned_to_child[0].lost); +} + +TEST_P(ResourceProviderTest, TransferInvalidSoftware) { + if (GetParam() != ResourceProvider::Bitmap) + return; + + gfx::Size size(1, 1); + ResourceFormat format = RGBA_8888; + size_t pixel_size = TextureSizeBytes(size, format); + ASSERT_EQ(4U, pixel_size); + + ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + uint8_t data1[4] = { 1, 2, 3, 4 }; + gfx::Rect rect(size); + child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); + + ReturnedResourceArray returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + { + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(id1); + TransferableResourceArray list; + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); + ASSERT_EQ(1u, list.size()); + // Make invalid. + list[0].mailbox.name[1] = 5; + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + resource_provider_->ReceiveFromChild(child_id, list); + } + + EXPECT_EQ(0u, resource_provider_->num_resources()); + ASSERT_EQ(1u, returned_to_child.size()); + EXPECT_EQ(returned_to_child[0].id, id1); + ResourceProvider::ResourceIdMap resource_map = + resource_provider_->GetChildToParentMap(child_id); + ResourceProvider::ResourceId mapped_id1 = resource_map[id1]; + EXPECT_EQ(0u, mapped_id1); + + resource_provider_->DestroyChild(child_id); + EXPECT_EQ(0u, resource_provider_->num_resources()); + + ASSERT_EQ(1u, returned_to_child.size()); + EXPECT_FALSE(returned_to_child[0].lost); +} + +TEST_P(ResourceProviderTest, DeleteExportedResources) { + gfx::Size size(1, 1); + ResourceFormat format = RGBA_8888; + size_t pixel_size = TextureSizeBytes(size, format); + ASSERT_EQ(4U, pixel_size); + + ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + uint8_t data1[4] = { 1, 2, 3, 4 }; + gfx::Rect rect(size); + child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); + + ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); uint8_t data2[4] = {5, 5, 5, 5}; - child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); + child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); ReturnedResourceArray returned_to_child; int child_id = @@ -748,13 +1171,15 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) { resource_ids_to_transfer.push_back(id1); resource_ids_to_transfer.push_back(id2); TransferableResourceArray list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, - &list); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); ASSERT_EQ(2u, list.size()); - EXPECT_NE(0u, list[0].sync_point); - EXPECT_NE(0u, list[1].sync_point); - EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); - EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2)); + if (GetParam() == ResourceProvider::GLTexture) { + EXPECT_NE(0u, list[0].sync_point); + EXPECT_NE(0u, list[1].sync_point); + } + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); resource_provider_->ReceiveFromChild(child_id, list); resource_provider_->DeclareUsedResourcesFromChild(child_id, resource_ids_to_transfer); @@ -779,8 +1204,10 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) { resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); ASSERT_EQ(2u, list.size()); - EXPECT_NE(0u, list[0].sync_point); - EXPECT_NE(0u, list[1].sync_point); + if (GetParam() == ResourceProvider::GLTexture) { + EXPECT_NE(0u, list[0].sync_point); + EXPECT_NE(0u, list[1].sync_point); + } EXPECT_TRUE(resource_provider_->InUseByConsumer(id1)); EXPECT_TRUE(resource_provider_->InUseByConsumer(id2)); @@ -803,44 +1230,31 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) { EXPECT_EQ(0u, resource_provider_->num_resources()); ASSERT_EQ(2u, returned_to_child.size()); - EXPECT_NE(0u, returned_to_child[0].sync_point); - EXPECT_NE(0u, returned_to_child[1].sync_point); + if (GetParam() == ResourceProvider::GLTexture) { + EXPECT_NE(0u, returned_to_child[0].sync_point); + EXPECT_NE(0u, returned_to_child[1].sync_point); + } EXPECT_FALSE(returned_to_child[0].lost); EXPECT_FALSE(returned_to_child[1].lost); } } TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) { - // Resource transfer is only supported with GL textures for now. - if (GetParam() != ResourceProvider::GLTexture) - return; - - scoped_ptr<ResourceProviderContext> child_context_owned( - ResourceProviderContext::Create(shared_data_.get())); - - FakeOutputSurfaceClient child_output_surface_client; - scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( - child_context_owned.PassAs<TestWebGraphicsContext3D>())); - CHECK(child_output_surface->BindToClient(&child_output_surface_client)); - - scoped_ptr<ResourceProvider> child_resource_provider( - ResourceProvider::Create(child_output_surface.get(), 0, false)); - gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; - size_t pixel_size = TextureSize(size, format); + size_t pixel_size = TextureSizeBytes(size, format); ASSERT_EQ(4U, pixel_size); - ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource( + ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); uint8_t data1[4] = {1, 2, 3, 4}; gfx::Rect rect(size); - child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); + child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); - ResourceProvider::ResourceId id2 = child_resource_provider->CreateResource( + ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); uint8_t data2[4] = {5, 5, 5, 5}; - child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); + child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); ReturnedResourceArray returned_to_child; int child_id = @@ -851,13 +1265,15 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) { resource_ids_to_transfer.push_back(id1); resource_ids_to_transfer.push_back(id2); TransferableResourceArray list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, - &list); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); ASSERT_EQ(2u, list.size()); - EXPECT_NE(0u, list[0].sync_point); - EXPECT_NE(0u, list[1].sync_point); - EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); - EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2)); + if (GetParam() == ResourceProvider::GLTexture) { + EXPECT_NE(0u, list[0].sync_point); + EXPECT_NE(0u, list[1].sync_point); + } + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); resource_provider_->ReceiveFromChild(child_id, list); resource_provider_->DeclareUsedResourcesFromChild(child_id, resource_ids_to_transfer); @@ -882,8 +1298,10 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) { resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); ASSERT_EQ(2u, list.size()); - EXPECT_NE(0u, list[0].sync_point); - EXPECT_NE(0u, list[1].sync_point); + if (GetParam() == ResourceProvider::GLTexture) { + EXPECT_NE(0u, list[0].sync_point); + EXPECT_NE(0u, list[1].sync_point); + } EXPECT_TRUE(resource_provider_->InUseByConsumer(id1)); EXPECT_TRUE(resource_provider_->InUseByConsumer(id2)); @@ -892,61 +1310,57 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) { ResourceProvider::ResourceIdArray no_resources; resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); - // Destroy the child, the resources should be returned immediately from the - // parent and marked as lost. + // Destroy the child, the resources should not be returned yet. EXPECT_EQ(0u, returned_to_child.size()); EXPECT_EQ(2u, resource_provider_->num_resources()); resource_provider_->DestroyChild(child_id); - EXPECT_EQ(0u, resource_provider_->num_resources()); - ASSERT_EQ(2u, returned_to_child.size()); - EXPECT_NE(0u, returned_to_child[0].sync_point); - EXPECT_NE(0u, returned_to_child[1].sync_point); - EXPECT_TRUE(returned_to_child[0].lost); - EXPECT_TRUE(returned_to_child[1].lost); - returned_to_child.clear(); + EXPECT_EQ(2u, resource_provider_->num_resources()); + ASSERT_EQ(0u, returned_to_child.size()); - // Return the resources from the grandparent to the parent. They should be - // dropped on the floor since they were already returned to the child. + // Return a resource from the grandparent, it should be returned at this + // point. EXPECT_EQ(2u, list.size()); EXPECT_EQ(mapped_id1, list[0].id); EXPECT_EQ(mapped_id2, list[1].id); + TransferableResourceArray return_list; + return_list.push_back(list[1]); + list.pop_back(); ReturnedResourceArray returned; - TransferableResource::ReturnResources(list, &returned); + TransferableResource::ReturnResources(return_list, &returned); resource_provider_->ReceiveReturnsFromParent(returned); - EXPECT_EQ(0u, returned_to_child.size()); + EXPECT_EQ(1u, resource_provider_->num_resources()); + ASSERT_EQ(1u, returned_to_child.size()); + if (GetParam() == ResourceProvider::GLTexture) { + EXPECT_NE(0u, returned_to_child[0].sync_point); + } + EXPECT_FALSE(returned_to_child[0].lost); + returned_to_child.clear(); + + // Destroy the parent resource provider. The resource that's left should be + // lost at this point, and returned. + resource_provider_.reset(); + ASSERT_EQ(1u, returned_to_child.size()); + if (GetParam() == ResourceProvider::GLTexture) { + EXPECT_NE(0u, returned_to_child[0].sync_point); + } + EXPECT_TRUE(returned_to_child[0].lost); } } TEST_P(ResourceProviderTest, DeleteTransferredResources) { - // Resource transfer is only supported with GL textures for now. - if (GetParam() != ResourceProvider::GLTexture) - return; - - scoped_ptr<ResourceProviderContext> child_context_owned( - ResourceProviderContext::Create(shared_data_.get())); - - FakeOutputSurfaceClient child_output_surface_client; - scoped_ptr<OutputSurface> child_output_surface( - FakeOutputSurface::Create3d( - child_context_owned.PassAs<TestWebGraphicsContext3D>())); - CHECK(child_output_surface->BindToClient(&child_output_surface_client)); - - scoped_ptr<ResourceProvider> child_resource_provider( - ResourceProvider::Create(child_output_surface.get(), 0, false)); - gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; - size_t pixel_size = TextureSize(size, format); + size_t pixel_size = TextureSizeBytes(size, format); ASSERT_EQ(4U, pixel_size); - ResourceProvider::ResourceId id = child_resource_provider->CreateResource( + ResourceProvider::ResourceId id = child_resource_provider_->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); uint8_t data[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); - child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d()); + child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d()); ReturnedResourceArray returned_to_child; int child_id = @@ -956,19 +1370,20 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) { ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(id); TransferableResourceArray list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, - &list); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); ASSERT_EQ(1u, list.size()); - EXPECT_NE(0u, list[0].sync_point); - EXPECT_TRUE(child_resource_provider->InUseByConsumer(id)); + if (GetParam() == ResourceProvider::GLTexture) + EXPECT_NE(0u, list[0].sync_point); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id)); resource_provider_->ReceiveFromChild(child_id, list); resource_provider_->DeclareUsedResourcesFromChild(child_id, resource_ids_to_transfer); } // Delete textures in the child, while they are transfered. - child_resource_provider->DeleteResource(id); - EXPECT_EQ(1u, child_resource_provider->num_resources()); + child_resource_provider_->DeleteResource(id); + EXPECT_EQ(1u, child_resource_provider_->num_resources()); { EXPECT_EQ(0u, returned_to_child.size()); @@ -978,10 +1393,11 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) { resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); ASSERT_EQ(1u, returned_to_child.size()); - EXPECT_NE(0u, returned_to_child[0].sync_point); - child_resource_provider->ReceiveReturnsFromParent(returned_to_child); + if (GetParam() == ResourceProvider::GLTexture) + EXPECT_NE(0u, returned_to_child[0].sync_point); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); } - EXPECT_EQ(0u, child_resource_provider->num_resources()); + EXPECT_EQ(0u, child_resource_provider_->num_resources()); } class ResourceProviderTestTextureFilters : public ResourceProviderTest { @@ -997,7 +1413,11 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { CHECK(child_output_surface->BindToClient(&child_output_surface_client)); scoped_ptr<ResourceProvider> child_resource_provider( - ResourceProvider::Create(child_output_surface.get(), 0, false)); + ResourceProvider::Create(child_output_surface.get(), + NULL, + 0, + false, + 1)); scoped_ptr<TextureStateTrackingContext> parent_context_owned( new TextureStateTrackingContext); @@ -1009,20 +1429,25 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { CHECK(parent_output_surface->BindToClient(&parent_output_surface_client)); scoped_ptr<ResourceProvider> parent_resource_provider( - ResourceProvider::Create(parent_output_surface.get(), 0, false)); + ResourceProvider::Create(parent_output_surface.get(), + NULL, + 0, + false, + 1)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; - int texture_id = 1; + int child_texture_id = 1; + int parent_texture_id = 2; - size_t pixel_size = TextureSize(size, format); + size_t pixel_size = TextureSizeBytes(size, format); ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id = child_resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); // The new texture is created with GL_LINEAR. - EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, texture_id)) + EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id)) .Times(2); // Once to create and once to allocate. EXPECT_CALL(*child_context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); @@ -1044,12 +1469,12 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { uint8_t data[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); - EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, texture_id)); + EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id)); child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d()); Mock::VerifyAndClearExpectations(child_context); // The texture is set to |child_filter| in the child. - EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, texture_id)); + EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id)); if (child_filter != GL_LINEAR) { EXPECT_CALL( *child_context, @@ -1070,7 +1495,7 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { resource_ids_to_transfer.push_back(id); TransferableResourceArray list; - EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, texture_id)); + EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id)); EXPECT_CALL(*child_context, produceTextureCHROMIUM(GL_TEXTURE_2D, _)); EXPECT_CALL(*child_context, insertSyncPoint()); @@ -1081,9 +1506,9 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { ASSERT_EQ(1u, list.size()); EXPECT_EQ(static_cast<unsigned>(child_filter), list[0].filter); - EXPECT_CALL(*parent_context, bindTexture(GL_TEXTURE_2D, texture_id)); EXPECT_CALL(*parent_context, - consumeTextureCHROMIUM(GL_TEXTURE_2D, _)); + bindTexture(GL_TEXTURE_2D, parent_texture_id)); + EXPECT_CALL(*parent_context, consumeTextureCHROMIUM(GL_TEXTURE_2D, _)); parent_resource_provider->ReceiveFromChild(child_id, list); Mock::VerifyAndClearExpectations(parent_context); @@ -1097,7 +1522,7 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { EXPECT_NE(0u, mapped_id); // The texture is set to |parent_filter| in the parent. - EXPECT_CALL(*parent_context, bindTexture(GL_TEXTURE_2D, texture_id)); + EXPECT_CALL(*parent_context, bindTexture(GL_TEXTURE_2D, parent_texture_id)); EXPECT_CALL( *parent_context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, parent_filter)); @@ -1109,7 +1534,7 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { // The texture should be reset to |child_filter| in the parent when it is // returned, since that is how it was received. - EXPECT_CALL(*parent_context, bindTexture(GL_TEXTURE_2D, texture_id)); + EXPECT_CALL(*parent_context, bindTexture(GL_TEXTURE_2D, parent_texture_id)); EXPECT_CALL( *parent_context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, child_filter)); @@ -1133,7 +1558,7 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { } // The child remembers the texture filter is set to |child_filter|. - EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, texture_id)); + EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id)); SetResourceFilter(child_resource_provider.get(), id, child_filter); Mock::VerifyAndClearExpectations(child_context); } @@ -1151,16 +1576,8 @@ TEST_P(ResourceProviderTest, TextureFilters_ChildLinearParentNearest) { ResourceProviderTestTextureFilters::RunTest(GL_LINEAR, GL_NEAREST); } -void ReleaseTextureMailbox(unsigned* release_sync_point, - bool* release_lost_resource, - unsigned sync_point, - bool lost_resource) { - *release_sync_point = sync_point; - *release_lost_resource = lost_resource; -} - TEST_P(ResourceProviderTest, TransferMailboxResources) { - // Resource transfer is only supported with GL textures for now. + // Other mailbox transfers tested elsewhere. if (GetParam() != ResourceProvider::GLTexture) return; unsigned texture = context()->createTexture(); @@ -1184,7 +1601,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) { resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox(mailbox, sync_point), SingleReleaseCallback::Create(callback)); - EXPECT_EQ(1, context()->texture_count()); + EXPECT_EQ(1u, context()->NumTextures()); EXPECT_EQ(0u, release_sync_point); { // Transfer the resource, expect the sync points to be consistent. @@ -1216,7 +1633,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) { ReturnedResourceArray returned; TransferableResource::ReturnResources(list, &returned); resource_provider_->ReceiveReturnsFromParent(returned); - EXPECT_EQ(1, context()->texture_count()); + EXPECT_EQ(1u, context()->NumTextures()); EXPECT_EQ(0u, release_sync_point); resource_provider_->DeleteResource(resource); @@ -1232,7 +1649,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) { resource = resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox(mailbox, sync_point), SingleReleaseCallback::Create(callback)); - EXPECT_EQ(1, context()->texture_count()); + EXPECT_EQ(1u, context()->NumTextures()); EXPECT_EQ(0u, release_sync_point); { // Transfer the resource, expect the sync points to be consistent. @@ -1261,7 +1678,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) { // Delete the resource, which shouldn't do anything. resource_provider_->DeleteResource(resource); - EXPECT_EQ(1, context()->texture_count()); + EXPECT_EQ(1u, context()->NumTextures()); EXPECT_EQ(0u, release_sync_point); // Then receive the resource which should release the mailbox, expect the @@ -1280,27 +1697,14 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) { } TEST_P(ResourceProviderTest, LostResourceInParent) { - // Resource transfer is only supported with GL textures for now. - if (GetParam() != ResourceProvider::GLTexture) - return; - - scoped_ptr<ResourceProviderContext> child_context_owned( - ResourceProviderContext::Create(shared_data_.get())); - - FakeOutputSurfaceClient child_output_surface_client; - scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( - child_context_owned.PassAs<TestWebGraphicsContext3D>())); - CHECK(child_output_surface->BindToClient(&child_output_surface_client)); - - scoped_ptr<ResourceProvider> child_resource_provider( - ResourceProvider::Create(child_output_surface.get(), 0, false)); - gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; ResourceProvider::ResourceId resource = - child_resource_provider->CreateResource( + child_resource_provider_->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - child_resource_provider->AllocateForTesting(resource); + child_resource_provider_->AllocateForTesting(resource); + // Expect a GL resource to be lost. + bool should_lose_resource = GetParam() == ResourceProvider::GLTexture; ReturnedResourceArray returned_to_child; int child_id = @@ -1310,8 +1714,8 @@ TEST_P(ResourceProviderTest, LostResourceInParent) { ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(resource); TransferableResourceArray list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, - &list); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); EXPECT_EQ(1u, list.size()); resource_provider_->ReceiveFromChild(child_id, list); @@ -1330,42 +1734,28 @@ TEST_P(ResourceProviderTest, LostResourceInParent) { ResourceProvider::ResourceIdArray no_resources; resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); - // Expect the resource to be lost. + // Expect a GL resource to be lost. ASSERT_EQ(1u, returned_to_child.size()); - EXPECT_TRUE(returned_to_child[0].lost); - child_resource_provider->ReceiveReturnsFromParent(returned_to_child); + EXPECT_EQ(should_lose_resource, returned_to_child[0].lost); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); returned_to_child.clear(); } - // The resource should be lost. - EXPECT_TRUE(child_resource_provider->IsLost(resource)); + // A GL resource should be lost. + EXPECT_EQ(should_lose_resource, child_resource_provider_->IsLost(resource)); // Lost resources stay in use in the parent forever. - EXPECT_TRUE(child_resource_provider->InUseByConsumer(resource)); + EXPECT_EQ(should_lose_resource, + child_resource_provider_->InUseByConsumer(resource)); } TEST_P(ResourceProviderTest, LostResourceInGrandParent) { - // Resource transfer is only supported with GL textures for now. - if (GetParam() != ResourceProvider::GLTexture) - return; - - scoped_ptr<ResourceProviderContext> child_context_owned( - ResourceProviderContext::Create(shared_data_.get())); - - FakeOutputSurfaceClient child_output_surface_client; - scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( - child_context_owned.PassAs<TestWebGraphicsContext3D>())); - CHECK(child_output_surface->BindToClient(&child_output_surface_client)); - - scoped_ptr<ResourceProvider> child_resource_provider( - ResourceProvider::Create(child_output_surface.get(), 0, false)); - gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; ResourceProvider::ResourceId resource = - child_resource_provider->CreateResource( + child_resource_provider_->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - child_resource_provider->AllocateForTesting(resource); + child_resource_provider_->AllocateForTesting(resource); ReturnedResourceArray returned_to_child; int child_id = @@ -1375,8 +1765,8 @@ TEST_P(ResourceProviderTest, LostResourceInGrandParent) { ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(resource); TransferableResourceArray list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, - &list); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); EXPECT_EQ(1u, list.size()); resource_provider_->ReceiveFromChild(child_id, list); @@ -1424,47 +1814,24 @@ TEST_P(ResourceProviderTest, LostResourceInGrandParent) { // Expect the resource to be lost. ASSERT_EQ(1u, returned_to_child.size()); EXPECT_TRUE(returned_to_child[0].lost); - child_resource_provider->ReceiveReturnsFromParent(returned_to_child); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); returned_to_child.clear(); } // The resource should be lost. - EXPECT_TRUE(child_resource_provider->IsLost(resource)); + EXPECT_TRUE(child_resource_provider_->IsLost(resource)); // Lost resources stay in use in the parent forever. - EXPECT_TRUE(child_resource_provider->InUseByConsumer(resource)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(resource)); } TEST_P(ResourceProviderTest, LostMailboxInParent) { - // Resource transfer is only supported with GL textures for now. - if (GetParam() != ResourceProvider::GLTexture) - return; - - scoped_ptr<ResourceProviderContext> child_context_owned( - ResourceProviderContext::Create(shared_data_.get())); - ResourceProviderContext* child_context = child_context_owned.get(); - - FakeOutputSurfaceClient child_output_surface_client; - scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( - child_context_owned.PassAs<TestWebGraphicsContext3D>())); - CHECK(child_output_surface->BindToClient(&child_output_surface_client)); - - scoped_ptr<ResourceProvider> child_resource_provider( - ResourceProvider::Create(child_output_surface.get(), 0, false)); - - unsigned texture = child_context->createTexture(); - gpu::Mailbox gpu_mailbox; - child_context->bindTexture(GL_TEXTURE_2D, texture); - child_context->genMailboxCHROMIUM(gpu_mailbox.name); - child_context->produceTextureCHROMIUM(GL_TEXTURE_2D, gpu_mailbox.name); - unsigned release_sync_point = 0; bool lost_resource = false; - ReleaseCallback callback = - base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource); - ResourceProvider::ResourceId resource = - child_resource_provider->CreateResourceFromTextureMailbox( - TextureMailbox(gpu_mailbox), SingleReleaseCallback::Create(callback)); + bool release_called = false; + unsigned sync_point = 0; + ResourceProvider::ResourceId resource = CreateChildMailbox( + &release_sync_point, &lost_resource, &release_called, &sync_point); ReturnedResourceArray returned_to_child; int child_id = @@ -1474,8 +1841,8 @@ TEST_P(ResourceProviderTest, LostMailboxInParent) { ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(resource); TransferableResourceArray list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, - &list); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); EXPECT_EQ(1u, list.size()); resource_provider_->ReceiveFromChild(child_id, list); @@ -1494,51 +1861,27 @@ TEST_P(ResourceProviderTest, LostMailboxInParent) { ResourceProvider::ResourceIdArray no_resources; resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); - // Expect the resource to be lost. ASSERT_EQ(1u, returned_to_child.size()); - EXPECT_TRUE(returned_to_child[0].lost); - child_resource_provider->ReceiveReturnsFromParent(returned_to_child); + // Losing an output surface only loses hardware resources. + EXPECT_EQ(returned_to_child[0].lost, + GetParam() == ResourceProvider::GLTexture); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); returned_to_child.clear(); } - // Delete the resource in the child. Expect the resource to be lost. - child_resource_provider->DeleteResource(resource); - EXPECT_TRUE(lost_resource); - - child_context->waitSyncPoint(release_sync_point); - child_context->deleteTexture(texture); + // Delete the resource in the child. Expect the resource to be lost if it's + // a GL texture. + child_resource_provider_->DeleteResource(resource); + EXPECT_EQ(lost_resource, GetParam() == ResourceProvider::GLTexture); } TEST_P(ResourceProviderTest, LostMailboxInGrandParent) { - // Resource transfer is only supported with GL textures for now. - if (GetParam() != ResourceProvider::GLTexture) - return; - - scoped_ptr<ResourceProviderContext> child_context_owned( - ResourceProviderContext::Create(shared_data_.get())); - ResourceProviderContext* child_context = child_context_owned.get(); - - FakeOutputSurfaceClient child_output_surface_client; - scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( - child_context_owned.PassAs<TestWebGraphicsContext3D>())); - CHECK(child_output_surface->BindToClient(&child_output_surface_client)); - - scoped_ptr<ResourceProvider> child_resource_provider( - ResourceProvider::Create(child_output_surface.get(), 0, false)); - - unsigned texture = child_context->createTexture(); - gpu::Mailbox gpu_mailbox; - child_context->bindTexture(GL_TEXTURE_2D, texture); - child_context->genMailboxCHROMIUM(gpu_mailbox.name); - child_context->produceTextureCHROMIUM(GL_TEXTURE_2D, gpu_mailbox.name); - unsigned release_sync_point = 0; bool lost_resource = false; - ReleaseCallback callback = - base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource); - ResourceProvider::ResourceId resource = - child_resource_provider->CreateResourceFromTextureMailbox( - TextureMailbox(gpu_mailbox), SingleReleaseCallback::Create(callback)); + bool release_called = false; + unsigned sync_point = 0; + ResourceProvider::ResourceId resource = CreateChildMailbox( + &release_sync_point, &lost_resource, &release_called, &sync_point); ReturnedResourceArray returned_to_child; int child_id = @@ -1548,8 +1891,8 @@ TEST_P(ResourceProviderTest, LostMailboxInGrandParent) { ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(resource); TransferableResourceArray list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, - &list); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); EXPECT_EQ(1u, list.size()); resource_provider_->ReceiveFromChild(child_id, list); @@ -1591,116 +1934,54 @@ TEST_P(ResourceProviderTest, LostMailboxInGrandParent) { // Expect the resource to be lost. ASSERT_EQ(1u, returned_to_child.size()); EXPECT_TRUE(returned_to_child[0].lost); - child_resource_provider->ReceiveReturnsFromParent(returned_to_child); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); returned_to_child.clear(); } // Delete the resource in the child. Expect the resource to be lost. - child_resource_provider->DeleteResource(resource); + child_resource_provider_->DeleteResource(resource); EXPECT_TRUE(lost_resource); - - child_context->waitSyncPoint(release_sync_point); - child_context->deleteTexture(texture); } TEST_P(ResourceProviderTest, Shutdown) { - // TextureMailbox callbacks only exist for GL textures for now. - if (GetParam() != ResourceProvider::GLTexture) - return; - unsigned texture = context()->createTexture(); - context()->bindTexture(GL_TEXTURE_2D, texture); - gpu::Mailbox mailbox; - context()->genMailboxCHROMIUM(mailbox.name); - context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); - unsigned sync_point = context()->insertSyncPoint(); - - EXPECT_LT(0u, sync_point); - unsigned release_sync_point = 0; bool lost_resource = false; - scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( - base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource)); - resource_provider_->CreateResourceFromTextureMailbox( - TextureMailbox(mailbox, sync_point), - callback.Pass()); + bool release_called = false; + unsigned sync_point = 0; + CreateChildMailbox( + &release_sync_point, &lost_resource, &release_called, &sync_point); EXPECT_EQ(0u, release_sync_point); EXPECT_FALSE(lost_resource); - resource_provider_.reset(); - - EXPECT_LE(sync_point, release_sync_point); - EXPECT_FALSE(lost_resource); -} - -static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory( - gfx::Size size, uint32_t value) { - scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory); - CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea())); - uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_memory->memory()); - CHECK(pixels); - std::fill_n(pixels, size.GetArea(), value); - return shared_memory.Pass(); -} - -static void ReleaseSharedMemoryCallback( - bool* release_called, - unsigned sync_point, bool lost_resource) { - *release_called = true; -} - -TEST_P(ResourceProviderTest, ShutdownSharedMemory) { - if (GetParam() != ResourceProvider::Bitmap) - return; - - gfx::Size size(64, 64); - scoped_ptr<base::SharedMemory> shared_memory( - CreateAndFillSharedMemory(size, 0)); - - bool release_called = false; - scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( - base::Bind(ReleaseSharedMemoryCallback, &release_called)); - resource_provider_->CreateResourceFromTextureMailbox( - TextureMailbox(shared_memory.get(), size), - callback.Pass()); - - resource_provider_.reset(); + child_resource_provider_.reset(); + if (GetParam() == ResourceProvider::GLTexture) { + EXPECT_LE(sync_point, release_sync_point); + } EXPECT_TRUE(release_called); + EXPECT_FALSE(lost_resource); } TEST_P(ResourceProviderTest, ShutdownWithExportedResource) { - // TextureMailbox callbacks only exist for GL textures for now. - if (GetParam() != ResourceProvider::GLTexture) - return; - unsigned texture = context()->createTexture(); - context()->bindTexture(GL_TEXTURE_2D, texture); - gpu::Mailbox mailbox; - context()->genMailboxCHROMIUM(mailbox.name); - context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); - unsigned sync_point = context()->insertSyncPoint(); - - EXPECT_LT(0u, sync_point); - unsigned release_sync_point = 0; bool lost_resource = false; - scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( - base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource)); - ResourceProvider::ResourceId resource = - resource_provider_->CreateResourceFromTextureMailbox( - TextureMailbox(mailbox, sync_point), - callback.Pass()); + bool release_called = false; + unsigned sync_point = 0; + ResourceProvider::ResourceId resource = CreateChildMailbox( + &release_sync_point, &lost_resource, &release_called, &sync_point); // Transfer the resource, so we can't release it properly on shutdown. ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(resource); TransferableResourceArray list; - resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); EXPECT_EQ(0u, release_sync_point); EXPECT_FALSE(lost_resource); - resource_provider_.reset(); + child_resource_provider_.reset(); // Since the resource is in the parent, the child considers it lost. EXPECT_EQ(0u, release_sync_point); @@ -1753,7 +2034,7 @@ TEST_P(ResourceProviderTest, ScopedSampler) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -1834,7 +2115,7 @@ TEST_P(ResourceProviderTest, ManagedResource) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -1842,7 +2123,11 @@ TEST_P(ResourceProviderTest, ManagedResource) { // Check that the texture gets created with the right sampler settings. ResourceProvider::ResourceId id = resource_provider->CreateManagedResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, + GL_TEXTURE_2D, + GL_CLAMP_TO_EDGE, + ResourceProvider::TextureUsageAny, + format); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)); EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); @@ -1879,18 +2164,18 @@ TEST_P(ResourceProviderTest, TextureWrapMode) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; - int texture_id = 1; GLenum texture_pool = GL_TEXTURE_POOL_UNMANAGED_CHROMIUM; - for (int i = 0; i < 2; ++i) { - GLint wrap_mode = i ? GL_CLAMP_TO_EDGE : GL_REPEAT; + for (int texture_id = 1; texture_id <= 2; ++texture_id) { + GLint wrap_mode = texture_id == 1 ? GL_CLAMP_TO_EDGE : GL_REPEAT; // Check that the texture gets created with the right sampler settings. ResourceProvider::ResourceId id = resource_provider->CreateGLTexture(size, + GL_TEXTURE_2D, texture_pool, wrap_mode, ResourceProvider::TextureUsageAny, @@ -1917,8 +2202,6 @@ TEST_P(ResourceProviderTest, TextureWrapMode) { } } -static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {} - TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) { if (GetParam() != ResourceProvider::Bitmap) return; @@ -1935,7 +2218,7 @@ TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( base::Bind(&EmptyReleaseCallback)); @@ -1970,7 +2253,7 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); unsigned texture_id = 1; unsigned sync_point = 30; @@ -2034,7 +2317,7 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); unsigned texture_id = 1; unsigned sync_point = 30; @@ -2085,59 +2368,77 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) { class AllocationTrackingContext3D : public TestWebGraphicsContext3D { public: - MOCK_METHOD0(createTexture, WebGLId()); - MOCK_METHOD1(deleteTexture, void(WebGLId texture_id)); - MOCK_METHOD2(bindTexture, void(WGC3Denum target, WebGLId texture)); + MOCK_METHOD0(NextTextureId, GLuint()); + MOCK_METHOD1(RetireTextureId, void(GLuint id)); + MOCK_METHOD2(bindTexture, void(GLenum target, GLuint texture)); + MOCK_METHOD5(texStorage2DEXT, + void(GLenum target, + GLint levels, + GLuint internalformat, + GLint width, + GLint height)); MOCK_METHOD9(texImage2D, - void(WGC3Denum target, - WGC3Dint level, - WGC3Denum internalformat, - WGC3Dsizei width, - WGC3Dsizei height, - WGC3Dint border, - WGC3Denum format, - WGC3Denum type, + void(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, const void* pixels)); MOCK_METHOD9(texSubImage2D, - void(WGC3Denum target, - WGC3Dint level, - WGC3Dint xoffset, - WGC3Dint yoffset, - WGC3Dsizei width, - WGC3Dsizei height, - WGC3Denum format, - WGC3Denum type, + void(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, const void* pixels)); MOCK_METHOD9(asyncTexImage2DCHROMIUM, - void(WGC3Denum target, - WGC3Dint level, - WGC3Denum internalformat, - WGC3Dsizei width, - WGC3Dsizei height, - WGC3Dint border, - WGC3Denum format, - WGC3Denum type, + void(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, const void* pixels)); MOCK_METHOD9(asyncTexSubImage2DCHROMIUM, - void(WGC3Denum target, - WGC3Dint level, - WGC3Dint xoffset, - WGC3Dint yoffset, - WGC3Dsizei width, - WGC3Dsizei height, - WGC3Denum format, - WGC3Denum type, + void(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, const void* pixels)); - MOCK_METHOD1(waitAsyncTexImage2DCHROMIUM, void(WGC3Denum)); - MOCK_METHOD3(createImageCHROMIUM, WGC3Duint(WGC3Dsizei, WGC3Dsizei, - WGC3Denum)); - MOCK_METHOD1(destroyImageCHROMIUM, void(WGC3Duint)); - MOCK_METHOD2(mapImageCHROMIUM, void*(WGC3Duint, WGC3Denum)); - MOCK_METHOD3(getImageParameterivCHROMIUM, void(WGC3Duint, WGC3Denum, - GLint*)); - MOCK_METHOD1(unmapImageCHROMIUM, void(WGC3Duint)); - MOCK_METHOD2(bindTexImage2DCHROMIUM, void(WGC3Denum, WGC3Dint)); - MOCK_METHOD2(releaseTexImage2DCHROMIUM, void(WGC3Denum, WGC3Dint)); + MOCK_METHOD8(compressedTexImage2D, + void(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei image_size, + const void* data)); + MOCK_METHOD1(waitAsyncTexImage2DCHROMIUM, void(GLenum)); + MOCK_METHOD3(createImageCHROMIUM, GLuint(GLsizei, GLsizei, GLenum)); + MOCK_METHOD1(destroyImageCHROMIUM, void(GLuint)); + MOCK_METHOD2(mapImageCHROMIUM, void*(GLuint, GLenum)); + MOCK_METHOD3(getImageParameterivCHROMIUM, void(GLuint, GLenum, GLint*)); + MOCK_METHOD1(unmapImageCHROMIUM, void(GLuint)); + MOCK_METHOD2(bindTexImage2DCHROMIUM, void(GLenum, GLint)); + MOCK_METHOD2(releaseTexImage2DCHROMIUM, void(GLenum, GLint)); + + // We're mocking bindTexture, so we override + // TestWebGraphicsContext3D::texParameteri to avoid assertions related to the + // currently bound texture. + virtual void texParameteri(GLenum target, GLenum pname, GLint param) {} }; TEST_P(ResourceProviderTest, TextureAllocation) { @@ -2154,7 +2455,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); gfx::Size size(2, 2); gfx::Vector2d offset(0, 0); @@ -2168,11 +2469,11 @@ TEST_P(ResourceProviderTest, TextureAllocation) { id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1); resource_provider->CreateForTesting(id); - EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1); + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); resource_provider->DeleteResource(id); Mock::VerifyAndClearExpectations(context); @@ -2181,13 +2482,13 @@ TEST_P(ResourceProviderTest, TextureAllocation) { id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3); EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)).Times(1); EXPECT_CALL(*context, texSubImage2D(_, _, _, _, 2, 2, _, _, _)).Times(1); resource_provider->SetPixels(id, pixels, rect, rect, offset); - EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1); + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); resource_provider->DeleteResource(id); Mock::VerifyAndClearExpectations(context); @@ -2197,7 +2498,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) { size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); resource_provider->AcquirePixelBuffer(id); - EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _)) .Times(1); @@ -2206,7 +2507,84 @@ TEST_P(ResourceProviderTest, TextureAllocation) { resource_provider->ReleasePixelBuffer(id); - EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1); + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); + resource_provider->DeleteResource(id); + + Mock::VerifyAndClearExpectations(context); +} + +TEST_P(ResourceProviderTest, TextureAllocationStorageUsageAny) { + // Only for GL textures. + if (GetParam() != ResourceProvider::GLTexture) + return; + scoped_ptr<AllocationTrackingContext3D> context_owned( + new StrictMock<AllocationTrackingContext3D>); + AllocationTrackingContext3D* context = context_owned.get(); + context->set_support_texture_storage(true); + + FakeOutputSurfaceClient output_surface_client; + scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( + context_owned.PassAs<TestWebGraphicsContext3D>())); + CHECK(output_surface->BindToClient(&output_surface_client)); + + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); + + gfx::Size size(2, 2); + ResourceFormat format = RGBA_8888; + ResourceProvider::ResourceId id = 0; + int texture_id = 123; + + // Lazy allocation. Don't allocate when creating the resource. + id = resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); + EXPECT_CALL(*context, texStorage2DEXT(_, _, _, 2, 2)).Times(1); + resource_provider->AllocateForTesting(id); + + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); + resource_provider->DeleteResource(id); + + Mock::VerifyAndClearExpectations(context); +} + +TEST_P(ResourceProviderTest, TextureAllocationStorageUsageFramebuffer) { + // Only for GL textures. + if (GetParam() != ResourceProvider::GLTexture) + return; + scoped_ptr<AllocationTrackingContext3D> context_owned( + new StrictMock<AllocationTrackingContext3D>); + AllocationTrackingContext3D* context = context_owned.get(); + context->set_support_texture_storage(true); + + FakeOutputSurfaceClient output_surface_client; + scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( + context_owned.PassAs<TestWebGraphicsContext3D>())); + CHECK(output_surface->BindToClient(&output_surface_client)); + + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); + + gfx::Size size(2, 2); + ResourceFormat format = RGBA_8888; + ResourceProvider::ResourceId id = 0; + int texture_id = 123; + + // Lazy allocation. Don't allocate when creating the resource. + id = resource_provider->CreateResource( + size, + GL_CLAMP_TO_EDGE, + ResourceProvider::TextureUsageFramebuffer, + format); + + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); + EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)).Times(1); + resource_provider->AllocateForTesting(id); + + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); resource_provider->DeleteResource(id); Mock::VerifyAndClearExpectations(context); @@ -2230,13 +2608,13 @@ TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) { int texture_id = 123; scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); resource_provider->AcquirePixelBuffer(id); - EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _)) .Times(1); @@ -2246,7 +2624,7 @@ TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) { resource_provider->ReleasePixelBuffer(id); - EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1); + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); resource_provider->DeleteResource(id); Mock::VerifyAndClearExpectations(context); @@ -2267,7 +2645,7 @@ TEST_P(ResourceProviderTest, PixelBuffer_Bitmap) { const uint32_t kBadBeef = 0xbadbeef; scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); @@ -2313,13 +2691,13 @@ TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) { int texture_id = 123; scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); resource_provider->AcquirePixelBuffer(id); - EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _)) .Times(1); @@ -2332,7 +2710,7 @@ TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) { resource_provider->ReleasePixelBuffer(id); - EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1); + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); resource_provider->DeleteResource(id); Mock::VerifyAndClearExpectations(context); @@ -2354,9 +2732,9 @@ TEST_P(ResourceProviderTest, PixelBufferLostContext) { int texture_id = 123; scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); - EXPECT_CALL(*context, createTexture()).WillRepeatedly(Return(texture_id)); + EXPECT_CALL(*context, NextTextureId()).WillRepeatedly(Return(texture_id)); id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); @@ -2392,7 +2770,7 @@ TEST_P(ResourceProviderTest, Image_GLTexture) { const unsigned kImageId = 234u; scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); @@ -2421,7 +2799,7 @@ TEST_P(ResourceProviderTest, Image_GLTexture) { .RetiresOnSaturation(); resource_provider->UnmapImage(id); - EXPECT_CALL(*context, createTexture()) + EXPECT_CALL(*context, NextTextureId()) .WillOnce(Return(kTextureId)) .RetiresOnSaturation(); // Once in CreateTextureId and once in BindForSampling @@ -2430,10 +2808,31 @@ TEST_P(ResourceProviderTest, Image_GLTexture) { EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId)) .Times(1) .RetiresOnSaturation(); + { + ResourceProvider::ScopedSamplerGL lock_gl( + resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR); + EXPECT_EQ(kTextureId, lock_gl.texture_id()); + } + + EXPECT_CALL(*context, mapImageCHROMIUM(kImageId, GL_READ_WRITE)) + .WillOnce(Return(dummy_mapped_buffer_address)) + .RetiresOnSaturation(); + resource_provider->MapImage(id); + + EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId)) + .Times(1) + .RetiresOnSaturation(); + resource_provider->UnmapImage(id); + + EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(1) + .RetiresOnSaturation(); EXPECT_CALL(*context, releaseTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*context, deleteTexture(kTextureId)) + EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*context, RetireTextureId(kTextureId)) .Times(1) .RetiresOnSaturation(); { @@ -2463,7 +2862,7 @@ TEST_P(ResourceProviderTest, Image_Bitmap) { const uint32_t kBadBeef = 0xbadbeef; scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); @@ -2514,7 +2913,7 @@ TEST(ResourceProviderTest, BasicInitializeGLSoftware) { scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice))); EXPECT_TRUE(output_surface->BindToClient(&client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL); @@ -2531,10 +2930,146 @@ TEST(ResourceProviderTest, BasicInitializeGLSoftware) { output_surface.get()); } +TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) { + if (GetParam() != ResourceProvider::GLTexture) + return; + + scoped_ptr<AllocationTrackingContext3D> context_owned( + new AllocationTrackingContext3D); + AllocationTrackingContext3D* context = context_owned.get(); + context_owned->set_support_compressed_texture_etc1(true); + + FakeOutputSurfaceClient output_surface_client; + scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( + context_owned.PassAs<TestWebGraphicsContext3D>())); + CHECK(output_surface->BindToClient(&output_surface_client)); + + gfx::Size size(4, 4); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + 0, + false, + 1)); + int texture_id = 123; + + ResourceProvider::ResourceId id = resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, ETC1); + EXPECT_NE(0u, id); + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); + resource_provider->AllocateForTesting(id); + + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); + resource_provider->DeleteResource(id); +} + +TEST_P(ResourceProviderTest, CompressedTextureETC1SetPixels) { + if (GetParam() != ResourceProvider::GLTexture) + return; + + scoped_ptr<AllocationTrackingContext3D> context_owned( + new AllocationTrackingContext3D); + AllocationTrackingContext3D* context = context_owned.get(); + context_owned->set_support_compressed_texture_etc1(true); + + FakeOutputSurfaceClient output_surface_client; + scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( + context_owned.PassAs<TestWebGraphicsContext3D>())); + CHECK(output_surface->BindToClient(&output_surface_client)); + + gfx::Size size(4, 4); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + 0, + false, + 1)); + int texture_id = 123; + uint8_t pixels[8]; + + ResourceProvider::ResourceId id = resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, ETC1); + EXPECT_NE(0u, id); + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3); + EXPECT_CALL(*context, + compressedTexImage2D( + _, 0, _, size.width(), size.height(), _, _, _)).Times(1); + resource_provider->SetPixels( + id, pixels, gfx::Rect(size), gfx::Rect(size), gfx::Vector2d(0, 0)); + + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); + resource_provider->DeleteResource(id); +} + INSTANTIATE_TEST_CASE_P( ResourceProviderTests, ResourceProviderTest, ::testing::Values(ResourceProvider::GLTexture, ResourceProvider::Bitmap)); +class TextureIdAllocationTrackingContext : public TestWebGraphicsContext3D { + public: + virtual GLuint NextTextureId() OVERRIDE { + base::AutoLock lock(namespace_->lock); + return namespace_->next_texture_id++; + } + virtual void RetireTextureId(GLuint) OVERRIDE {} + GLuint PeekTextureId() { + base::AutoLock lock(namespace_->lock); + return namespace_->next_texture_id; + } +}; + +TEST(ResourceProviderTest, TextureAllocationChunkSize) { + scoped_ptr<TextureIdAllocationTrackingContext> context_owned( + new TextureIdAllocationTrackingContext); + TextureIdAllocationTrackingContext* context = context_owned.get(); + + FakeOutputSurfaceClient output_surface_client; + scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( + context_owned.PassAs<TestWebGraphicsContext3D>())); + CHECK(output_surface->BindToClient(&output_surface_client)); + + gfx::Size size(1, 1); + ResourceFormat format = RGBA_8888; + + { + size_t kTextureAllocationChunkSize = 1; + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + NULL, + 0, + false, + kTextureAllocationChunkSize)); + + ResourceProvider::ResourceId id = resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + resource_provider->AllocateForTesting(id); + Mock::VerifyAndClearExpectations(context); + + DCHECK_EQ(2u, context->PeekTextureId()); + resource_provider->DeleteResource(id); + } + + { + size_t kTextureAllocationChunkSize = 8; + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + NULL, + 0, + false, + kTextureAllocationChunkSize)); + + ResourceProvider::ResourceId id = resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + resource_provider->AllocateForTesting(id); + Mock::VerifyAndClearExpectations(context); + + DCHECK_EQ(10u, context->PeekTextureId()); + resource_provider->DeleteResource(id); + } +} + } // namespace } // namespace cc diff --git a/chromium/cc/resources/resource_update_controller.cc b/chromium/cc/resources/resource_update_controller.cc index 3c8b1e709ff..868133596be 100644 --- a/chromium/cc/resources/resource_update_controller.cc +++ b/chromium/cc/resources/resource_update_controller.cc @@ -9,6 +9,7 @@ #include "base/single_thread_task_runner.h" #include "cc/resources/prioritized_resource.h" #include "cc/resources/resource_provider.h" +#include "ui/gfx/frame_time.h" namespace { @@ -31,11 +32,7 @@ size_t ResourceUpdateController::MaxPartialTextureUpdates() { size_t ResourceUpdateController::MaxFullUpdatesPerTick( ResourceProvider* resource_provider) { - double textures_per_second = resource_provider->EstimatedUploadsPerSecond(); - size_t textures_per_tick = - floor(resource_provider->TextureUpdateTickRate().InSecondsF() * - textures_per_second); - return textures_per_tick ? textures_per_tick : 1; + return resource_provider->EstimatedUploadsPerTick(); } ResourceUpdateController::ResourceUpdateController( @@ -49,8 +46,8 @@ ResourceUpdateController::ResourceUpdateController( texture_updates_per_tick_(MaxFullUpdatesPerTick(resource_provider)), first_update_attempt_(true), task_runner_(task_runner), - weak_factory_(this), - task_posted_(false) {} + task_posted_(false), + weak_factory_(this) {} ResourceUpdateController::~ResourceUpdateController() {} @@ -112,12 +109,9 @@ void ResourceUpdateController::OnTimerFired() { client_->ReadyToFinalizeTextureUpdates(); } -base::TimeTicks ResourceUpdateController::Now() const { - return base::TimeTicks::Now(); -} - -base::TimeDelta ResourceUpdateController::UpdateMoreTexturesTime() const { - return resource_provider_->TextureUpdateTickRate(); +base::TimeTicks ResourceUpdateController::UpdateMoreTexturesCompletionTime() { + return resource_provider_->EstimatedUploadCompletionTime( + texture_updates_per_tick_); } size_t ResourceUpdateController::UpdateMoreTexturesSize() const { @@ -128,25 +122,14 @@ size_t ResourceUpdateController::MaxBlockingUpdates() const { return UpdateMoreTexturesSize() * kMaxBlockingUpdateIntervals; } -base::TimeDelta ResourceUpdateController::PendingUpdateTime() const { - base::TimeDelta update_one_resource_time = - UpdateMoreTexturesTime() / UpdateMoreTexturesSize(); - return update_one_resource_time * resource_provider_->NumBlockingUploads(); -} - bool ResourceUpdateController::UpdateMoreTexturesIfEnoughTimeRemaining() { while (resource_provider_->NumBlockingUploads() < MaxBlockingUpdates()) { if (!queue_->FullUploadSize()) return false; if (!time_limit_.is_null()) { - // Estimated completion time of all pending updates. - base::TimeTicks completion_time = Now() + PendingUpdateTime(); - - // Time remaining based on current completion estimate. - base::TimeDelta time_remaining = time_limit_ - completion_time; - - if (time_remaining < UpdateMoreTexturesTime()) + base::TimeTicks completion_time = UpdateMoreTexturesCompletionTime(); + if (completion_time > time_limit_) return true; } diff --git a/chromium/cc/resources/resource_update_controller.h b/chromium/cc/resources/resource_update_controller.h index 97138bcf5d5..4425f377f71 100644 --- a/chromium/cc/resources/resource_update_controller.h +++ b/chromium/cc/resources/resource_update_controller.h @@ -48,9 +48,8 @@ class CC_EXPORT ResourceUpdateController { // Virtual for testing. - virtual base::TimeTicks Now() const; - virtual base::TimeDelta UpdateMoreTexturesTime() const; virtual size_t UpdateMoreTexturesSize() const; + virtual base::TimeTicks UpdateMoreTexturesCompletionTime(); protected: ResourceUpdateController(ResourceUpdateControllerClient* client, @@ -62,7 +61,6 @@ class CC_EXPORT ResourceUpdateController { static size_t MaxFullUpdatesPerTick(ResourceProvider* resource_provider); size_t MaxBlockingUpdates() const; - base::TimeDelta PendingUpdateTime() const; void UpdateTexture(ResourceUpdate update); @@ -79,8 +77,8 @@ class CC_EXPORT ResourceUpdateController { size_t texture_updates_per_tick_; bool first_update_attempt_; base::SingleThreadTaskRunner* task_runner_; - base::WeakPtrFactory<ResourceUpdateController> weak_factory_; bool task_posted_; + base::WeakPtrFactory<ResourceUpdateController> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ResourceUpdateController); }; diff --git a/chromium/cc/resources/resource_update_controller_unittest.cc b/chromium/cc/resources/resource_update_controller_unittest.cc index 31b5d71662a..8979925caea 100644 --- a/chromium/cc/resources/resource_update_controller_unittest.cc +++ b/chromium/cc/resources/resource_update_controller_unittest.cc @@ -5,24 +5,18 @@ #include "cc/resources/resource_update_controller.h" #include "base/test/test_simple_task_runner.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/resources/prioritized_resource_manager.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_proxy.h" #include "cc/test/scheduler_test_common.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "cc/test/tiled_layer_test_common.h" #include "cc/trees/single_thread_proxy.h" // For DebugScopedSetImplThread #include "testing/gtest/include/gtest/gtest.h" #include "third_party/khronos/GLES2/gl2ext.h" using testing::Test; -using WebKit::WGC3Denum; -using WebKit::WGC3Dint; -using WebKit::WGC3Duint; -using WebKit::WGC3Dsizei; -using WebKit::WebGLId; -using WebKit::WebString; namespace cc { namespace { @@ -35,28 +29,22 @@ class ResourceUpdateControllerTest; class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D { public: explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest* test) - : test_(test) { - test_capabilities_.shallow_flush = true; - } - - virtual void flush(void) OVERRIDE; - virtual void shallowFlushCHROMIUM(void) OVERRIDE; - virtual void texSubImage2D( - WGC3Denum target, - WGC3Dint level, - WGC3Dint xoffset, - WGC3Dint yoffset, - WGC3Dsizei width, - WGC3Dsizei height, - WGC3Denum format, - WGC3Denum type, - const void* pixels) OVERRIDE; - virtual GrGLInterface* onCreateGrGLInterface() OVERRIDE { return NULL; } - - virtual void getQueryObjectuivEXT( - WebGLId id, - WGC3Denum pname, - WGC3Duint* value); + : test_(test) {} + + virtual void flush() OVERRIDE; + virtual void shallowFlushCHROMIUM() OVERRIDE; + virtual void texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void* pixels) OVERRIDE; + virtual GrGLInterface* createGrGLInterface() OVERRIDE { return NULL; } + + virtual void getQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* value); private: ResourceUpdateControllerTest* test_; @@ -137,7 +125,7 @@ class ResourceUpdateControllerTest : public Test { CHECK(output_surface_->BindToClient(&output_surface_client_)); resource_provider_ = - ResourceProvider::Create(output_surface_.get(), 0, false); + ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1); } void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count, @@ -214,29 +202,27 @@ class ResourceUpdateControllerTest : public Test { int num_total_flushes_; }; -void WebGraphicsContext3DForUploadTest::flush(void) { test_->OnFlush(); } +void WebGraphicsContext3DForUploadTest::flush() { test_->OnFlush(); } -void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM(void) { +void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() { test_->OnFlush(); } -void WebGraphicsContext3DForUploadTest::texSubImage2D( - WGC3Denum target, - WGC3Dint level, - WGC3Dint xoffset, - WGC3Dint yoffset, - WGC3Dsizei width, - WGC3Dsizei height, - WGC3Denum format, - WGC3Denum type, - const void* pixels) { +void WebGraphicsContext3DForUploadTest::texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void* pixels) { test_->OnUpload(); } -void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT( - WebGLId id, - WGC3Denum pname, - WGC3Duint* params) { +void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(GLuint id, + GLenum pname, + GLuint* params) { if (pname == GL_QUERY_RESULT_AVAILABLE_EXT) *params = test_->IsQueryResultAvailable(); } @@ -355,12 +341,14 @@ class FakeResourceUpdateController : public ResourceUpdateController { } void SetNow(base::TimeTicks time) { now_ = time; } - virtual base::TimeTicks Now() const OVERRIDE { return now_; } - void SetUpdateMoreTexturesTime(base::TimeDelta time) { - update_more_textures_time_ = time; + base::TimeTicks Now() const { return now_; } + void SetUpdateTextureTime(base::TimeDelta time) { + update_textures_time_ = time; } - virtual base::TimeDelta UpdateMoreTexturesTime() const OVERRIDE { - return update_more_textures_time_; + virtual base::TimeTicks UpdateMoreTexturesCompletionTime() OVERRIDE { + size_t total_updates = + resource_provider_->NumBlockingUploads() + update_more_textures_size_; + return now_ + total_updates * update_textures_time_; } void SetUpdateMoreTexturesSize(size_t size) { update_more_textures_size_ = size; @@ -376,10 +364,12 @@ class FakeResourceUpdateController : public ResourceUpdateController { ResourceProvider* resource_provider) : ResourceUpdateController( client, task_runner, queue.Pass(), resource_provider), + resource_provider_(resource_provider), update_more_textures_size_(0) {} + ResourceProvider* resource_provider_; base::TimeTicks now_; - base::TimeDelta update_more_textures_time_; + base::TimeDelta update_textures_time_; size_t update_more_textures_size_; }; @@ -408,14 +398,14 @@ TEST_F(ResourceUpdateControllerTest, UpdateMoreTextures) { resource_provider_.get())); controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1)); - controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(100)); + controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100)); controller->SetUpdateMoreTexturesSize(1); // Not enough time for any updates. controller->PerformMoreUpdates(controller->Now() + base::TimeDelta::FromMilliseconds(90)); EXPECT_FALSE(task_runner->HasPendingTask()); - controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(100)); + controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100)); controller->SetUpdateMoreTexturesSize(1); // Only enough time for 1 update. controller->PerformMoreUpdates(controller->Now() + @@ -426,7 +416,7 @@ TEST_F(ResourceUpdateControllerTest, UpdateMoreTextures) { // Complete one upload. MakeQueryResultAvailable(); - controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(100)); + controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100)); controller->SetUpdateMoreTexturesSize(1); // Enough time for 2 updates. controller->PerformMoreUpdates(controller->Now() + @@ -455,7 +445,7 @@ TEST_F(ResourceUpdateControllerTest, NoMoreUpdates) { resource_provider_.get())); controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1)); - controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(100)); + controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100)); controller->SetUpdateMoreTexturesSize(1); // Enough time for 3 updates but only 2 necessary. controller->PerformMoreUpdates(controller->Now() + @@ -465,7 +455,7 @@ TEST_F(ResourceUpdateControllerTest, NoMoreUpdates) { EXPECT_TRUE(client.ReadyToFinalizeCalled()); EXPECT_EQ(2, num_total_uploads_); - controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(100)); + controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100)); controller->SetUpdateMoreTexturesSize(1); // Enough time for updates but no more updates left. controller->PerformMoreUpdates(controller->Now() + @@ -495,7 +485,7 @@ TEST_F(ResourceUpdateControllerTest, UpdatesCompleteInFiniteTime) { resource_provider_.get())); controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1)); - controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(500)); + controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(500)); controller->SetUpdateMoreTexturesSize(1); for (int i = 0; i < 100; i++) { diff --git a/chromium/cc/resources/scoped_resource.cc b/chromium/cc/resources/scoped_resource.cc index 5fcaaca7acc..99f93c9bc85 100644 --- a/chromium/cc/resources/scoped_resource.cc +++ b/chromium/cc/resources/scoped_resource.cc @@ -15,7 +15,7 @@ ScopedResource::~ScopedResource() { Free(); } -bool ScopedResource::Allocate(gfx::Size size, +void ScopedResource::Allocate(gfx::Size size, ResourceProvider::TextureUsageHint hint, ResourceFormat format) { DCHECK(!id()); @@ -28,8 +28,25 @@ bool ScopedResource::Allocate(gfx::Size size, #ifndef NDEBUG allocate_thread_id_ = base::PlatformThread::CurrentId(); #endif +} - return id() != 0; +void ScopedResource::AllocateManaged(gfx::Size size, + GLenum target, + ResourceFormat format) { + DCHECK(!id()); + DCHECK(!size.IsEmpty()); + + set_dimensions(size, format); + set_id(resource_provider_->CreateManagedResource( + size, + target, + GL_CLAMP_TO_EDGE, + ResourceProvider::TextureUsageAny, + format)); + +#ifndef NDEBUG + allocate_thread_id_ = base::PlatformThread::CurrentId(); +#endif } void ScopedResource::Free() { diff --git a/chromium/cc/resources/scoped_resource.h b/chromium/cc/resources/scoped_resource.h index 8e316eb76db..63f2cd48c47 100644 --- a/chromium/cc/resources/scoped_resource.h +++ b/chromium/cc/resources/scoped_resource.h @@ -19,15 +19,16 @@ namespace cc { class CC_EXPORT ScopedResource : public Resource { public: - static scoped_ptr<ScopedResource> create( + static scoped_ptr<ScopedResource> Create( ResourceProvider* resource_provider) { return make_scoped_ptr(new ScopedResource(resource_provider)); } virtual ~ScopedResource(); - bool Allocate(gfx::Size size, + void Allocate(gfx::Size size, ResourceProvider::TextureUsageHint hint, - ResourceFormat texture_format); + ResourceFormat format); + void AllocateManaged(gfx::Size size, GLenum target, ResourceFormat format); void Free(); void Leak(); diff --git a/chromium/cc/resources/scoped_resource_unittest.cc b/chromium/cc/resources/scoped_resource_unittest.cc index 8b59995f289..93ad3208b83 100644 --- a/chromium/cc/resources/scoped_resource_unittest.cc +++ b/chromium/cc/resources/scoped_resource_unittest.cc @@ -19,9 +19,9 @@ TEST(ScopedResourceTest, NewScopedResource) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); scoped_ptr<ScopedResource> texture = - ScopedResource::create(resource_provider.get()); + ScopedResource::Create(resource_provider.get()); // New scoped textures do not hold a texture yet. EXPECT_EQ(0u, texture->id()); @@ -37,9 +37,9 @@ TEST(ScopedResourceTest, CreateScopedResource) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); scoped_ptr<ScopedResource> texture = - ScopedResource::create(resource_provider.get()); + ScopedResource::Create(resource_provider.get()); texture->Allocate(gfx::Size(30, 30), ResourceProvider::TextureUsageAny, RGBA_8888); @@ -59,10 +59,10 @@ TEST(ScopedResourceTest, ScopedResourceIsDeleted) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); { scoped_ptr<ScopedResource> texture = - ScopedResource::create(resource_provider.get()); + ScopedResource::Create(resource_provider.get()); EXPECT_EQ(0u, resource_provider->num_resources()); texture->Allocate(gfx::Size(30, 30), @@ -75,7 +75,7 @@ TEST(ScopedResourceTest, ScopedResourceIsDeleted) { EXPECT_EQ(0u, resource_provider->num_resources()); { scoped_ptr<ScopedResource> texture = - ScopedResource::create(resource_provider.get()); + ScopedResource::Create(resource_provider.get()); EXPECT_EQ(0u, resource_provider->num_resources()); texture->Allocate(gfx::Size(30, 30), ResourceProvider::TextureUsageAny, @@ -93,10 +93,10 @@ TEST(ScopedResourceTest, LeakScopedResource) { CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<ResourceProvider> resource_provider( - ResourceProvider::Create(output_surface.get(), 0, false)); + ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1)); { scoped_ptr<ScopedResource> texture = - ScopedResource::create(resource_provider.get()); + ScopedResource::Create(resource_provider.get()); EXPECT_EQ(0u, resource_provider->num_resources()); texture->Allocate(gfx::Size(30, 30), diff --git a/chromium/cc/resources/shared_bitmap.cc b/chromium/cc/resources/shared_bitmap.cc new file mode 100644 index 00000000000..3a6fc3589e3 --- /dev/null +++ b/chromium/cc/resources/shared_bitmap.cc @@ -0,0 +1,17 @@ +// Copyright 2013 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 "cc/resources/shared_bitmap.h" + +namespace cc { + +SharedBitmap::SharedBitmap( + base::SharedMemory* memory, + const SharedBitmapId& id, + const base::Callback<void(SharedBitmap*)>& free_callback) + : memory_(memory), id_(id), free_callback_(free_callback) {} + +SharedBitmap::~SharedBitmap() { free_callback_.Run(this); } + +} // namespace cc diff --git a/chromium/cc/resources/shared_bitmap.h b/chromium/cc/resources/shared_bitmap.h new file mode 100644 index 00000000000..9575068411a --- /dev/null +++ b/chromium/cc/resources/shared_bitmap.h @@ -0,0 +1,51 @@ +// Copyright 2013 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 CC_RESOURCES_SHARED_BITMAP_H_ +#define CC_RESOURCES_SHARED_BITMAP_H_ + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/memory/shared_memory.h" +#include "cc/base/cc_export.h" +#include "gpu/command_buffer/common/mailbox.h" + +namespace base { class SharedMemory; } + +namespace cc { +typedef gpu::Mailbox SharedBitmapId; + +class CC_EXPORT SharedBitmap { + public: + SharedBitmap(base::SharedMemory* memory, + const SharedBitmapId& id, + const base::Callback<void(SharedBitmap*)>& free_callback); + + ~SharedBitmap(); + + bool operator<(const SharedBitmap& right) const { + if (memory_ < right.memory_) + return true; + if (memory_ > right.memory_) + return false; + return id_ < right.id_; + } + + uint8* pixels() { return static_cast<uint8*>(memory_->memory()); } + + base::SharedMemory* memory() { return memory_; } + + SharedBitmapId id() { return id_; } + + private: + base::SharedMemory* memory_; + SharedBitmapId id_; + base::Callback<void(SharedBitmap*)> free_callback_; + + DISALLOW_COPY_AND_ASSIGN(SharedBitmap); +}; + +} // namespace cc + +#endif // CC_RESOURCES_SHARED_BITMAP_H_ diff --git a/chromium/cc/resources/shared_bitmap_manager.h b/chromium/cc/resources/shared_bitmap_manager.h new file mode 100644 index 00000000000..53dd156470c --- /dev/null +++ b/chromium/cc/resources/shared_bitmap_manager.h @@ -0,0 +1,32 @@ +// Copyright 2013 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 CC_RESOURCES_SHARED_BITMAP_MANAGER_H_ +#define CC_RESOURCES_SHARED_BITMAP_MANAGER_H_ + +#include "base/basictypes.h" +#include "cc/base/cc_export.h" +#include "cc/resources/shared_bitmap.h" +#include "ui/gfx/size.h" + +namespace cc { + +class CC_EXPORT SharedBitmapManager { + public: + SharedBitmapManager() {} + + virtual scoped_ptr<SharedBitmap> AllocateSharedBitmap(gfx::Size) = 0; + virtual scoped_ptr<SharedBitmap> GetSharedBitmapFromId( + gfx::Size, + const SharedBitmapId&) = 0; + virtual scoped_ptr<SharedBitmap> GetBitmapForSharedMemory( + base::SharedMemory*) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(SharedBitmapManager); +}; + +} // namespace cc + +#endif // CC_RESOURCES_SHARED_BITMAP_MANAGER_H_ diff --git a/chromium/cc/resources/sync_point_helper.cc b/chromium/cc/resources/sync_point_helper.cc deleted file mode 100644 index f5822a41ae9..00000000000 --- a/chromium/cc/resources/sync_point_helper.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2013 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 "cc/resources/sync_point_helper.h" - -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" - -namespace cc { - -class SignalSyncPointCallbackClass - : public WebKit::WebGraphicsContext3D::WebGraphicsSyncPointCallback { - public: - explicit SignalSyncPointCallbackClass(const base::Closure& closure) - : closure_(closure) {} - - virtual void onSyncPointReached() { - if (!closure_.is_null()) - closure_.Run(); - } - - private: - base::Closure closure_; -}; - -void SyncPointHelper::SignalSyncPoint( - WebKit::WebGraphicsContext3D* context3d, - unsigned sync_point, - const base::Closure& closure) { - SignalSyncPointCallbackClass* callback_class = - new SignalSyncPointCallbackClass(closure); - - // Pass ownership of the CallbackClass to WebGraphicsContext3D. - context3d->signalSyncPoint(sync_point, callback_class); -} - -void SyncPointHelper::SignalQuery( - WebKit::WebGraphicsContext3D* context3d, - WebKit::WebGLId query, - const base::Closure& closure) { - SignalSyncPointCallbackClass* callback_class = - new SignalSyncPointCallbackClass(closure); - - // Pass ownership of the CallbackClass to WebGraphicsContext3D. - context3d->signalQuery(query, callback_class); -} - -} // namespace cc diff --git a/chromium/cc/resources/sync_point_helper.h b/chromium/cc/resources/sync_point_helper.h deleted file mode 100644 index e33a7f25364..00000000000 --- a/chromium/cc/resources/sync_point_helper.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2013 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 CC_RESOURCES_SYNC_POINT_HELPER_H_ -#define CC_RESOURCES_SYNC_POINT_HELPER_H_ - -#include "base/callback.h" -#include "cc/base/cc_export.h" - -namespace WebKit { class WebGraphicsContext3D; } - -namespace cc { - -class CC_EXPORT SyncPointHelper { - public: - // Requests a callback to |closure| when the |sync_point| is reached by the - // |context3d|. - // - // If the |context3d| is destroyed or lost before the callback fires, then - // AbortBecauseDidLoseOrDestroyContext() must be called to clean up the - // callback's resources. - static void SignalSyncPoint(WebKit::WebGraphicsContext3D* context3d, - unsigned sync_point, - const base::Closure& closure); - - // Requests a callback to |closure| when the results for |query| is available. - // - // If the |context3d| is destroyed or lost before the callback fires, then - // AbortBecauseDidLoseOrDestroyContext() must be called to clean up the - // callback's resources. - static void SignalQuery(WebKit::WebGraphicsContext3D* context3d, - unsigned int query, - const base::Closure& closure); - - private: - SyncPointHelper(); - - DISALLOW_COPY_AND_ASSIGN(SyncPointHelper); -}; - -} // namespace cc - -#endif // CC_RESOURCES_SYNC_POINT_HELPER_H_ diff --git a/chromium/cc/resources/texture_mailbox_deleter.cc b/chromium/cc/resources/texture_mailbox_deleter.cc index ae6df17691d..cf7b3b6107f 100644 --- a/chromium/cc/resources/texture_mailbox_deleter.cc +++ b/chromium/cc/resources/texture_mailbox_deleter.cc @@ -10,7 +10,7 @@ #include "base/message_loop/message_loop_proxy.h" #include "cc/output/context_provider.h" #include "cc/resources/single_release_callback.h" -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" +#include "gpu/command_buffer/client/gles2_interface.h" namespace cc { @@ -20,8 +20,8 @@ static void DeleteTextureOnImplThread( unsigned sync_point, bool is_lost) { if (sync_point) - context_provider->Context3d()->waitSyncPoint(sync_point); - context_provider->Context3d()->deleteTexture(texture_id); + context_provider->ContextGL()->WaitSyncPointCHROMIUM(sync_point); + context_provider->ContextGL()->DeleteTextures(1, &texture_id); } static void PostTaskFromMainToImplThread( diff --git a/chromium/cc/resources/texture_mailbox_deleter.h b/chromium/cc/resources/texture_mailbox_deleter.h index 072dcab375b..9b6d771c0f5 100644 --- a/chromium/cc/resources/texture_mailbox_deleter.h +++ b/chromium/cc/resources/texture_mailbox_deleter.h @@ -37,8 +37,8 @@ class CC_EXPORT TextureMailboxDeleter { unsigned sync_point, bool is_lost); - base::WeakPtrFactory<TextureMailboxDeleter> weak_ptr_factory_; ScopedPtrVector<SingleReleaseCallback> impl_callbacks_; + base::WeakPtrFactory<TextureMailboxDeleter> weak_ptr_factory_; }; } // namespace cc diff --git a/chromium/cc/resources/texture_mailbox_deleter_unittest.cc b/chromium/cc/resources/texture_mailbox_deleter_unittest.cc index a6ec48ed2ed..d08da84af90 100644 --- a/chromium/cc/resources/texture_mailbox_deleter_unittest.cc +++ b/chromium/cc/resources/texture_mailbox_deleter_unittest.cc @@ -4,9 +4,9 @@ #include "cc/resources/texture_mailbox_deleter.h" -#include "cc/debug/test_context_provider.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/resources/single_release_callback.h" +#include "cc/test/test_context_provider.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { diff --git a/chromium/cc/resources/tile.cc b/chromium/cc/resources/tile.cc index d7e1d2c2da2..209780679cb 100644 --- a/chromium/cc/resources/tile.cc +++ b/chromium/cc/resources/tile.cc @@ -21,26 +21,24 @@ Tile::Tile(TileManager* tile_manager, float contents_scale, int layer_id, int source_frame_number, - bool can_use_lcd_text) - : tile_manager_(tile_manager), + int flags) + : RefCountedManaged<Tile>(tile_manager), + tile_manager_(tile_manager), tile_size_(tile_size), content_rect_(content_rect), contents_scale_(contents_scale), opaque_rect_(opaque_rect), layer_id_(layer_id), source_frame_number_(source_frame_number), - can_use_lcd_text_(can_use_lcd_text), + flags_(flags), id_(s_next_id_++) { set_picture_pile(picture_pile); - tile_manager_->RegisterTile(this); } Tile::~Tile() { TRACE_EVENT_OBJECT_DELETED_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("cc.debug") "," - TRACE_DISABLED_BY_DEFAULT("cc.debug.quads"), + TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Tile", this); - tile_manager_->UnregisterTile(this); } void Tile::SetPriority(WhichTree tree, const TilePriority& priority) { @@ -61,7 +59,8 @@ void Tile::MarkRequiredForActivation() { scoped_ptr<base::Value> Tile::AsValue() const { scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); - TracedValue::MakeDictIntoImplicitSnapshot(res.get(), "cc::Tile", this); + TracedValue::MakeDictIntoImplicitSnapshotWithCategory( + TRACE_DISABLED_BY_DEFAULT("cc.debug"), res.get(), "cc::Tile", this); res->Set("picture_pile", TracedValue::CreateIDRef(picture_pile_.get()).release()); res->SetDouble("contents_scale", contents_scale_); @@ -70,6 +69,8 @@ scoped_ptr<base::Value> Tile::AsValue() const { res->Set("active_priority", priority_[ACTIVE_TREE].AsValue().release()); res->Set("pending_priority", priority_[PENDING_TREE].AsValue().release()); res->Set("managed_state", managed_state_.AsValue().release()); + res->SetBoolean("can_use_lcd_text", can_use_lcd_text()); + res->SetBoolean("use_gpu_rasterization", use_gpu_rasterization()); return res.PassAs<base::Value>(); } diff --git a/chromium/cc/resources/tile.h b/chromium/cc/resources/tile.h index 3caa407ae9c..e7c96360fe5 100644 --- a/chromium/cc/resources/tile.h +++ b/chromium/cc/resources/tile.h @@ -8,6 +8,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" +#include "cc/base/ref_counted_managed.h" #include "cc/resources/managed_tile_state.h" #include "cc/resources/raster_mode.h" #include "cc/resources/tile_priority.h" @@ -18,19 +19,14 @@ namespace cc { class PicturePileImpl; -class CC_EXPORT Tile : public base::RefCounted<Tile> { +class CC_EXPORT Tile : public RefCountedManaged<Tile> { public: - typedef uint64 Id; + enum TileRasterFlags { + USE_LCD_TEXT = 1 << 0, + USE_GPU_RASTERIZATION = 1 << 1 + }; - Tile(TileManager* tile_manager, - PicturePileImpl* picture_pile, - gfx::Size tile_size, - gfx::Rect content_rect, - gfx::Rect opaque_rect, - float contents_scale, - int layer_id, - int source_frame_number, - bool can_use_lcd_text); + typedef uint64 Id; Id id() const { return id_; @@ -62,11 +58,25 @@ class CC_EXPORT Tile : public base::RefCounted<Tile> { } void set_can_use_lcd_text(bool can_use_lcd_text) { - can_use_lcd_text_ = can_use_lcd_text; + if (can_use_lcd_text) + flags_ |= USE_LCD_TEXT; + else + flags_ &= ~USE_LCD_TEXT; } bool can_use_lcd_text() const { - return can_use_lcd_text_; + return !!(flags_ & USE_LCD_TEXT); + } + + void set_use_gpu_rasterization(bool use_gpu_rasterization) { + if (use_gpu_rasterization) + flags_ |= USE_GPU_RASTERIZATION; + else + flags_ &= ~USE_GPU_RASTERIZATION; + } + + bool use_gpu_rasterization() const { + return !!(flags_ & USE_GPU_RASTERIZATION); } scoped_ptr<base::Value> AsValue() const; @@ -116,18 +126,27 @@ class CC_EXPORT Tile : public base::RefCounted<Tile> { gfx::Size size() const { return tile_size_.size(); } private: - // Methods called by by tile manager. friend class TileManager; friend class PrioritizedTileSet; friend class FakeTileManager; friend class BinComparator; - ManagedTileState& managed_state() { return managed_state_; } - const ManagedTileState& managed_state() const { return managed_state_; } + friend class FakePictureLayerImpl; - // Normal private methods. - friend class base::RefCounted<Tile>; + // Methods called by by tile manager. + Tile(TileManager* tile_manager, + PicturePileImpl* picture_pile, + gfx::Size tile_size, + gfx::Rect content_rect, + gfx::Rect opaque_rect, + float contents_scale, + int layer_id, + int source_frame_number, + int flags); ~Tile(); + ManagedTileState& managed_state() { return managed_state_; } + const ManagedTileState& managed_state() const { return managed_state_; } + TileManager* tile_manager_; scoped_refptr<PicturePileImpl> picture_pile_; gfx::Rect tile_size_; @@ -139,7 +158,7 @@ class CC_EXPORT Tile : public base::RefCounted<Tile> { ManagedTileState managed_state_; int layer_id_; int source_frame_number_; - bool can_use_lcd_text_; + int flags_; Id id_; static Id s_next_id_; diff --git a/chromium/cc/resources/tile_manager.cc b/chromium/cc/resources/tile_manager.cc index b8cbdca1fa7..2fbb6d18913 100644 --- a/chromium/cc/resources/tile_manager.cc +++ b/chromium/cc/resources/tile_manager.cc @@ -12,7 +12,6 @@ #include "base/json/json_writer.h" #include "base/logging.h" #include "base/metrics/histogram.h" -#include "cc/debug/devtools_instrumentation.h" #include "cc/debug/traced_value.h" #include "cc/resources/image_raster_worker_pool.h" #include "cc/resources/pixel_buffer_raster_worker_pool.h" @@ -34,75 +33,121 @@ const ManagedTileBin kBinPolicyMap[NUM_TILE_MEMORY_LIMIT_POLICIES][NUM_BINS] = { NEVER_BIN, // [EVENTUALLY_BIN] NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN] NEVER_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] + NEVER_BIN }, { // [ALLOW_ABSOLUTE_MINIMUM] - NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NOW_BIN, // [NOW_BIN] + NOW_AND_READY_TO_DRAW_BIN, + NOW_BIN, NEVER_BIN, // [SOON_BIN] NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] NEVER_BIN, // [EVENTUALLY_BIN] NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN] NEVER_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] + NEVER_BIN }, { // [ALLOW_PREPAINT_ONLY] - NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NOW_BIN, // [NOW_BIN] - SOON_BIN, // [SOON_BIN] + NOW_AND_READY_TO_DRAW_BIN, + NOW_BIN, + SOON_BIN, NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] NEVER_BIN, // [EVENTUALLY_BIN] NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN] NEVER_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] + NEVER_BIN }, { // [ALLOW_ANYTHING] - NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NOW_BIN, // [NOW_BIN] - SOON_BIN, // [SOON_BIN] - EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] - EVENTUALLY_BIN, // [EVENTUALLY_BIN] - AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN] - AT_LAST_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] + NOW_AND_READY_TO_DRAW_BIN, + NOW_BIN, + SOON_BIN, + EVENTUALLY_AND_ACTIVE_BIN, + EVENTUALLY_BIN, + AT_LAST_AND_ACTIVE_BIN, + AT_LAST_BIN, + NEVER_BIN + } +}; + +// Ready to draw works by mapping NOW_BIN to NOW_AND_READY_TO_DRAW_BIN. +const ManagedTileBin kBinReadyToDrawMap[2][NUM_BINS] = { + { // Not ready + NOW_AND_READY_TO_DRAW_BIN, + NOW_BIN, + SOON_BIN, + EVENTUALLY_AND_ACTIVE_BIN, + EVENTUALLY_BIN, + AT_LAST_AND_ACTIVE_BIN, + AT_LAST_BIN, + NEVER_BIN + }, { // Ready + NOW_AND_READY_TO_DRAW_BIN, + NOW_AND_READY_TO_DRAW_BIN, // [NOW_BIN] + SOON_BIN, + EVENTUALLY_AND_ACTIVE_BIN, + EVENTUALLY_BIN, + AT_LAST_AND_ACTIVE_BIN, + AT_LAST_BIN, + NEVER_BIN + } +}; + +// Active works by mapping some bin stats to equivalent _ACTIVE_BIN state. +const ManagedTileBin kBinIsActiveMap[2][NUM_BINS] = { + { // Inactive + NOW_AND_READY_TO_DRAW_BIN, + NOW_BIN, + SOON_BIN, + EVENTUALLY_AND_ACTIVE_BIN, + EVENTUALLY_BIN, + AT_LAST_AND_ACTIVE_BIN, + AT_LAST_BIN, + NEVER_BIN + }, { // Active + NOW_AND_READY_TO_DRAW_BIN, + NOW_BIN, + SOON_BIN, + EVENTUALLY_AND_ACTIVE_BIN, + EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_BIN] + AT_LAST_AND_ACTIVE_BIN, + AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_BIN] + NEVER_BIN } }; // Determine bin based on three categories of tiles: things we need now, // things we need soon, and eventually. -inline ManagedTileBin BinFromTilePriority(const TilePriority& prio, - TreePriority tree_priority, - bool is_ready_to_draw, - bool is_active) { - // The amount of time for which we want to have prepainting coverage. +inline ManagedTileBin BinFromTilePriority(const TilePriority& prio) { + // The amount of time/pixels for which we want to have prepainting coverage. + // Note: All very arbitrary constants: metric-based tuning is welcome! const float kPrepaintingWindowTimeSeconds = 1.0f; const float kBackflingGuardDistancePixels = 314.0f; - - // Don't let low res tiles be in the now bin unless we're in a mode where - // we're prioritizing checkerboard prevention. - bool can_be_in_now_bin = tree_priority == SMOOTHNESS_TAKES_PRIORITY || - prio.resolution != LOW_RESOLUTION; + // Note: The max distances here assume that SOON_BIN will never help overcome + // raster being too slow (only caching in advance will do that), so we just + // need enough padding to handle some latency and per-tile variability. + const float kMaxPrepaintingDistancePixelsHighRes = 2000.0f; + const float kMaxPrepaintingDistancePixelsLowRes = 4000.0f; if (prio.distance_to_visible_in_pixels == std::numeric_limits<float>::infinity()) return NEVER_BIN; - if (can_be_in_now_bin && prio.time_to_visible_in_seconds == 0) - return is_ready_to_draw ? NOW_AND_READY_TO_DRAW_BIN : NOW_BIN; + if (prio.time_to_visible_in_seconds == 0) + return NOW_BIN; if (prio.resolution == NON_IDEAL_RESOLUTION) - return is_active ? EVENTUALLY_AND_ACTIVE_BIN : EVENTUALLY_BIN; + return EVENTUALLY_BIN; + + float max_prepainting_distance_pixels = + (prio.resolution == HIGH_RESOLUTION) + ? kMaxPrepaintingDistancePixelsHighRes + : kMaxPrepaintingDistancePixelsLowRes; + // Soon bin if we are within backfling-guard, or under both the time window + // and the max distance window. if (prio.distance_to_visible_in_pixels < kBackflingGuardDistancePixels || - prio.time_to_visible_in_seconds < kPrepaintingWindowTimeSeconds) + (prio.time_to_visible_in_seconds < kPrepaintingWindowTimeSeconds && + prio.distance_to_visible_in_pixels <= max_prepainting_distance_pixels)) return SOON_BIN; - return is_active ? EVENTUALLY_AND_ACTIVE_BIN : EVENTUALLY_BIN; + return EVENTUALLY_BIN; } -// Limit to the number of raster tasks that can be scheduled. -// This is high enough to not cause unnecessary scheduling but -// gives us an insurance that we're not spending a huge amount -// of time scheduling one enormous set of tasks. -const size_t kMaxRasterTasks = 256u; - } // namespace RasterTaskCompletionStats::RasterTaskCompletionStats() @@ -125,18 +170,23 @@ scoped_ptr<TileManager> TileManager::Create( size_t num_raster_threads, RenderingStatsInstrumentation* rendering_stats_instrumentation, bool use_map_image, - size_t max_transfer_buffer_usage_bytes) { + size_t max_transfer_buffer_usage_bytes, + size_t max_raster_usage_bytes, + GLenum map_image_texture_target) { return make_scoped_ptr( new TileManager(client, resource_provider, use_map_image ? ImageRasterWorkerPool::Create( - resource_provider, num_raster_threads) : + resource_provider, + num_raster_threads, + map_image_texture_target) : PixelBufferRasterWorkerPool::Create( resource_provider, num_raster_threads, max_transfer_buffer_usage_bytes), num_raster_threads, + max_raster_usage_bytes, rendering_stats_instrumentation)); } @@ -145,9 +195,13 @@ TileManager::TileManager( ResourceProvider* resource_provider, scoped_ptr<RasterWorkerPool> raster_worker_pool, size_t num_raster_threads, + size_t max_raster_usage_bytes, RenderingStatsInstrumentation* rendering_stats_instrumentation) : client_(client), - resource_pool_(ResourcePool::Create(resource_provider)), + resource_pool_(ResourcePool::Create( + resource_provider, + raster_worker_pool->GetResourceTarget(), + raster_worker_pool->GetResourceFormat())), raster_worker_pool_(raster_worker_pool.Pass()), prioritized_tiles_dirty_(false), all_tiles_that_need_to_be_rasterized_have_memory_(true), @@ -156,6 +210,7 @@ TileManager::TileManager( memory_nice_to_have_bytes_(0), bytes_releasable_(0), resources_releasable_(0), + max_raster_usage_bytes_(max_raster_usage_bytes), ever_exceeded_memory_budget_(false), rendering_stats_instrumentation_(rendering_stats_instrumentation), did_initialize_visible_tile_(false), @@ -168,6 +223,7 @@ TileManager::~TileManager() { // our memory usage to drop to zero. global_state_ = GlobalStateThatImpactsTilePriority(); + CleanUpReleasedTiles(); DCHECK_EQ(0u, tiles_.size()); RasterWorkerPool::RasterTask::Queue empty; @@ -182,56 +238,53 @@ TileManager::~TileManager() { DCHECK_EQ(0u, resources_releasable_); } -void TileManager::SetGlobalState( - const GlobalStateThatImpactsTilePriority& global_state) { - global_state_ = global_state; - resource_pool_->SetResourceUsageLimits( - global_state_.memory_limit_in_bytes, - global_state_.unused_memory_limit_in_bytes, - global_state_.num_resources_limit); +void TileManager::Release(Tile* tile) { + prioritized_tiles_dirty_ = true; + released_tiles_.push_back(tile); } -void TileManager::RegisterTile(Tile* tile) { - DCHECK(!tile->required_for_activation()); - DCHECK(tiles_.find(tile->id()) == tiles_.end()); - - tiles_[tile->id()] = tile; - used_layer_counts_[tile->layer_id()]++; +void TileManager::DidChangeTilePriority(Tile* tile) { prioritized_tiles_dirty_ = true; } -void TileManager::UnregisterTile(Tile* tile) { - FreeResourcesForTile(tile); +bool TileManager::ShouldForceTasksRequiredForActivationToComplete() const { + return global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY; +} - DCHECK(tiles_.find(tile->id()) != tiles_.end()); - tiles_.erase(tile->id()); +void TileManager::CleanUpReleasedTiles() { + for (std::vector<Tile*>::iterator it = released_tiles_.begin(); + it != released_tiles_.end(); + ++it) { + Tile* tile = *it; - LayerCountMap::iterator layer_it = used_layer_counts_.find(tile->layer_id()); - DCHECK_GT(layer_it->second, 0); - if (--layer_it->second == 0) { - used_layer_counts_.erase(layer_it); - image_decode_tasks_.erase(tile->layer_id()); - } + FreeResourcesForTile(tile); - prioritized_tiles_dirty_ = true; -} + DCHECK(tiles_.find(tile->id()) != tiles_.end()); + tiles_.erase(tile->id()); -void TileManager::DidChangeTilePriority(Tile* tile) { - prioritized_tiles_dirty_ = true; -} + LayerCountMap::iterator layer_it = + used_layer_counts_.find(tile->layer_id()); + DCHECK_GT(layer_it->second, 0); + if (--layer_it->second == 0) { + used_layer_counts_.erase(layer_it); + image_decode_tasks_.erase(tile->layer_id()); + } -bool TileManager::ShouldForceTasksRequiredForActivationToComplete() const { - return GlobalState().tree_priority != SMOOTHNESS_TAKES_PRIORITY; + delete tile; + } + + released_tiles_.clear(); } -PrioritizedTileSet* TileManager::GetPrioritizedTileSet() { +void TileManager::UpdatePrioritizedTileSetIfNeeded() { if (!prioritized_tiles_dirty_) - return &prioritized_tiles_; + return; + + CleanUpReleasedTiles(); prioritized_tiles_.Clear(); GetTilesWithAssignedBins(&prioritized_tiles_); prioritized_tiles_dirty_ = false; - return &prioritized_tiles_; } void TileManager::DidFinishRunningTasks() { @@ -246,7 +299,7 @@ void TileManager::DidFinishRunningTasks() { did_check_for_completed_tasks_since_last_schedule_tasks_ = true; TileVector tiles_that_need_to_be_rasterized; - AssignGpuMemoryToTiles(GetPrioritizedTileSet(), + AssignGpuMemoryToTiles(&prioritized_tiles_, &tiles_that_need_to_be_rasterized); // |tiles_that_need_to_be_rasterized| will be empty when we reach a @@ -318,44 +371,68 @@ void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet* tiles) { // Get the active priority and bin. TilePriority active_priority = tile->priority(ACTIVE_TREE); - ManagedTileBin active_bin = BinFromTilePriority( - active_priority, tree_priority, tile_is_ready_to_draw, tile_is_active); - mts.tree_bin[ACTIVE_TREE] = kBinPolicyMap[memory_policy][active_bin]; + ManagedTileBin active_bin = BinFromTilePriority(active_priority); // Get the pending priority and bin. TilePriority pending_priority = tile->priority(PENDING_TREE); - ManagedTileBin pending_bin = BinFromTilePriority( - pending_priority, tree_priority, tile_is_ready_to_draw, tile_is_active); - mts.tree_bin[PENDING_TREE] = kBinPolicyMap[memory_policy][pending_bin]; - - // Get the combined priority and bin. - TilePriority combined_priority = tile->combined_priority(); - ManagedTileBin combined_bin = BinFromTilePriority(combined_priority, - tree_priority, - tile_is_ready_to_draw, - tile_is_active); + ManagedTileBin pending_bin = BinFromTilePriority(pending_priority); + + bool pending_is_low_res = + pending_priority.resolution == LOW_RESOLUTION; + bool pending_is_non_ideal = + pending_priority.resolution == NON_IDEAL_RESOLUTION; + bool active_is_non_ideal = + active_priority.resolution == NON_IDEAL_RESOLUTION; + + // Adjust pending bin state for low res tiles. This prevents + // pending tree low-res tiles from being initialized before + // high-res tiles. + if (pending_is_low_res) + pending_bin = std::max(pending_bin, EVENTUALLY_BIN); + + // Adjust bin state based on if ready to draw. + active_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][active_bin]; + pending_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][pending_bin]; + + // Adjust bin state based on if active. + active_bin = kBinIsActiveMap[tile_is_active][active_bin]; + pending_bin = kBinIsActiveMap[tile_is_active][pending_bin]; + + // We never want to paint new non-ideal tiles, as we always have + // a high-res tile covering that content (paint that instead). + if (!tile_is_ready_to_draw && active_is_non_ideal) + active_bin = NEVER_BIN; + if (!tile_is_ready_to_draw && pending_is_non_ideal) + pending_bin = NEVER_BIN; + + // Compute combined bin. + ManagedTileBin combined_bin = std::min(active_bin, pending_bin); + + ManagedTileBin tree_bin[NUM_TREES]; + tree_bin[ACTIVE_TREE] = kBinPolicyMap[memory_policy][active_bin]; + tree_bin[PENDING_TREE] = kBinPolicyMap[memory_policy][pending_bin]; // The bin that the tile would have if the GPU memory manager had // a maximally permissive policy, send to the GPU memory manager // to determine policy. ManagedTileBin gpu_memmgr_stats_bin = NEVER_BIN; + TilePriority tile_priority; - TilePriority* high_priority = NULL; switch (tree_priority) { case SAME_PRIORITY_FOR_BOTH_TREES: mts.bin = kBinPolicyMap[memory_policy][combined_bin]; gpu_memmgr_stats_bin = combined_bin; - high_priority = &combined_priority; + tile_priority = tile->combined_priority(); break; case SMOOTHNESS_TAKES_PRIORITY: - mts.bin = mts.tree_bin[ACTIVE_TREE]; + mts.bin = tree_bin[ACTIVE_TREE]; gpu_memmgr_stats_bin = active_bin; - high_priority = &active_priority; + tile_priority = active_priority; break; case NEW_CONTENT_TAKES_PRIORITY: - mts.bin = mts.tree_bin[PENDING_TREE]; + mts.bin = tree_bin[PENDING_TREE]; gpu_memmgr_stats_bin = pending_bin; - high_priority = &pending_priority; + tile_priority = pending_priority; break; } @@ -370,22 +447,20 @@ void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet* tiles) { // Bump up the priority if we determined it's NEVER_BIN on one tree, // but is still required on the other tree. bool is_in_never_bin_on_both_trees = - mts.tree_bin[ACTIVE_TREE] == NEVER_BIN && - mts.tree_bin[PENDING_TREE] == NEVER_BIN; + tree_bin[ACTIVE_TREE] == NEVER_BIN && + tree_bin[PENDING_TREE] == NEVER_BIN; if (mts.bin == NEVER_BIN && !is_in_never_bin_on_both_trees) mts.bin = tile_is_active ? AT_LAST_AND_ACTIVE_BIN : AT_LAST_BIN; - DCHECK(high_priority != NULL); - - mts.resolution = high_priority->resolution; - mts.time_to_needed_in_seconds = high_priority->time_to_visible_in_seconds; + mts.resolution = tile_priority.resolution; + mts.time_to_needed_in_seconds = tile_priority.time_to_visible_in_seconds; mts.distance_to_visible_in_pixels = - high_priority->distance_to_visible_in_pixels; - mts.required_for_activation = high_priority->required_for_activation; + tile_priority.distance_to_visible_in_pixels; + mts.required_for_activation = tile_priority.required_for_activation; mts.visible_and_ready_to_draw = - mts.tree_bin[ACTIVE_TREE] == NOW_AND_READY_TO_DRAW_BIN; + tree_bin[ACTIVE_TREE] == NOW_AND_READY_TO_DRAW_BIN; if (mts.bin == NEVER_BIN) { FreeResourcesForTile(tile); @@ -406,9 +481,19 @@ void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet* tiles) { } } -void TileManager::ManageTiles() { +void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) { TRACE_EVENT0("cc", "TileManager::ManageTiles"); + // Update internal state. + if (state != global_state_) { + global_state_ = state; + prioritized_tiles_dirty_ = true; + resource_pool_->SetResourceUsageLimits( + global_state_.memory_limit_in_bytes, + global_state_.unused_memory_limit_in_bytes, + global_state_.num_resources_limit); + } + // We need to call CheckForCompletedTasks() once in-between each call // to ScheduleTasks() to prevent canceled tasks from being scheduled. if (!did_check_for_completed_tasks_since_last_schedule_tasks_) { @@ -416,8 +501,10 @@ void TileManager::ManageTiles() { did_check_for_completed_tasks_since_last_schedule_tasks_ = true; } + UpdatePrioritizedTileSetIfNeeded(); + TileVector tiles_that_need_to_be_rasterized; - AssignGpuMemoryToTiles(GetPrioritizedTileSet(), + AssignGpuMemoryToTiles(&prioritized_tiles_, &tiles_that_need_to_be_rasterized); // Finally, schedule rasterizer tasks. @@ -523,6 +610,13 @@ void TileManager::AssignGpuMemoryToTiles( TileVector* tiles_that_need_to_be_rasterized) { TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles"); + // Maintain the list of released resources that can potentially be re-used + // or deleted. + // If this operation becomes expensive too, only do this after some + // resource(s) was returned. Note that in that case, one also need to + // invalidate when releasing some resource from the pool. + resource_pool_->CheckBusyResources(); + // Now give memory out to the tiles until we're out, and build // the needs-to-be-rasterized queue. all_tiles_that_need_to_be_rasterized_have_memory_ = true; @@ -547,6 +641,14 @@ void TileManager::AssignGpuMemoryToTiles( size_t resources_left = resources_allocatable; bool oomed = false; + // Memory we assign to raster tasks now will be deducted from our memory + // in future iterations if priorities change. By assigning at most half + // the raster limit, we will always have another 50% left even if priorities + // change completely (assuming we check for completed/cancelled rasters + // between each call to this function). + size_t max_raster_bytes = max_raster_usage_bytes_ / 2; + size_t raster_bytes = 0; + unsigned schedule_priority = 1u; for (PrioritizedTileSet::Iterator it(tiles, true); it; @@ -571,13 +673,16 @@ void TileManager::AssignGpuMemoryToTiles( continue; } + size_t bytes_if_allocated = BytesConsumedIfAllocated(tile); + size_t raster_bytes_if_rastered = raster_bytes + bytes_if_allocated; + size_t tile_bytes = 0; size_t tile_resources = 0; // It costs to maintain a resource. for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { if (mts.tile_versions[mode].resource_) { - tile_bytes += BytesConsumedIfAllocated(tile); + tile_bytes += bytes_if_allocated; tile_resources++; } } @@ -585,11 +690,11 @@ void TileManager::AssignGpuMemoryToTiles( // Allow lower priority tiles with initialized resources to keep // their memory by only assigning memory to new raster tasks if // they can be scheduled. - if (tiles_that_need_to_be_rasterized->size() < kMaxRasterTasks) { + if (raster_bytes_if_rastered <= max_raster_bytes) { // If we don't have the required version, and it's not in flight // then we'll have to pay to create a new task. if (!tile_version.resource_ && tile_version.raster_task_.is_null()) { - tile_bytes += BytesConsumedIfAllocated(tile); + tile_bytes += bytes_if_allocated; tile_resources++; } } @@ -624,7 +729,7 @@ void TileManager::AssignGpuMemoryToTiles( // 1. Tile size should not impact raster priority. // 2. Tiles with existing raster task could otherwise incorrectly // be added as they are not affected by |bytes_allocatable|. - if (oomed || tiles_that_need_to_be_rasterized->size() >= kMaxRasterTasks) { + if (oomed || raster_bytes_if_rastered > max_raster_bytes) { all_tiles_that_need_to_be_rasterized_have_memory_ = false; if (tile->required_for_activation()) all_tiles_required_for_activation_have_memory_ = false; @@ -632,6 +737,7 @@ void TileManager::AssignGpuMemoryToTiles( continue; } + raster_bytes = raster_bytes_if_rastered; tiles_that_need_to_be_rasterized->push_back(tile); } @@ -742,11 +848,9 @@ RasterWorkerPool::Task TileManager::CreateImageDecodeTask( RasterWorkerPool::RasterTask TileManager::CreateRasterTask(Tile* tile) { ManagedTileState& mts = tile->managed_state(); - scoped_ptr<ResourcePool::Resource> resource = - resource_pool_->AcquireResource( - tile->tile_size_.size(), - raster_worker_pool_->GetResourceFormat()); - const Resource* const_resource = resource.get(); + scoped_ptr<ScopedResource> resource = + resource_pool_->AcquireResource(tile->tile_size_.size()); + const ScopedResource* const_resource = resource.get(); // Create and queue all image decode tasks that this tile depends on. RasterWorkerPool::Task::Set decode_tasks; @@ -778,7 +882,6 @@ RasterWorkerPool::RasterTask TileManager::CreateRasterTask(Tile* tile) { tile->content_rect(), tile->contents_scale(), mts.raster_mode, - mts.tree_bin[PENDING_TREE] == NOW_BIN, mts.resolution, tile->layer_id(), static_cast<const void *>(tile), @@ -817,7 +920,7 @@ void TileManager::OnImageDecodeTaskCompleted( void TileManager::OnRasterTaskCompleted( Tile::Id tile_id, - scoped_ptr<ResourcePool::Resource> resource, + scoped_ptr<ScopedResource> resource, RasterMode raster_mode, const PicturePileImpl::Analysis& analysis, bool was_canceled) { @@ -860,4 +963,29 @@ void TileManager::OnRasterTaskCompleted( did_initialize_visible_tile_ = true; } +scoped_refptr<Tile> TileManager::CreateTile(PicturePileImpl* picture_pile, + gfx::Size tile_size, + gfx::Rect content_rect, + gfx::Rect opaque_rect, + float contents_scale, + int layer_id, + int source_frame_number, + int flags) { + scoped_refptr<Tile> tile = make_scoped_refptr(new Tile(this, + picture_pile, + tile_size, + content_rect, + opaque_rect, + contents_scale, + layer_id, + source_frame_number, + flags)); + DCHECK(tiles_.find(tile->id()) == tiles_.end()); + + tiles_[tile->id()] = tile; + used_layer_counts_[tile->layer_id()]++; + prioritized_tiles_dirty_ = true; + return tile; +} + } // namespace cc diff --git a/chromium/cc/resources/tile_manager.h b/chromium/cc/resources/tile_manager.h index 3f262bcf28d..78beb1b15fb 100644 --- a/chromium/cc/resources/tile_manager.h +++ b/chromium/cc/resources/tile_manager.h @@ -12,6 +12,7 @@ #include "base/containers/hash_tables.h" #include "base/memory/scoped_ptr.h" #include "base/values.h" +#include "cc/base/ref_counted_managed.h" #include "cc/debug/rendering_stats_instrumentation.h" #include "cc/resources/managed_tile_state.h" #include "cc/resources/memory_history.h" @@ -45,7 +46,8 @@ scoped_ptr<base::Value> RasterTaskCompletionStatsAsValue( // should no longer have any memory assigned to them. Tile objects are "owned" // by layers; they automatically register with the manager when they are // created, and unregister from the manager when they are deleted. -class CC_EXPORT TileManager : public RasterWorkerPoolClient { +class CC_EXPORT TileManager : public RasterWorkerPoolClient, + public RefCountedManager<Tile> { public: static scoped_ptr<TileManager> Create( TileManagerClient* client, @@ -53,19 +55,25 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient { size_t num_raster_threads, RenderingStatsInstrumentation* rendering_stats_instrumentation, bool use_map_image, - size_t max_transfer_buffer_usage_bytes); + size_t max_transfer_buffer_usage_bytes, + size_t max_raster_usage_bytes, + GLenum map_image_texture_target); virtual ~TileManager(); - const GlobalStateThatImpactsTilePriority& GlobalState() const { - return global_state_; - } - void SetGlobalState(const GlobalStateThatImpactsTilePriority& state); - - void ManageTiles(); + void ManageTiles(const GlobalStateThatImpactsTilePriority& state); // Returns true when visible tiles have been initialized. bool UpdateVisibleTiles(); + scoped_refptr<Tile> CreateTile(PicturePileImpl* picture_pile, + gfx::Size tile_size, + gfx::Rect content_rect, + gfx::Rect opaque_rect, + float contents_scale, + int layer_id, + int source_frame_number, + int flags); + scoped_ptr<base::Value> BasicStateAsValue() const; scoped_ptr<base::Value> AllTilesAsValue() const; void GetMemoryStats(size_t* memory_required_bytes, @@ -85,10 +93,8 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient { ManagedTileState::TileVersion& tile_version = mts.tile_versions[HIGH_QUALITY_NO_LCD_RASTER_MODE]; - tile_version.resource_ = make_scoped_ptr( - new ResourcePool::Resource(resource_provider, - gfx::Size(1, 1), - resource_provider->best_texture_format())); + tile_version.resource_ = resource_pool_->AcquireResource( + gfx::Size(1, 1)); bytes_releasable_ += BytesConsumedIfAllocated(tiles[i]); ++resources_releasable_; @@ -98,19 +104,35 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient { return raster_worker_pool_.get(); } + void SetGlobalStateForTesting( + const GlobalStateThatImpactsTilePriority& state) { + if (state != global_state_) { + global_state_ = state; + prioritized_tiles_dirty_ = true; + resource_pool_->SetResourceUsageLimits( + global_state_.memory_limit_in_bytes, + global_state_.unused_memory_limit_in_bytes, + global_state_.num_resources_limit); + } + } + protected: TileManager(TileManagerClient* client, ResourceProvider* resource_provider, scoped_ptr<RasterWorkerPool> raster_worker_pool, size_t num_raster_threads, + size_t max_raster_usage_bytes, RenderingStatsInstrumentation* rendering_stats_instrumentation); // Methods called by Tile friend class Tile; - void RegisterTile(Tile* tile); - void UnregisterTile(Tile* tile); void DidChangeTilePriority(Tile* tile); + void CleanUpReleasedTiles(); + + // Overriden from RefCountedManager<Tile>: + virtual void Release(Tile* tile) OVERRIDE; + // Overriden from RasterWorkerPoolClient: virtual bool ShouldForceTasksRequiredForActivationToComplete() const OVERRIDE; @@ -134,12 +156,11 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient { int layer_id, skia::LazyPixelRef* pixel_ref, bool was_canceled); - void OnRasterTaskCompleted( - Tile::Id tile, - scoped_ptr<ResourcePool::Resource> resource, - RasterMode raster_mode, - const PicturePileImpl::Analysis& analysis, - bool was_canceled); + void OnRasterTaskCompleted(Tile::Id tile, + scoped_ptr<ScopedResource> resource, + RasterMode raster_mode, + const PicturePileImpl::Analysis& analysis, + bool was_canceled); inline size_t BytesConsumedIfAllocated(const Tile* tile) const { return Resource::MemorySizeBytes(tile->size(), @@ -154,7 +175,7 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient { Tile* tile, skia::LazyPixelRef* pixel_ref); RasterWorkerPool::RasterTask CreateRasterTask(Tile* tile); scoped_ptr<base::Value> GetMemoryRequirementsAsValue() const; - PrioritizedTileSet* GetPrioritizedTileSet(); + void UpdatePrioritizedTileSetIfNeeded(); TileManagerClient* client_; scoped_ptr<ResourcePool> resource_pool_; @@ -175,6 +196,7 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient { size_t bytes_releasable_; size_t resources_releasable_; + size_t max_raster_usage_bytes_; bool ever_exceeded_memory_budget_; MemoryHistory::Entry memory_stats_from_last_assign_; @@ -193,6 +215,8 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient { RasterTaskCompletionStats update_visible_tiles_stats_; + std::vector<Tile*> released_tiles_; + DISALLOW_COPY_AND_ASSIGN(TileManager); }; diff --git a/chromium/cc/resources/tile_manager_perftest.cc b/chromium/cc/resources/tile_manager_perftest.cc index 99d16a187e7..9a651a2afa4 100644 --- a/chromium/cc/resources/tile_manager_perftest.cc +++ b/chromium/cc/resources/tile_manager_perftest.cc @@ -40,10 +40,16 @@ class TileManagerPerfTest : public testing::Test { CHECK(output_surface_->BindToClient(&output_surface_client_)); resource_provider_ = - ResourceProvider::Create(output_surface_.get(), 0, false); + ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1); + size_t raster_task_limit_bytes = 32 * 1024 * 1024; // 16-64MB in practice. tile_manager_ = make_scoped_ptr( - new FakeTileManager(&tile_manager_client_, resource_provider_.get())); + new FakeTileManager(&tile_manager_client_, + resource_provider_.get(), + raster_task_limit_bytes)); + picture_pile_ = FakePicturePileImpl::CreatePile(); + } + GlobalStateThatImpactsTilePriority GlobalStateForTest() { GlobalStateThatImpactsTilePriority state; gfx::Size tile_size = settings_.default_tile_size; state.memory_limit_in_bytes = @@ -52,9 +58,7 @@ class TileManagerPerfTest : public testing::Test { state.num_resources_limit = 10000; state.memory_limit_policy = ALLOW_ANYTHING; state.tree_priority = SMOOTHNESS_TAKES_PRIORITY; - - tile_manager_->SetGlobalState(state); - picture_pile_ = FakePicturePileImpl::CreatePile(); + return state; } virtual void TearDown() OVERRIDE { @@ -105,15 +109,14 @@ class TileManagerPerfTest : public testing::Test { void CreateBinTiles(int count, ManagedTileBin bin, TileBinVector* tiles) { for (int i = 0; i < count; ++i) { scoped_refptr<Tile> tile = - make_scoped_refptr(new Tile(tile_manager_.get(), - picture_pile_.get(), - settings_.default_tile_size, - gfx::Rect(), - gfx::Rect(), - 1.0, - 0, - 0, - true)); + tile_manager_->CreateTile(picture_pile_.get(), + settings_.default_tile_size, + gfx::Rect(), + gfx::Rect(), + 1.0, + 0, + 0, + Tile::USE_LCD_TEXT); tile->SetPriority(ACTIVE_TREE, GetTilePriorityFromBin(bin)); tile->SetPriority(PENDING_TREE, GetTilePriorityFromBin(bin)); tiles->push_back(std::make_pair(tile, bin)); @@ -151,7 +154,7 @@ class TileManagerPerfTest : public testing::Test { } } - tile_manager_->ManageTiles(); + tile_manager_->ManageTiles(GlobalStateForTest()); tile_manager_->CheckForCompletedTasks(); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); diff --git a/chromium/cc/resources/tile_manager_unittest.cc b/chromium/cc/resources/tile_manager_unittest.cc index 0274914a324..8339bd07b0a 100644 --- a/chromium/cc/resources/tile_manager_unittest.cc +++ b/chromium/cc/resources/tile_manager_unittest.cc @@ -26,7 +26,7 @@ class TileManagerTest : public testing::TestWithParam<bool> { CHECK(output_surface_->BindToClient(&output_surface_client_)); resource_provider_ = - ResourceProvider::Create(output_surface_.get(), 0, false); + ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1); tile_manager_ = make_scoped_ptr( new FakeTileManager(&tile_manager_client_, resource_provider_.get())); @@ -49,7 +49,8 @@ class TileManagerTest : public testing::TestWithParam<bool> { state.memory_limit_policy = memory_limit_policy; state.tree_priority = tree_priority; - tile_manager_->SetGlobalState(state); + global_state_ = state; + tile_manager_->SetGlobalStateForTesting(state); picture_pile_ = FakePicturePileImpl::CreatePile(); } @@ -62,7 +63,7 @@ class TileManagerTest : public testing::TestWithParam<bool> { state.memory_limit_policy = memory_limit_policy_; state.num_resources_limit = 100; state.tree_priority = tree_priority; - tile_manager_->SetGlobalState(state); + global_state_ = state; } virtual void TearDown() OVERRIDE { @@ -78,16 +79,14 @@ class TileManagerTest : public testing::TestWithParam<bool> { gfx::Size tile_size) { TileVector tiles; for (int i = 0; i < count; ++i) { - scoped_refptr<Tile> tile = - make_scoped_refptr(new Tile(tile_manager_.get(), - picture_pile_.get(), - tile_size, - gfx::Rect(), - gfx::Rect(), - 1.0, - 0, - 0, - true)); + scoped_refptr<Tile> tile = tile_manager_->CreateTile(picture_pile_.get(), + tile_size, + gfx::Rect(), + gfx::Rect(), + 1.0, + 0, + 0, + Tile::USE_LCD_TEXT); tile->SetPriority(ACTIVE_TREE, active_priority); tile->SetPriority(PENDING_TREE, pending_priority); tiles.push_back(tile); @@ -130,6 +129,9 @@ class TileManagerTest : public testing::TestWithParam<bool> { return has_lcd_count; } + protected: + GlobalStateThatImpactsTilePriority global_state_; + private: FakeTileManagerClient tile_manager_client_; LayerTreeSettings settings_; @@ -154,7 +156,7 @@ TEST_P(TileManagerTest, EnoughMemoryAllowAnything) { 3, TilePriorityForSoonBin(), TilePriorityForSoonBin()); TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority()); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(3, AssignedMemoryCount(active_now)); EXPECT_EQ(3, AssignedMemoryCount(pending_now)); @@ -175,7 +177,7 @@ TEST_P(TileManagerTest, EnoughMemoryAllowPrepaintOnly) { 3, TilePriorityForSoonBin(), TilePriorityForSoonBin()); TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority()); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(3, AssignedMemoryCount(active_now)); EXPECT_EQ(3, AssignedMemoryCount(pending_now)); @@ -196,7 +198,7 @@ TEST_P(TileManagerTest, EnoughMemoryAllowAbsoluteMinimum) { 3, TilePriorityForSoonBin(), TilePriorityForSoonBin()); TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority()); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(3, AssignedMemoryCount(active_now)); EXPECT_EQ(3, AssignedMemoryCount(pending_now)); @@ -217,7 +219,7 @@ TEST_P(TileManagerTest, EnoughMemoryAllowNothing) { 3, TilePriorityForSoonBin(), TilePriorityForSoonBin()); TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority()); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(0, AssignedMemoryCount(active_now)); EXPECT_EQ(0, AssignedMemoryCount(pending_now)); @@ -237,13 +239,13 @@ TEST_P(TileManagerTest, PartialOOMMemoryToPending) { TileVector pending_tree_tiles = CreateTiles(5, TilePriority(), TilePriorityRequiredForActivation()); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(5, AssignedMemoryCount(active_tree_tiles)); EXPECT_EQ(3, AssignedMemoryCount(pending_tree_tiles)); SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(3, AssignedMemoryCount(active_tree_tiles)); EXPECT_EQ(5, AssignedMemoryCount(pending_tree_tiles)); @@ -260,7 +262,7 @@ TEST_P(TileManagerTest, PartialOOMMemoryToActive) { TileVector pending_tree_tiles = CreateTiles(5, TilePriority(), TilePriorityForNowBin()); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(5, AssignedMemoryCount(active_tree_tiles)); EXPECT_EQ(3, AssignedMemoryCount(pending_tree_tiles)); @@ -278,13 +280,13 @@ TEST_P(TileManagerTest, TotalOOMMemoryToPending) { TileVector pending_tree_tiles = CreateTiles(5, TilePriority(), TilePriorityRequiredForActivation()); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles)); EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles)); SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles)); EXPECT_EQ(4, AssignedMemoryCount(pending_tree_tiles)); @@ -302,13 +304,13 @@ TEST_P(TileManagerTest, TotalOOMActiveSoonMemoryToPending) { TileVector pending_tree_tiles = CreateTiles(5, TilePriority(), TilePriorityRequiredForActivation()); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles)); EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles)); SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles)); EXPECT_EQ(4, AssignedMemoryCount(pending_tree_tiles)); @@ -325,7 +327,7 @@ TEST_P(TileManagerTest, TotalOOMMemoryToActive) { TileVector pending_tree_tiles = CreateTiles(5, TilePriority(), TilePriorityForNowBin()); - tile_manager()->AssignMemoryToTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles)); EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles)); @@ -340,7 +342,7 @@ TEST_P(TileManagerTest, RasterAsLCD) { TileVector pending_tree_tiles = CreateTiles(5, TilePriority(), TilePriorityForNowBin()); - tile_manager()->ManageTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles)); EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles)); @@ -364,7 +366,7 @@ TEST_P(TileManagerTest, RasterAsNoLCD) { (*it)->set_can_use_lcd_text(false); } - tile_manager()->ManageTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(0, TilesWithLCDCount(active_tree_tiles)); EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles)); @@ -377,7 +379,7 @@ TEST_P(TileManagerTest, ReRasterAsNoLCD) { TileVector pending_tree_tiles = CreateTiles(5, TilePriority(), TilePriorityForNowBin()); - tile_manager()->ManageTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles)); EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles)); @@ -393,7 +395,7 @@ TEST_P(TileManagerTest, ReRasterAsNoLCD) { (*it)->set_can_use_lcd_text(false); } - tile_manager()->ManageTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(0, TilesWithLCDCount(active_tree_tiles)); EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles)); @@ -406,7 +408,7 @@ TEST_P(TileManagerTest, NoTextDontReRasterAsNoLCD) { TileVector pending_tree_tiles = CreateTiles(5, TilePriority(), TilePriorityForNowBin()); - tile_manager()->ManageTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles)); EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles)); @@ -430,7 +432,7 @@ TEST_P(TileManagerTest, NoTextDontReRasterAsNoLCD) { EXPECT_TRUE((*it)->IsReadyToDraw()); } - tile_manager()->ManageTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles)); EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles)); @@ -443,7 +445,7 @@ TEST_P(TileManagerTest, TextReRasterAsNoLCD) { TileVector pending_tree_tiles = CreateTiles(5, TilePriority(), TilePriorityForNowBin()); - tile_manager()->ManageTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles)); EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles)); @@ -472,7 +474,7 @@ TEST_P(TileManagerTest, TextReRasterAsNoLCD) { EXPECT_TRUE((*it)->IsReadyToDraw()); } - tile_manager()->ManageTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); EXPECT_EQ(0, TilesWithLCDCount(active_tree_tiles)); EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles)); @@ -488,20 +490,19 @@ TEST_P(TileManagerTest, RespectMemoryLimit) { size_t memory_allocated_bytes; size_t memory_used_bytes; - tile_manager()->ManageTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); tile_manager()->GetMemoryStats(&memory_required_bytes, &memory_nice_to_have_bytes, &memory_allocated_bytes, &memory_used_bytes); // Allocated bytes should never be more than the memory limit. - EXPECT_LE(memory_allocated_bytes, - tile_manager()->GlobalState().memory_limit_in_bytes); + EXPECT_LE(memory_allocated_bytes, global_state_.memory_limit_in_bytes); // Finish raster of large tiles. tile_manager()->UpdateVisibleTiles(); // Remove all large tiles. This will leave the memory currently - // used by these tiles as unused when ManageTiles() is called. + // used by these tiles as unused when AssignMemoryToTiles() is called. large_tiles.clear(); // Create a new set of tiles using a different size. These tiles @@ -510,14 +511,13 @@ TEST_P(TileManagerTest, RespectMemoryLimit) { TileVector small_tiles = CreateTilesWithSize( 5, TilePriorityForNowBin(), TilePriority(), gfx::Size(128, 128)); - tile_manager()->ManageTiles(); + tile_manager()->AssignMemoryToTiles(global_state_); tile_manager()->GetMemoryStats(&memory_required_bytes, &memory_nice_to_have_bytes, &memory_allocated_bytes, &memory_used_bytes); // Allocated bytes should never be more than the memory limit. - EXPECT_LE(memory_allocated_bytes, - tile_manager()->GlobalState().memory_limit_in_bytes); + EXPECT_LE(memory_allocated_bytes, global_state_.memory_limit_in_bytes); } // If true, the max tile limit should be applied as bytes; if false, diff --git a/chromium/cc/resources/tile_priority.cc b/chromium/cc/resources/tile_priority.cc index eeb87cdcbbc..9cf4634f7d5 100644 --- a/chromium/cc/resources/tile_priority.cc +++ b/chromium/cc/resources/tile_priority.cc @@ -18,14 +18,6 @@ struct Range { float end_; }; -inline bool Intersects(const Range& a, const Range& b) { - return a.start_ < b.end_ && b.start_ < a.end_; -} - -inline Range Intersect(const Range& a, const Range& b) { - return Range(std::max(a.start_, b.start_), std::min(a.end_, b.end_)); -} - bool Range::IsEmpty() { return start_ >= end_; } diff --git a/chromium/cc/resources/tile_priority.h b/chromium/cc/resources/tile_priority.h index e613dd77b04..0052e40ddce 100644 --- a/chromium/cc/resources/tile_priority.h +++ b/chromium/cc/resources/tile_priority.h @@ -75,26 +75,9 @@ struct CC_EXPORT TilePriority { std::min(active.distance_to_visible_in_pixels, pending.distance_to_visible_in_pixels); } - void set_current_screen_quad(const gfx::QuadF& q) { current_screen_quad = q; } scoped_ptr<base::Value> AsValue() const; - static inline float manhattanDistance(const gfx::RectF& a, - const gfx::RectF& b) { - // Compute the union explicitly. - gfx::RectF c = gfx::RectF( - std::min(a.x(), b.x()), - std::min(a.y(), b.y()), - std::max(a.right(), b.right()) - std::min(a.x(), b.x()), - std::max(a.bottom(), b.bottom()) - std::min(a.y(), b.y())); - - // Rects touching the edge of the screen should not be considered visible. - // So we add 1 pixel here to avoid that situation. - float x = std::max(0.0f, c.width() - a.width() - b.width() + 1.0f); - float y = std::max(0.0f, c.height() - a.height() - b.height() + 1.0f); - return (x + y); - } - // Calculate the time for the |current_bounds| to intersect with the // |target_bounds| given its previous location and time delta. // This function should work for both scaling and scrolling case. @@ -108,8 +91,6 @@ struct CC_EXPORT TilePriority { time_to_visible_in_seconds == other.time_to_visible_in_seconds && distance_to_visible_in_pixels == other.distance_to_visible_in_pixels && required_for_activation == other.required_for_activation; - // No need to compare current_screen_quad which is for debug only and - // never changes by itself. } bool operator !=(const TilePriority& other) const { @@ -120,9 +101,6 @@ struct CC_EXPORT TilePriority { bool required_for_activation; float time_to_visible_in_seconds; float distance_to_visible_in_pixels; - - private: - gfx::QuadF current_screen_quad; }; enum TileMemoryLimitPolicy { @@ -172,6 +150,17 @@ class GlobalStateThatImpactsTilePriority { TreePriority tree_priority; + bool operator==(const GlobalStateThatImpactsTilePriority& other) const { + return memory_limit_policy == other.memory_limit_policy + && memory_limit_in_bytes == other.memory_limit_in_bytes + && unused_memory_limit_in_bytes == other.unused_memory_limit_in_bytes + && num_resources_limit == other.num_resources_limit + && tree_priority == other.tree_priority; + } + bool operator!=(const GlobalStateThatImpactsTilePriority& other) const { + return !(*this == other); + } + scoped_ptr<base::Value> AsValue() const; }; diff --git a/chromium/cc/resources/tile_priority_unittest.cc b/chromium/cc/resources/tile_priority_unittest.cc index 97de199b094..0f4c6717aff 100644 --- a/chromium/cc/resources/tile_priority_unittest.cc +++ b/chromium/cc/resources/tile_priority_unittest.cc @@ -49,19 +49,5 @@ TEST(TilePriorityTest, TimeForBoundsToIntersectWithScale) { gfx::Rect(-450, -450, 50, 50), current, 1, target)); } -TEST(TilePriorityTest, ManhattanDistanceBetweenRects) { - EXPECT_EQ(0, TilePriority::manhattanDistance( - gfx::RectF(0, 0, 400, 400), gfx::RectF(0, 0, 100, 100))); - - EXPECT_EQ(2, TilePriority::manhattanDistance( - gfx::Rect(0, 0, 400, 400), gfx::Rect(-100, -100, 100, 100))); - - EXPECT_EQ(1, TilePriority::manhattanDistance( - gfx::Rect(0, 0, 400, 400), gfx::Rect(0, -100, 100, 100))); - - EXPECT_EQ(202, TilePriority::manhattanDistance( - gfx::Rect(0, 0, 100, 100), gfx::Rect(200, 200, 100, 100))); -} - } // namespace } // namespace cc diff --git a/chromium/cc/resources/transferable_resource.cc b/chromium/cc/resources/transferable_resource.cc index 1b8930f34ad..62f1bdb1641 100644 --- a/chromium/cc/resources/transferable_resource.cc +++ b/chromium/cc/resources/transferable_resource.cc @@ -12,8 +12,9 @@ TransferableResource::TransferableResource() : id(0), sync_point(0), format(RGBA_8888), - filter(0) { -} + target(0), + filter(0), + is_software(false) {} TransferableResource::~TransferableResource() { } diff --git a/chromium/cc/resources/transferable_resource.h b/chromium/cc/resources/transferable_resource.h index 0ea62436991..5c93d1c042f 100644 --- a/chromium/cc/resources/transferable_resource.h +++ b/chromium/cc/resources/transferable_resource.h @@ -31,9 +31,11 @@ struct CC_EXPORT TransferableResource { unsigned id; unsigned sync_point; ResourceFormat format; + uint32 target; uint32 filter; gfx::Size size; gpu::Mailbox mailbox; + bool is_software; }; } // namespace cc diff --git a/chromium/cc/resources/ui_resource_bitmap.cc b/chromium/cc/resources/ui_resource_bitmap.cc index 86acfa5185c..b813d973537 100644 --- a/chromium/cc/resources/ui_resource_bitmap.cc +++ b/chromium/cc/resources/ui_resource_bitmap.cc @@ -6,26 +6,29 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "cc/resources/etc1_pixel_ref.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkPixelRef.h" namespace cc { void UIResourceBitmap::Create(const skia::RefPtr<SkPixelRef>& pixel_ref, UIResourceFormat format, - UIResourceWrapMode wrap_mode, gfx::Size size) { DCHECK(size.width()); DCHECK(size.height()); DCHECK(pixel_ref); DCHECK(pixel_ref->isImmutable()); format_ = format; - wrap_mode_ = wrap_mode; size_ = size; pixel_ref_ = pixel_ref; + + // Default values for secondary parameters. + wrap_mode_ = CLAMP_TO_EDGE; + opaque_ = (format == ETC1); } -UIResourceBitmap::UIResourceBitmap(const SkBitmap& skbitmap, - UIResourceWrapMode wrap_mode) { +UIResourceBitmap::UIResourceBitmap(const SkBitmap& skbitmap) { DCHECK_EQ(skbitmap.config(), SkBitmap::kARGB_8888_Config); DCHECK_EQ(skbitmap.width(), skbitmap.rowBytesAsPixels()); DCHECK(skbitmap.isImmutable()); @@ -33,8 +36,15 @@ UIResourceBitmap::UIResourceBitmap(const SkBitmap& skbitmap, skia::RefPtr<SkPixelRef> pixel_ref = skia::SharePtr(skbitmap.pixelRef()); Create(pixel_ref, UIResourceBitmap::RGBA8, - wrap_mode, gfx::Size(skbitmap.width(), skbitmap.height())); + + SetOpaque(skbitmap.isOpaque()); +} + +UIResourceBitmap::UIResourceBitmap( + const skia::RefPtr<ETC1PixelRef>& etc1_pixel_ref, + gfx::Size size) { + Create(etc1_pixel_ref, ETC1, size); } UIResourceBitmap::~UIResourceBitmap() {} diff --git a/chromium/cc/resources/ui_resource_bitmap.h b/chromium/cc/resources/ui_resource_bitmap.h index 78cb4658125..ea54f613b10 100644 --- a/chromium/cc/resources/ui_resource_bitmap.h +++ b/chromium/cc/resources/ui_resource_bitmap.h @@ -17,14 +17,17 @@ class SkBitmap; namespace cc { -// A bitmap class that contains a ref-counted reference to a SkPixelRef* that +class ETC1PixelRef; + +// A bitmap class that contains a ref-counted reference to a SkPixelRef that // holds the content of the bitmap (cannot use SkBitmap because of ETC1). // Thread-safety (by ways of SkPixelRef) ensures that both main and impl threads // can hold references to the bitmap and that asynchronous uploads are allowed. class CC_EXPORT UIResourceBitmap { public: enum UIResourceFormat { - RGBA8 + RGBA8, + ETC1 }; enum UIResourceWrapMode { CLAMP_TO_EDGE, @@ -34,12 +37,16 @@ class CC_EXPORT UIResourceBitmap { gfx::Size GetSize() const { return size_; } UIResourceFormat GetFormat() const { return format_; } UIResourceWrapMode GetWrapMode() const { return wrap_mode_; } + void SetWrapMode(UIResourceWrapMode wrap_mode) { wrap_mode_ = wrap_mode; } + bool GetOpaque() const { return opaque_; } + void SetOpaque(bool opaque) { opaque_ = opaque; } + + // User must ensure that |skbitmap| is immutable. The SkBitmap Format should + // be 32-bit RGBA. + explicit UIResourceBitmap(const SkBitmap& skbitmap); - // The constructor for the UIResourceBitmap. User must ensure that |skbitmap| - // is immutable. The SkBitmap format should be in 32-bit RGBA. Wrap mode is - // unnecessary for most UI resources and is defaulted to CLAMP_TO_EDGE. - UIResourceBitmap(const SkBitmap& skbitmap, - UIResourceWrapMode wrap_mode = CLAMP_TO_EDGE); + UIResourceBitmap(const skia::RefPtr<ETC1PixelRef>& etc1_pixel_ref, + gfx::Size size); ~UIResourceBitmap(); @@ -47,13 +54,13 @@ class CC_EXPORT UIResourceBitmap { friend class AutoLockUIResourceBitmap; void Create(const skia::RefPtr<SkPixelRef>& pixel_ref, UIResourceFormat format, - UIResourceWrapMode wrap_mode, gfx::Size size); skia::RefPtr<SkPixelRef> pixel_ref_; UIResourceFormat format_; UIResourceWrapMode wrap_mode_; gfx::Size size_; + bool opaque_; }; class CC_EXPORT AutoLockUIResourceBitmap { diff --git a/chromium/cc/resources/ui_resource_request.cc b/chromium/cc/resources/ui_resource_request.cc new file mode 100644 index 00000000000..75680369c6d --- /dev/null +++ b/chromium/cc/resources/ui_resource_request.cc @@ -0,0 +1,37 @@ +// Copyright 2013 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 "cc/resources/ui_resource_request.h" + +namespace cc { + +UIResourceRequest::UIResourceRequest(UIResourceRequestType type, + UIResourceId id) + : type_(type), id_(id) {} + +UIResourceRequest::UIResourceRequest(UIResourceRequestType type, + UIResourceId id, + const UIResourceBitmap& bitmap) + : type_(type), id_(id), bitmap_(new UIResourceBitmap(bitmap)) {} + +UIResourceRequest::UIResourceRequest(const UIResourceRequest& request) { + (*this) = request; +} + +UIResourceRequest& UIResourceRequest::operator=( + const UIResourceRequest& request) { + type_ = request.type_; + id_ = request.id_; + if (request.bitmap_) { + bitmap_ = make_scoped_ptr(new UIResourceBitmap(*request.bitmap_.get())); + } else { + bitmap_.reset(); + } + + return *this; +} + +UIResourceRequest::~UIResourceRequest() {} + +} // namespace cc diff --git a/chromium/cc/resources/ui_resource_request.h b/chromium/cc/resources/ui_resource_request.h new file mode 100644 index 00000000000..6d89761d44b --- /dev/null +++ b/chromium/cc/resources/ui_resource_request.h @@ -0,0 +1,49 @@ +// Copyright 2013 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 CC_RESOURCES_UI_RESOURCE_REQUEST_H_ +#define CC_RESOURCES_UI_RESOURCE_REQUEST_H_ + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "cc/resources/ui_resource_bitmap.h" +#include "cc/resources/ui_resource_client.h" + +namespace cc { + +class CC_EXPORT UIResourceRequest { + public: + enum UIResourceRequestType { + UIResourceCreate, + UIResourceDelete, + UIResourceInvalidRequest + }; + + UIResourceRequest(UIResourceRequestType type, UIResourceId id); + UIResourceRequest(UIResourceRequestType type, + UIResourceId id, + const UIResourceBitmap& bitmap); + UIResourceRequest(const UIResourceRequest& request); + + ~UIResourceRequest(); + + UIResourceRequestType GetType() const { return type_; } + UIResourceId GetId() const { return id_; } + UIResourceBitmap GetBitmap() const { + DCHECK(bitmap_); + return *bitmap_.get(); + } + + UIResourceRequest& operator=(const UIResourceRequest& request); + + private: + UIResourceRequestType type_; + UIResourceId id_; + scoped_ptr<UIResourceBitmap> bitmap_; +}; + +} // namespace cc + +#endif // CC_RESOURCES_UI_RESOURCE_REQUEST_H_ diff --git a/chromium/cc/resources/video_resource_updater.cc b/chromium/cc/resources/video_resource_updater.cc index 34c7ab65c35..4abeab149d3 100644 --- a/chromium/cc/resources/video_resource_updater.cc +++ b/chromium/cc/resources/video_resource_updater.cc @@ -8,9 +8,9 @@ #include "cc/output/gl_renderer.h" #include "cc/resources/resource_provider.h" #include "gpu/GLES2/gl2extchromium.h" +#include "gpu/command_buffer/client/gles2_interface.h" #include "media/base/video_frame.h" #include "media/filters/skcanvas_video_renderer.h" -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "ui/gfx/size_conversions.h" @@ -69,16 +69,16 @@ bool VideoResourceUpdater::VerifyFrame( case media::VideoFrame::YV12: case media::VideoFrame::YV12A: case media::VideoFrame::YV16: + case media::VideoFrame::YV12J: case media::VideoFrame::NATIVE_TEXTURE: -#if defined(GOOGLE_TV) +#if defined(VIDEO_HOLE) case media::VideoFrame::HOLE: -#endif +#endif // defined(VIDEO_HOLE) return true; // Unacceptable inputs. ¯\(°_o)/¯ - case media::VideoFrame::INVALID: - case media::VideoFrame::RGB32: - case media::VideoFrame::EMPTY: + case media::VideoFrame::UNKNOWN: + case media::VideoFrame::HISTOGRAM_MAX: case media::VideoFrame::I420: break; } @@ -100,18 +100,18 @@ static gfx::Size SoftwarePlaneDimension( switch (input_frame_format) { case media::VideoFrame::YV12: case media::VideoFrame::YV12A: + case media::VideoFrame::YV12J: return gfx::ToFlooredSize(gfx::ScaleSize(coded_size, 0.5f, 0.5f)); case media::VideoFrame::YV16: return gfx::ToFlooredSize(gfx::ScaleSize(coded_size, 0.5f, 1.f)); - case media::VideoFrame::INVALID: - case media::VideoFrame::RGB32: - case media::VideoFrame::EMPTY: + case media::VideoFrame::UNKNOWN: case media::VideoFrame::I420: case media::VideoFrame::NATIVE_TEXTURE: -#if defined(GOOGLE_TV) + case media::VideoFrame::HISTOGRAM_MAX: +#if defined(VIDEO_HOLE) case media::VideoFrame::HOLE: -#endif +#endif // defined(VIDEO_HOLE) NOTREACHED(); } } @@ -124,20 +124,22 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( const scoped_refptr<media::VideoFrame>& video_frame) { media::VideoFrame::Format input_frame_format = video_frame->format(); -#if defined(GOOGLE_TV) +#if defined(VIDEO_HOLE) if (input_frame_format == media::VideoFrame::HOLE) { VideoFrameExternalResources external_resources; external_resources.type = VideoFrameExternalResources::HOLE; return external_resources; } -#endif +#endif // defined(VIDEO_HOLE) // Only YUV software video frames are supported. DCHECK(input_frame_format == media::VideoFrame::YV12 || input_frame_format == media::VideoFrame::YV12A || + input_frame_format == media::VideoFrame::YV12J || input_frame_format == media::VideoFrame::YV16); if (input_frame_format != media::VideoFrame::YV12 && input_frame_format != media::VideoFrame::YV12A && + input_frame_format != media::VideoFrame::YV12J && input_frame_format != media::VideoFrame::YV16) return VideoFrameExternalResources(); @@ -203,20 +205,18 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( if (!software_compositor) { DCHECK(context_provider_); - WebKit::WebGraphicsContext3D* context = - context_provider_->Context3d(); + gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); - GLC(context, context->genMailboxCHROMIUM(mailbox.name)); + GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name)); if (mailbox.IsZero()) { resource_provider_->DeleteResource(resource_id); resource_id = 0; } else { ResourceProvider::ScopedWriteLockGL lock( resource_provider_, resource_id); - GLC(context, context->bindTexture(GL_TEXTURE_2D, lock.texture_id())); - GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D, - mailbox.name)); - GLC(context, context->bindTexture(GL_TEXTURE_2D, 0)); + GLC(gl, gl->BindTexture(GL_TEXTURE_2D, lock.texture_id())); + GLC(gl, gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name)); + GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0)); } } @@ -261,24 +261,30 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( 0xff); } - // In software mode, the resource provider won't be lost. Soon this callback - // will be called directly from the resource provider, same as 3d - // compositing mode, so this raw unretained resource_provider will always - // be valid when the callback is fired. RecycleResourceData recycle_data = { plane_resources[0].resource_id, plane_resources[0].resource_size, plane_resources[0].resource_format, gpu::Mailbox() }; + base::SharedMemory* shared_memory = + resource_provider_->GetSharedMemory(plane_resources[0].resource_id); + if (shared_memory) { + external_resources.mailboxes.push_back( + TextureMailbox(shared_memory, plane_resources[0].resource_size)); + external_resources.release_callbacks + .push_back(base::Bind(&RecycleResource, AsWeakPtr(), recycle_data)); + external_resources.type = VideoFrameExternalResources::RGB_RESOURCE; + } else { + // TODO(jbauman): Remove this path once shared memory is available + // everywhere. + external_resources.software_resources + .push_back(plane_resources[0].resource_id); + external_resources.software_release_callback = + base::Bind(&RecycleResource, AsWeakPtr(), recycle_data); + external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; + } - external_resources.software_resources.push_back( - plane_resources[0].resource_id); - external_resources.software_release_callback = - base::Bind(&RecycleResource, AsWeakPtr(), recycle_data); - - - external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; return external_resources; } @@ -316,11 +322,10 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( return external_resources; } -static void ReturnTexture( - scoped_refptr<media::VideoFrame::MailboxHolder> mailbox_holder, - unsigned sync_point, - bool lost_resource) { - mailbox_holder->Return(sync_point); +static void ReturnTexture(const scoped_refptr<media::VideoFrame>& frame, + unsigned sync_point, + bool lost_resource) { + frame->texture_mailbox()->Resync(sync_point); } VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( @@ -351,7 +356,7 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( return VideoFrameExternalResources(); } - scoped_refptr<media::VideoFrame::MailboxHolder> mailbox_holder = + media::VideoFrame::MailboxHolder* mailbox_holder = video_frame->texture_mailbox(); external_resources.mailboxes.push_back( @@ -359,7 +364,7 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( video_frame->texture_target(), mailbox_holder->sync_point())); external_resources.release_callbacks.push_back( - base::Bind(&ReturnTexture, mailbox_holder)); + base::Bind(&ReturnTexture, video_frame)); return external_resources; } @@ -376,8 +381,8 @@ void VideoResourceUpdater::RecycleResource( ContextProvider* context_provider = updater->context_provider_; if (context_provider && sync_point) { - GLC(context_provider->Context3d(), - context_provider->Context3d()->waitSyncPoint(sync_point)); + GLC(context_provider->ContextGL(), + context_provider->ContextGL()->WaitSyncPointCHROMIUM(sync_point)); } if (lost_resource) { diff --git a/chromium/cc/resources/video_resource_updater.h b/chromium/cc/resources/video_resource_updater.h index e3476d44bb4..2a27739cef7 100644 --- a/chromium/cc/resources/video_resource_updater.h +++ b/chromium/cc/resources/video_resource_updater.h @@ -37,11 +37,11 @@ class CC_EXPORT VideoFrameExternalResources { STREAM_TEXTURE_RESOURCE, IO_SURFACE, -#if defined(GOOGLE_TV) +#if defined(VIDEO_HOLE) // TODO(danakj): Implement this with a solid color layer instead of a video // frame and video layer. HOLE, -#endif +#endif // defined(VIDEO_HOLE) // TODO(danakj): Remove this and abstract TextureMailbox into // "ExternalResource" that can hold a hardware or software backing. diff --git a/chromium/cc/resources/video_resource_updater_unittest.cc b/chromium/cc/resources/video_resource_updater_unittest.cc index c36689e16c1..dcb72e349d3 100644 --- a/chromium/cc/resources/video_resource_updater_unittest.cc +++ b/chromium/cc/resources/video_resource_updater_unittest.cc @@ -5,10 +5,10 @@ #include "cc/resources/video_resource_updater.h" #include "base/memory/shared_memory.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/resources/resource_provider.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "media/base/video_frame.h" #include "testing/gtest/include/gtest/gtest.h" @@ -26,7 +26,7 @@ class VideoResourceUpdaterTest : public testing::Test { FakeOutputSurface::Create3d(context3d.Pass()); CHECK(output_surface3d_->BindToClient(&client_)); resource_provider3d_ = - ResourceProvider::Create(output_surface3d_.get(), 0, false); + ResourceProvider::Create(output_surface3d_.get(), NULL, 0, false, 1); } scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame() { diff --git a/chromium/cc/scheduler/delay_based_time_source.cc b/chromium/cc/scheduler/delay_based_time_source.cc index d150c717a12..00515b72f76 100644 --- a/chromium/cc/scheduler/delay_based_time_source.cc +++ b/chromium/cc/scheduler/delay_based_time_source.cc @@ -33,6 +33,27 @@ static const double kPhaseChangeThreshold = 0.25; } // namespace +// The following methods correspond to the DelayBasedTimeSource that uses +// the base::TimeTicks::HighResNow as the timebase. +scoped_refptr<DelayBasedTimeSourceHighRes> DelayBasedTimeSourceHighRes::Create( + base::TimeDelta interval, + base::SingleThreadTaskRunner* task_runner) { + return make_scoped_refptr( + new DelayBasedTimeSourceHighRes(interval, task_runner)); +} + +DelayBasedTimeSourceHighRes::DelayBasedTimeSourceHighRes( + base::TimeDelta interval, base::SingleThreadTaskRunner* task_runner) + : DelayBasedTimeSource(interval, task_runner) {} + +DelayBasedTimeSourceHighRes::~DelayBasedTimeSourceHighRes() {} + +base::TimeTicks DelayBasedTimeSourceHighRes::Now() const { + return base::TimeTicks::HighResNow(); +} + +// The following methods correspond to the DelayBasedTimeSource that uses +// the base::TimeTicks::Now as the timebase. scoped_refptr<DelayBasedTimeSource> DelayBasedTimeSource::Create( base::TimeDelta interval, base::SingleThreadTaskRunner* task_runner) { diff --git a/chromium/cc/scheduler/delay_based_time_source.h b/chromium/cc/scheduler/delay_based_time_source.h index 55aac5a97fb..ddb89da3566 100644 --- a/chromium/cc/scheduler/delay_based_time_source.h +++ b/chromium/cc/scheduler/delay_based_time_source.h @@ -15,7 +15,7 @@ namespace cc { // This timer implements a time source that achieves the specified interval // in face of millisecond-precision delayed callbacks and random queueing -// delays. +// delays. DelayBasedTimeSource uses base::TimeTicks::Now as its timebase. class CC_EXPORT DelayBasedTimeSource : public TimeSource { public: static scoped_refptr<DelayBasedTimeSource> Create( @@ -73,6 +73,23 @@ class CC_EXPORT DelayBasedTimeSource : public TimeSource { DISALLOW_COPY_AND_ASSIGN(DelayBasedTimeSource); }; +// DelayBasedTimeSource uses base::TimeTicks::HighResNow as its timebase. +class DelayBasedTimeSourceHighRes : public DelayBasedTimeSource { + public: + static scoped_refptr<DelayBasedTimeSourceHighRes> Create( + base::TimeDelta interval, base::SingleThreadTaskRunner* task_runner); + + virtual base::TimeTicks Now() const OVERRIDE; + + protected: + DelayBasedTimeSourceHighRes(base::TimeDelta interval, + base::SingleThreadTaskRunner* task_runner); + virtual ~DelayBasedTimeSourceHighRes(); + + private: + DISALLOW_COPY_AND_ASSIGN(DelayBasedTimeSourceHighRes); +}; + } // namespace cc #endif // CC_SCHEDULER_DELAY_BASED_TIME_SOURCE_H_ diff --git a/chromium/cc/scheduler/frame_rate_controller.cc b/chromium/cc/scheduler/frame_rate_controller.cc index cefe764fc78..243ef6b6291 100644 --- a/chromium/cc/scheduler/frame_rate_controller.cc +++ b/chromium/cc/scheduler/frame_rate_controller.cc @@ -11,6 +11,7 @@ #include "base/single_thread_task_runner.h" #include "cc/scheduler/delay_based_time_source.h" #include "cc/scheduler/time_source.h" +#include "ui/gfx/frame_time.h" namespace cc { @@ -43,8 +44,9 @@ FrameRateController::FrameRateController(scoped_refptr<TimeSource> timer) time_source_(timer), active_(false), is_time_source_throttling_(true), - weak_factory_(this), - task_runner_(NULL) { + manual_tick_pending_(false), + task_runner_(NULL), + weak_factory_(this) { time_source_client_adapter_ = FrameRateControllerTimeSourceAdapter::Create(this); time_source_->SetClient(time_source_client_adapter_.get()); @@ -58,8 +60,9 @@ FrameRateController::FrameRateController( interval_(BeginFrameArgs::DefaultInterval()), active_(false), is_time_source_throttling_(false), - weak_factory_(this), - task_runner_(task_runner) {} + manual_tick_pending_(false), + task_runner_(task_runner), + weak_factory_(this) {} FrameRateController::~FrameRateController() { if (is_time_source_throttling_) @@ -80,10 +83,12 @@ BeginFrameArgs FrameRateController::SetActive(bool active) { missed_tick_time, deadline + deadline_adjustment_, interval_); } } else { - if (active) + if (active) { PostManualTick(); - else + } else { weak_factory_.InvalidateWeakPtrs(); + manual_tick_pending_ = false; + } } return BeginFrameArgs(); @@ -128,7 +133,8 @@ void FrameRateController::OnTimerTick() { } void FrameRateController::PostManualTick() { - if (active_) { + if (active_ && !manual_tick_pending_) { + manual_tick_pending_ = true; task_runner_->PostTask(FROM_HERE, base::Bind(&FrameRateController::ManualTick, weak_factory_.GetWeakPtr())); @@ -136,6 +142,7 @@ void FrameRateController::PostManualTick() { } void FrameRateController::ManualTick() { + manual_tick_pending_ = false; OnTimerTick(); } @@ -165,7 +172,7 @@ base::TimeTicks FrameRateController::LastTickTime() { if (is_time_source_throttling_) return time_source_->LastTickTime(); - return base::TimeTicks::Now(); + return gfx::FrameTime::Now(); } } // namespace cc diff --git a/chromium/cc/scheduler/frame_rate_controller.h b/chromium/cc/scheduler/frame_rate_controller.h index b68c73db0c8..6d86d974966 100644 --- a/chromium/cc/scheduler/frame_rate_controller.h +++ b/chromium/cc/scheduler/frame_rate_controller.h @@ -88,8 +88,9 @@ class CC_EXPORT FrameRateController { // Members for unthrottled frame-rate. bool is_time_source_throttling_; - base::WeakPtrFactory<FrameRateController> weak_factory_; + bool manual_tick_pending_; base::SingleThreadTaskRunner* task_runner_; + base::WeakPtrFactory<FrameRateController> weak_factory_; private: DISALLOW_COPY_AND_ASSIGN(FrameRateController); diff --git a/chromium/cc/scheduler/frame_rate_controller_unittest.cc b/chromium/cc/scheduler/frame_rate_controller_unittest.cc index 353d9844caf..e7d75802eb3 100644 --- a/chromium/cc/scheduler/frame_rate_controller_unittest.cc +++ b/chromium/cc/scheduler/frame_rate_controller_unittest.cc @@ -11,20 +11,21 @@ namespace cc { namespace { -class FakeFrameRateControllerClient : public cc::FrameRateControllerClient { +class FakeFrameRateControllerClient : public FrameRateControllerClient { public: FakeFrameRateControllerClient() { Reset(); } - void Reset() { began_frame_ = false; } - bool BeganFrame() const { return began_frame_; } + void Reset() { frame_count_ = 0; } + bool BeganFrame() const { return frame_count_ > 0; } + int frame_count() const { return frame_count_; } virtual void FrameRateControllerTick( bool throttled, const BeginFrameArgs& args) OVERRIDE { - began_frame_ = !throttled; + frame_count_ += throttled ? 0 : 1; } protected: - bool began_frame_; + int frame_count_; }; TEST(FrameRateControllerTest, TestFrameThrottling_ImmediateAck) { @@ -182,5 +183,29 @@ TEST(FrameRateControllerTest, TestFrameThrottling_Unthrottled) { EXPECT_TRUE(client.BeganFrame()); } +TEST(FrameRateControllerTest, TestFrameThrottling_NoDoubleTicking) { + scoped_refptr<base::TestSimpleTaskRunner> task_runner = + new base::TestSimpleTaskRunner; + FakeFrameRateControllerClient client; + FrameRateController controller(task_runner.get()); + controller.SetClient(&client); + + // SetActive triggers 1st frame and queues another tick task since the time + // source isn't throttling. + controller.SetActive(true); + task_runner->RunPendingTasks(); + EXPECT_TRUE(client.BeganFrame()); + client.Reset(); + EXPECT_TRUE(task_runner->HasPendingTask()); + + // Simulate a frame swap. This shouldn't queue a second tick task. + controller.DidSwapBuffers(); + controller.DidSwapBuffersComplete(); + + // The client should only be ticked once. + task_runner->RunPendingTasks(); + EXPECT_EQ(1, client.frame_count()); +} + } // namespace } // namespace cc diff --git a/chromium/cc/scheduler/rate_limiter.cc b/chromium/cc/scheduler/rate_limiter.cc deleted file mode 100644 index d89d95b8cf2..00000000000 --- a/chromium/cc/scheduler/rate_limiter.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2011 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 "cc/scheduler/rate_limiter.h" - -#include "base/bind.h" -#include "base/debug/trace_event.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/single_thread_task_runner.h" -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" - -namespace cc { - -scoped_refptr<RateLimiter> RateLimiter::Create( - WebKit::WebGraphicsContext3D* context, - RateLimiterClient* client, - base::SingleThreadTaskRunner* task_runner) { - return make_scoped_refptr(new RateLimiter(context, client, task_runner)); -} - -RateLimiter::RateLimiter(WebKit::WebGraphicsContext3D* context, - RateLimiterClient* client, - base::SingleThreadTaskRunner* task_runner) - : context_(context), - active_(false), - client_(client), - task_runner_(task_runner) { - DCHECK(context); -} - -RateLimiter::~RateLimiter() {} - -void RateLimiter::Start() { - if (active_) - return; - - TRACE_EVENT0("cc", "RateLimiter::Start"); - active_ = true; - task_runner_->PostTask(FROM_HERE, - base::Bind(&RateLimiter::RateLimitContext, this)); -} - -void RateLimiter::Stop() { - TRACE_EVENT0("cc", "RateLimiter::Stop"); - client_ = NULL; -} - -void RateLimiter::RateLimitContext() { - if (!client_) - return; - - TRACE_EVENT0("cc", "RateLimiter::RateLimitContext"); - - active_ = false; - client_->RateLimit(); - context_->rateLimitOffscreenContextCHROMIUM(); -} - -} // namespace cc diff --git a/chromium/cc/scheduler/rate_limiter.h b/chromium/cc/scheduler/rate_limiter.h deleted file mode 100644 index 04b90772e36..00000000000 --- a/chromium/cc/scheduler/rate_limiter.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2011 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 CC_SCHEDULER_RATE_LIMITER_H_ -#define CC_SCHEDULER_RATE_LIMITER_H_ - -#include "base/memory/ref_counted.h" - -namespace base { class SingleThreadTaskRunner; } - -namespace WebKit { class WebGraphicsContext3D; } - -namespace cc { - -class RateLimiterClient { - public: - virtual void RateLimit() = 0; - - protected: - virtual ~RateLimiterClient() {} -}; - -// A RateLimiter can be used to make sure that a single context does not -// dominate all execution time. To use, construct a RateLimiter class around -// the context and call Start() whenever calls are made on the context outside -// of normal flow control. RateLimiter will block if the context is too far -// ahead of the compositor. -class RateLimiter : public base::RefCounted<RateLimiter> { - public: - static scoped_refptr<RateLimiter> Create( - WebKit::WebGraphicsContext3D* context, - RateLimiterClient* client, - base::SingleThreadTaskRunner* task_runner); - - void Start(); - - // Context and client will not be accessed after Stop(). - void Stop(); - - private: - friend class base::RefCounted<RateLimiter>; - - RateLimiter(WebKit::WebGraphicsContext3D* context, - RateLimiterClient* client, - base::SingleThreadTaskRunner* task_runner); - ~RateLimiter(); - - void RateLimitContext(); - - WebKit::WebGraphicsContext3D* context_; - bool active_; - RateLimiterClient* client_; - base::SingleThreadTaskRunner* task_runner_; - - DISALLOW_COPY_AND_ASSIGN(RateLimiter); -}; - -} // namespace cc - -#endif // CC_SCHEDULER_RATE_LIMITER_H_ diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc index c81513feebd..d31f042e761 100644 --- a/chromium/cc/scheduler/scheduler.cc +++ b/chromium/cc/scheduler/scheduler.cc @@ -8,21 +8,25 @@ #include "base/auto_reset.h" #include "base/debug/trace_event.h" #include "base/logging.h" +#include "cc/debug/devtools_instrumentation.h" #include "cc/debug/traced_value.h" +#include "ui/gfx/frame_time.h" namespace cc { Scheduler::Scheduler(SchedulerClient* client, - const SchedulerSettings& scheduler_settings) + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id) : settings_(scheduler_settings), client_(client), - weak_factory_(this), - last_set_needs_begin_frame_(false), + layer_tree_host_id_(layer_tree_host_id), + last_set_needs_begin_impl_frame_(false), state_machine_(scheduler_settings), inside_process_scheduled_actions_(false), - inside_action_(SchedulerStateMachine::ACTION_NONE) { + inside_action_(SchedulerStateMachine::ACTION_NONE), + weak_factory_(this) { DCHECK(client_); - DCHECK(!state_machine_.BeginFrameNeededByImplThread()); + DCHECK(!state_machine_.BeginImplFrameNeeded()); } Scheduler::~Scheduler() {} @@ -94,24 +98,28 @@ void Scheduler::FinishCommit() { ProcessScheduledActions(); } -void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { - TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread"); - state_machine_.BeginFrameAbortedByMainThread(did_handle); +void Scheduler::BeginMainFrameAborted(bool did_handle) { + TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted"); + state_machine_.BeginMainFrameAborted(did_handle); ProcessScheduledActions(); } +void Scheduler::DidManageTiles() { + state_machine_.DidManageTiles(); +} + void Scheduler::DidLoseOutputSurface() { TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); - last_set_needs_begin_frame_ = false; - begin_frame_deadline_closure_.Cancel(); + last_set_needs_begin_impl_frame_ = false; + begin_impl_frame_deadline_closure_.Cancel(); state_machine_.DidLoseOutputSurface(); ProcessScheduledActions(); } void Scheduler::DidCreateAndInitializeOutputSurface() { TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); - DCHECK(!last_set_needs_begin_frame_); - DCHECK(begin_frame_deadline_closure_.IsCancelled()); + DCHECK(!last_set_needs_begin_impl_frame_); + DCHECK(begin_impl_frame_deadline_closure_.IsCancelled()); state_machine_.DidCreateAndInitializeOutputSurface(); ProcessScheduledActions(); } @@ -119,46 +127,49 @@ void Scheduler::DidCreateAndInitializeOutputSurface() { base::TimeTicks Scheduler::AnticipatedDrawTime() { TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); - if (!last_set_needs_begin_frame_ || - last_begin_frame_args_.interval <= base::TimeDelta()) + if (!last_set_needs_begin_impl_frame_ || + last_begin_impl_frame_args_.interval <= base::TimeDelta()) return base::TimeTicks(); - base::TimeTicks now = base::TimeTicks::Now(); - base::TimeTicks timebase = std::max(last_begin_frame_args_.frame_time, - last_begin_frame_args_.deadline); - int64 intervals = 1 + ((now - timebase) / last_begin_frame_args_.interval); - return timebase + (last_begin_frame_args_.interval * intervals); + base::TimeTicks now = gfx::FrameTime::Now(); + base::TimeTicks timebase = std::max(last_begin_impl_frame_args_.frame_time, + last_begin_impl_frame_args_.deadline); + int64 intervals = + 1 + ((now - timebase) / last_begin_impl_frame_args_.interval); + return timebase + (last_begin_impl_frame_args_.interval * intervals); } -base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { - return last_begin_frame_args_.frame_time; +base::TimeTicks Scheduler::LastBeginImplFrameTime() { + return last_begin_impl_frame_args_.frame_time; } -void Scheduler::SetupNextBeginFrameIfNeeded() { - bool needs_begin_frame = - state_machine_.BeginFrameNeededByImplThread(); +void Scheduler::SetupNextBeginImplFrameIfNeeded() { + bool needs_begin_impl_frame = + state_machine_.BeginImplFrameNeeded(); bool at_end_of_deadline = - state_machine_.begin_frame_state() == - SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE; - - bool should_call_set_needs_begin_frame = - // Always request the BeginFrame immediately if it wasn't needed before. - (needs_begin_frame && !last_set_needs_begin_frame_) || - // We always need to explicitly request our next BeginFrame. + state_machine_.begin_impl_frame_state() == + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; + + bool should_call_set_needs_begin_impl_frame = + // Always request the BeginImplFrame immediately if it wasn't needed + // before. + (needs_begin_impl_frame && !last_set_needs_begin_impl_frame_) || + // We always need to explicitly request our next BeginImplFrame. at_end_of_deadline; - if (should_call_set_needs_begin_frame) { - client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); - last_set_needs_begin_frame_ = needs_begin_frame; + if (should_call_set_needs_begin_impl_frame) { + client_->SetNeedsBeginImplFrame(needs_begin_impl_frame); + last_set_needs_begin_impl_frame_ = needs_begin_impl_frame; } + bool needs_advance_commit_state_timer = false; // Setup PollForAnticipatedDrawTriggers if we need to monitor state but - // aren't expecting any more BeginFrames. This should only be needed by the - // synchronous compositor when BeginFrameNeededByImplThread is false. + // aren't expecting any more BeginImplFrames. This should only be needed by + // the synchronous compositor when BeginImplFrameNeeded is false. if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { - DCHECK(settings_.using_synchronous_renderer_compositor); - DCHECK(!needs_begin_frame); + DCHECK(!state_machine_.SupportsProactiveBeginImplFrame()); + DCHECK(!needs_begin_impl_frame); if (poll_for_draw_triggers_closure_.IsCancelled()) { poll_for_draw_triggers_closure_.Reset( base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, @@ -166,92 +177,124 @@ void Scheduler::SetupNextBeginFrameIfNeeded() { base::MessageLoop::current()->PostDelayedTask( FROM_HERE, poll_for_draw_triggers_closure_.callback(), - last_begin_frame_args_.interval); + last_begin_impl_frame_args_.interval); } } else { poll_for_draw_triggers_closure_.Cancel(); + + // At this point we'd prefer to advance through the commit flow by + // drawing a frame, however it's possible that the frame rate controller + // will not give us a BeginImplFrame until the commit completes. See + // crbug.com/317430 for an example of a swap ack being held on commit. Thus + // we set a repeating timer to poll on ProcessScheduledActions until we + // successfully reach BeginImplFrame. + if (state_machine_.IsCommitStateWaiting()) + needs_advance_commit_state_timer = true; + } + if (needs_advance_commit_state_timer != + advance_commit_state_timer_.IsRunning()) { + if (needs_advance_commit_state_timer && + last_begin_impl_frame_args_.IsValid()) { + // Since we'd rather get a BeginImplFrame by the normally mechanism, we set + // the interval to twice the interval from the previous frame. + advance_commit_state_timer_.Start( + FROM_HERE, + last_begin_impl_frame_args_.interval * 2, + base::Bind(&Scheduler::ProcessScheduledActions, + base::Unretained(this))); + } else { + advance_commit_state_timer_.Stop(); + } } } -void Scheduler::BeginFrame(const BeginFrameArgs& args) { - TRACE_EVENT0("cc", "Scheduler::BeginFrame"); - DCHECK(state_machine_.begin_frame_state() == - SchedulerStateMachine::BEGIN_FRAME_STATE_IDLE); +void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { + TRACE_EVENT0("cc", "Scheduler::BeginImplFrame"); + DCHECK(state_machine_.begin_impl_frame_state() == + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); DCHECK(state_machine_.HasInitializedOutputSurface()); - last_begin_frame_args_ = args; - last_begin_frame_args_.deadline -= client_->DrawDurationEstimate(); - state_machine_.OnBeginFrame(last_begin_frame_args_); + last_begin_impl_frame_args_ = args; + last_begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate(); + state_machine_.OnBeginImplFrame(last_begin_impl_frame_args_); + + if (settings_.switch_to_low_latency_if_possible) { + state_machine_.SetSkipBeginMainFrameToReduceLatency( + state_machine_.MainThreadIsInHighLatencyMode() && + CanCommitAndActivateBeforeDeadline()); + } + ProcessScheduledActions(); if (!state_machine_.HasInitializedOutputSurface()) return; - state_machine_.OnBeginFrameDeadlinePending(); - + state_machine_.OnBeginImplFrameDeadlinePending(); + devtools_instrumentation::didBeginFrame(layer_tree_host_id_); if (settings_.using_synchronous_renderer_compositor) { // The synchronous renderer compositor has to make its GL calls - // within this call to BeginFrame. + // within this call to BeginImplFrame. // TODO(brianderson): Have the OutputSurface initiate the deadline tasks - // so the sychronous renderer compoistor can take advantage of splitting - // up the BeginFrame and deadline as well. - OnBeginFrameDeadline(); + // so the sychronous renderer compositor can take advantage of splitting + // up the BeginImplFrame and deadline as well. + OnBeginImplFrameDeadline(); } else if (!settings_.deadline_scheduling_enabled) { // We emulate the old non-deadline scheduler here by posting the // deadline task without any delay. - PostBeginFrameDeadline(base::TimeTicks()); - } else if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) { + PostBeginImplFrameDeadline(base::TimeTicks()); + } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { // We are ready to draw a new active tree immediately. - PostBeginFrameDeadline(base::TimeTicks()); + PostBeginImplFrameDeadline(base::TimeTicks()); } else if (state_machine_.needs_redraw()) { // We have an animation or fast input path on the impl thread that wants // to draw, so don't wait too long for a new active tree. - PostBeginFrameDeadline(last_begin_frame_args_.deadline); + PostBeginImplFrameDeadline(last_begin_impl_frame_args_.deadline); } else { // The impl thread doesn't have anything it wants to draw and we are just // waiting for a new active tree, so post the deadline for the next - // expected BeginFrame start. This allows us to draw immediately when - // there is a new active tree, instead of waiting for the next BeginFrame. + // expected BeginImplFrame start. This allows us to draw immediately when + // there is a new active tree, instead of waiting for the next + // BeginImplFrame. // TODO(brianderson): Handle long deadlines (that are past the next frame's // frame time) properly instead of using this hack. - PostBeginFrameDeadline(last_begin_frame_args_.frame_time + - last_begin_frame_args_.interval); + PostBeginImplFrameDeadline(last_begin_impl_frame_args_.frame_time + + last_begin_impl_frame_args_.interval); } } -void Scheduler::PostBeginFrameDeadline(base::TimeTicks deadline) { - begin_frame_deadline_closure_.Cancel(); - begin_frame_deadline_closure_.Reset( - base::Bind(&Scheduler::OnBeginFrameDeadline, weak_factory_.GetWeakPtr())); - client_->PostBeginFrameDeadline(begin_frame_deadline_closure_.callback(), - deadline); +void Scheduler::PostBeginImplFrameDeadline(base::TimeTicks deadline) { + begin_impl_frame_deadline_closure_.Cancel(); + begin_impl_frame_deadline_closure_.Reset( + base::Bind(&Scheduler::OnBeginImplFrameDeadline, + weak_factory_.GetWeakPtr())); + client_->PostBeginImplFrameDeadline( + begin_impl_frame_deadline_closure_.callback(), deadline); } -void Scheduler::OnBeginFrameDeadline() { - TRACE_EVENT0("cc", "Scheduler::OnBeginFrameDeadline"); +void Scheduler::OnBeginImplFrameDeadline() { + TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); DCHECK(state_machine_.HasInitializedOutputSurface()); - begin_frame_deadline_closure_.Cancel(); - state_machine_.OnBeginFrameDeadline(); + begin_impl_frame_deadline_closure_.Cancel(); + state_machine_.OnBeginImplFrameDeadline(); ProcessScheduledActions(); if (state_machine_.HasInitializedOutputSurface()) { - // We only transition out of BEGIN_FRAME_STATE_INSIDE_DEADLINE when all + // We only transition out of BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE when all // actions that occur back-to-back in response to entering - // BEGIN_FRAME_STATE_INSIDE_DEADLINE have completed. This is important - // because sending the BeginFrame to the main thread will not occur if - // we transition to BEGIN_FRAME_STATE_IDLE too early. - state_machine_.OnBeginFrameIdle(); + // BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE have completed. This is important + // because sending the BeginMainFrame will not occur if we transition to + // BEGIN_IMPL_FRAME_STATE_IDLE too early. + state_machine_.OnBeginImplFrameIdle(); } - client_->DidBeginFrameDeadlineOnImplThread(); + client_->DidBeginImplFrameDeadline(); } void Scheduler::PollForAnticipatedDrawTriggers() { TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); + poll_for_draw_triggers_closure_.Cancel(); state_machine_.DidEnterPollForAnticipatedDrawTriggers(); ProcessScheduledActions(); state_machine_.DidLeavePollForAnticipatedDrawTriggers(); - - poll_for_draw_triggers_closure_.Cancel(); } void Scheduler::DrawAndSwapIfPossible() { @@ -291,8 +334,8 @@ void Scheduler::ProcessScheduledActions() { switch (action) { case SchedulerStateMachine::ACTION_NONE: break; - case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: - client_->ScheduledActionSendBeginFrameToMainThread(); + case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: + client_->ScheduledActionSendBeginMainFrame(); break; case SchedulerStateMachine::ACTION_COMMIT: client_->ScheduledActionCommit(); @@ -328,15 +371,26 @@ void Scheduler::ProcessScheduledActions() { } } while (action != SchedulerStateMachine::ACTION_NONE); - SetupNextBeginFrameIfNeeded(); + SetupNextBeginImplFrameIfNeeded(); client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); - if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) - PostBeginFrameDeadline(base::TimeTicks()); + if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) + PostBeginImplFrameDeadline(base::TimeTicks()); } bool Scheduler::WillDrawIfNeeded() const { return !state_machine_.PendingDrawsShouldBeAborted(); } +bool Scheduler::CanCommitAndActivateBeforeDeadline() const { + // Check if the main thread computation and commit can be finished before the + // impl thread's deadline. + base::TimeTicks estimated_draw_time = + last_begin_impl_frame_args_.frame_time + + client_->BeginMainFrameToCommitDurationEstimate() + + client_->CommitToActivateDurationEstimate(); + + return estimated_draw_time < last_begin_impl_frame_args_.deadline; +} + } // namespace cc diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h index 3403b7a2e06..92097829390 100644 --- a/chromium/cc/scheduler/scheduler.h +++ b/chromium/cc/scheduler/scheduler.h @@ -33,8 +33,8 @@ struct DrawSwapReadbackResult { class SchedulerClient { public: - virtual void SetNeedsBeginFrameOnImplThread(bool enable) = 0; - virtual void ScheduledActionSendBeginFrameToMainThread() = 0; + virtual void SetNeedsBeginImplFrame(bool enable) = 0; + virtual void ScheduledActionSendBeginMainFrame() = 0; virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() = 0; virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() = 0; virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() = 0; @@ -46,11 +46,11 @@ class SchedulerClient { virtual void ScheduledActionManageTiles() = 0; virtual void DidAnticipatedDrawTimeChange(base::TimeTicks time) = 0; virtual base::TimeDelta DrawDurationEstimate() = 0; - virtual base::TimeDelta BeginFrameToCommitDurationEstimate() = 0; + virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() = 0; virtual base::TimeDelta CommitToActivateDurationEstimate() = 0; - virtual void PostBeginFrameDeadline(const base::Closure& closure, - base::TimeTicks deadline) = 0; - virtual void DidBeginFrameDeadlineOnImplThread() = 0; + virtual void PostBeginImplFrameDeadline(const base::Closure& closure, + base::TimeTicks deadline) = 0; + virtual void DidBeginImplFrameDeadline() = 0; protected: virtual ~SchedulerClient() {} @@ -60,8 +60,10 @@ class CC_EXPORT Scheduler { public: static scoped_ptr<Scheduler> Create( SchedulerClient* client, - const SchedulerSettings& scheduler_settings) { - return make_scoped_ptr(new Scheduler(client, scheduler_settings)); + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id) { + return make_scoped_ptr( + new Scheduler(client, scheduler_settings, layer_tree_host_id)); } virtual ~Scheduler(); @@ -89,8 +91,9 @@ class CC_EXPORT Scheduler { void SetSmoothnessTakesPriority(bool smoothness_takes_priority); void FinishCommit(); - void BeginFrameAbortedByMainThread(bool did_handle); + void BeginMainFrameAborted(bool did_handle); + void DidManageTiles(); void DidLoseOutputSurface(); void DidCreateAndInitializeOutputSurface(); bool HasInitializedOutputSurface() const { @@ -102,15 +105,18 @@ class CC_EXPORT Scheduler { bool ManageTilesPending() const { return state_machine_.ManageTilesPending(); } + bool MainThreadIsInHighLatencyMode() const { + return state_machine_.MainThreadIsInHighLatencyMode(); + } bool WillDrawIfNeeded() const; base::TimeTicks AnticipatedDrawTime(); - base::TimeTicks LastBeginFrameOnImplThreadTime(); + base::TimeTicks LastBeginImplFrameTime(); - void BeginFrame(const BeginFrameArgs& args); - void OnBeginFrameDeadline(); + void BeginImplFrame(const BeginFrameArgs& args); + void OnBeginImplFrameDeadline(); void PollForAnticipatedDrawTriggers(); scoped_ptr<base::Value> StateAsValue() { @@ -123,29 +129,36 @@ class CC_EXPORT Scheduler { private: Scheduler(SchedulerClient* client, - const SchedulerSettings& scheduler_settings); + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id); - void PostBeginFrameDeadline(base::TimeTicks deadline); - void SetupNextBeginFrameIfNeeded(); + void PostBeginImplFrameDeadline(base::TimeTicks deadline); + void SetupNextBeginImplFrameIfNeeded(); void ActivatePendingTree(); void DrawAndSwapIfPossible(); void DrawAndSwapForced(); void DrawAndReadback(); void ProcessScheduledActions(); + bool CanCommitAndActivateBeforeDeadline() const; + void AdvanceCommitStateIfPossible(); + const SchedulerSettings settings_; SchedulerClient* client_; + int layer_tree_host_id_; - base::WeakPtrFactory<Scheduler> weak_factory_; - bool last_set_needs_begin_frame_; - BeginFrameArgs last_begin_frame_args_; - base::CancelableClosure begin_frame_deadline_closure_; + bool last_set_needs_begin_impl_frame_; + BeginFrameArgs last_begin_impl_frame_args_; + base::CancelableClosure begin_impl_frame_deadline_closure_; base::CancelableClosure poll_for_draw_triggers_closure_; + base::RepeatingTimer<Scheduler> advance_commit_state_timer_; SchedulerStateMachine state_machine_; bool inside_process_scheduled_actions_; SchedulerStateMachine::Action inside_action_; + base::WeakPtrFactory<Scheduler> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(Scheduler); }; diff --git a/chromium/cc/scheduler/scheduler_settings.cc b/chromium/cc/scheduler/scheduler_settings.cc index 6c1db6bf10c..ad925d4d135 100644 --- a/chromium/cc/scheduler/scheduler_settings.cc +++ b/chromium/cc/scheduler/scheduler_settings.cc @@ -7,12 +7,13 @@ namespace cc { SchedulerSettings::SchedulerSettings() - : deadline_scheduling_enabled(false), + : deadline_scheduling_enabled(true), impl_side_painting(false), timeout_and_draw_when_animation_checkerboards(true), maximum_number_of_failed_draws_before_draw_is_forced_(3), using_synchronous_renderer_compositor(false), - throttle_frame_production(true) {} + throttle_frame_production(true), + switch_to_low_latency_if_possible(false) {} SchedulerSettings::~SchedulerSettings() {} diff --git a/chromium/cc/scheduler/scheduler_settings.h b/chromium/cc/scheduler/scheduler_settings.h index 7857a70fe9e..b35cb7e6af6 100644 --- a/chromium/cc/scheduler/scheduler_settings.h +++ b/chromium/cc/scheduler/scheduler_settings.h @@ -20,6 +20,7 @@ class CC_EXPORT SchedulerSettings { int maximum_number_of_failed_draws_before_draw_is_forced_; bool using_synchronous_renderer_compositor; bool throttle_frame_production; + bool switch_to_low_latency_if_possible; }; } // namespace cc diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc index 955a6b32eee..7d8fcd721a3 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.cc +++ b/chromium/cc/scheduler/scheduler_state_machine.cc @@ -4,17 +4,19 @@ #include "cc/scheduler/scheduler_state_machine.h" +#include "base/debug/trace_event.h" #include "base/format_macros.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "base/values.h" +#include "ui/gfx/frame_time.h" namespace cc { SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) : settings_(settings), output_surface_state_(OUTPUT_SURFACE_LOST), - begin_frame_state_(BEGIN_FRAME_STATE_IDLE), + begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE), commit_state_(COMMIT_STATE_IDLE), texture_state_(LAYER_TEXTURE_STATE_UNLOCKED), forced_redraw_state_(FORCED_REDRAW_STATE_IDLE), @@ -22,8 +24,9 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) commit_count_(0), current_frame_number_(0), last_frame_number_swap_performed_(-1), - last_frame_number_begin_frame_sent_to_main_thread_(-1), + last_frame_number_begin_main_frame_sent_(-1), last_frame_number_update_visible_tiles_was_called_(-1), + last_frame_number_manage_tiles_called_(-1), consecutive_failed_draws_(0), needs_redraw_(false), needs_manage_tiles_(false), @@ -39,7 +42,8 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) active_tree_needs_first_draw_(false), draw_if_possible_failed_(false), did_create_and_initialize_first_output_surface_(false), - smoothness_takes_priority_(false) {} + smoothness_takes_priority_(false), + skip_begin_main_frame_to_reduce_latency_(false) {} const char* SchedulerStateMachine::OutputSurfaceStateToString( OutputSurfaceState state) { @@ -59,17 +63,17 @@ const char* SchedulerStateMachine::OutputSurfaceStateToString( return "???"; } -const char* SchedulerStateMachine::BeginFrameStateToString( - BeginFrameState state) { +const char* SchedulerStateMachine::BeginImplFrameStateToString( + BeginImplFrameState state) { switch (state) { - case BEGIN_FRAME_STATE_IDLE: - return "BEGIN_FRAME_STATE_IDLE"; - case BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING: - return "BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING"; - case BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME: - return "BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME"; - case BEGIN_FRAME_STATE_INSIDE_DEADLINE: - return "BEGIN_FRAME_STATE_INSIDE_DEADLINE"; + case BEGIN_IMPL_FRAME_STATE_IDLE: + return "BEGIN_IMPL_FRAME_STATE_IDLE"; + case BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING: + return "BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING"; + case BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME: + return "BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME"; + case BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE: + return "BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE"; } NOTREACHED(); return "???"; @@ -108,8 +112,8 @@ const char* SchedulerStateMachine::SynchronousReadbackStateToString( switch (state) { case READBACK_STATE_IDLE: return "READBACK_STATE_IDLE"; - case READBACK_STATE_NEEDS_BEGIN_FRAME: - return "READBACK_STATE_NEEDS_BEGIN_FRAME"; + case READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME: + return "READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME"; case READBACK_STATE_WAITING_FOR_COMMIT: return "READBACK_STATE_WAITING_FOR_COMMIT"; case READBACK_STATE_WAITING_FOR_ACTIVATION: @@ -145,8 +149,8 @@ const char* SchedulerStateMachine::ActionToString(Action action) { switch (action) { case ACTION_NONE: return "ACTION_NONE"; - case ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: - return "ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD"; + case ACTION_SEND_BEGIN_MAIN_FRAME: + return "ACTION_SEND_BEGIN_MAIN_FRAME"; case ACTION_COMMIT: return "ACTION_COMMIT"; case ACTION_UPDATE_VISIBLE_TILES: @@ -177,8 +181,8 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const { scoped_ptr<base::DictionaryValue> major_state(new base::DictionaryValue); major_state->SetString("next_action", ActionToString(NextAction())); - major_state->SetString("begin_frame_state", - BeginFrameStateToString(begin_frame_state_)); + major_state->SetString("begin_impl_frame_state", + BeginImplFrameStateToString(begin_impl_frame_state_)); major_state->SetString("commit_state", CommitStateToString(commit_state_)); major_state->SetString("texture_state_", TextureStateToString(texture_state_)); @@ -192,29 +196,33 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const { state->Set("major_state", major_state.release()); scoped_ptr<base::DictionaryValue> timestamps_state(new base::DictionaryValue); - base::TimeTicks now = base::TimeTicks::Now(); + base::TimeTicks now = gfx::FrameTime::Now(); timestamps_state->SetDouble( - "0_interval", last_begin_frame_args_.interval.InMicroseconds() / 1000.0L); + "0_interval", + last_begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L); timestamps_state->SetDouble( "1_now_to_deadline", - (last_begin_frame_args_.deadline - now).InMicroseconds() / 1000.0L); + (last_begin_impl_frame_args_.deadline - now).InMicroseconds() / 1000.0L); timestamps_state->SetDouble( "2_frame_time_to_now", - (now - last_begin_frame_args_.frame_time).InMicroseconds() / 1000.0L); + (now - last_begin_impl_frame_args_.frame_time).InMicroseconds() / + 1000.0L); timestamps_state->SetDouble( "3_frame_time_to_deadline", - (last_begin_frame_args_.deadline - last_begin_frame_args_.frame_time) - .InMicroseconds() / + (last_begin_impl_frame_args_.deadline - + last_begin_impl_frame_args_.frame_time).InMicroseconds() / 1000.0L); timestamps_state->SetDouble( "4_now", (now - base::TimeTicks()).InMicroseconds() / 1000.0L); timestamps_state->SetDouble( "5_frame_time", - (last_begin_frame_args_.frame_time - base::TimeTicks()).InMicroseconds() / + (last_begin_impl_frame_args_.frame_time - base::TimeTicks()) + .InMicroseconds() / 1000.0L); timestamps_state->SetDouble( "6_deadline", - (last_begin_frame_args_.deadline - base::TimeTicks()).InMicroseconds() / + (last_begin_impl_frame_args_.deadline - base::TimeTicks()) + .InMicroseconds() / 1000.0L); state->Set("major_timestamps_in_ms", timestamps_state.release()); @@ -225,8 +233,8 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const { minor_state->SetInteger("last_frame_number_swap_performed", last_frame_number_swap_performed_); minor_state->SetInteger( - "last_frame_number_begin_frame_sent_to_main_thread", - last_frame_number_begin_frame_sent_to_main_thread_); + "last_frame_number_begin_main_frame_sent", + last_frame_number_begin_main_frame_sent_); minor_state->SetInteger( "last_frame_number_update_visible_tiles_was_called", last_frame_number_update_visible_tiles_was_called_); @@ -253,14 +261,18 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const { did_create_and_initialize_first_output_surface_); minor_state->SetBoolean("smoothness_takes_priority", smoothness_takes_priority_); + minor_state->SetBoolean("main_thread_is_in_high_latency_mode", + MainThreadIsInHighLatencyMode()); + minor_state->SetBoolean("skip_begin_main_frame_to_reduce_latency", + skip_begin_main_frame_to_reduce_latency_); state->Set("minor_state", minor_state.release()); return state.PassAs<base::Value>(); } -bool SchedulerStateMachine::HasSentBeginFrameToMainThreadThisFrame() const { +bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const { return current_frame_number_ == - last_frame_number_begin_frame_sent_to_main_thread_; + last_frame_number_begin_main_frame_sent_; } bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const { @@ -356,8 +368,9 @@ bool SchedulerStateMachine::ShouldDraw() const { if (HasSwappedThisFrame()) return false; - // Except for the cases above, do not draw outside of the BeginFrame deadline. - if (begin_frame_state_ != BEGIN_FRAME_STATE_INSIDE_DEADLINE) + // Except for the cases above, do not draw outside of the BeginImplFrame + // deadline. + if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) return false; // Only handle forced redraws due to timeouts on the regular deadline. @@ -409,7 +422,7 @@ bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const { // We should not check for visible tiles until we've entered the deadline so // we check as late as possible and give the tiles more time to initialize. - if (begin_frame_state_ != BEGIN_FRAME_STATE_INSIDE_DEADLINE) + if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) return false; // If the last swap drew with checkerboard or missing tiles, we should @@ -421,12 +434,11 @@ bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const { return false; } -bool SchedulerStateMachine::ShouldSendBeginFrameToMainThread() const { +bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { if (!needs_commit_) return false; - // Only send BeginFrame to the main thread when there isn't another commit - // pending already. + // Only send BeginMainFrame when there isn't another commit pending already. if (commit_state_ != COMMIT_STATE_IDLE) return false; @@ -435,10 +447,10 @@ bool SchedulerStateMachine::ShouldSendBeginFrameToMainThread() const { return false; // We want to handle readback commits immediately to unblock the main thread. - // Note: This BeginFrame will correspond to the replacement commit that comes - // after the readback commit itself, so we only send the BeginFrame if a - // commit isn't already pending behind the readback. - if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_FRAME) + // Note: This BeginMainFrame will correspond to the replacement commit that + // comes after the readback commit itself, so we only send the BeginMainFrame + // if a commit isn't already pending behind the readback. + if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME) return !CommitPending(); // We do not need commits if we are not visible, unless there's a @@ -450,21 +462,20 @@ bool SchedulerStateMachine::ShouldSendBeginFrameToMainThread() const { if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) return true; - // With deadline scheduling enabled, we should not send BeginFrame to the - // main thread while we are in BEGIN_FRAME_STATE_IDLE, since we might have - // new user input coming in soon. - // However, if we are not expecting a BeginFrame on the Impl thread to take - // us out of idle, we should not early out here to avoid blocking commits - // forever. + // With deadline scheduling enabled, we should not send BeginMainFrame while + // we are in BEGIN_IMPL_FRAME_STATE_IDLE, since we might have new user input + // coming in soon. + // However, if we are not expecting a BeginImplFrame to take us out of idle, + // we should not early out here to avoid blocking commits forever. // This only works well when deadline scheduling is enabled because there is // an interval over which to accept the commit and draw. Without deadline // scheduling, delaying the commit could prevent us from having something - // to draw on the next BeginFrame. - // TODO(brianderson): Allow sending BeginFrame to main thread while idle - // when the main thread isn't consuming user input. + // to draw on the next BeginImplFrame. + // TODO(brianderson): Allow sending BeginMainFrame while idle when the main + // thread isn't consuming user input. if (settings_.deadline_scheduling_enabled && - begin_frame_state_ == BEGIN_FRAME_STATE_IDLE && - BeginFrameNeededByImplThread()) + begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_IDLE && + BeginImplFrameNeeded()) return false; // We need a new commit for the forced redraw. This honors the @@ -473,13 +484,16 @@ bool SchedulerStateMachine::ShouldSendBeginFrameToMainThread() const { return true; // After this point, we only start a commit once per frame. - if (HasSentBeginFrameToMainThreadThisFrame()) + if (HasSentBeginMainFrameThisFrame()) return false; // We shouldn't normally accept commits if there isn't an OutputSurface. if (!HasInitializedOutputSurface()) return false; + if (skip_begin_main_frame_to_reduce_latency_) + return false; + return true; } @@ -487,11 +501,21 @@ bool SchedulerStateMachine::ShouldCommit() const { return commit_state_ == COMMIT_STATE_READY_TO_COMMIT; } +bool SchedulerStateMachine::IsCommitStateWaiting() const { + return commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS; +} + bool SchedulerStateMachine::ShouldManageTiles() const { + // ManageTiles only really needs to be called immediately after commit + // and then periodically after that. Limiting to once per frame prevents + // post-commit and post-draw ManageTiles on the same frame. + if (last_frame_number_manage_tiles_called_ == current_frame_number_) + return false; + // Limiting to once per-frame is not enough, since we only want to // manage tiles _after_ draws. Polling for draw triggers and // begin-frame are mutually exclusive, so we limit to these two cases. - if (begin_frame_state_ != BEGIN_FRAME_STATE_INSIDE_DEADLINE && + if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE && !inside_poll_for_anticipated_draw_triggers_) return false; return needs_manage_tiles_; @@ -518,8 +542,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { } if (ShouldManageTiles()) return ACTION_MANAGE_TILES; - if (ShouldSendBeginFrameToMainThread()) - return ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD; + if (ShouldSendBeginMainFrame()) + return ACTION_SEND_BEGIN_MAIN_FRAME; if (ShouldBeginOutputSurfaceCreation()) return ACTION_BEGIN_OUTPUT_SURFACE_CREATION; return ACTION_NONE; @@ -546,14 +570,15 @@ void SchedulerStateMachine::UpdateState(Action action) { UpdateStateOnActivation(); return; - case ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: + case ACTION_SEND_BEGIN_MAIN_FRAME: DCHECK(!has_pending_tree_); - DCHECK(visible_ || readback_state_ == READBACK_STATE_NEEDS_BEGIN_FRAME); + DCHECK(visible_ || + readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME); commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS; needs_commit_ = false; - if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_FRAME) + if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME) readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT; - last_frame_number_begin_frame_sent_to_main_thread_ = + last_frame_number_begin_main_frame_sent_ = current_frame_number_; return; @@ -650,13 +675,15 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) { // Update the commit state. We expect and wait for a draw if the commit // was not aborted or if we are in a readback or forced draw. - if (!commit_was_aborted) + if (!commit_was_aborted) { + DCHECK(commit_state_ == COMMIT_STATE_READY_TO_COMMIT); commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW; - else if (readback_state_ != READBACK_STATE_IDLE || - forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE) + } else if (readback_state_ != READBACK_STATE_IDLE || + forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE) { commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW; - else + } else { commit_state_ = COMMIT_STATE_IDLE; + } // Update state if we have a new active tree to draw, or if the active tree // was unchanged but we need to do a readback or forced draw. @@ -715,7 +742,7 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) { // we should not have a pending tree. DCHECK(!has_pending_tree_); // We transition to COMMIT_STATE_FRAME_IN_PROGRESS because there is a - // pending BeginFrame on the main thread behind the readback request. + // pending BeginMainFrame behind the readback request. commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS; readback_state_ = READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT; } else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) { @@ -748,38 +775,50 @@ void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() { main_thread_needs_layer_textures_ = true; } -bool SchedulerStateMachine::BeginFrameNeededByImplThread() const { - // Proactive BeginFrames are bad for the synchronous compositor because we - // have to draw when we get the BeginFrame and could end up drawing many +void SchedulerStateMachine::SetSkipBeginMainFrameToReduceLatency(bool skip) { + skip_begin_main_frame_to_reduce_latency_ = skip; +} + +bool SchedulerStateMachine::BeginImplFrameNeeded() const { + // Proactive BeginImplFrames are bad for the synchronous compositor because we + // have to draw when we get the BeginImplFrame and could end up drawing many // duplicate frames if our new frame isn't ready in time. // To poll for state with the synchronous compositor without having to draw, // we rely on ShouldPollForAnticipatedDrawTriggers instead. - if (settings_.using_synchronous_renderer_compositor) - return BeginFrameNeededToDrawByImplThread(); + if (!SupportsProactiveBeginImplFrame()) + return BeginImplFrameNeededToDraw(); - return BeginFrameNeededToDrawByImplThread() || - ProactiveBeginFrameWantedByImplThread(); + return BeginImplFrameNeededToDraw() || + ProactiveBeginImplFrameWanted(); } bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const { // ShouldPollForAnticipatedDrawTriggers is what we use in place of - // ProactiveBeginFrameWantedByImplThread when we are using the synchronous + // ProactiveBeginImplFrameWanted when we are using the synchronous // compositor. - if (settings_.using_synchronous_renderer_compositor) { - return !BeginFrameNeededToDrawByImplThread() && - ProactiveBeginFrameWantedByImplThread(); + if (!SupportsProactiveBeginImplFrame()) { + return !BeginImplFrameNeededToDraw() && + ProactiveBeginImplFrameWanted(); } // Non synchronous compositors should rely on - // ProactiveBeginFrameWantedByImplThread to poll for state instead. + // ProactiveBeginImplFrameWanted to poll for state instead. return false; } +bool SchedulerStateMachine::SupportsProactiveBeginImplFrame() const { + // Both the synchronous compositor and disabled vsync settings + // make it undesirable to proactively request BeginImplFrames. + // If this is true, the scheduler should poll. + return !settings_.using_synchronous_renderer_compositor && + settings_.throttle_frame_production; +} + // These are the cases where we definitely (or almost definitely) have a // new frame to draw and can draw. -bool SchedulerStateMachine::BeginFrameNeededToDrawByImplThread() const { - // The output surface is the provider of BeginFrames for the impl thread, - // so we are not going to get them even if we ask for them. +bool SchedulerStateMachine::BeginImplFrameNeededToDraw() const { + // The output surface is the provider of BeginImplFrames, so we are not going + // to get them even if we ask for them. if (!HasInitializedOutputSurface()) return false; @@ -788,7 +827,7 @@ bool SchedulerStateMachine::BeginFrameNeededToDrawByImplThread() const { return false; // The forced draw respects our normal draw scheduling, so we need to - // request a BeginFrame on the impl thread for it. + // request a BeginImplFrame for it. if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) return true; @@ -796,8 +835,8 @@ bool SchedulerStateMachine::BeginFrameNeededToDrawByImplThread() const { if (!visible_) return false; - // We need to draw a more complete frame than we did the last BeginFrame, - // so request another BeginFrame in anticipation that we will have + // We need to draw a more complete frame than we did the last BeginImplFrame, + // so request another BeginImplFrame in anticipation that we will have // additional visible tiles. if (swap_used_incomplete_tile_) return true; @@ -806,29 +845,25 @@ bool SchedulerStateMachine::BeginFrameNeededToDrawByImplThread() const { } // These are cases where we are very likely to draw soon, but might not -// actually have a new frame to draw when we receive the next BeginFrame. -// Proactively requesting the BeginFrame helps hide the round trip latency of -// the SetNeedsBeginFrame request that has to go to the Browser. -bool SchedulerStateMachine::ProactiveBeginFrameWantedByImplThread() const { - // The output surface is the provider of BeginFrames for the impl thread, +// actually have a new frame to draw when we receive the next BeginImplFrame. +// Proactively requesting the BeginImplFrame helps hide the round trip latency +// of the SetNeedsBeginImplFrame request that has to go to the Browser. +bool SchedulerStateMachine::ProactiveBeginImplFrameWanted() const { + // The output surface is the provider of BeginImplFrames, // so we are not going to get them even if we ask for them. if (!HasInitializedOutputSurface()) return false; - // Do not be proactive if vsync is off. - if (!settings_.throttle_frame_production) - return false; - // Do not be proactive when invisible. if (!visible_) return false; - // We should proactively request a BeginFrame if a commit is pending + // We should proactively request a BeginImplFrame if a commit is pending // because we will want to draw if the commit completes quickly. if (needs_commit_ || commit_state_ != COMMIT_STATE_IDLE) return true; - // If the pending tree activates quickly, we'll want a BeginFrame soon + // If the pending tree activates quickly, we'll want a BeginImplFrame soon // to draw the new active tree. if (has_pending_tree_) return true; @@ -839,41 +874,43 @@ bool SchedulerStateMachine::ProactiveBeginFrameWantedByImplThread() const { return true; // If we just swapped, it's likely that we are going to produce another - // frame soon. This helps avoid negative glitches in our SetNeedsBeginFrame - // requests, which may propagate to the BeginFrame provider and get sampled - // at an inopportune time, delaying the next BeginFrame. + // frame soon. This helps avoid negative glitches in our + // SetNeedsBeginImplFrame requests, which may propagate to the BeginImplFrame + // provider and get sampled at an inopportune time, delaying the next + // BeginImplFrame. if (last_frame_number_swap_performed_ == current_frame_number_) return true; return false; } -void SchedulerStateMachine::OnBeginFrame(const BeginFrameArgs& args) { +void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) { current_frame_number_++; - last_begin_frame_args_ = args; - DCHECK_EQ(begin_frame_state_, BEGIN_FRAME_STATE_IDLE) << *AsValue(); - begin_frame_state_ = BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING; + last_begin_impl_frame_args_ = args; + DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) << *AsValue(); + begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING; } -void SchedulerStateMachine::OnBeginFrameDeadlinePending() { - DCHECK_EQ(begin_frame_state_, BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING) +void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() { + DCHECK_EQ(begin_impl_frame_state_, + BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) << *AsValue(); - begin_frame_state_ = BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME; + begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME; } -void SchedulerStateMachine::OnBeginFrameDeadline() { - DCHECK_EQ(begin_frame_state_, BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME) +void SchedulerStateMachine::OnBeginImplFrameDeadline() { + DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) << *AsValue(); - begin_frame_state_ = BEGIN_FRAME_STATE_INSIDE_DEADLINE; + begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; } -void SchedulerStateMachine::OnBeginFrameIdle() { - DCHECK_EQ(begin_frame_state_, BEGIN_FRAME_STATE_INSIDE_DEADLINE) +void SchedulerStateMachine::OnBeginImplFrameIdle() { + DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) << *AsValue(); - begin_frame_state_ = BEGIN_FRAME_STATE_IDLE; + begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE; } -bool SchedulerStateMachine::ShouldTriggerBeginFrameDeadlineEarly() const { +bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const { // TODO(brianderson): This should take into account multiple commit sources. // If we are in the middle of the readback, we won't swap, so there is @@ -881,7 +918,7 @@ bool SchedulerStateMachine::ShouldTriggerBeginFrameDeadlineEarly() const { if (readback_state_ != READBACK_STATE_IDLE) return false; - if (begin_frame_state_ != BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME) + if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) return false; if (active_tree_needs_first_draw_) @@ -905,6 +942,44 @@ bool SchedulerStateMachine::ShouldTriggerBeginFrameDeadlineEarly() const { return false; } +bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { + // If we just sent a BeginMainFrame and haven't hit the deadline yet, the main + // thread is in a low latency mode. + if (last_frame_number_begin_main_frame_sent_ == current_frame_number_ && + (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING || + begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)) + return false; + + // If there's a commit in progress it must either be from the previous frame + // or it started after the impl thread's deadline. In either case the main + // thread is in high latency mode. + if (commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS || + commit_state_ == COMMIT_STATE_READY_TO_COMMIT) + return true; + + // Similarly, if there's a pending tree the main thread is in high latency + // mode, because either + // it's from the previous frame + // or + // we're currently drawing the active tree and the pending tree will thus + // only be drawn in the next frame. + if (has_pending_tree_) + return true; + + if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) { + // Even if there's a new active tree to draw at the deadline or we've just + // drawn it, it may have been triggered by a previous BeginImplFrame, in + // which case the main thread is in a high latency mode. + return (active_tree_needs_first_draw_ || + last_frame_number_swap_performed_ == current_frame_number_) && + last_frame_number_begin_main_frame_sent_ != current_frame_number_; + } + + // If the active tree needs its first draw in any other state, we know the + // main thread is in a high latency mode. + return active_tree_needs_first_draw_; +} + void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() { current_frame_number_++; inside_poll_for_anticipated_draw_triggers_ = true; @@ -921,7 +996,11 @@ void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; } void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; } void SchedulerStateMachine::SetNeedsManageTiles() { - needs_manage_tiles_ = true; + if (!needs_manage_tiles_) { + TRACE_EVENT0("cc", + "SchedulerStateMachine::SetNeedsManageTiles"); + needs_manage_tiles_ = true; + } } void SchedulerStateMachine::SetSwapUsedIncompleteTile( @@ -938,6 +1017,12 @@ void SchedulerStateMachine::DidDrawIfPossibleCompleted(bool success) { draw_if_possible_failed_ = !success; if (draw_if_possible_failed_) { needs_redraw_ = true; + + // If we're already in the middle of a redraw, we don't need to + // restart it. + if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE) + return; + needs_commit_ = true; consecutive_failed_draws_++; if (settings_.timeout_and_draw_when_animation_checkerboards && @@ -950,6 +1035,7 @@ void SchedulerStateMachine::DidDrawIfPossibleCompleted(bool success) { } } else { consecutive_failed_draws_ = 0; + forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE; } } @@ -966,14 +1052,14 @@ void SchedulerStateMachine::SetNeedsForcedCommitForReadback() { // If there is already a commit in progress when we get the readback request // (we are in COMMIT_STATE_FRAME_IN_PROGRESS), then we don't need to send a - // BeginFrame for the replacement commit, since there's already a BeginFrame - // behind the readback request. In that case, we can skip - // READBACK_STATE_NEEDS_BEGIN_FRAME and go directly to + // BeginMainFrame for the replacement commit, since there's already a + // BeginMainFrame behind the readback request. In that case, we can skip + // READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME and go directly to // READBACK_STATE_WAITING_FOR_COMMIT if (commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS) readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT; else - readback_state_ = READBACK_STATE_NEEDS_BEGIN_FRAME; + readback_state_ = READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME; } void SchedulerStateMachine::FinishCommit() { @@ -981,7 +1067,7 @@ void SchedulerStateMachine::FinishCommit() { commit_state_ = COMMIT_STATE_READY_TO_COMMIT; } -void SchedulerStateMachine::BeginFrameAbortedByMainThread(bool did_handle) { +void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) { DCHECK_EQ(commit_state_, COMMIT_STATE_FRAME_IN_PROGRESS); if (did_handle) { bool commit_was_aborted = true; @@ -993,13 +1079,18 @@ void SchedulerStateMachine::BeginFrameAbortedByMainThread(bool did_handle) { } } +void SchedulerStateMachine::DidManageTiles() { + needs_manage_tiles_ = false; + last_frame_number_manage_tiles_called_ = current_frame_number_; +} + void SchedulerStateMachine::DidLoseOutputSurface() { if (output_surface_state_ == OUTPUT_SURFACE_LOST || output_surface_state_ == OUTPUT_SURFACE_CREATING) return; output_surface_state_ = OUTPUT_SURFACE_LOST; needs_redraw_ = false; - begin_frame_state_ = BEGIN_FRAME_STATE_IDLE; + begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE; } void SchedulerStateMachine::NotifyReadyToActivate() { diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h index a3d67ef765e..2e61224fb28 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.h +++ b/chromium/cc/scheduler/scheduler_state_machine.h @@ -45,17 +45,17 @@ class CC_EXPORT SchedulerStateMachine { }; static const char* OutputSurfaceStateToString(OutputSurfaceState state); - // Note: BeginFrameState will always cycle through all the states in order. - // Whether or not it actually waits or draws, it will at least try to wait in - // BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME and try to draw in - // BEGIN_FRAME_STATE_INSIDE_DEADLINE - enum BeginFrameState { - BEGIN_FRAME_STATE_IDLE, - BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING, - BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME, - BEGIN_FRAME_STATE_INSIDE_DEADLINE, + // Note: BeginImplFrameState will always cycle through all the states in + // order. Whether or not it actually waits or draws, it will at least try to + // wait in BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME and try to draw in + // BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE + enum BeginImplFrameState { + BEGIN_IMPL_FRAME_STATE_IDLE, + BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, + BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME, + BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, }; - static const char* BeginFrameStateToString(BeginFrameState state); + static const char* BeginImplFrameStateToString(BeginImplFrameState state); enum CommitState { COMMIT_STATE_IDLE, @@ -74,7 +74,7 @@ class CC_EXPORT SchedulerStateMachine { enum SynchronousReadbackState { READBACK_STATE_IDLE, - READBACK_STATE_NEEDS_BEGIN_FRAME, + READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME, READBACK_STATE_WAITING_FOR_COMMIT, READBACK_STATE_WAITING_FOR_ACTIVATION, READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK, @@ -103,7 +103,7 @@ class CC_EXPORT SchedulerStateMachine { enum Action { ACTION_NONE, - ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD, + ACTION_SEND_BEGIN_MAIN_FRAME, ACTION_COMMIT, ACTION_UPDATE_VISIBLE_TILES, ACTION_ACTIVATE_PENDING_TREE, @@ -124,28 +124,32 @@ class CC_EXPORT SchedulerStateMachine { void CheckInvariants(); - // Indicates whether the main thread needs a begin frame callback in order to - // make progress. - bool BeginFrameNeededByImplThread() const; + // Indicates whether the impl thread needs a BeginImplFrame callback in order + // to make progress. + bool BeginImplFrameNeeded() const; - // Idicates that we need to independently poll for new state and actions - // because we can't expect a BeginFrame. This is mostly used to avoid + // Indicates that we need to independently poll for new state and actions + // because we can't expect a BeginImplFrame. This is mostly used to avoid // drawing repeat frames with the synchronous compositor without dropping // necessary actions on the floor. bool ShouldPollForAnticipatedDrawTriggers() const; - // Indicates that the system has entered and left a BeginFrame callback. - // The scheduler will not draw more than once in a given BeginFrame - // callback nor send more than one BeginFrame message. - void OnBeginFrame(const BeginFrameArgs& args); - void OnBeginFrameDeadlinePending(); - void OnBeginFrameDeadline(); - void OnBeginFrameIdle(); - bool ShouldTriggerBeginFrameDeadlineEarly() const; - BeginFrameState begin_frame_state() const { - return begin_frame_state_; + // Indicates that the system has entered and left a BeginImplFrame callback. + // The scheduler will not draw more than once in a given BeginImplFrame + // callback nor send more than one BeginMainFrame message. + void OnBeginImplFrame(const BeginFrameArgs& args); + void OnBeginImplFrameDeadlinePending(); + void OnBeginImplFrameDeadline(); + void OnBeginImplFrameIdle(); + bool ShouldTriggerBeginImplFrameDeadlineEarly() const; + BeginImplFrameState begin_impl_frame_state() const { + return begin_impl_frame_state_; } + // If the main thread didn't manage to produce a new frame in time for the + // impl thread to draw, it is in a high latency mode. + bool MainThreadIsInHighLatencyMode() const; + // PollForAnticipatedDrawTriggers is used by the synchronous compositor to // avoid requesting BeginImplFrames when we won't actually draw but still // need to advance our state at vsync intervals. @@ -183,22 +187,21 @@ class CC_EXPORT SchedulerStateMachine { // thread to main. void SetNeedsCommit(); - // As SetNeedsCommit(), but ensures the begin frame will be sent to the main - // thread even if we are not visible. After this call we expect to go through + // As SetNeedsCommit(), but ensures the BeginMainFrame will be sent even + // if we are not visible. After this call we expect to go through // the forced commit flow and then return to waiting for a non-forced - // begin frame to finish. + // BeginMainFrame to finish. void SetNeedsForcedCommitForReadback(); - // Call this only in response to receiving an - // ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD from NextAction. + // Call this only in response to receiving an ACTION_SEND_BEGIN_MAIN_FRAME + // from NextAction. // Indicates that all painting is complete. void FinishCommit(); - // Call this only in response to receiving an - // ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD from NextAction if the client - // rejects the begin frame message. If did_handle is false, then - // another commit will be retried soon. - void BeginFrameAbortedByMainThread(bool did_handle); + // Call this only in response to receiving an ACTION_SEND_BEGIN_MAIN_FRAME + // from NextAction if the client rejects the BeginMainFrame message. + // If did_handle is false, then another commit will be retried soon. + void BeginMainFrameAborted(bool did_handle); // Request exclusive access to the textures that back single buffered // layers on behalf of the main thread. Upon acquisition, @@ -210,8 +213,10 @@ class CC_EXPORT SchedulerStateMachine { // Set that we can create the first OutputSurface and start the scheduler. void SetCanStart() { can_start_ = true; } + void SetSkipBeginMainFrameToReduceLatency(bool skip); + // Indicates whether drawing would, at this time, make sense. - // CanDraw can be used to supress flashes or checkerboarding + // CanDraw can be used to suppress flashes or checkerboarding // when such behavior would be undesirable. void SetCanDraw(bool can); @@ -220,6 +225,7 @@ class CC_EXPORT SchedulerStateMachine { bool has_pending_tree() const { return has_pending_tree_; } + void DidManageTiles(); void DidLoseOutputSurface(); void DidCreateAndInitializeOutputSurface(); bool HasInitializedOutputSurface() const; @@ -227,9 +233,13 @@ class CC_EXPORT SchedulerStateMachine { // True if we need to abort draws to make forward progress. bool PendingDrawsShouldBeAborted() const; + bool SupportsProactiveBeginImplFrame() const; + + bool IsCommitStateWaiting() const; + protected: - bool BeginFrameNeededToDrawByImplThread() const; - bool ProactiveBeginFrameWantedByImplThread() const; + bool BeginImplFrameNeededToDraw() const; + bool ProactiveBeginImplFrameWanted() const; // True if we need to force activations to make forward progress. bool PendingActivationsShouldBeForced() const; @@ -240,11 +250,11 @@ class CC_EXPORT SchedulerStateMachine { bool ShouldActivatePendingTree() const; bool ShouldAcquireLayerTexturesForMainThread() const; bool ShouldUpdateVisibleTiles() const; - bool ShouldSendBeginFrameToMainThread() const; + bool ShouldSendBeginMainFrame() const; bool ShouldCommit() const; bool ShouldManageTiles() const; - bool HasSentBeginFrameToMainThreadThisFrame() const; + bool HasSentBeginMainFrameThisFrame() const; bool HasScheduledManageTilesThisFrame() const; bool HasUpdatedVisibleTilesThisFrame() const; bool HasSwappedThisFrame() const; @@ -257,19 +267,20 @@ class CC_EXPORT SchedulerStateMachine { const SchedulerSettings settings_; OutputSurfaceState output_surface_state_; - BeginFrameState begin_frame_state_; + BeginImplFrameState begin_impl_frame_state_; CommitState commit_state_; TextureState texture_state_; ForcedRedrawOnTimeoutState forced_redraw_state_; SynchronousReadbackState readback_state_; - BeginFrameArgs last_begin_frame_args_; + BeginFrameArgs last_begin_impl_frame_args_; int commit_count_; int current_frame_number_; int last_frame_number_swap_performed_; - int last_frame_number_begin_frame_sent_to_main_thread_; + int last_frame_number_begin_main_frame_sent_; int last_frame_number_update_visible_tiles_was_called_; + int last_frame_number_manage_tiles_called_; int consecutive_failed_draws_; bool needs_redraw_; @@ -287,6 +298,7 @@ class CC_EXPORT SchedulerStateMachine { bool draw_if_possible_failed_; bool did_create_and_initialize_first_output_surface_; bool smoothness_takes_priority_; + bool skip_begin_main_frame_to_reduce_latency_; private: DISALLOW_COPY_AND_ASSIGN(SchedulerStateMachine); diff --git a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc index af3231b0db3..67925a059b3 100644 --- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc @@ -7,38 +7,38 @@ #include "cc/scheduler/scheduler.h" #include "testing/gtest/include/gtest/gtest.h" -#define EXPECT_ACTION_UPDATE_STATE(action) \ - EXPECT_EQ(action, state.NextAction()) << *state.AsValue(); \ - if (action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE || \ - action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED) { \ - if (SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW == \ - state.CommitState() && \ - SchedulerStateMachine::OUTPUT_SURFACE_ACTIVE != \ - state.output_surface_state()) \ - return; \ - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE, \ - state.begin_frame_state()) \ - << *state.AsValue(); \ - } \ - state.UpdateState(action); \ - if (action == SchedulerStateMachine::ACTION_NONE) { \ - if (state.begin_frame_state() == \ - SchedulerStateMachine::BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING) \ - state.OnBeginFrameDeadlinePending(); \ - if (state.begin_frame_state() == \ - SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE) \ - state.OnBeginFrameIdle(); \ +#define EXPECT_ACTION_UPDATE_STATE(action) \ + EXPECT_EQ(action, state.NextAction()) << *state.AsValue(); \ + if (action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE || \ + action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED) { \ + if (SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW == \ + state.CommitState() && \ + SchedulerStateMachine::OUTPUT_SURFACE_ACTIVE != \ + state.output_surface_state()) \ + return; \ + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, \ + state.begin_impl_frame_state()) \ + << *state.AsValue(); \ + } \ + state.UpdateState(action); \ + if (action == SchedulerStateMachine::ACTION_NONE) { \ + if (state.begin_impl_frame_state() == \ + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) \ + state.OnBeginImplFrameDeadlinePending(); \ + if (state.begin_impl_frame_state() == \ + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) \ + state.OnBeginImplFrameIdle(); \ } namespace cc { namespace { -const SchedulerStateMachine::BeginFrameState all_begin_frame_states[] = { - SchedulerStateMachine::BEGIN_FRAME_STATE_IDLE, - SchedulerStateMachine::BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING, - SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME, - SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE, }; +const SchedulerStateMachine::BeginImplFrameState all_begin_impl_frame_states[] = + {SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE, + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME, + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, }; const SchedulerStateMachine::CommitState all_commit_states[] = { SchedulerStateMachine::COMMIT_STATE_IDLE, @@ -60,9 +60,17 @@ class StateMachine : public SchedulerStateMachine { void SetCommitState(CommitState cs) { commit_state_ = cs; } CommitState CommitState() const { return commit_state_; } - void SetBeginFrameState(BeginFrameState bfs) { begin_frame_state_ = bfs; } + ForcedRedrawOnTimeoutState ForcedRedrawState() const { + return forced_redraw_state_; + } + + void SetBeginImplFrameState(BeginImplFrameState bifs) { + begin_impl_frame_state_ = bifs; + } - BeginFrameState begin_frame_state() const { return begin_frame_state_; } + BeginImplFrameState begin_impl_frame_state() const { + return begin_impl_frame_state_; + } OutputSurfaceState output_surface_state() const { return output_surface_state_; @@ -115,14 +123,14 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) { state.SetNeedsRedraw(false); state.SetVisible(true); - EXPECT_FALSE(state.BeginFrameNeededByImplThread()); + EXPECT_FALSE(state.BeginImplFrameNeeded()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_FALSE(state.BeginFrameNeededByImplThread()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_FALSE(state.BeginImplFrameNeeded()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); } // If commit requested but can_start is still false, do nothing. @@ -132,13 +140,13 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) { state.SetNeedsRedraw(false); state.SetVisible(true); - EXPECT_FALSE(state.BeginFrameNeededByImplThread()); + EXPECT_FALSE(state.BeginImplFrameNeeded()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_FALSE(state.BeginFrameNeededByImplThread()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_FALSE(state.BeginImplFrameNeeded()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); } // If commit requested, begin a main frame. @@ -148,7 +156,7 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) { state.SetCanStart(); state.SetNeedsRedraw(false); state.SetVisible(true); - EXPECT_FALSE(state.BeginFrameNeededByImplThread()); + EXPECT_FALSE(state.BeginImplFrameNeeded()); } // Begin the frame, make sure needs_commit and commit_state update correctly. @@ -158,8 +166,7 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) { state.UpdateState(state.NextAction()); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); state.SetVisible(true); - state.UpdateState( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + state.UpdateState(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.CommitState()); EXPECT_FALSE(state.NeedsCommit()); @@ -177,10 +184,10 @@ TEST(SchedulerStateMachineTest, state.SetCanDraw(true); state.SetNeedsRedraw(true); EXPECT_TRUE(state.RedrawPending()); - EXPECT_TRUE(state.BeginFrameNeededByImplThread()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_TRUE(state.BeginImplFrameNeeded()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); // We're drawing now. EXPECT_ACTION_UPDATE_STATE( @@ -192,9 +199,9 @@ TEST(SchedulerStateMachineTest, // Failing the draw makes us require a commit. state.DidDrawIfPossibleCompleted(false); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_TRUE(state.RedrawPending()); EXPECT_TRUE(state.CommitPending()); } @@ -211,10 +218,10 @@ TEST(SchedulerStateMachineTest, state.SetCanDraw(true); state.SetNeedsRedraw(true); EXPECT_TRUE(state.RedrawPending()); - EXPECT_TRUE(state.BeginFrameNeededByImplThread()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_TRUE(state.BeginImplFrameNeeded()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); // We're drawing now. EXPECT_ACTION_UPDATE_STATE( @@ -223,16 +230,16 @@ TEST(SchedulerStateMachineTest, EXPECT_FALSE(state.RedrawPending()); EXPECT_FALSE(state.CommitPending()); - // While still in the same begin frame callback on the main thread, + // While still in the same BeginMainFrame callback on the main thread, // set needs redraw again. This should not redraw. state.SetNeedsRedraw(true); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Failing the draw makes us require a commit. state.DidDrawIfPossibleCompleted(false); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_TRUE(state.RedrawPending()); } @@ -252,27 +259,27 @@ void TestFailedDrawsWillEventuallyForceADrawAfterTheNextCommit( state.SetNeedsCommit(); if (!deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); if (deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.CommitPending()); // Then initiate a draw. state.SetNeedsRedraw(true); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); // Fail the draw. state.DidDrawIfPossibleCompleted(false); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_TRUE(state.BeginFrameNeededByImplThread()); + EXPECT_TRUE(state.BeginImplFrameNeeded()); EXPECT_TRUE(state.RedrawPending()); // But the commit is ongoing. EXPECT_TRUE(state.CommitPending()); @@ -284,10 +291,10 @@ void TestFailedDrawsWillEventuallyForceADrawAfterTheNextCommit( EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.RedrawPending()); - // The redraw should be forced at the end of the next BeginFrame. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + // The redraw should be forced at the end of the next BeginImplFrame. + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED); } @@ -306,8 +313,90 @@ TEST(SchedulerStateMachineTest, deadline_scheduling_enabled); } +void TestFailedDrawsDoNotRestartForcedDraw( + bool deadline_scheduling_enabled) { + SchedulerSettings scheduler_settings; + int drawLimit = 1; + scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ = + drawLimit; + scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; + scheduler_settings.impl_side_painting = true; + StateMachine state(scheduler_settings); + state.SetCanStart(); + state.UpdateState(state.NextAction()); + state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); + state.SetVisible(true); + state.SetCanDraw(true); + + // Start a commit. + state.SetNeedsCommit(); + if (!deadline_scheduling_enabled) { + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); + } + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); + if (deadline_scheduling_enabled) { + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); + } + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + EXPECT_TRUE(state.CommitPending()); + + // Then initiate a draw. + state.SetNeedsRedraw(true); + state.OnBeginImplFrameDeadline(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); + + // Fail the draw enough times to force a redraw, + // then once more for good measure. + for (int i = 0; i < drawLimit; ++i) + state.DidDrawIfPossibleCompleted(false); + state.DidDrawIfPossibleCompleted(false); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + EXPECT_TRUE(state.BeginImplFrameNeeded()); + EXPECT_TRUE(state.RedrawPending()); + // But the commit is ongoing. + EXPECT_TRUE(state.CommitPending()); + EXPECT_TRUE(state.ForcedRedrawState() == + SchedulerStateMachine::FORCED_REDRAW_STATE_WAITING_FOR_COMMIT); + + state.FinishCommit(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + EXPECT_TRUE(state.RedrawPending()); + EXPECT_FALSE(state.CommitPending()); + + // Now force redraw should be in waiting for activation + EXPECT_TRUE(state.ForcedRedrawState() == + SchedulerStateMachine::FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION); + + // After failing additional draws, we should still be in a forced + // redraw, but not back in WAITING_FOR_COMMIT. + for (int i = 0; i < drawLimit; ++i) + state.DidDrawIfPossibleCompleted(false); + state.DidDrawIfPossibleCompleted(false); + EXPECT_TRUE(state.RedrawPending()); + EXPECT_TRUE(state.ForcedRedrawState() == + SchedulerStateMachine::FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION); +} + +TEST(SchedulerStateMachineTest, + TestFailedDrawsDoNotRestartForcedDraw) { + bool deadline_scheduling_enabled = false; + TestFailedDrawsDoNotRestartForcedDraw( + deadline_scheduling_enabled); +} + TEST(SchedulerStateMachineTest, - TestFailedDrawIsRetriedInNextBeginFrameForImplThread) { + TestFailedDrawsDoNotRestartForcedDraw_Deadline) { + bool deadline_scheduling_enabled = true; + TestFailedDrawsDoNotRestartForcedDraw( + deadline_scheduling_enabled); +} + +TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); @@ -318,10 +407,10 @@ TEST(SchedulerStateMachineTest, // Start a draw. state.SetNeedsRedraw(true); - EXPECT_TRUE(state.BeginFrameNeededByImplThread()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_TRUE(state.BeginImplFrameNeeded()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_TRUE(state.RedrawPending()); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); @@ -329,18 +418,18 @@ TEST(SchedulerStateMachineTest, // Fail the draw state.DidDrawIfPossibleCompleted(false); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.RedrawPending()); // We should not be trying to draw again now, but we have a commit pending. - EXPECT_TRUE(state.BeginFrameNeededByImplThread()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_TRUE(state.BeginImplFrameNeeded()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // We should try to draw again at the end of the next BeginFrame on + // We should try to draw again at the end of the next BeginImplFrame on // the impl thread. - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -357,57 +446,58 @@ TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) { state.SetNeedsRedraw(true); // Draw the first frame. - EXPECT_TRUE(state.BeginFrameNeededByImplThread()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_TRUE(state.BeginImplFrameNeeded()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidDrawIfPossibleCompleted(true); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // Before the next begin frame for the impl thread, set needs redraw - // again. This should not redraw until the next begin frame. + // Before the next BeginImplFrame, set needs redraw again. + // This should not redraw until the next BeginImplFrame. state.SetNeedsRedraw(true); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Move to another frame. This should now draw. - EXPECT_TRUE(state.BeginFrameNeededByImplThread()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_TRUE(state.BeginImplFrameNeeded()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidDrawIfPossibleCompleted(true); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // We just swapped, so we should proactively request another BeginFrame. - EXPECT_TRUE(state.BeginFrameNeededByImplThread()); + // We just swapped, so we should proactively request another BeginImplFrame. + EXPECT_TRUE(state.BeginImplFrameNeeded()); } -TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginFrame) { +TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginImplFrame) { SchedulerSettings default_scheduler_settings; - // When not in BeginFrame deadline, or in BeginFrame deadline but not visible, - // don't draw. + // When not in BeginImplFrame deadline, or in BeginImplFrame deadline + // but not visible, don't draw. size_t num_commit_states = sizeof(all_commit_states) / sizeof(SchedulerStateMachine::CommitState); - size_t num_begin_frame_states = - sizeof(all_begin_frame_states) / - sizeof(SchedulerStateMachine::BeginFrameState); + size_t num_begin_impl_frame_states = + sizeof(all_begin_impl_frame_states) / + sizeof(SchedulerStateMachine::BeginImplFrameState); for (size_t i = 0; i < num_commit_states; ++i) { - for (size_t j = 0; j < num_begin_frame_states; ++j) { + for (size_t j = 0; j < num_begin_impl_frame_states; ++j) { StateMachine state(default_scheduler_settings); state.SetCanStart(); state.UpdateState(state.NextAction()); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); state.SetCommitState(all_commit_states[i]); - state.SetBeginFrameState(all_begin_frame_states[j]); - bool visible = (all_begin_frame_states[j] != - SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE); + state.SetBeginImplFrameState(all_begin_impl_frame_states[j]); + bool visible = + (all_begin_impl_frame_states[j] != + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); state.SetVisible(visible); // Case 1: needs_commit=false @@ -422,7 +512,7 @@ TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginFrame) { } } - // When in BeginFrame deadline we should always draw for SetNeedsRedraw or + // When in BeginImplFrame deadline we should always draw for SetNeedsRedraw or // SetNeedsForcedRedrawForReadback have been called... except if we're // ready to commit, in which case we expect a commit first. for (size_t i = 0; i < num_commit_states; ++i) { @@ -441,8 +531,8 @@ TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginFrame) { state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); state.SetCanDraw(true); state.SetCommitState(all_commit_states[i]); - state.SetBeginFrameState( - SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE); + state.SetBeginImplFrameState( + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); if (request_readback) { state.SetNeedsForcedRedrawForReadback(); } else { @@ -466,13 +556,13 @@ TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginFrame) { } // Case 1: needs_commit=false. - EXPECT_NE(state.BeginFrameNeededByImplThread(), request_readback) + EXPECT_NE(state.BeginImplFrameNeeded(), request_readback) << *state.AsValue(); EXPECT_EQ(expected_action, state.NextAction()) << *state.AsValue(); // Case 2: needs_commit=true. state.SetNeedsCommit(); - EXPECT_NE(state.BeginFrameNeededByImplThread(), request_readback) + EXPECT_NE(state.BeginImplFrameNeeded(), request_readback) << *state.AsValue(); EXPECT_EQ(expected_action, state.NextAction()) << *state.AsValue(); } @@ -485,7 +575,7 @@ TEST(SchedulerStateMachineTest, TestNoCommitStatesRedrawWhenInvisible) { size_t num_commit_states = sizeof(all_commit_states) / sizeof(SchedulerStateMachine::CommitState); for (size_t i = 0; i < num_commit_states; ++i) { - // There shouldn't be any drawing regardless of BeginFrame. + // There shouldn't be any drawing regardless of BeginImplFrame. for (size_t j = 0; j < 2; ++j) { StateMachine state(default_scheduler_settings); state.SetCanStart(); @@ -495,8 +585,8 @@ TEST(SchedulerStateMachineTest, TestNoCommitStatesRedrawWhenInvisible) { state.SetVisible(false); state.SetNeedsRedraw(true); if (j == 1) { - state.SetBeginFrameState( - SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE); + state.SetBeginImplFrameState( + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); } // Case 1: needs_commit=false. @@ -518,7 +608,7 @@ TEST(SchedulerStateMachineTest, TestCanRedraw_StopsDraw) { size_t num_commit_states = sizeof(all_commit_states) / sizeof(SchedulerStateMachine::CommitState); for (size_t i = 0; i < num_commit_states; ++i) { - // There shouldn't be any drawing regardless of BeginFrame. + // There shouldn't be any drawing regardless of BeginImplFrame. for (size_t j = 0; j < 2; ++j) { StateMachine state(default_scheduler_settings); state.SetCanStart(); @@ -528,7 +618,7 @@ TEST(SchedulerStateMachineTest, TestCanRedraw_StopsDraw) { state.SetVisible(false); state.SetNeedsRedraw(true); if (j == 1) - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); state.SetCanDraw(false); EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE, @@ -552,14 +642,14 @@ TEST(SchedulerStateMachineTest, state.SetNeedsRedraw(true); state.SetVisible(true); state.SetCanDraw(false); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.FinishCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } @@ -574,12 +664,12 @@ TEST(SchedulerStateMachineTest, TestsetNeedsCommitIsNotLost) { state.SetVisible(true); state.SetCanDraw(true); - EXPECT_TRUE(state.BeginFrameNeededByImplThread()); + EXPECT_TRUE(state.BeginImplFrameNeeded()); // Begin the frame. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.CommitState()); @@ -592,35 +682,35 @@ TEST(SchedulerStateMachineTest, TestsetNeedsCommitIsNotLost) { EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT, state.CommitState()); - // Expect to commit regardless of BeginFrame state. - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING, - state.begin_frame_state()); + // Expect to commit regardless of BeginImplFrame state. + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction()); - state.OnBeginFrameDeadlinePending(); - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME, - state.begin_frame_state()); + state.OnBeginImplFrameDeadlinePending(); + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction()); - state.OnBeginFrameDeadline(); - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE, - state.begin_frame_state()); + state.OnBeginImplFrameDeadline(); + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction()); - state.OnBeginFrameIdle(); - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_IDLE, - state.begin_frame_state()); + state.OnBeginImplFrameIdle(); + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING, - state.begin_frame_state()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction()); - // Commit and make sure we draw on next BeginFrame + // Commit and make sure we draw on next BeginImplFrame EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW, state.CommitState()); EXPECT_ACTION_UPDATE_STATE( @@ -629,7 +719,7 @@ TEST(SchedulerStateMachineTest, TestsetNeedsCommitIsNotLost) { // Verify that another commit will start immediately after draw. EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } @@ -646,9 +736,9 @@ TEST(SchedulerStateMachineTest, TestFullCycle) { state.SetNeedsCommit(); // Begin the frame. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.CommitState()); EXPECT_FALSE(state.NeedsCommit()); @@ -665,11 +755,11 @@ TEST(SchedulerStateMachineTest, TestFullCycle) { state.CommitState()); EXPECT_TRUE(state.needs_redraw()); - // Expect to do nothing until BeginFrame deadline + // Expect to do nothing until BeginImplFrame deadline EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // At BeginFrame deadline, draw. - state.OnBeginFrameDeadline(); + // At BeginImplFrame deadline, draw. + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidDrawIfPossibleCompleted(true); @@ -693,9 +783,9 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) { state.SetNeedsCommit(); // Begin the frame. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.CommitState()); EXPECT_FALSE(state.NeedsCommit()); @@ -716,11 +806,11 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) { state.CommitState()); EXPECT_TRUE(state.needs_redraw()); - // Expect to do nothing until BeginFrame deadline. + // Expect to do nothing until BeginImplFrame deadline. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // At BeginFrame deadline, draw. - state.OnBeginFrameDeadline(); + // At BeginImplFrame deadline, draw. + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidDrawIfPossibleCompleted(true); @@ -730,10 +820,10 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) { EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState()); EXPECT_FALSE(state.needs_redraw()); - // Next BeginFrame should initiate second commit. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + // Next BeginImplFrame should initiate second commit. + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } TEST(SchedulerStateMachineTest, TestRequestCommitInvisible) { @@ -759,39 +849,39 @@ TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) { state.SetNeedsCommit(); // Begin the frame while visible. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.CommitState()); EXPECT_FALSE(state.NeedsCommit()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // Become invisible and abort the main thread's begin frame. + // Become invisible and abort BeginMainFrame. state.SetVisible(false); - state.BeginFrameAbortedByMainThread(false); + state.BeginMainFrameAborted(false); // We should now be back in the idle state as if we never started the frame. EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // We shouldn't do anything on the BeginFrame deadline. - state.OnBeginFrameDeadline(); + // We shouldn't do anything on the BeginImplFrame deadline. + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Become visible again. state.SetVisible(true); // Although we have aborted on this frame and haven't cancelled the commit - // (i.e. need another), don't send another begin frame yet. + // (i.e. need another), don't send another BeginMainFrame yet. EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState()); EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction()); EXPECT_TRUE(state.NeedsCommit()); // Start a new frame. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); // We should be starting the commit now. EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, @@ -799,7 +889,7 @@ TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } -TEST(SchedulerStateMachineTest, AbortBeginFrameAndCancelCommit) { +TEST(SchedulerStateMachineTest, AbortBeginMainFrameAndCancelCommit) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); @@ -812,14 +902,14 @@ TEST(SchedulerStateMachineTest, AbortBeginFrameAndCancelCommit) { state.SetNeedsCommit(); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.CommitState()); EXPECT_FALSE(state.NeedsCommit()); EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction()); // Abort the commit, cancelling future commits. - state.BeginFrameAbortedByMainThread(true); + state.BeginMainFrameAborted(true); // Verify that another commit doesn't start on the same frame. EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState()); @@ -828,9 +918,9 @@ TEST(SchedulerStateMachineTest, AbortBeginFrameAndCancelCommit) { // Start a new frame; draw because this is the first frame since output // surface init'd. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); @@ -842,7 +932,7 @@ TEST(SchedulerStateMachineTest, AbortBeginFrameAndCancelCommit) { // Verify another commit can start if requested, though. state.SetNeedsCommit(); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState()); - EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD, + EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME, state.NextAction()); } @@ -859,16 +949,16 @@ TEST(SchedulerStateMachineTest, TestFirstContextCreation) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Check that the first init does not SetNeedsCommit. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // Check that a needs commit initiates a BeginFrame to the main thread. + // Check that a needs commit initiates a BeginMainFrame. state.SetNeedsCommit(); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) { @@ -896,9 +986,9 @@ TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) { state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); // When the context is recreated, we should begin a commit. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } TEST(SchedulerStateMachineTest, @@ -920,16 +1010,16 @@ TEST(SchedulerStateMachineTest, EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Once context recreation begins, nothing should happen. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // While context is recreating, commits shouldn't begin. state.SetNeedsCommit(); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Recreate the context @@ -938,7 +1028,7 @@ TEST(SchedulerStateMachineTest, // When the context is recreated, we should begin a commit EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.CommitState()); @@ -951,9 +1041,9 @@ TEST(SchedulerStateMachineTest, // Once the context is recreated, whether we draw should be based on // SetCanDraw. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE, state.NextAction()); state.SetCanDraw(false); @@ -978,24 +1068,23 @@ void TestContextLostWhileCommitInProgress(bool deadline_scheduling_enabled) { state.SetNeedsCommit(); if (!deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } // Set damage and expect a draw. state.SetNeedsRedraw(true); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); if (deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // Cause a lost context while the begin frame is in flight - // for the main thread. + // Cause a lost context while the BeginMainFrame is in flight. state.DidLoseOutputSurface(); // Ask for another draw. Expect nothing happens. @@ -1013,27 +1102,27 @@ void TestContextLostWhileCommitInProgress(bool deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT); // Expect to be told to begin context recreation, independent of - // BeginFrame state. - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_IDLE, - state.begin_frame_state()); + // BeginImplFrame state. + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING, - state.begin_frame_state()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); - state.OnBeginFrameDeadlinePending(); - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME, - state.begin_frame_state()); + state.OnBeginImplFrameDeadlinePending(); + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); - state.OnBeginFrameDeadline(); - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE, - state.begin_frame_state()); + state.OnBeginImplFrameDeadline(); + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); } @@ -1063,25 +1152,24 @@ void TestContextLostWhileCommitInProgressAndAnotherCommitRequested( state.SetNeedsCommit(); if (!deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Set damage and expect a draw. state.SetNeedsRedraw(true); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); if (deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // Cause a lost context while the begin frame is in flight - // for the main thread. + // Cause a lost context while the BeginMainFrame is in flight. state.DidLoseOutputSurface(); // Ask for another draw and also set needs commit. Expect nothing happens. @@ -1099,27 +1187,27 @@ void TestContextLostWhileCommitInProgressAndAnotherCommitRequested( EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT); // Expect to be told to begin context recreation, independent of - // BeginFrame state - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_IDLE, - state.begin_frame_state()); + // BeginImplFrame state + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_BEGIN_FRAME_STARTING, - state.begin_frame_state()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); - state.OnBeginFrameDeadlinePending(); - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME, - state.begin_frame_state()); + state.OnBeginImplFrameDeadlinePending(); + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); - state.OnBeginFrameDeadline(); - EXPECT_EQ(SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE, - state.begin_frame_state()); + state.OnBeginImplFrameDeadline(); + EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, + state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); @@ -1127,15 +1215,15 @@ void TestContextLostWhileCommitInProgressAndAnotherCommitRequested( EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); - state.OnBeginFrameIdle(); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrameIdle(); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.FinishCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1171,7 +1259,7 @@ TEST(SchedulerStateMachineTest, TestFinishAllRenderingWhileContextLost) { state.SetCommitState( SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW); state.SetNeedsForcedRedrawForReadback(); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_READBACK); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1186,12 +1274,12 @@ TEST(SchedulerStateMachineTest, TestFinishAllRenderingWhileContextLost) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT); // Expect to be told to begin context recreation, independent of - // BeginFrame state + // BeginImplFrame state EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState()); EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); - state.OnBeginFrameDeadline(); + state.OnBeginImplFrameDeadline(); EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); @@ -1222,13 +1310,13 @@ TEST(SchedulerStateMachineTest, DontDrawBeforeCommitAfterLostOutputSurface) { state.DidCreateAndInitializeOutputSurface(); EXPECT_FALSE(state.RedrawPending()); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD, + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME, state.NextAction()); } TEST(SchedulerStateMachineTest, - TestSendBeginFrameToMainThreadWhenInvisibleAndForceCommit) { + TestSendBeginMainFrameWhenInvisibleAndForceCommit) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); @@ -1237,19 +1325,19 @@ TEST(SchedulerStateMachineTest, state.SetVisible(false); state.SetNeedsCommit(); state.SetNeedsForcedCommitForReadback(); - EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD, + EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME, state.NextAction()); } TEST(SchedulerStateMachineTest, - TestSendBeginFrameToMainThreadWhenCanStartFalseAndForceCommit) { + TestSendBeginMainFrameWhenCanStartFalseAndForceCommit) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetVisible(true); state.SetCanDraw(true); state.SetNeedsCommit(); state.SetNeedsForcedCommitForReadback(); - EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD, + EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME, state.NextAction()); } @@ -1292,8 +1380,8 @@ TEST(SchedulerStateMachineTest, TestFinishCommitWhenForcedCommitInProgress) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_READBACK); // When the readback interrupts the normal commit, we should not get - // another BeginFrame on the impl thread when the readback completes. - EXPECT_NE(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD, + // another BeginMainFrame when the readback completes. + EXPECT_NE(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME, state.NextAction()); // The normal commit can then proceed. @@ -1321,19 +1409,19 @@ TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) { EXPECT_EQ(state.output_surface_state(), SchedulerStateMachine::OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT); - // We should not send a BeginFrame to them main thread when we are invisible, - // even if we've lost the output surface and are trying to get the first - // commit, since the main thread will just abort anyway. + // We should not send a BeginMainFrame when we are invisible, even if we've + // lost the output surface and are trying to get the first commit, since the + // main thread will just abort anyway. state.SetVisible(false); - EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, - state.NextAction()) << *state.AsValue(); + EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction()) + << *state.AsValue(); // If there is a forced commit, however, we could be blocking a readback // on the main thread, so we need to unblock it before we can get our // output surface, even if we are not visible. state.SetNeedsForcedCommitForReadback(); - EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD, - state.NextAction()) + EXPECT_EQ( + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME, state.NextAction()) << *state.AsValue(); } @@ -1350,7 +1438,7 @@ TEST(SchedulerStateMachineTest, TestImmediateFinishCommit) { state.SetNeedsCommit(); state.SetNeedsForcedCommitForReadback(); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); state.FinishCommit(); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT, @@ -1365,7 +1453,7 @@ TEST(SchedulerStateMachineTest, TestImmediateFinishCommit) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // Should be waiting for the normal begin frame from the main thread. + // Should be waiting for the normal BeginMainFrame. EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.CommitState()); } @@ -1384,7 +1472,7 @@ void TestImmediateFinishCommitDuringCommit(bool deadline_scheduling_enabled) { state.SetNeedsCommit(); if (!deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1392,7 +1480,7 @@ void TestImmediateFinishCommitDuringCommit(bool deadline_scheduling_enabled) { state.SetNeedsForcedCommitForReadback(); if (deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.FinishCommit(); @@ -1407,14 +1495,13 @@ void TestImmediateFinishCommitDuringCommit(bool deadline_scheduling_enabled) { state.DidDrawIfPossibleCompleted(true); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // Should be waiting for the normal begin frame from the main thread. + // Should be waiting for the normal BeginMainFrame. EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.CommitState()) << *state.AsValue(); } -TEST(SchedulerStateMachineTest, - TestImmediateFinishCommitDuringCommit) { +TEST(SchedulerStateMachineTest, TestImmediateFinishCommitDuringCommit) { bool deadline_scheduling_enabled = false; TestImmediateFinishCommitDuringCommit(deadline_scheduling_enabled); } @@ -1425,7 +1512,7 @@ TEST(SchedulerStateMachineTest, TestImmediateFinishCommitDuringCommit(deadline_scheduling_enabled); } -void ImmediateBeginFrameAbortedByMainThreadWhileInvisible( +void ImmediateBeginMainFrameAbortedWhileInvisible( bool deadline_scheduling_enabled) { SchedulerSettings scheduler_settings; scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; @@ -1439,7 +1526,7 @@ void ImmediateBeginFrameAbortedByMainThreadWhileInvisible( state.SetNeedsCommit(); if (!deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1447,7 +1534,7 @@ void ImmediateBeginFrameAbortedByMainThreadWhileInvisible( state.SetNeedsForcedCommitForReadback(); if (deadline_scheduling_enabled) { EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } state.FinishCommit(); @@ -1462,14 +1549,14 @@ void ImmediateBeginFrameAbortedByMainThreadWhileInvisible( state.DidDrawIfPossibleCompleted(true); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // Should be waiting for the main thread's begin frame. + // Should be waiting for BeginMainFrame. EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.CommitState()) << *state.AsValue(); - // Become invisible and abort the main thread's begin frame. + // Become invisible and abort BeginMainFrame. state.SetVisible(false); - state.BeginFrameAbortedByMainThread(false); + state.BeginMainFrameAborted(false); // Should be back in the idle state, but needing a commit. EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState()); @@ -1477,16 +1564,16 @@ void ImmediateBeginFrameAbortedByMainThreadWhileInvisible( } TEST(SchedulerStateMachineTest, - ImmediateBeginFrameAbortedByMainThreadWhileInvisible) { + ImmediateBeginMainFrameAbortedWhileInvisible) { bool deadline_scheduling_enabled = false; - ImmediateBeginFrameAbortedByMainThreadWhileInvisible( + ImmediateBeginMainFrameAbortedWhileInvisible( deadline_scheduling_enabled); } TEST(SchedulerStateMachineTest, - ImmediateBeginFrameAbortedByMainThreadWhileInvisible_Deadline) { + ImmediateBeginMainFrameAbortedWhileInvisible_Deadline) { bool deadline_scheduling_enabled = true; - ImmediateBeginFrameAbortedByMainThreadWhileInvisible( + ImmediateBeginMainFrameAbortedWhileInvisible( deadline_scheduling_enabled); } @@ -1564,9 +1651,9 @@ TEST(SchedulerStateMachineTest, ReportIfNotDrawingFromAcquiredTextures) { EXPECT_TRUE(state.PendingActivationsShouldBeForced()); state.SetNeedsCommit(); - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_TRUE(state.PendingDrawsShouldBeAborted()); EXPECT_TRUE(state.PendingActivationsShouldBeForced()); @@ -1600,14 +1687,14 @@ TEST(SchedulerStateMachineTest, AcquireTexturesWithAbort) { EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction()); state.SetNeedsCommit(); - EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD, + EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME, state.NextAction()); state.UpdateState(state.NextAction()); EXPECT_TRUE(state.PendingDrawsShouldBeAborted()); EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction()); - state.BeginFrameAbortedByMainThread(true); + state.BeginMainFrameAborted(true); EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction()); EXPECT_FALSE(state.PendingDrawsShouldBeAborted()); @@ -1627,7 +1714,7 @@ TEST(SchedulerStateMachineTest, // This test mirrors what happens during the first frame of a scroll gesture. // First we get the input event and a BeginFrame. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); // As a response the compositor requests a redraw and a commit to tell the // main thread about the new scroll offset. @@ -1636,16 +1723,16 @@ TEST(SchedulerStateMachineTest, // We should start the commit normally. EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Since only the scroll offset changed, the main thread will abort the // commit. - state.BeginFrameAbortedByMainThread(true); + state.BeginMainFrameAborted(true); // Since the commit was aborted, we should draw right away instead of waiting // for the deadline. - EXPECT_TRUE(state.ShouldTriggerBeginFrameDeadlineEarly()); + EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); } TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyForSmoothness) { @@ -1661,17 +1748,17 @@ TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyForSmoothness) { // This test ensures that impl-draws are prioritized over main thread updates // in prefer smoothness mode. - state.OnBeginFrame(BeginFrameArgs::CreateForTesting()); + state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting()); state.SetNeedsRedraw(true); state.SetNeedsCommit(); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD); + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // The deadline is not triggered early until we enter prefer smoothness mode. - EXPECT_FALSE(state.ShouldTriggerBeginFrameDeadlineEarly()); + EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); state.SetSmoothnessTakesPriority(true); - EXPECT_TRUE(state.ShouldTriggerBeginFrameDeadlineEarly()); + EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); } } // namespace diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc index a1da822cff1..6f5eb2c2dcd 100644 --- a/chromium/cc/scheduler/scheduler_unittest.cc +++ b/chromium/cc/scheduler/scheduler_unittest.cc @@ -8,6 +8,9 @@ #include "base/logging.h" #include "base/memory/scoped_vector.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/time/time.h" #include "cc/test/scheduler_test_common.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -33,17 +36,18 @@ void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler) { scheduler->SetNeedsCommit(); scheduler->FinishCommit(); // Go through the motions to draw the commit. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); - // We need another BeginFrame so Scheduler calls SetNeedsBeginFrame(false). - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); + // We need another BeginImplFrame so Scheduler calls + // SetNeedsBeginImplFrame(false). + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); } class FakeSchedulerClient : public SchedulerClient { public: FakeSchedulerClient() - : needs_begin_frame_(false) { + : needs_begin_impl_frame_(false) { Reset(); } @@ -53,14 +57,20 @@ class FakeSchedulerClient : public SchedulerClient { draw_will_happen_ = true; swap_will_happen_if_draw_happens_ = true; num_draws_ = 0; + log_anticipated_draw_time_change_ = false; } Scheduler* CreateScheduler(const SchedulerSettings& settings) { - scheduler_ = Scheduler::Create(this, settings); + scheduler_ = Scheduler::Create(this, settings, 0); return scheduler_.get(); } - bool needs_begin_frame() { return needs_begin_frame_; } + // Most tests don't care about DidAnticipatedDrawTimeChange, so only record it + // for tests that do. + void set_log_anticipated_draw_time_change(bool log) { + log_anticipated_draw_time_change_ = log; + } + bool needs_begin_impl_frame() { return needs_begin_impl_frame_; } int num_draws() const { return num_draws_; } int num_actions_() const { return static_cast<int>(actions_.size()); } const char* Action(int i) const { return actions_[i]; } @@ -84,14 +94,14 @@ class FakeSchedulerClient : public SchedulerClient { swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens; } - // Scheduler Implementation. - virtual void SetNeedsBeginFrameOnImplThread(bool enable) OVERRIDE { - actions_.push_back("SetNeedsBeginFrameOnImplThread"); + // SchedulerClient implementation. + virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE { + actions_.push_back("SetNeedsBeginImplFrame"); states_.push_back(scheduler_->StateAsValue().release()); - needs_begin_frame_ = enable; + needs_begin_impl_frame_ = enable; } - virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE { - actions_.push_back("ScheduledActionSendBeginFrameToMainThread"); + virtual void ScheduledActionSendBeginMainFrame() OVERRIDE { + actions_.push_back("ScheduledActionSendBeginMainFrame"); states_.push_back(scheduler_->StateAsValue().release()); } virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() @@ -145,36 +155,40 @@ class FakeSchedulerClient : public SchedulerClient { actions_.push_back("ScheduledActionManageTiles"); states_.push_back(scheduler_->StateAsValue().release()); } - virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {} + virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE { + if (log_anticipated_draw_time_change_) + actions_.push_back("DidAnticipatedDrawTimeChange"); + } virtual base::TimeDelta DrawDurationEstimate() OVERRIDE { return base::TimeDelta(); } - virtual base::TimeDelta BeginFrameToCommitDurationEstimate() OVERRIDE { + virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE { return base::TimeDelta(); } virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE { return base::TimeDelta(); } - virtual void PostBeginFrameDeadline(const base::Closure& closure, - base::TimeTicks deadline) OVERRIDE { - actions_.push_back("PostBeginFrameDeadlineTask"); + virtual void PostBeginImplFrameDeadline(const base::Closure& closure, + base::TimeTicks deadline) OVERRIDE { + actions_.push_back("PostBeginImplFrameDeadlineTask"); states_.push_back(scheduler_->StateAsValue().release()); } - virtual void DidBeginFrameDeadlineOnImplThread() OVERRIDE {} + virtual void DidBeginImplFrameDeadline() OVERRIDE {} protected: - bool needs_begin_frame_; + bool needs_begin_impl_frame_; bool draw_will_happen_; bool swap_will_happen_if_draw_happens_; int num_draws_; + bool log_anticipated_draw_time_change_; std::vector<const char*> actions_; ScopedVector<base::Value> states_; scoped_ptr<Scheduler> scheduler_; }; -TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginFrame) { +TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) { FakeSchedulerClient client; SchedulerSettings default_scheduler_settings; Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); @@ -200,63 +214,64 @@ void RequestCommit(bool deadline_scheduling_enabled) { EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); InitializeOutputSurfaceAndFirstCommit(scheduler); - // SetNeedsCommit should begin the frame on the next BeginFrame. + // SetNeedsCommit should begin the frame on the next BeginImplFrame. client.Reset(); scheduler->SetNeedsCommit(); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); if (deadline_scheduling_enabled) { - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); } else { EXPECT_EQ(client.num_actions_(), 2); - EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginFrameToMainThread")); - EXPECT_TRUE(client.HasAction("SetNeedsBeginFrameOnImplThread")); + EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); + EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame")); } client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); if (deadline_scheduling_enabled) { - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); + EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); } else { - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); } - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); - // If we don't swap on the deadline, we need to request another BeginFrame. - scheduler->OnBeginFrameDeadline(); - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); - EXPECT_TRUE(client.needs_begin_frame()); + // If we don't swap on the deadline, we need to request another + // BeginImplFrame. + scheduler->OnBeginImplFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); // FinishCommit should commit scheduler->FinishCommit(); EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); - // BeginFrame should prepare the draw. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); - EXPECT_TRUE(client.needs_begin_frame()); + // BeginImplFrame should prepare the draw. + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); - // BeginFrame deadline should draw. - scheduler->OnBeginFrameDeadline(); + // BeginImplFrame deadline should draw. + scheduler->OnBeginImplFrameDeadline(); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); - // The following BeginFrame deadline should SetNeedsBeginFrame(false) to avoid - // excessive toggles. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + // The following BeginImplFrame deadline should SetNeedsBeginImplFrame(false) + // to avoid excessive toggles. + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); client.Reset(); - scheduler->OnBeginFrameDeadline(); - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); - EXPECT_FALSE(client.needs_begin_frame()); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); + EXPECT_FALSE(client.needs_begin_impl_frame()); client.Reset(); } @@ -270,7 +285,7 @@ TEST(SchedulerTest, RequestCommit_Deadline) { RequestCommit(deadline_scheduling_enabled); } -void RequestCommitAfterBeginFrameSentToMainThread( +void RequestCommitAfterBeginMainFrameSent( bool deadline_scheduling_enabled) { FakeSchedulerClient client; SchedulerSettings scheduler_settings; @@ -287,24 +302,24 @@ void RequestCommitAfterBeginFrameSentToMainThread( // SetNeedsCommit should begin the frame. scheduler->SetNeedsCommit(); if (deadline_scheduling_enabled) { - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); } else { EXPECT_EQ(client.num_actions_(), 2); - EXPECT_TRUE(client.HasAction("SetNeedsBeginFrameOnImplThread")); - EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginFrameToMainThread")); + EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame")); + EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); } client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); if (deadline_scheduling_enabled) { EXPECT_EQ(client.num_actions_(), 2); - EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginFrameToMainThread")); - EXPECT_TRUE(client.HasAction("PostBeginFrameDeadlineTask")); + EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); + EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask")); } else { - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); } - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); // Now SetNeedsCommit again. Calling here means we need a second commit. @@ -315,32 +330,32 @@ void RequestCommitAfterBeginFrameSentToMainThread( // Finish the first commit. scheduler->FinishCommit(); EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); - EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); client.Reset(); - scheduler->OnBeginFrameDeadline(); + scheduler->OnBeginImplFrameDeadline(); if (deadline_scheduling_enabled) { EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); } else { EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3); - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 1, 3); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 2, 3); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 3); + EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3); } // Because we just swapped, the Scheduler should also request the next - // BeginFrame from the OutputSurface. - EXPECT_TRUE(client.needs_begin_frame()); + // BeginImplFrame from the OutputSurface. + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); - // Since another commit is needed, the next BeginFrame should initiate + // Since another commit is needed, the next BeginImplFrame should initiate // the second commit. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); if (deadline_scheduling_enabled) { EXPECT_EQ(client.num_actions_(), 2); - EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginFrameToMainThread")); - EXPECT_TRUE(client.HasAction("PostBeginFrameDeadlineTask")); + EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); + EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask")); } else { - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); } client.Reset(); @@ -348,30 +363,30 @@ void RequestCommitAfterBeginFrameSentToMainThread( // to trigger the deadline early. scheduler->FinishCommit(); EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); - EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); client.Reset(); - scheduler->OnBeginFrameDeadline(); + scheduler->OnBeginImplFrameDeadline(); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); - // On the next BeginFrame, verify we go back to a quiescent state and - // no longer request BeginFrames. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); - EXPECT_FALSE(client.needs_begin_frame()); + // On the next BeginImplFrame, verify we go back to a quiescent state and + // no longer request BeginImplFrames. + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_FALSE(client.needs_begin_impl_frame()); client.Reset(); } -TEST(SchedulerTest, RequestCommitAfterBeginFrameSentToMainThread) { +TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { bool deadline_scheduling_enabled = false; - RequestCommitAfterBeginFrameSentToMainThread(deadline_scheduling_enabled); + RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled); } -TEST(SchedulerTest, RequestCommitAfterBeginFrameSentToMainThread_Deadline) { +TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent_Deadline) { bool deadline_scheduling_enabled = true; - RequestCommitAfterBeginFrameSentToMainThread(deadline_scheduling_enabled); + RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled); } void TextureAcquisitionCausesCommitInsteadOfDraw( @@ -389,90 +404,90 @@ void TextureAcquisitionCausesCommitInsteadOfDraw( client.Reset(); scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); client.Reset(); - scheduler->OnBeginFrameDeadline(); + scheduler->OnBeginImplFrameDeadline(); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); client.Reset(); - scheduler->OnBeginFrameDeadline(); - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_FALSE(client.needs_begin_frame()); + EXPECT_FALSE(client.needs_begin_impl_frame()); client.Reset(); scheduler->SetMainThreadNeedsLayerTextures(); EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread", client); - // We should request a BeginFrame in anticipation of a draw. + // We should request a BeginImplFrame in anticipation of a draw. client.Reset(); scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); + EXPECT_TRUE(client.needs_begin_impl_frame()); // No draw happens since the textures are acquired by the main thread. client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); client.Reset(); - scheduler->OnBeginFrameDeadline(); - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); scheduler->SetNeedsCommit(); if (deadline_scheduling_enabled) { EXPECT_EQ(0, client.num_actions_()); } else { - EXPECT_SINGLE_ACTION("ScheduledActionSendBeginFrameToMainThread", client); + EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client); } client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); if (deadline_scheduling_enabled) { - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); + EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); } else { - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); } // Commit will release the texture. client.Reset(); scheduler->FinishCommit(); EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); - EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); EXPECT_TRUE(scheduler->RedrawPending()); // Now we can draw again after the commit happens. client.Reset(); - scheduler->OnBeginFrameDeadline(); + scheduler->OnBeginImplFrameDeadline(); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); - // Make sure we stop requesting BeginFrames if we don't swap. + // Make sure we stop requesting BeginImplFrames if we don't swap. client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); client.Reset(); - scheduler->OnBeginFrameDeadline(); - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); - EXPECT_FALSE(client.needs_begin_frame()); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); + EXPECT_FALSE(client.needs_begin_impl_frame()); } TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) { @@ -500,10 +515,10 @@ void TextureAcquisitionCollision(bool deadline_scheduling_enabled) { client.Reset(); scheduler->SetNeedsCommit(); if (deadline_scheduling_enabled) { - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); } else { - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); + EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); } client.Reset(); @@ -512,26 +527,26 @@ if (deadline_scheduling_enabled) { "ScheduledActionAcquireLayerTexturesForMainThread", client); client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); if (deadline_scheduling_enabled) { - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); + EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); } else { - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); } client.Reset(); - scheduler->OnBeginFrameDeadline(); - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); // Although the compositor cannot draw because textures are locked by main - // thread, we continue requesting SetNeedsBeginFrame in anticipation of the - // unlock. - EXPECT_TRUE(client.needs_begin_frame()); + // thread, we continue requesting SetNeedsBeginImplFrame in anticipation of + // the unlock. + EXPECT_TRUE(client.needs_begin_impl_frame()); // Trigger the commit scheduler->FinishCommit(); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); // Between commit and draw, texture acquisition for main thread delayed, // and main thread blocks. @@ -541,61 +556,61 @@ if (deadline_scheduling_enabled) { // No implicit commit is expected. client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); client.Reset(); - scheduler->OnBeginFrameDeadline(); + scheduler->OnBeginImplFrameDeadline(); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3); EXPECT_ACTION( "ScheduledActionAcquireLayerTexturesForMainThread", client, 1, 3); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 2, 3); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3); + EXPECT_TRUE(client.needs_begin_impl_frame()); // The compositor should not draw because textures are locked by main // thread. client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); client.Reset(); - scheduler->OnBeginFrameDeadline(); - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); - EXPECT_FALSE(client.needs_begin_frame()); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); + EXPECT_FALSE(client.needs_begin_impl_frame()); // The impl thread need an explicit commit from the main thread to lock // the textures. client.Reset(); scheduler->SetNeedsCommit(); if (deadline_scheduling_enabled) { - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client); } else { - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); + EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); } - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); if (deadline_scheduling_enabled) { - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); + EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); } else { - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); } client.Reset(); // Trigger the commit, which will trigger the deadline task early. scheduler->FinishCommit(); EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); - EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); - // Verify we draw on the next BeginFrame deadline - scheduler->OnBeginFrameDeadline(); + // Verify we draw on the next BeginImplFrame deadline + scheduler->OnBeginImplFrameDeadline(); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.Reset(); } @@ -624,8 +639,8 @@ void VisibilitySwitchWithTextureAcquisition(bool deadline_scheduling_enabled) { scheduler->SetNeedsCommit(); if (deadline_scheduling_enabled) { - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); } scheduler->FinishCommit(); scheduler->SetMainThreadNeedsLayerTextures(); @@ -640,15 +655,15 @@ void VisibilitySwitchWithTextureAcquisition(bool deadline_scheduling_enabled) { client.Reset(); scheduler->SetVisible(true); EXPECT_EQ(0, client.num_actions_()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); // Regaining visibility with textures acquired by main thread while // compositor is waiting for first draw should result in a request // for a new frame in order to escape a deadlock. client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2); + EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2); } TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) { @@ -663,7 +678,7 @@ TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition_Deadline) { class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient { public: - virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {} + virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {} virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE { // Only SetNeedsRedraw the first time this is called @@ -701,27 +716,28 @@ TEST(SchedulerTest, RequestRedrawInsideDraw) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); EXPECT_EQ(0, client.num_draws()); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(1, client.num_draws()); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); - // We stop requesting BeginFrames after a BeginFrame where we don't swap. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + // We stop requesting BeginImplFrames after a BeginImplFrame where we don't + // swap. + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_FALSE(client.needs_begin_frame()); + EXPECT_FALSE(client.needs_begin_impl_frame()); } // Test that requesting redraw inside a failed draw doesn't lose the request. @@ -739,36 +755,36 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); EXPECT_EQ(0, client.num_draws()); // Fail the draw. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(1, client.num_draws()); // We have a commit pending and the draw failed, and we didn't lose the redraw // request. EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); // Fail the draw again. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(2, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); // Draw successfully. client.SetDrawWillHappen(true); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(3, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); } class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient { @@ -776,7 +792,7 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient { SchedulerClientThatSetNeedsCommitInsideDraw() : set_needs_commit_on_next_draw_(false) {} - virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {} + virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {} virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE { // Only SetNeedsCommit the first time this is called @@ -817,36 +833,37 @@ TEST(SchedulerTest, RequestCommitInsideDraw) { InitializeOutputSurfaceAndFirstCommit(scheduler); client.Reset(); - EXPECT_FALSE(client.needs_begin_frame()); + EXPECT_FALSE(client.needs_begin_impl_frame()); scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_EQ(0, client.num_draws()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); client.SetNeedsCommitOnNextDraw(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); client.SetNeedsCommitOnNextDraw(); - scheduler->OnBeginFrameDeadline(); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(1, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); scheduler->FinishCommit(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); EXPECT_FALSE(scheduler->CommitPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); - // We stop requesting BeginFrames after a BeginFrame where we don't swap. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + // We stop requesting BeginImplFrames after a BeginImplFrame where we don't + // swap. + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); EXPECT_FALSE(scheduler->CommitPending()); - EXPECT_FALSE(client.needs_begin_frame()); + EXPECT_FALSE(client.needs_begin_impl_frame()); } // Tests that when a draw fails then the pending commit should not be dropped. @@ -864,36 +881,36 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); EXPECT_EQ(0, client.num_draws()); // Fail the draw. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(1, client.num_draws()); // We have a commit pending and the draw failed, and we didn't lose the commit // request. EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); // Fail the draw again. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(2, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); // Draw successfully. client.SetDrawWillHappen(true); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(3, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); } TEST(SchedulerTest, NoSwapWhenDrawFails) { @@ -908,24 +925,24 @@ TEST(SchedulerTest, NoSwapWhenDrawFails) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); EXPECT_EQ(0, client.num_draws()); // Draw successfully, this starts a new frame. client.SetNeedsCommitOnNextDraw(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(1, client.num_draws()); scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); // Fail to draw, this should not start a frame. client.SetDrawWillHappen(false); client.SetNeedsCommitOnNextDraw(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - scheduler->OnBeginFrameDeadline(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(2, client.num_draws()); } @@ -992,26 +1009,26 @@ TEST(SchedulerTest, ManageTiles) { InitializeOutputSurfaceAndFirstCommit(scheduler); // Request both draw and manage tiles. ManageTiles shouldn't - // be trigged until BeginFrame. + // be trigged until BeginImplFrame. client.Reset(); scheduler->SetNeedsManageTiles(); scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_TRUE(scheduler->ManageTilesPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); EXPECT_EQ(0, client.num_draws()); EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles")); EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); - // We have no immediate actions to perform, so the BeginFrame should post + // We have no immediate actions to perform, so the BeginImplFrame should post // the deadline task. client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); // On the deadline, he actions should have occured in the right order. client.Reset(); - scheduler->OnBeginFrameDeadline(); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(1, client.num_draws()); EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); @@ -1025,20 +1042,20 @@ TEST(SchedulerTest, ManageTiles) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_FALSE(scheduler->ManageTilesPending()); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); EXPECT_EQ(0, client.num_draws()); - // We have no immediate actions to perform, so the BeginFrame should post + // We have no immediate actions to perform, so the BeginImplFrame should post // the deadline task. client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); // Draw. The draw will trigger SetNeedsManageTiles, and // then the ManageTiles action will be triggered after the Draw. // Afterwards, neither a draw nor ManageTiles are pending. client.Reset(); - scheduler->OnBeginFrameDeadline(); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(1, client.num_draws()); EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); @@ -1047,34 +1064,223 @@ TEST(SchedulerTest, ManageTiles) { EXPECT_FALSE(scheduler->RedrawPending()); EXPECT_FALSE(scheduler->ManageTilesPending()); - // We need a BeginFrame where we don't swap to go idle. + // We need a BeginImplFrame where we don't swap to go idle. client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); client.Reset(); - scheduler->OnBeginFrameDeadline(); - EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client);; + scheduler->OnBeginImplFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);; EXPECT_EQ(0, client.num_draws()); // Now trigger a ManageTiles outside of a draw. We will then need // a begin-frame for the ManageTiles, but we don't need a draw. client.Reset(); - EXPECT_FALSE(client.needs_begin_frame()); + EXPECT_FALSE(client.needs_begin_impl_frame()); scheduler->SetNeedsManageTiles(); - EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_impl_frame()); EXPECT_TRUE(scheduler->ManageTilesPending()); EXPECT_FALSE(scheduler->RedrawPending()); - // BeginFrame. There will be no draw, only ManageTiles. + // BeginImplFrame. There will be no draw, only ManageTiles. client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); client.Reset(); - scheduler->OnBeginFrameDeadline(); + scheduler->OnBeginImplFrameDeadline(); EXPECT_EQ(0, client.num_draws()); EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); } +// Test that ManageTiles only happens once per frame. If an external caller +// initiates it, then the state machine should not on that frame. +TEST(SchedulerTest, ManageTilesOncePerFrame) { + FakeSchedulerClient client; + SchedulerSettings default_scheduler_settings; + Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); + scheduler->SetCanStart(); + scheduler->SetVisible(true); + scheduler->SetCanDraw(true); + InitializeOutputSurfaceAndFirstCommit(scheduler); + + // If DidManageTiles during a frame, then ManageTiles should not occur again. + scheduler->SetNeedsManageTiles(); + scheduler->SetNeedsRedraw(); + client.Reset(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); + + EXPECT_TRUE(scheduler->ManageTilesPending()); + scheduler->DidManageTiles(); + EXPECT_FALSE(scheduler->ManageTilesPending()); + + client.Reset(); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_EQ(1, client.num_draws()); + EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); + EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles")); + EXPECT_FALSE(scheduler->RedrawPending()); + EXPECT_FALSE(scheduler->ManageTilesPending()); + + // Next frame without DidManageTiles should ManageTiles with draw. + scheduler->SetNeedsManageTiles(); + scheduler->SetNeedsRedraw(); + client.Reset(); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); + + client.Reset(); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_EQ(1, client.num_draws()); + EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); + EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); + EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"), + client.ActionIndex("ScheduledActionManageTiles")); + EXPECT_FALSE(scheduler->RedrawPending()); + EXPECT_FALSE(scheduler->ManageTilesPending()); +} + +class SchedulerClientWithFixedEstimates : public FakeSchedulerClient { + public: + SchedulerClientWithFixedEstimates( + base::TimeDelta draw_duration, + base::TimeDelta begin_main_frame_to_commit_duration, + base::TimeDelta commit_to_activate_duration) + : draw_duration_(draw_duration), + begin_main_frame_to_commit_duration_( + begin_main_frame_to_commit_duration), + commit_to_activate_duration_(commit_to_activate_duration) {} + + virtual base::TimeDelta DrawDurationEstimate() OVERRIDE { + return draw_duration_; + } + virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE { + return begin_main_frame_to_commit_duration_; + } + virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE { + return commit_to_activate_duration_; + } + + private: + base::TimeDelta draw_duration_; + base::TimeDelta begin_main_frame_to_commit_duration_; + base::TimeDelta commit_to_activate_duration_; +}; + +void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms, + int64 commit_to_activate_estimate_in_ms, + bool should_send_begin_main_frame) { + // Set up client with specified estimates (draw duration is set to 1). + SchedulerClientWithFixedEstimates client( + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds( + begin_main_frame_to_commit_estimate_in_ms), + base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms)); + SchedulerSettings scheduler_settings; + scheduler_settings.deadline_scheduling_enabled = true; + scheduler_settings.switch_to_low_latency_if_possible = true; + Scheduler* scheduler = client.CreateScheduler(scheduler_settings); + scheduler->SetCanStart(); + scheduler->SetVisible(true); + scheduler->SetCanDraw(true); + InitializeOutputSurfaceAndFirstCommit(scheduler); + + // Impl thread hits deadline before commit finishes. + client.Reset(); + scheduler->SetNeedsCommit(); + EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode()); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode()); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); + scheduler->FinishCommit(); + EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame")); + + client.Reset(); + scheduler->SetNeedsCommit(); + EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); + scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); + scheduler->OnBeginImplFrameDeadline(); + EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(), + should_send_begin_main_frame); + EXPECT_EQ(client.HasAction("ScheduledActionSendBeginMainFrame"), + should_send_begin_main_frame); +} + +TEST(SchedulerTest, + SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) { + // Set up client so that estimates indicate that we can commit and activate + // before the deadline (~8ms by default). + MainFrameInHighLatencyMode(1, 1, false); +} + +TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) { + // Set up client so that estimates indicate that the commit cannot finish + // before the deadline (~8ms by default). + MainFrameInHighLatencyMode(10, 1, true); +} + +TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) { + // Set up client so that estimates indicate that the activate cannot finish + // before the deadline (~8ms by default). + MainFrameInHighLatencyMode(1, 10, true); +} + +void SpinForMillis(int millis) { + base::RunLoop run_loop; + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + run_loop.QuitClosure(), + base::TimeDelta::FromMilliseconds(millis)); + run_loop.Run(); +} + +TEST(SchedulerTest, PollForCommitCompletion) { + FakeSchedulerClient client; + client.set_log_anticipated_draw_time_change(true); + SchedulerSettings settings = SchedulerSettings(); + settings.throttle_frame_production = false; + Scheduler* scheduler = client.CreateScheduler(settings); + + scheduler->SetCanDraw(true); + scheduler->SetCanStart(); + scheduler->SetVisible(true); + scheduler->DidCreateAndInitializeOutputSurface(); + + scheduler->SetNeedsCommit(); + EXPECT_TRUE(scheduler->CommitPending()); + scheduler->FinishCommit(); + scheduler->SetNeedsRedraw(); + BeginFrameArgs impl_frame_args = BeginFrameArgs::CreateForTesting(); + const int interval = 1; + impl_frame_args.interval = base::TimeDelta::FromMilliseconds(interval); + scheduler->BeginImplFrame(impl_frame_args); + scheduler->OnBeginImplFrameDeadline(); + + // At this point, we've drawn a frame. Start another commit, but hold off on + // the FinishCommit for now. + EXPECT_FALSE(scheduler->CommitPending()); + scheduler->SetNeedsCommit(); + EXPECT_TRUE(scheduler->CommitPending()); + + // Spin the event loop a few times and make sure we get more + // DidAnticipateDrawTimeChange calls every time. + int actions_so_far = client.num_actions_(); + + // Does three iterations to make sure that the timer is properly repeating. + for (int i = 0; i < 3; ++i) { + // Wait for 2x the frame interval to match + // Scheduler::advance_commit_state_timer_'s rate. + SpinForMillis(interval * 2); + EXPECT_GT(client.num_actions_(), actions_so_far); + EXPECT_STREQ(client.Action(client.num_actions_() - 1), + "DidAnticipatedDrawTimeChange"); + actions_so_far = client.num_actions_(); + } +} + } // namespace } // namespace cc diff --git a/chromium/cc/scheduler/texture_uploader.cc b/chromium/cc/scheduler/texture_uploader.cc index 677029081fc..6758f11de2d 100644 --- a/chromium/cc/scheduler/texture_uploader.cc +++ b/chromium/cc/scheduler/texture_uploader.cc @@ -13,12 +13,14 @@ #include "cc/resources/prioritized_resource.h" #include "cc/resources/resource.h" #include "gpu/GLES2/gl2extchromium.h" -#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" +#include "gpu/command_buffer/client/gles2_interface.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "ui/gfx/rect.h" #include "ui/gfx/vector2d.h" +using gpu::gles2::GLES2Interface; + namespace { // How many previous uploads to use when predicting future throughput. @@ -38,50 +40,46 @@ static const size_t kTextureUploadFlushPeriod = 4; namespace cc { -TextureUploader::Query::Query(WebKit::WebGraphicsContext3D* context) - : context_(context), +TextureUploader::Query::Query(GLES2Interface* gl) + : gl_(gl), query_id_(0), value_(0), has_value_(false), is_non_blocking_(false) { - query_id_ = context_->createQueryEXT(); + gl_->GenQueriesEXT(1, &query_id_); } -TextureUploader::Query::~Query() { context_->deleteQueryEXT(query_id_); } +TextureUploader::Query::~Query() { gl_->DeleteQueriesEXT(1, &query_id_); } void TextureUploader::Query::Begin() { has_value_ = false; is_non_blocking_ = false; - context_->beginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query_id_); + gl_->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query_id_); } void TextureUploader::Query::End() { - context_->endQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); + gl_->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); } bool TextureUploader::Query::IsPending() { unsigned available = 1; - context_->getQueryObjectuivEXT( + gl_->GetQueryObjectuivEXT( query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available); return !available; } unsigned TextureUploader::Query::Value() { if (!has_value_) { - context_->getQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &value_); + gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &value_); has_value_ = true; } return value_; } -TextureUploader::TextureUploader(WebKit::WebGraphicsContext3D* context, - bool use_map_tex_sub_image, - bool use_shallow_flush) - : context_(context), +TextureUploader::TextureUploader(GLES2Interface* gl) + : gl_(gl), num_blocking_texture_uploads_(0), - use_map_tex_sub_image_(use_map_tex_sub_image), sub_image_size_(0), - use_shallow_flush_(use_shallow_flush), num_texture_uploads_since_last_flush_(0) { for (size_t i = kUploadHistorySizeInitial; i > 0; i--) textures_per_second_history_.insert(kDefaultEstimatedTexturesPerSecond); @@ -119,7 +117,7 @@ double TextureUploader::EstimatedTexturesPerSecond() { void TextureUploader::BeginQuery() { if (available_queries_.empty()) - available_queries_.push_back(Query::Create(context_)); + available_queries_.push_back(Query::Create(gl_)); available_queries_.front()->Begin(); } @@ -143,11 +141,13 @@ void TextureUploader::Upload(const uint8* image, if (is_full_upload) BeginQuery(); - if (use_map_tex_sub_image_) { + if (format == ETC1) { + // ETC1 does not support subimage uploads. + DCHECK(is_full_upload); + UploadWithTexImageETC1(image, size); + } else { UploadWithMapTexSubImage( image, image_rect, source_rect, dest_offset, format); - } else { - UploadWithTexSubImage(image, image_rect, source_rect, dest_offset, format); } if (is_full_upload) @@ -162,8 +162,7 @@ void TextureUploader::Flush() { if (!num_texture_uploads_since_last_flush_) return; - if (use_shallow_flush_) - context_->shallowFlushCHROMIUM(); + gl_->ShallowFlushCHROMIUM(); num_texture_uploads_since_last_flush_ = 0; } @@ -190,7 +189,7 @@ void TextureUploader::UploadWithTexSubImage(const uint8* image, gfx::Vector2d offset(source_rect.origin() - image_rect.origin()); const uint8* pixel_source; - unsigned bytes_per_pixel = ResourceProvider::BytesPerPixel(format); + unsigned bytes_per_pixel = BitsPerPixel(format) / 8; // Use 4-byte row alignment (OpenGL default) for upload performance. // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. unsigned upload_image_stride = @@ -210,21 +209,21 @@ void TextureUploader::UploadWithTexSubImage(const uint8* image, for (int row = 0; row < source_rect.height(); ++row) memcpy(&sub_image_[upload_image_stride * row], &image[bytes_per_pixel * - (offset.x() + (offset.y() + row) * image_rect.width())], + (offset.x() + (offset.y() + row) * image_rect.width())], source_rect.width() * bytes_per_pixel); pixel_source = &sub_image_[0]; } - context_->texSubImage2D(GL_TEXTURE_2D, - 0, - dest_offset.x(), - dest_offset.y(), - source_rect.width(), - source_rect.height(), - ResourceProvider::GetGLDataFormat(format), - ResourceProvider::GetGLDataType(format), - pixel_source); + gl_->TexSubImage2D(GL_TEXTURE_2D, + 0, + dest_offset.x(), + dest_offset.y(), + source_rect.width(), + source_rect.height(), + GLDataFormat(format), + GLDataType(format), + pixel_source); } void TextureUploader::UploadWithMapTexSubImage(const uint8* image, @@ -239,29 +238,29 @@ void TextureUploader::UploadWithMapTexSubImage(const uint8* image, if (source_rect.IsEmpty()) return; DCHECK(image); + // Compressed textures have no implementation of mapTexSubImage. + DCHECK_NE(ETC1, format); // Offset from image-rect to source-rect. gfx::Vector2d offset(source_rect.origin() - image_rect.origin()); - unsigned bytes_per_pixel = ResourceProvider::BytesPerPixel(format); + unsigned bytes_per_pixel = BitsPerPixel(format) / 8; // Use 4-byte row alignment (OpenGL default) for upload performance. // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. unsigned upload_image_stride = RoundUp(bytes_per_pixel * source_rect.width(), 4u); // Upload tile data via a mapped transfer buffer - uint8* pixel_dest = static_cast<uint8*>( - context_->mapTexSubImage2DCHROMIUM(GL_TEXTURE_2D, - 0, - dest_offset.x(), - dest_offset.y(), - source_rect.width(), - source_rect.height(), - ResourceProvider::GetGLDataFormat( - format), - ResourceProvider::GetGLDataType( - format), - GL_WRITE_ONLY)); + uint8* pixel_dest = + static_cast<uint8*>(gl_->MapTexSubImage2DCHROMIUM(GL_TEXTURE_2D, + 0, + dest_offset.x(), + dest_offset.y(), + source_rect.width(), + source_rect.height(), + GLDataFormat(format), + GLDataType(format), + GL_WRITE_ONLY)); if (!pixel_dest) { UploadWithTexSubImage(image, image_rect, source_rect, dest_offset, format); @@ -279,12 +278,28 @@ void TextureUploader::UploadWithMapTexSubImage(const uint8* image, for (int row = 0; row < source_rect.height(); ++row) { memcpy(&pixel_dest[upload_image_stride * row], &image[bytes_per_pixel * - (offset.x() + (offset.y() + row) * image_rect.width())], + (offset.x() + (offset.y() + row) * image_rect.width())], source_rect.width() * bytes_per_pixel); } } - context_->unmapTexSubImage2DCHROMIUM(pixel_dest); + gl_->UnmapTexSubImage2DCHROMIUM(pixel_dest); +} + +void TextureUploader::UploadWithTexImageETC1(const uint8* image, + gfx::Size size) { + TRACE_EVENT0("cc", "TextureUploader::UploadWithTexImageETC1"); + DCHECK_EQ(0, size.width() % 4); + DCHECK_EQ(0, size.height() % 4); + + gl_->CompressedTexImage2D(GL_TEXTURE_2D, + 0, + GLInternalFormat(ETC1), + size.width(), + size.height(), + 0, + Resource::MemorySizeBytes(size, ETC1), + image); } void TextureUploader::ProcessQueries() { diff --git a/chromium/cc/scheduler/texture_uploader.h b/chromium/cc/scheduler/texture_uploader.h index a131ba04f9e..815282e2c4b 100644 --- a/chromium/cc/scheduler/texture_uploader.h +++ b/chromium/cc/scheduler/texture_uploader.h @@ -13,24 +13,24 @@ #include "cc/base/scoped_ptr_deque.h" #include "cc/resources/resource_provider.h" -namespace WebKit { class WebGraphicsContext3D; } - namespace gfx { class Rect; class Size; class Vector2d; } +namespace gpu { +namespace gles2 { +class GLES2Interface; +} +} + namespace cc { class CC_EXPORT TextureUploader { public: - static scoped_ptr<TextureUploader> Create( - WebKit::WebGraphicsContext3D* context, - bool use_map_tex_sub_image, - bool use_shallow_flush) { - return make_scoped_ptr( - new TextureUploader(context, use_map_tex_sub_image, use_shallow_flush)); + static scoped_ptr<TextureUploader> Create(gpu::gles2::GLES2Interface* gl) { + return make_scoped_ptr(new TextureUploader(gl)); } ~TextureUploader(); @@ -55,8 +55,8 @@ class CC_EXPORT TextureUploader { private: class Query { public: - static scoped_ptr<Query> Create(WebKit::WebGraphicsContext3D* context) { - return make_scoped_ptr(new Query(context)); + static scoped_ptr<Query> Create(gpu::gles2::GLES2Interface* gl) { + return make_scoped_ptr(new Query(gl)); } virtual ~Query(); @@ -74,9 +74,9 @@ class CC_EXPORT TextureUploader { } private: - explicit Query(WebKit::WebGraphicsContext3D* context); + explicit Query(gpu::gles2::GLES2Interface* gl); - WebKit::WebGraphicsContext3D* context_; + gpu::gles2::GLES2Interface* gl_; unsigned query_id_; unsigned value_; bool has_value_; @@ -85,9 +85,7 @@ class CC_EXPORT TextureUploader { DISALLOW_COPY_AND_ASSIGN(Query); }; - TextureUploader(WebKit::WebGraphicsContext3D* context, - bool use_map_tex_sub_image, - bool use_shallow_flush); + explicit TextureUploader(gpu::gles2::GLES2Interface* gl); void BeginQuery(); void EndQuery(); @@ -103,18 +101,17 @@ class CC_EXPORT TextureUploader { gfx::Rect source_rect, gfx::Vector2d dest_offset, ResourceFormat format); + void UploadWithTexImageETC1(const uint8* image, gfx::Size size); - WebKit::WebGraphicsContext3D* context_; + gpu::gles2::GLES2Interface* gl_; ScopedPtrDeque<Query> pending_queries_; ScopedPtrDeque<Query> available_queries_; std::multiset<double> textures_per_second_history_; size_t num_blocking_texture_uploads_; - bool use_map_tex_sub_image_; size_t sub_image_size_; scoped_ptr<uint8[]> sub_image_; - bool use_shallow_flush_; size_t num_texture_uploads_since_last_flush_; DISALLOW_COPY_AND_ASSIGN(TextureUploader); diff --git a/chromium/cc/scheduler/texture_uploader_unittest.cc b/chromium/cc/scheduler/texture_uploader_unittest.cc index 68413df92e1..792216cf081 100644 --- a/chromium/cc/scheduler/texture_uploader_unittest.cc +++ b/chromium/cc/scheduler/texture_uploader_unittest.cc @@ -5,29 +5,21 @@ #include "cc/scheduler/texture_uploader.h" #include "cc/base/util.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/resources/prioritized_resource.h" +#include "gpu/command_buffer/client/gles2_interface_stub.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" -using WebKit::WGC3Denum; -using WebKit::WGC3Dint; -using WebKit::WGC3Dsizei; -using WebKit::WebGLId; -using WebKit::WGC3Duint; - namespace cc { namespace { -class TestWebGraphicsContext3DTextureUpload : public TestWebGraphicsContext3D { +class TextureUploadTestContext : public gpu::gles2::GLES2InterfaceStub { public: - TestWebGraphicsContext3DTextureUpload() - : result_available_(0), - unpack_alignment_(4) {} + TextureUploadTestContext() : result_available_(0), unpack_alignment_(4) {} - virtual void pixelStorei(WGC3Denum pname, WGC3Dint param) OVERRIDE { + virtual void PixelStorei(GLenum pname, GLint param) OVERRIDE { switch (pname) { case GL_UNPACK_ALIGNMENT: // Param should be a power of two <= 8. @@ -49,8 +41,9 @@ class TestWebGraphicsContext3DTextureUpload : public TestWebGraphicsContext3D { } } - virtual void getQueryObjectuivEXT(WebGLId, WGC3Denum type, WGC3Duint* value) - OVERRIDE { + virtual void GetQueryObjectuivEXT(GLuint, + GLenum type, + GLuint* value) OVERRIDE { switch (type) { case GL_QUERY_RESULT_AVAILABLE_EXT: *value = result_available_; @@ -61,14 +54,14 @@ class TestWebGraphicsContext3DTextureUpload : public TestWebGraphicsContext3D { } } - virtual void texSubImage2D(WGC3Denum target, - WGC3Dint level, - WGC3Dint xoffset, - WGC3Dint yoffset, - WGC3Dsizei width, - WGC3Dsizei height, - WGC3Denum format, - WGC3Denum type, + virtual void TexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, const void* pixels) OVERRIDE { EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); EXPECT_EQ(0, level); @@ -131,7 +124,7 @@ class TestWebGraphicsContext3DTextureUpload : public TestWebGraphicsContext3D { // be 0x2. const unsigned int stride = RoundUp(bytes_per_pixel * width, unpack_alignment_); - for (WGC3Dsizei row = 0; row < height; ++row) { + for (GLsizei row = 0; row < height; ++row) { const uint8* row_bytes = bytes + (xoffset * bytes_per_pixel + (yoffset + row) * stride); EXPECT_EQ(0x1, row_bytes[0]); @@ -147,7 +140,7 @@ class TestWebGraphicsContext3DTextureUpload : public TestWebGraphicsContext3D { unsigned result_available_; unsigned unpack_alignment_; - DISALLOW_COPY_AND_ASSIGN(TestWebGraphicsContext3DTextureUpload); + DISALLOW_COPY_AND_ASSIGN(TextureUploadTestContext); }; void UploadTexture(TextureUploader* uploader, @@ -163,19 +156,17 @@ void UploadTexture(TextureUploader* uploader, } TEST(TextureUploaderTest, NumBlockingUploads) { - scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context( - new TestWebGraphicsContext3DTextureUpload); - scoped_ptr<TextureUploader> uploader = - TextureUploader::Create(fake_context.get(), false, false); + TextureUploadTestContext context; + scoped_ptr<TextureUploader> uploader = TextureUploader::Create(&context); - fake_context->SetResultAvailable(0); + context.SetResultAvailable(0); EXPECT_EQ(0u, uploader->NumBlockingUploads()); UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL); EXPECT_EQ(1u, uploader->NumBlockingUploads()); UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL); EXPECT_EQ(2u, uploader->NumBlockingUploads()); - fake_context->SetResultAvailable(1); + context.SetResultAvailable(1); EXPECT_EQ(0u, uploader->NumBlockingUploads()); UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL); EXPECT_EQ(0u, uploader->NumBlockingUploads()); @@ -185,12 +176,10 @@ TEST(TextureUploaderTest, NumBlockingUploads) { } TEST(TextureUploaderTest, MarkPendingUploadsAsNonBlocking) { - scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context( - new TestWebGraphicsContext3DTextureUpload); - scoped_ptr<TextureUploader> uploader = - TextureUploader::Create(fake_context.get(), false, false); + TextureUploadTestContext context; + scoped_ptr<TextureUploader> uploader = TextureUploader::Create(&context); - fake_context->SetResultAvailable(0); + context.SetResultAvailable(0); EXPECT_EQ(0u, uploader->NumBlockingUploads()); UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL); UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL); @@ -201,7 +190,7 @@ TEST(TextureUploaderTest, MarkPendingUploadsAsNonBlocking) { UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL); EXPECT_EQ(1u, uploader->NumBlockingUploads()); - fake_context->SetResultAvailable(1); + context.SetResultAvailable(1); EXPECT_EQ(0u, uploader->NumBlockingUploads()); UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL); uploader->MarkPendingUploadsAsNonBlocking(); @@ -209,10 +198,9 @@ TEST(TextureUploaderTest, MarkPendingUploadsAsNonBlocking) { } TEST(TextureUploaderTest, UploadContentsTest) { - scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context( - new TestWebGraphicsContext3DTextureUpload); - scoped_ptr<TextureUploader> uploader = - TextureUploader::Create(fake_context.get(), false, false); + TextureUploadTestContext context; + scoped_ptr<TextureUploader> uploader = TextureUploader::Create(&context); + uint8 buffer[256 * 256 * 4]; // Upload a tightly packed 256x256 RGBA texture. diff --git a/chromium/cc/trees/damage_tracker.cc b/chromium/cc/trees/damage_tracker.cc index 64b15867e07..9895458c99a 100644 --- a/chromium/cc/trees/damage_tracker.cc +++ b/chromium/cc/trees/damage_tracker.cc @@ -21,8 +21,7 @@ scoped_ptr<DamageTracker> DamageTracker::Create() { } DamageTracker::DamageTracker() - : current_rect_history_(new RectMap), - next_rect_history_(new RectMap) {} + : mailboxId_(0) {} DamageTracker::~DamageTracker() {} @@ -52,8 +51,7 @@ void DamageTracker::UpdateDamageTrackingState( bool target_surface_property_changed_only_from_descendant, gfx::Rect target_surface_content_rect, LayerImpl* target_surface_mask_layer, - const FilterOperations& filters, - SkImageFilter* filter) { + const FilterOperations& filters) { // // This function computes the "damage rect" of a target surface, and updates // the state that is used to correctly track damage across frames. The damage @@ -106,23 +104,23 @@ void DamageTracker::UpdateDamageTrackingState( // - See comments in the rest of the code to see what exactly is considered a // "change" in a layer/surface. // - // - To correctly manage exposed rects, two RectMaps are maintained: + // - To correctly manage exposed rects, SortedRectMap is maintained: // - // 1. The "current" map contains all the layer bounds that contributed to + // 1. All existing rects from the previous frame are marked as + // not updated. + // 2. The map contains all the layer bounds that contributed to // the previous frame (even outside the previous damaged area). If a // layer changes or does not exist anymore, those regions are then // exposed and damage the target surface. As the algorithm progresses, - // entries are removed from the map until it has only leftover layers - // that no longer exist. - // - // 2. The "next" map starts out empty, and as the algorithm progresses, - // every layer/surface that contributes to the surface is added to the - // map. + // entries are updated in the map until only leftover layers + // that no longer exist stay marked not updated. // - // 3. After the damage rect is computed, the two maps are swapped, so - // that the damage tracker is ready for the next frame. + // 3. After the damage rect is computed, the leftover not marked regions + // in a map are used to compute are damaged by deleted layers and + // erased from map. // + PrepareRectHistoryForUpdate(); // These functions cannot be bypassed with early-exits, even if we know what // the damage will be for this frame, because we need to update the damage // tracker state to correctly track the next frame. @@ -143,43 +141,35 @@ void DamageTracker::UpdateDamageTrackingState( damage_rect_for_this_update.Union(damage_from_surface_mask); damage_rect_for_this_update.Union(damage_from_leftover_rects); - if (filters.HasFilterThatMovesPixels()) { - ExpandRectWithFilters(&damage_rect_for_this_update, filters); - } else if (filter) { + if (filters.HasReferenceFilter()) { // TODO(senorblanco): Once SkImageFilter reports its outsets, use // those here to limit damage. damage_rect_for_this_update = target_surface_content_rect; + } else if (filters.HasFilterThatMovesPixels()) { + ExpandRectWithFilters(&damage_rect_for_this_update, filters); } } // Damage accumulates until we are notified that we actually did draw on that // frame. current_damage_rect_.Union(damage_rect_for_this_update); - - // The next history map becomes the current map for the next frame. Note this - // must happen every frame to correctly track changes, even if damage - // accumulates over multiple frames before actually being drawn. - swap(current_rect_history_, next_rect_history_); } -gfx::RectF DamageTracker::RemoveRectFromCurrentFrame(int layer_id, - bool* layer_is_new) { - RectMap::iterator iter = current_rect_history_->find(layer_id); - *layer_is_new = iter == current_rect_history_->end(); - if (*layer_is_new) - return gfx::RectF(); +DamageTracker::RectMapData& DamageTracker::RectDataForLayer( + int layer_id, + bool* layer_is_new) { - gfx::RectF ret = iter->second; - current_rect_history_->erase(iter); - return ret; -} + RectMapData data(layer_id); + + SortedRectMap::iterator it = std::lower_bound(rect_history_.begin(), + rect_history_.end(), data); + + if (it == rect_history_.end() || it->layer_id_ != layer_id) { + *layer_is_new = true; + it = rect_history_.insert(it, data); + } -void DamageTracker::SaveRectForNextFrame(int layer_id, - const gfx::RectF& target_space_rect) { - // This layer should not yet exist in next frame's history. - DCHECK_GT(layer_id, 0); - DCHECK(next_rect_history_->find(layer_id) == next_rect_history_->end()); - (*next_rect_history_)[layer_id] = target_space_rect; + return *it; } gfx::RectF DamageTracker::TrackDamageFromActiveLayers( @@ -226,32 +216,48 @@ gfx::RectF DamageTracker::TrackDamageFromSurfaceMask( return damage_rect; } +void DamageTracker::PrepareRectHistoryForUpdate() { + mailboxId_++; +} + gfx::RectF DamageTracker::TrackDamageFromLeftoverRects() { // After computing damage for all active layers, any leftover items in the // current rect history correspond to layers/surfaces that no longer exist. // So, these regions are now exposed on the target surface. gfx::RectF damage_rect = gfx::RectF(); + SortedRectMap::iterator cur_pos = rect_history_.begin(); + SortedRectMap::iterator copy_pos = cur_pos; + + // Loop below basically implements std::remove_if loop with and extra + // processing (adding deleted rect to damage_rect) for deleted items. + // cur_pos iterator runs through all elements of the vector, but copy_pos + // always points to the element after the last not deleted element. If new + // not deleted element found then it is copied to the *copy_pos and copy_pos + // moved to the next position. + // If there are no deleted elements then copy_pos iterator is in sync with + // cur_pos and no copy happens. + while (cur_pos < rect_history_.end()) { + if (cur_pos->mailboxId_ == mailboxId_) { + if (cur_pos != copy_pos) + *copy_pos = *cur_pos; + + ++copy_pos; + } else { + damage_rect.Union(cur_pos->rect_); + } - for (RectMap::iterator it = current_rect_history_->begin(); - it != current_rect_history_->end(); - ++it) - damage_rect.Union(it->second); + ++cur_pos; + } - current_rect_history_->clear(); + if (copy_pos != rect_history_.end()) + rect_history_.erase(copy_pos, rect_history_.end()); - return damage_rect; -} + // If the vector has excessive storage, shrink it + if (rect_history_.capacity() > rect_history_.size() * 4) + SortedRectMap(rect_history_).swap(rect_history_); -static bool LayerNeedsToRedrawOntoItsTargetSurface(LayerImpl* layer) { - // If the layer does NOT own a surface but has SurfacePropertyChanged, - // this means that its target surface is affected and needs to be redrawn. - // However, if the layer DOES own a surface, then the SurfacePropertyChanged - // flag should not be used here, because that flag represents whether the - // layer's surface has changed. - if (layer->render_surface()) - return layer->LayerPropertyChanged(); - return layer->LayerPropertyChanged() || layer->LayerSurfacePropertyChanged(); + return damage_rect; } void DamageTracker::ExtendDamageForLayer(LayerImpl* layer, @@ -275,15 +281,15 @@ void DamageTracker::ExtendDamageForLayer(LayerImpl* layer, // ancestor surface, ExtendDamageForRenderSurface() must be called instead. bool layer_is_new = false; - gfx::RectF old_rect_in_target_space = - RemoveRectFromCurrentFrame(layer->id(), &layer_is_new); + RectMapData& data = RectDataForLayer(layer->id(), &layer_is_new); + gfx::RectF old_rect_in_target_space = data.rect_; gfx::RectF rect_in_target_space = MathUtil::MapClippedRect( layer->draw_transform(), gfx::RectF(gfx::PointF(), layer->content_bounds())); - SaveRectForNextFrame(layer->id(), rect_in_target_space); + data.Update(rect_in_target_space, mailboxId_); - if (layer_is_new || LayerNeedsToRedrawOntoItsTargetSurface(layer)) { + if (layer_is_new || layer->LayerPropertyChanged()) { // If a layer is new or has changed, then its entire layer rect affects the // target surface. target_damage_rect->Union(rect_in_target_space); @@ -322,18 +328,16 @@ void DamageTracker::ExtendDamageForRenderSurface( RenderSurfaceImpl* render_surface = layer->render_surface(); bool surface_is_new = false; - gfx::RectF old_surface_rect = RemoveRectFromCurrentFrame(layer->id(), - &surface_is_new); + RectMapData& data = RectDataForLayer(layer->id(), &surface_is_new); + gfx::RectF old_surface_rect = data.rect_; // The drawableContextRect() already includes the replica if it exists. gfx::RectF surface_rect_in_target_space = render_surface->DrawableContentRect(); - SaveRectForNextFrame(layer->id(), surface_rect_in_target_space); + data.Update(surface_rect_in_target_space, mailboxId_); gfx::RectF damage_rect_in_local_space; - if (surface_is_new || - render_surface->SurfacePropertyChanged() || - layer->LayerSurfacePropertyChanged()) { + if (surface_is_new || render_surface->SurfacePropertyChanged()) { // The entire surface contributes damage. damage_rect_in_local_space = render_surface->content_rect(); @@ -367,14 +371,15 @@ void DamageTracker::ExtendDamageForRenderSurface( LayerImpl* replica_mask_layer = layer->replica_layer()->mask_layer(); bool replica_is_new = false; - RemoveRectFromCurrentFrame(replica_mask_layer->id(), &replica_is_new); + RectMapData& data = + RectDataForLayer(replica_mask_layer->id(), &replica_is_new); const gfx::Transform& replica_draw_transform = render_surface->replica_draw_transform(); gfx::RectF replica_mask_layer_rect = MathUtil::MapClippedRect( replica_draw_transform, gfx::RectF(gfx::PointF(), replica_mask_layer->bounds())); - SaveRectForNextFrame(replica_mask_layer->id(), replica_mask_layer_rect); + data.Update(replica_mask_layer_rect, mailboxId_); // In the current implementation, a change in the replica mask damages the // entire replica region. diff --git a/chromium/cc/trees/damage_tracker.h b/chromium/cc/trees/damage_tracker.h index ce72fcc842c..37a1900f788 100644 --- a/chromium/cc/trees/damage_tracker.h +++ b/chromium/cc/trees/damage_tracker.h @@ -6,7 +6,6 @@ #define CC_TREES_DAMAGE_TRACKER_H_ #include <vector> -#include "base/containers/hash_tables.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" #include "cc/layers/layer_lists.h" @@ -40,8 +39,7 @@ class CC_EXPORT DamageTracker { bool target_surface_property_changed_only_from_descendant, gfx::Rect target_surface_content_rect, LayerImpl* target_surface_mask_layer, - const FilterOperations& filters, - SkImageFilter* filter); + const FilterOperations& filters); gfx::RectF current_damage_rect() { return current_damage_rect_; } @@ -54,22 +52,36 @@ class CC_EXPORT DamageTracker { gfx::RectF TrackDamageFromSurfaceMask(LayerImpl* target_surface_mask_layer); gfx::RectF TrackDamageFromLeftoverRects(); - gfx::RectF RemoveRectFromCurrentFrame(int layer_id, bool* layer_is_new); - void SaveRectForNextFrame(int layer_id, const gfx::RectF& target_space_rect); + void PrepareRectHistoryForUpdate(); // These helper functions are used only in TrackDamageFromActiveLayers(). void ExtendDamageForLayer(LayerImpl* layer, gfx::RectF* target_damage_rect); void ExtendDamageForRenderSurface(LayerImpl* layer, gfx::RectF* target_damage_rect); - // To correctly track exposed regions, two hashtables of rects are maintained. - // The "current" map is used to compute exposed regions of the current frame, - // while the "next" map is used to collect layer rects that are used in the - // next frame. - typedef base::hash_map<int, gfx::RectF> RectMap; - scoped_ptr<RectMap> current_rect_history_; - scoped_ptr<RectMap> next_rect_history_; + struct RectMapData { + RectMapData() : layer_id_(0), mailboxId_(0) {} + explicit RectMapData(int layer_id) : layer_id_(layer_id), mailboxId_(0) {} + void Update(const gfx::RectF& rect, unsigned int mailboxId) { + mailboxId_ = mailboxId; + rect_ = rect; + } + bool operator < (const RectMapData& other) const { + return layer_id_ < other.layer_id_; + } + + int layer_id_; + unsigned int mailboxId_; + gfx::RectF rect_; + }; + typedef std::vector<RectMapData> SortedRectMap; + + RectMapData& RectDataForLayer(int layer_id, bool* layer_is_new); + + SortedRectMap rect_history_; + + unsigned int mailboxId_; gfx::RectF current_damage_rect_; DISALLOW_COPY_AND_ASSIGN(DamageTracker); diff --git a/chromium/cc/trees/damage_tracker_unittest.cc b/chromium/cc/trees/damage_tracker_unittest.cc index 8a862074410..7fb8720b83d 100644 --- a/chromium/cc/trees/damage_tracker_unittest.cc +++ b/chromium/cc/trees/damage_tracker_unittest.cc @@ -63,8 +63,7 @@ void EmulateDrawingOneFrame(LayerImpl* root) { target_surface->SurfacePropertyChangedOnlyFromDescendant(), target_surface->content_rect(), render_surface_layer_list[i]->mask_layer(), - render_surface_layer_list[i]->filters(), - render_surface_layer_list[i]->filter().get()); + render_surface_layer_list[i]->filters()); } root->ResetAllChangeTrackingForSubtree(); @@ -446,10 +445,12 @@ TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) { skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(new SkBlurImageFilter(SkIntToScalar(2), SkIntToScalar(2))); + FilterOperations filters; + filters.Append(FilterOperation::CreateReferenceFilter(filter)); // Setting the filter will damage the whole surface. ClearDamageForAllSurfaces(root.get()); - child->SetFilter(filter); + child->SetFilters(filters); EmulateDrawingOneFrame(root.get()); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -1297,8 +1298,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForEmptyLayerList) { false, gfx::Rect(), NULL, - FilterOperations(), - NULL); + FilterOperations()); gfx::RectF damage_rect = target_surface->damage_tracker()->current_damage_rect(); diff --git a/chromium/cc/trees/layer_sorter_unittest.cc b/chromium/cc/trees/layer_sorter_unittest.cc index b1d7b819fc5..6669100fccf 100644 --- a/chromium/cc/trees/layer_sorter_unittest.cc +++ b/chromium/cc/trees/layer_sorter_unittest.cc @@ -177,7 +177,7 @@ TEST(LayerSorterTest, LayersUnderPathologicalPerspectiveTransform) { // layer_a. When it is not clipped, its bounds will actually incorrectly // appear much smaller and the correct sorting dependency will not be found. gfx::Transform transform_b; - transform_b.Translate3d(0.0, 0.0, 0.7); + transform_b.Translate3d(0.f, 0.f, 0.7f); transform_b.RotateAboutYAxis(45.0); transform_b.Translate(-5.0, -5.0); LayerShape layer_b(10.f, 10.f, perspective_matrix * transform_b); @@ -287,7 +287,7 @@ TEST(LayerSorterTest, VerifyConcidentLayerPrecisionLossResultsInDocumentOrder) { // in calculated order. gfx::Transform BehindMatrix; - BehindMatrix.Translate3d(0.0, 0.0, 0.999999); + BehindMatrix.Translate3d(0.f, 0.f, 0.999999f); BehindMatrix.RotateAboutXAxis(38.5); BehindMatrix.RotateAboutYAxis(77.0); gfx::Transform FrontMatrix; diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc index f8f0d614440..74321976ff3 100644 --- a/chromium/cc/trees/layer_tree_host.cc +++ b/chromium/cc/trees/layer_tree_host.cc @@ -6,7 +6,9 @@ #include <algorithm> #include <stack> +#include <string> +#include "base/atomic_sequence_num.h" #include "base/bind.h" #include "base/command_line.h" #include "base/debug/trace_event.h" @@ -17,7 +19,6 @@ #include "cc/animation/animation_registrar.h" #include "cc/animation/layer_animation_controller.h" #include "cc/base/math_util.h" -#include "cc/debug/benchmark_instrumentation.h" #include "cc/debug/devtools_instrumentation.h" #include "cc/debug/overdraw_metrics.h" #include "cc/debug/rendering_stats_instrumentation.h" @@ -29,7 +30,7 @@ #include "cc/layers/painted_scrollbar_layer.h" #include "cc/layers/render_surface.h" #include "cc/resources/prioritized_resource_manager.h" -#include "cc/resources/ui_resource_client.h" +#include "cc/resources/ui_resource_request.h" #include "cc/trees/layer_tree_host_client.h" #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_host_impl.h" @@ -41,7 +42,7 @@ #include "ui/gfx/size_conversions.h" namespace { -static int s_num_layer_tree_instances; +static base::StaticAtomicSequenceNumber s_layer_tree_host_sequence_number; } namespace cc { @@ -49,7 +50,6 @@ namespace cc { RendererCapabilities::RendererCapabilities() : best_texture_format(RGBA_8888), using_partial_swap(false), - using_set_visibility(false), using_egl_image(false), allow_partial_texture_updates(false), using_offscreen_context3d(false), @@ -61,54 +61,38 @@ RendererCapabilities::RendererCapabilities() RendererCapabilities::~RendererCapabilities() {} -UIResourceRequest::UIResourceRequest(UIResourceRequestType type, - UIResourceId id) - : type_(type), id_(id) {} - -UIResourceRequest::UIResourceRequest(UIResourceRequestType type, - UIResourceId id, - const UIResourceBitmap& bitmap) - : type_(type), id_(id), bitmap_(new UIResourceBitmap(bitmap)) {} - -UIResourceRequest::UIResourceRequest(const UIResourceRequest& request) { - (*this) = request; -} - -UIResourceRequest& UIResourceRequest::operator=( - const UIResourceRequest& request) { - type_ = request.type_; - id_ = request.id_; - if (request.bitmap_) { - bitmap_ = make_scoped_ptr(new UIResourceBitmap(*request.bitmap_.get())); - } else { - bitmap_.reset(); - } - - return *this; -} - -UIResourceRequest::~UIResourceRequest() {} - -bool LayerTreeHost::AnyLayerTreeHostInstanceExists() { - return s_num_layer_tree_instances > 0; -} - -scoped_ptr<LayerTreeHost> LayerTreeHost::Create( +scoped_ptr<LayerTreeHost> LayerTreeHost::CreateThreaded( LayerTreeHostClient* client, + SharedBitmapManager* manager, const LayerTreeSettings& settings, scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) { - scoped_ptr<LayerTreeHost> layer_tree_host(new LayerTreeHost(client, - settings)); - if (!layer_tree_host->Initialize(impl_task_runner)) + DCHECK(impl_task_runner); + scoped_ptr<LayerTreeHost> layer_tree_host( + new LayerTreeHost(client, manager, settings)); + if (!layer_tree_host->InitializeThreaded(impl_task_runner)) + return scoped_ptr<LayerTreeHost>(); + return layer_tree_host.Pass(); +} + +scoped_ptr<LayerTreeHost> LayerTreeHost::CreateSingleThreaded( + LayerTreeHostClient* client, + LayerTreeHostSingleThreadClient* single_thread_client, + SharedBitmapManager* manager, + const LayerTreeSettings& settings) { + scoped_ptr<LayerTreeHost> layer_tree_host( + new LayerTreeHost(client, manager, settings)); + if (!layer_tree_host->InitializeSingleThreaded(single_thread_client)) return scoped_ptr<LayerTreeHost>(); return layer_tree_host.Pass(); } -static int s_next_tree_id = 1; -LayerTreeHost::LayerTreeHost(LayerTreeHostClient* client, - const LayerTreeSettings& settings) - : next_ui_resource_id_(1), +LayerTreeHost::LayerTreeHost( + LayerTreeHostClient* client, + SharedBitmapManager* manager, + const LayerTreeSettings& settings) + : micro_benchmark_controller_(this), + next_ui_resource_id_(1), animating_(false), needs_full_tree_sync_(true), needs_filter_context_(false), @@ -132,20 +116,24 @@ LayerTreeHost::LayerTreeHost(LayerTreeHostClient* client, partial_texture_update_requests_(0), in_paint_layer_contents_(false), total_frames_used_for_lcd_text_metrics_(0), - tree_id_(s_next_tree_id++) { + id_(s_layer_tree_host_sequence_number.GetNext() + 1), + next_commit_forces_redraw_(false), + shared_bitmap_manager_(manager) { if (settings_.accelerated_animation_enabled) animation_registrar_ = AnimationRegistrar::Create(); - s_num_layer_tree_instances++; rendering_stats_instrumentation_->set_record_rendering_stats( debug_state_.RecordRenderingStats()); } -bool LayerTreeHost::Initialize( +bool LayerTreeHost::InitializeThreaded( scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) { - if (impl_task_runner.get()) - return InitializeProxy(ThreadProxy::Create(this, impl_task_runner)); - else - return InitializeProxy(SingleThreadProxy::Create(this)); + return InitializeProxy(ThreadProxy::Create(this, impl_task_runner)); +} + +bool LayerTreeHost::InitializeSingleThreaded( + LayerTreeHostSingleThreadClient* single_thread_client) { + return InitializeProxy( + SingleThreadProxy::Create(this, single_thread_client)); } bool LayerTreeHost::InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing) { @@ -177,11 +165,6 @@ LayerTreeHost::~LayerTreeHost() { proxy_->Stop(); } - s_num_layer_tree_instances--; - RateLimiterMap::iterator it = rate_limiters_.begin(); - if (it != rate_limiters_.end()) - it->second->Stop(); - if (root_layer_.get()) { // The layer tree must be destroyed before the layer tree host. We've // made a contract with our animation controllers that the registrar @@ -194,6 +177,10 @@ void LayerTreeHost::SetLayerTreeHostClientReady() { proxy_->SetLayerTreeHostClientReady(); } +static void LayerTreeHostOnOutputSurfaceCreatedCallback(Layer* layer) { + layer->OnOutputSurfaceCreated(); +} + LayerTreeHost::CreateResult LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted(bool success) { TRACE_EVENT1("cc", @@ -205,24 +192,19 @@ LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted(bool success) { if (success) { output_surface_lost_ = false; - // Update settings_ based on partial update capability. - size_t max_partial_texture_updates = 0; - if (proxy_->GetRendererCapabilities().allow_partial_texture_updates && - !settings_.impl_side_painting) { - max_partial_texture_updates = std::min( - settings_.max_partial_texture_updates, - proxy_->MaxPartialTextureUpdates()); - } - settings_.max_partial_texture_updates = max_partial_texture_updates; - - if (!contents_texture_manager_ && - (!settings_.impl_side_painting || !settings_.solid_color_scrollbars)) { + if (!contents_texture_manager_ && !settings_.impl_side_painting) { contents_texture_manager_ = PrioritizedResourceManager::Create(proxy_.get()); surface_memory_placeholder_ = contents_texture_manager_->CreateTexture(gfx::Size(), RGBA_8888); } + if (root_layer()) { + LayerTreeHostCommon::CallFunctionForSubtree( + root_layer(), + base::Bind(&LayerTreeHostOnOutputSurfaceCreatedCallback)); + } + client_->DidInitializeOutputSurface(true); return CreateSucceeded; } @@ -257,8 +239,8 @@ void LayerTreeHost::AcquireLayerTextures() { proxy_->AcquireLayerTextures(); } -void LayerTreeHost::DidBeginFrame() { - client_->DidBeginFrame(); +void LayerTreeHost::DidBeginMainFrame() { + client_->DidBeginMainFrame(); } void LayerTreeHost::UpdateClientAnimations(base::TimeTicks frame_begin_time) { @@ -309,7 +291,8 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) { host_impl->set_max_memory_needed_bytes( contents_texture_manager_->MaxMemoryNeededBytes()); - contents_texture_manager_->UpdateBackingsInDrawingImplTree(); + contents_texture_manager_->UpdateBackingsState( + host_impl->resource_provider()); } // In impl-side painting, synchronize to the pending tree so that it has @@ -322,11 +305,17 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) { DCHECK(!host_impl->pending_tree()); host_impl->CreatePendingTree(); sync_tree = host_impl->pending_tree(); + if (next_commit_forces_redraw_) + sync_tree->ForceRedrawNextActivation(); } else { + if (next_commit_forces_redraw_) + host_impl->SetFullRootLayerDamage(); contents_texture_manager_->ReduceMemory(host_impl->resource_provider()); sync_tree = host_impl->active_tree(); } + next_commit_forces_redraw_ = false; + sync_tree->set_source_frame_number(source_frame_number()); if (needs_full_tree_sync_) @@ -384,8 +373,8 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) { min_page_scale_factor_, max_page_scale_factor_); sync_tree->SetPageScaleDelta(page_scale_delta / sent_page_scale_delta); - sync_tree->SetLatencyInfo(latency_info_); - latency_info_.Clear(); + + sync_tree->PassSwapPromises(&swap_promise_list_); host_impl->SetViewportSize(device_viewport_size_); host_impl->SetOverdrawBottomHeight(overdraw_bottom_height_); @@ -425,8 +414,11 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) { // If we're not in impl-side painting, the tree is immediately // considered active. sync_tree->DidBecomeActive(); + devtools_instrumentation::didActivateLayerTree(id_, source_frame_number_); } + micro_benchmark_controller_.ScheduleImplBenchmarks(host_impl); + source_frame_number_++; } @@ -462,7 +454,10 @@ scoped_ptr<LayerTreeHostImpl> LayerTreeHost::CreateLayerTreeHostImpl( LayerTreeHostImpl::Create(settings_, client, proxy_.get(), - rendering_stats_instrumentation_.get()); + rendering_stats_instrumentation_.get(), + shared_bitmap_manager_, + id_); + shared_bitmap_manager_ = NULL; if (settings_.calculate_top_controls_position && host_impl->top_controls_manager()) { top_controls_manager_weak_ptr_ = @@ -525,11 +520,14 @@ const RendererCapabilities& LayerTreeHost::GetRendererCapabilities() const { } void LayerTreeHost::SetNeedsAnimate() { - DCHECK(proxy_->HasImplThread()); proxy_->SetNeedsAnimate(); + NotifySwapPromiseMonitorsOfSetNeedsCommit(); } -void LayerTreeHost::SetNeedsUpdateLayers() { proxy_->SetNeedsUpdateLayers(); } +void LayerTreeHost::SetNeedsUpdateLayers() { + proxy_->SetNeedsUpdateLayers(); + NotifySwapPromiseMonitorsOfSetNeedsCommit(); +} void LayerTreeHost::SetNeedsCommit() { if (!prepaint_callback_.IsCancelled()) { @@ -539,6 +537,7 @@ void LayerTreeHost::SetNeedsCommit() { prepaint_callback_.Cancel(); } proxy_->SetNeedsCommit(); + NotifySwapPromiseMonitorsOfSetNeedsCommit(); } void LayerTreeHost::SetNeedsFullTreeSync() { @@ -552,18 +551,25 @@ void LayerTreeHost::SetNeedsRedraw() { void LayerTreeHost::SetNeedsRedrawRect(gfx::Rect damage_rect) { proxy_->SetNeedsRedraw(damage_rect); - if (!proxy_->HasImplThread()) - client_->ScheduleComposite(); } bool LayerTreeHost::CommitRequested() const { return proxy_->CommitRequested(); } +bool LayerTreeHost::BeginMainFrameRequested() const { + return proxy_->BeginMainFrameRequested(); +} + + void LayerTreeHost::SetNextCommitWaitsForActivation() { proxy_->SetNextCommitWaitsForActivation(); } +void LayerTreeHost::SetNextCommitForcesRedraw() { + next_commit_forces_redraw_ = true; +} + void LayerTreeHost::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events, base::Time wall_clock_time) { DCHECK(proxy_->IsMainThread()); @@ -588,6 +594,10 @@ void LayerTreeHost::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events, wall_clock_time.ToDoubleT()); break; + case AnimationEvent::Aborted: + (*iter).second->NotifyAnimationAborted((*events)[event_index]); + break; + case AnimationEvent::PropertyUpdate: (*iter).second->NotifyAnimationPropertyUpdate((*events)[event_index]); break; @@ -677,8 +687,9 @@ void LayerTreeHost::SetOverhangBitmap(const SkBitmap& bitmap) { bitmap_copy.setImmutable(); } - overhang_ui_resource_ = ScopedUIResource::Create( - this, UIResourceBitmap(bitmap_copy, UIResourceBitmap::REPEAT)); + UIResourceBitmap overhang_bitmap(bitmap_copy); + overhang_bitmap.SetWrapMode(UIResourceBitmap::REPEAT); + overhang_ui_resource_ = ScopedUIResource::Create(this, overhang_bitmap); } void LayerTreeHost::SetVisible(bool visible) { @@ -690,10 +701,6 @@ void LayerTreeHost::SetVisible(bool visible) { proxy_->SetVisible(visible); } -void LayerTreeHost::SetLatencyInfo(const ui::LatencyInfo& latency_info) { - latency_info_.MergeWith(latency_info); -} - void LayerTreeHost::StartPageScaleAnimation(gfx::Vector2d target_offset, bool use_anchor, float scale, @@ -719,10 +726,6 @@ void LayerTreeHost::Composite(base::TimeTicks frame_begin_time) { SetNeedsCommit(); } -void LayerTreeHost::ScheduleComposite() { - client_->ScheduleComposite(); -} - bool LayerTreeHost::InitializeOutputSurfaceIfNeeded() { if (!output_surface_can_be_initialized_) return false; @@ -740,7 +743,11 @@ bool LayerTreeHost::UpdateLayers(ResourceUpdateQueue* queue) { DCHECK(!root_layer()->parent()); - return UpdateLayers(root_layer(), queue); + bool result = UpdateLayers(root_layer(), queue); + + micro_benchmark_controller_.DidUpdateLayers(); + + return result; } static Layer* FindFirstScrollableLayer(Layer* layer) { @@ -777,10 +784,8 @@ bool LayerTreeHost::UsingSharedMemoryResources() { bool LayerTreeHost::UpdateLayers(Layer* root_layer, ResourceUpdateQueue* queue) { - TRACE_EVENT1(benchmark_instrumentation::kCategory, - benchmark_instrumentation::kLayerTreeHostUpdateLayers, - benchmark_instrumentation::kSourceFrameNumber, - source_frame_number()); + TRACE_EVENT1("cc", "LayerTreeHost::UpdateLayers", + "source_frame_number", source_frame_number()); RenderSurfaceLayerList update_list; { @@ -797,6 +802,7 @@ bool LayerTreeHost::UpdateLayers(Layer* root_layer, } TRACE_EVENT0("cc", "LayerTreeHost::UpdateLayers::CalcDrawProps"); + bool can_render_to_separate_surface = true; LayerTreeHostCommon::CalcDrawPropsMainInputs inputs( root_layer, device_viewport_size(), @@ -806,6 +812,7 @@ bool LayerTreeHost::UpdateLayers(Layer* root_layer, page_scale_layer, GetRendererCapabilities().max_texture_size, settings_.can_use_lcd_text, + can_render_to_separate_surface, settings_.layer_transforms_should_scale_layer_contents, &update_list); LayerTreeHostCommon::CalculateDrawProperties(&inputs); @@ -888,11 +895,10 @@ void LayerTreeHost::SetPrioritiesForSurfaces(size_t surface_memory_bytes) { void LayerTreeHost::SetPrioritiesForLayers( const RenderSurfaceLayerList& update_list) { - // Use BackToFront since it's cheap and this isn't order-dependent. typedef LayerIterator<Layer, RenderSurfaceLayerList, RenderSurface, - LayerIteratorActions::BackToFront> LayerIteratorType; + LayerIteratorActions::FrontToBack> LayerIteratorType; PriorityCalculator calculator; LayerIteratorType end = LayerIteratorType::End(&update_list); @@ -973,10 +979,6 @@ void LayerTreeHost::PaintMasksForRenderSurface(Layer* render_surface_layer, Layer* mask_layer = render_surface_layer->mask_layer(); if (mask_layer) { - devtools_instrumentation::ScopedLayerTreeTask - update_layer(devtools_instrumentation::kUpdateLayer, - mask_layer->id(), - id()); *did_paint_content |= mask_layer->Update(queue, NULL); *need_more_updates |= mask_layer->NeedMoreUpdates(); } @@ -985,10 +987,6 @@ void LayerTreeHost::PaintMasksForRenderSurface(Layer* render_surface_layer, render_surface_layer->replica_layer() ? render_surface_layer->replica_layer()->mask_layer() : NULL; if (replica_mask_layer) { - devtools_instrumentation::ScopedLayerTreeTask - update_layer(devtools_instrumentation::kUpdateLayer, - replica_mask_layer->id(), - id()); *did_paint_content |= replica_mask_layer->Update(queue, NULL); *need_more_updates |= replica_mask_layer->NeedMoreUpdates(); } @@ -1025,15 +1023,12 @@ void LayerTreeHost::PaintLayerContents( LayerIteratorType::Begin(&render_surface_layer_list); it != end; ++it) { - bool prevent_occlusion = it.target_render_surface_layer()->HasCopyRequest(); - occlusion_tracker.EnterLayer(it, prevent_occlusion); + occlusion_tracker.EnterLayer(it); if (it.represents_target_render_surface()) { PaintMasksForRenderSurface( *it, queue, did_paint_content, need_more_updates); - } else if (it.represents_itself()) { - devtools_instrumentation::ScopedLayerTreeTask - update_layer(devtools_instrumentation::kUpdateLayer, it->id(), id()); + } else if (it.represents_itself() && it->DrawsContent()) { DCHECK(!it->paint_properties().bounds.IsEmpty()); *did_paint_content |= it->Update(queue, &occlusion_tracker); *need_more_updates |= it->NeedMoreUpdates(); @@ -1085,28 +1080,20 @@ void LayerTreeHost::ApplyScrollAndScale(const ScrollAndScaleSet& info) { } } -void LayerTreeHost::StartRateLimiter(WebKit::WebGraphicsContext3D* context3d) { +void LayerTreeHost::StartRateLimiter() { if (animating_) return; - DCHECK(context3d); - RateLimiterMap::iterator it = rate_limiters_.find(context3d); - if (it != rate_limiters_.end()) { - it->second->Start(); - } else { - scoped_refptr<RateLimiter> rate_limiter = - RateLimiter::Create(context3d, this, proxy_->MainThreadTaskRunner()); - rate_limiters_[context3d] = rate_limiter; - rate_limiter->Start(); + if (!rate_limit_timer_.IsRunning()) { + rate_limit_timer_.Start(FROM_HERE, + base::TimeDelta(), + this, + &LayerTreeHost::RateLimit); } } -void LayerTreeHost::StopRateLimiter(WebKit::WebGraphicsContext3D* context3d) { - RateLimiterMap::iterator it = rate_limiters_.find(context3d); - if (it != rate_limiters_.end()) { - it->second->Stop(); - rate_limiters_.erase(it); - } +void LayerTreeHost::StopRateLimiter() { + rate_limit_timer_.Stop(); } void LayerTreeHost::RateLimit() { @@ -1114,10 +1101,28 @@ void LayerTreeHost::RateLimit() { // commands will wait for the compositing context, and therefore for the // SwapBuffers. proxy_->ForceSerializeOnSwapBuffers(); + client_->RateLimitSharedMainThreadContext(); +} + +bool LayerTreeHost::AlwaysUsePartialTextureUpdates() { + if (!proxy_->GetRendererCapabilities().allow_partial_texture_updates) + return false; + return !proxy_->HasImplThread(); +} + +size_t LayerTreeHost::MaxPartialTextureUpdates() const { + size_t max_partial_texture_updates = 0; + if (proxy_->GetRendererCapabilities().allow_partial_texture_updates && + !settings_.impl_side_painting) { + max_partial_texture_updates = + std::min(settings_.max_partial_texture_updates, + proxy_->MaxPartialTextureUpdates()); + } + return max_partial_texture_updates; } bool LayerTreeHost::RequestPartialTextureUpdate() { - if (partial_texture_update_requests_ >= settings_.max_partial_texture_updates) + if (partial_texture_update_requests_ >= MaxPartialTextureUpdates()) return false; partial_texture_update_requests_++; @@ -1155,7 +1160,6 @@ scoped_ptr<base::Value> LayerTreeHost::AsValue() const { } void LayerTreeHost::AnimateLayers(base::TimeTicks time) { - rendering_stats_instrumentation_->IncrementAnimationFrameCount(); if (!settings_.accelerated_animation_enabled || animation_registrar_->active_animation_controllers().empty()) return; @@ -1240,4 +1244,39 @@ void LayerTreeHost::RegisterViewportLayers( outer_viewport_scroll_layer_ = outer_viewport_scroll_layer; } +bool LayerTreeHost::ScheduleMicroBenchmark( + const std::string& benchmark_name, + scoped_ptr<base::Value> value, + const MicroBenchmark::DoneCallback& callback) { + return micro_benchmark_controller_.ScheduleRun( + benchmark_name, value.Pass(), callback); +} + +void LayerTreeHost::InsertSwapPromiseMonitor(SwapPromiseMonitor* monitor) { + swap_promise_monitor_.insert(monitor); +} + +void LayerTreeHost::RemoveSwapPromiseMonitor(SwapPromiseMonitor* monitor) { + swap_promise_monitor_.erase(monitor); +} + +void LayerTreeHost::NotifySwapPromiseMonitorsOfSetNeedsCommit() { + std::set<SwapPromiseMonitor*>::iterator it = swap_promise_monitor_.begin(); + for (; it != swap_promise_monitor_.end(); it++) + (*it)->OnSetNeedsCommitOnMain(); +} + +void LayerTreeHost::QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise) { + DCHECK(swap_promise); + if (swap_promise_list_.size() > kMaxQueuedSwapPromiseNumber) + BreakSwapPromises(SwapPromise::SWAP_PROMISE_LIST_OVERFLOW); + swap_promise_list_.push_back(swap_promise.Pass()); +} + +void LayerTreeHost::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) { + for (size_t i = 0; i < swap_promise_list_.size(); i++) + swap_promise_list_[i]->DidNotSwap(reason); + swap_promise_list_.clear(); +} + } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h index 72a5628a9ad..8b9c1cf3226 100644 --- a/chromium/cc/trees/layer_tree_host.h +++ b/chromium/cc/trees/layer_tree_host.h @@ -7,6 +7,8 @@ #include <limits> #include <list> +#include <set> +#include <string> #include <vector> #include "base/basictypes.h" @@ -16,9 +18,14 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" +#include "base/timer/timer.h" #include "cc/animation/animation_events.h" #include "cc/base/cc_export.h" #include "cc/base/scoped_ptr_vector.h" +#include "cc/base/swap_promise.h" +#include "cc/base/swap_promise_monitor.h" +#include "cc/debug/micro_benchmark.h" +#include "cc/debug/micro_benchmark_controller.h" #include "cc/input/input_handler.h" #include "cc/input/scrollbar.h" #include "cc/input/top_controls_state.h" @@ -26,31 +33,14 @@ #include "cc/output/output_surface.h" #include "cc/resources/resource_format.h" #include "cc/resources/scoped_ui_resource.h" -#include "cc/resources/ui_resource_bitmap.h" -#include "cc/resources/ui_resource_client.h" -#include "cc/scheduler/rate_limiter.h" #include "cc/trees/layer_tree_host_client.h" #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_settings.h" #include "cc/trees/occlusion_tracker.h" #include "cc/trees/proxy.h" #include "third_party/skia/include/core/SkColor.h" -#include "ui/events/latency_info.h" #include "ui/gfx/rect.h" -namespace WebKit { class WebGraphicsContext3D; } - -#if defined(COMPILER_GCC) -namespace BASE_HASH_NAMESPACE { -template <> -struct hash<WebKit::WebGraphicsContext3D*> { - size_t operator()(WebKit::WebGraphicsContext3D* ptr) const { - return hash<size_t>()(reinterpret_cast<size_t>(ptr)); - } -}; -} // namespace BASE_HASH_NAMESPACE -#endif // COMPILER - namespace cc { class AnimationRegistrar; @@ -58,13 +48,16 @@ class HeadsUpDisplayLayer; class Layer; class LayerTreeHostImpl; class LayerTreeHostImplClient; -class PrioritizedResourceManager; +class LayerTreeHostSingleThreadClient; class PrioritizedResource; +class PrioritizedResourceManager; class Region; class RenderingStatsInstrumentation; class ResourceProvider; class ResourceUpdateQueue; +class SharedBitmapManager; class TopControlsManager; +class UIResourceRequest; struct RenderingStats; struct ScrollAndScaleSet; @@ -76,7 +69,6 @@ struct CC_EXPORT RendererCapabilities { ResourceFormat best_texture_format; bool using_partial_swap; - bool using_set_visibility; bool using_egl_image; bool allow_partial_texture_updates; bool using_offscreen_context3d; @@ -87,58 +79,34 @@ struct CC_EXPORT RendererCapabilities { bool using_discard_framebuffer; }; -class CC_EXPORT UIResourceRequest { - public: - enum UIResourceRequestType { - UIResourceCreate, - UIResourceDelete, - UIResourceInvalidRequest - }; - - UIResourceRequest(UIResourceRequestType type, UIResourceId id); - UIResourceRequest(UIResourceRequestType type, - UIResourceId id, - const UIResourceBitmap& bitmap); - UIResourceRequest(const UIResourceRequest& request); - - ~UIResourceRequest(); - - UIResourceRequestType GetType() const { return type_; } - UIResourceId GetId() const { return id_; } - UIResourceBitmap GetBitmap() const { - DCHECK(bitmap_); - return *bitmap_.get(); - } - - UIResourceRequest& operator=(const UIResourceRequest& request); - - private: - UIResourceRequestType type_; - UIResourceId id_; - scoped_ptr<UIResourceBitmap> bitmap_; -}; - -class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) { +class CC_EXPORT LayerTreeHost { public: - static scoped_ptr<LayerTreeHost> Create( + // The SharedBitmapManager will be used on the compositor thread. + static scoped_ptr<LayerTreeHost> CreateThreaded( LayerTreeHostClient* client, + SharedBitmapManager* manager, const LayerTreeSettings& settings, scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner); + + static scoped_ptr<LayerTreeHost> CreateSingleThreaded( + LayerTreeHostClient* client, + LayerTreeHostSingleThreadClient* single_thread_client, + SharedBitmapManager* manager, + const LayerTreeSettings& settings); virtual ~LayerTreeHost(); void SetLayerTreeHostClientReady(); - // Returns true if any LayerTreeHost is alive. - static bool AnyLayerTreeHostInstanceExists(); - void set_needs_filter_context() { needs_filter_context_ = true; } bool needs_offscreen_context() const { return needs_filter_context_; } // LayerTreeHost interface to Proxy. - void WillBeginFrame() { client_->WillBeginFrame(); } - void DidBeginFrame(); + void WillBeginMainFrame() { + client_->WillBeginMainFrame(source_frame_number_); + } + void DidBeginMainFrame(); void UpdateClientAnimations(base::TimeTicks monotonic_frame_begin_time); void AnimateLayers(base::TimeTicks monotonic_frame_begin_time); void DidStopFlinging(); @@ -175,9 +143,6 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) { void Composite(base::TimeTicks frame_begin_time); - // Only used when compositing on the main thread. - void ScheduleComposite(); - // Composites and attempts to read back the result into the provided // buffer. If it wasn't possible, e.g. due to context lost, will return // false. @@ -209,15 +174,19 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) { void SetNeedsRedraw(); void SetNeedsRedrawRect(gfx::Rect damage_rect); bool CommitRequested() const; + bool BeginMainFrameRequested() const; void SetNextCommitWaitsForActivation(); + void SetNextCommitForcesRedraw(); + void SetAnimationEvents(scoped_ptr<AnimationEventsVector> events, base::Time wall_clock_time); void SetRootLayer(scoped_refptr<Layer> root_layer); Layer* root_layer() { return root_layer_.get(); } const Layer* root_layer() const { return root_layer_.get(); } + const Layer* page_scale_layer() const { return page_scale_layer_.get(); } void RegisterViewportLayers( scoped_refptr<Layer> page_scale_layer, scoped_refptr<Layer> inner_viewport_scroll_layer, @@ -264,18 +233,15 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) { void ApplyScrollAndScale(const ScrollAndScaleSet& info); void SetImplTransform(const gfx::Transform& transform); - void SetLatencyInfo(const ui::LatencyInfo& latency_info); - virtual void StartRateLimiter(WebKit::WebGraphicsContext3D* context3d); - virtual void StopRateLimiter(WebKit::WebGraphicsContext3D* context3d); + // Virtual for tests. + virtual void StartRateLimiter(); + virtual void StopRateLimiter(); - // RateLimiterClient implementation. - virtual void RateLimit() OVERRIDE; + void RateLimit(); - bool buffered_updates() const { - return settings_.max_partial_texture_updates != - std::numeric_limits<size_t>::max(); - } + bool AlwaysUsePartialTextureUpdates(); + size_t MaxPartialTextureUpdates() const; bool RequestPartialTextureUpdate(); void SetDeviceScaleFactor(float device_scale_factor); @@ -314,12 +280,39 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) { virtual gfx::Size GetUIResourceSize(UIResourceId id) const; bool UsingSharedMemoryResources(); - int id() const { return tree_id_; } + int id() const { return id_; } + + bool ScheduleMicroBenchmark(const std::string& benchmark_name, + scoped_ptr<base::Value> value, + const MicroBenchmark::DoneCallback& callback); + + // When a SwapPromiseMonitor is created on the main thread, it calls + // InsertSwapPromiseMonitor() to register itself with LayerTreeHost. + // When the monitor is destroyed, it calls RemoveSwapPromiseMonitor() + // to unregister itself. + void InsertSwapPromiseMonitor(SwapPromiseMonitor* monitor); + void RemoveSwapPromiseMonitor(SwapPromiseMonitor* monitor); + + // Call this function when you expect there to be a swap buffer. + // See swap_promise.h for how to use SwapPromise. + void QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise); + + void BreakSwapPromises(SwapPromise::DidNotSwapReason reason); protected: - LayerTreeHost(LayerTreeHostClient* client, const LayerTreeSettings& settings); - bool Initialize(scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner); + LayerTreeHost(LayerTreeHostClient* client, + SharedBitmapManager* manager, + const LayerTreeSettings& settings); + bool InitializeThreaded( + scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner); + bool InitializeSingleThreaded( + LayerTreeHostSingleThreadClient* single_thread_client); bool InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing); + void SetOutputSurfaceLostForTesting(bool is_lost) { + output_surface_lost_ = is_lost; + } + + MicroBenchmarkController micro_benchmark_controller_; private: bool InitializeProxy(scoped_ptr<Proxy> proxy); @@ -364,6 +357,8 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) { void CalculateLCDTextMetricsCallback(Layer* layer); + void NotifySwapPromiseMonitorsOfSetNeedsCommit(); + bool animating_; bool needs_full_tree_sync_; bool needs_filter_context_; @@ -389,7 +384,7 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) { base::WeakPtr<InputHandler> input_handler_weak_ptr_; base::WeakPtr<TopControlsManager> top_controls_manager_weak_ptr_; - LayerTreeSettings settings_; + const LayerTreeSettings settings_; LayerTreeDebugState debug_state_; gfx::Size device_viewport_size_; @@ -398,9 +393,7 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) { bool visible_; - typedef base::hash_map<WebKit::WebGraphicsContext3D*, - scoped_refptr<RateLimiter> > RateLimiterMap; - RateLimiterMap rate_limiters_; + base::OneShotTimer<LayerTreeHost> rate_limit_timer_; float page_scale_factor_; float min_page_scale_factor_; @@ -430,8 +423,6 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) { bool in_paint_layer_contents_; - ui::LatencyInfo latency_info_; - static const int kTotalFramesToUseForLCDTextMetrics = 50; int total_frames_used_for_lcd_text_metrics_; @@ -446,12 +437,18 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) { int64 total_num_cc_layers_will_use_lcd_text; }; LCDTextMetrics lcd_text_metrics_; - int tree_id_; + int id_; + bool next_commit_forces_redraw_; scoped_refptr<Layer> page_scale_layer_; scoped_refptr<Layer> inner_viewport_scroll_layer_; scoped_refptr<Layer> outer_viewport_scroll_layer_; + SharedBitmapManager* shared_bitmap_manager_; + + ScopedPtrVector<SwapPromise> swap_promise_list_; + std::set<SwapPromiseMonitor*> swap_promise_monitor_; + DISALLOW_COPY_AND_ASSIGN(LayerTreeHost); }; diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h index 9e11f7cbd5d..2e3023a7f79 100644 --- a/chromium/cc/trees/layer_tree_host_client.h +++ b/chromium/cc/trees/layer_tree_host_client.h @@ -19,10 +19,10 @@ class OutputSurface; class LayerTreeHostClient { public: - virtual void WillBeginFrame() = 0; + virtual void WillBeginMainFrame(int frame_id) = 0; // Marks finishing compositing-related tasks on the main thread. In threaded // mode, this corresponds to DidCommit(). - virtual void DidBeginFrame() = 0; + virtual void DidBeginMainFrame() = 0; virtual void Animate(double frame_begin_time) = 0; virtual void Layout() = 0; virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, @@ -36,15 +36,16 @@ class LayerTreeHostClient { virtual void DidCommitAndDrawFrame() = 0; virtual void DidCompleteSwapBuffers() = 0; - // Used only in the single-threaded path. - virtual void ScheduleComposite() = 0; + // If the client provides an OutputSurface bound to a 3d context for direct + // rendering, this must return a provider that provides contexts usable from + // the same thread as the OutputSurface's context. + virtual scoped_refptr<ContextProvider> OffscreenContextProvider() = 0; - // These must always return a valid ContextProvider. But the provider does not - // need to be capable of creating contexts. - virtual scoped_refptr<cc::ContextProvider> - OffscreenContextProviderForMainThread() = 0; - virtual scoped_refptr<cc::ContextProvider> - OffscreenContextProviderForCompositorThread() = 0; + // Requests that the client insert a rate limiting token in the shared main + // thread context's command stream that will block if the context gets too far + // ahead of the compositor's command stream. Only needed if the tree contains + // a TextureLayer that calls SetRateLimitContext(true). + virtual void RateLimitSharedMainThreadContext() {} // This hook is for testing. virtual void DidFailToInitializeOutputSurface() {} diff --git a/chromium/cc/trees/layer_tree_host_common.cc b/chromium/cc/trees/layer_tree_host_common.cc index 8017fa9a933..33236cf52e4 100644 --- a/chromium/cc/trees/layer_tree_host_common.cc +++ b/chromium/cc/trees/layer_tree_host_common.cc @@ -123,7 +123,7 @@ static LayerType* NextTargetSurface(LayerType* layer) { // translation components of the draw transforms of each target between the // ancestor and descendant. These transforms must be 2D translations, and this // requirement is enforced at every step. -template <typename LayerType, typename RenderSurfaceType> +template <typename LayerType> static gfx::Vector2dF ComputeChangeOfBasisTranslation( const LayerType& ancestor_layer, const LayerType& descendant_layer) { @@ -151,14 +151,13 @@ enum TranslateRectDirection { TranslateRectDirectionToDescendant }; -template <typename LayerType, typename RenderSurfaceType> +template <typename LayerType> static gfx::Rect TranslateRectToTargetSpace(const LayerType& ancestor_layer, const LayerType& descendant_layer, gfx::Rect rect, TranslateRectDirection direction) { - gfx::Vector2dF translation = - ComputeChangeOfBasisTranslation<LayerType, RenderSurfaceType>( - ancestor_layer, descendant_layer); + gfx::Vector2dF translation = ComputeChangeOfBasisTranslation<LayerType>( + ancestor_layer, descendant_layer); if (direction == TranslateRectDirectionToDescendant) translation.Scale(-1.f); return gfx::ToEnclosingRect( @@ -167,7 +166,7 @@ static gfx::Rect TranslateRectToTargetSpace(const LayerType& ancestor_layer, // Attempts to update the clip rects for the given layer. If the layer has a // clip_parent, it may not inherit its immediate ancestor's clip. -template <typename LayerType, typename RenderSurfaceType> +template <typename LayerType> static void UpdateClipRectsForClipChild( const LayerType* layer, gfx::Rect* clip_rect_in_parent_target_space, @@ -175,7 +174,11 @@ static void UpdateClipRectsForClipChild( // If the layer has no clip_parent, or the ancestor is the same as its actual // parent, then we don't need special clip rects. Bail now and leave the out // parameters untouched. - const LayerType* clip_parent = layer->clip_parent(); + const LayerType* clip_parent = layer->scroll_parent(); + + if (!clip_parent) + clip_parent = layer->clip_parent(); + if (!clip_parent || clip_parent == layer->parent()) return; @@ -192,12 +195,23 @@ static void UpdateClipRectsForClipChild( // wanted to. But more importantly, this matches the expectations of // CalculateDrawPropertiesInternal. If we, say, create a render surface, these // clip rects will want to be in its target space, not ours. - *clip_rect_in_parent_target_space = - TranslateRectToTargetSpace<LayerType, RenderSurfaceType>( - *clip_parent, - *layer->parent(), - *clip_rect_in_parent_target_space, - TranslateRectDirectionToDescendant); + if (clip_parent == layer->clip_parent()) { + *clip_rect_in_parent_target_space = TranslateRectToTargetSpace<LayerType>( + *clip_parent, + *layer->parent(), + *clip_rect_in_parent_target_space, + TranslateRectDirectionToDescendant); + } else { + // If we're being clipped by our scroll parent, we must translate through + // our common ancestor. This happens to be our parent, so it is sufficent to + // translate from our clip parent's space to the space of its ancestor (our + // parent). + *clip_rect_in_parent_target_space = + TranslateRectToTargetSpace<LayerType>(*layer->parent(), + *clip_parent, + *clip_rect_in_parent_target_space, + TranslateRectDirectionToAncestor); + } } // We collect an accumulated drawable content rect per render surface. @@ -223,7 +237,7 @@ struct AccumulatedSurfaceState { LayerType* render_target; }; -template <typename LayerType, typename RenderSurfaceType> +template <typename LayerType> void UpdateAccumulatedSurfaceState( LayerType* layer, gfx::Rect drawable_content_rect, @@ -257,7 +271,7 @@ void UpdateAccumulatedSurfaceState( // If the layer has a clip parent, the clip rect may be in the wrong space, // so we'll need to transform it before it is applied. if (layer->clip_parent()) { - clip_rect = TranslateRectToTargetSpace<LayerType, RenderSurfaceType>( + clip_rect = TranslateRectToTargetSpace<LayerType>( *layer->clip_parent(), *layer, clip_rect, @@ -423,10 +437,10 @@ static bool LayerShouldBeSkipped(LayerType* layer, bool layer_is_visible) { // Layers can be skipped if any of these conditions are met. // - is not visible due to it or one of its ancestors being hidden. - // - does not draw content. - // - is transparent // - has empty bounds // - the layer is not double-sided, but its back face is visible. + // - is transparent + // - does not draw content and does not participate in hit testing. // // Some additional conditions need to be computed at a later point after the // recursion is finished. @@ -440,7 +454,7 @@ static bool LayerShouldBeSkipped(LayerType* layer, if (!layer_is_visible) return true; - if (!layer->DrawsContent() || layer->bounds().IsEmpty()) + if (layer->bounds().IsEmpty()) return true; LayerType* backface_test_layer = layer; @@ -457,6 +471,13 @@ static bool LayerShouldBeSkipped(LayerType* layer, IsLayerBackFaceVisible(backface_test_layer)) return true; + // The layer is visible to events. If it's subject to hit testing, then + // we can't skip it. + bool can_accept_input = !layer->touch_event_handler_region().IsEmpty() || + layer->have_wheel_event_handlers(); + if (!layer->DrawsContent() && !can_accept_input) + return true; + return false; } @@ -480,6 +501,7 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, // The opacity of a layer always applies to its children (either implicitly // via a render surface or explicitly if the parent preserves 3D), so the // entire subtree can be skipped if this layer is fully transparent. + // TODO(sad): Don't skip layers used for hit testing crbug.com/295295. return !layer->opacity(); } @@ -500,26 +522,11 @@ static inline bool SubtreeShouldBeSkipped(Layer* layer, // In particular, it should not cause the subtree to be skipped. // Similarly, for layers that might animate opacity using an impl-only // animation, their subtree should also not be skipped. + // TODO(sad): Don't skip layers used for hit testing crbug.com/295295. return !layer->opacity() && !layer->OpacityIsAnimating() && !layer->OpacityCanAnimateOnImplThread(); } -// Called on each layer that could be drawn after all information from -// CalcDrawProperties has been updated on that layer. May have some false -// positives (e.g. layers get this called on them but don't actually get drawn). -static inline void UpdateTilePrioritiesForLayer(LayerImpl* layer) { - layer->UpdateTilePriorities(); - - // Mask layers don't get this call, so explicitly update them so they can - // kick off tile rasterization. - if (layer->mask_layer()) - layer->mask_layer()->UpdateTilePriorities(); - if (layer->replica_layer() && layer->replica_layer()->mask_layer()) - layer->replica_layer()->mask_layer()->UpdateTilePriorities(); -} - -static inline void UpdateTilePrioritiesForLayer(Layer* layer) {} - static inline void SavePaintPropertiesLayer(LayerImpl* layer) {} static inline void SavePaintPropertiesLayer(Layer* layer) { @@ -560,8 +567,7 @@ static bool SubtreeShouldRenderToSeparateSurface( } // If the layer uses a CSS filter. - if (!layer->filters().IsEmpty() || !layer->background_filters().IsEmpty() || - layer->filter()) { + if (!layer->filters().IsEmpty() || !layer->background_filters().IsEmpty()) { DCHECK(!is_root); return true; } @@ -581,12 +587,25 @@ static bool SubtreeShouldRenderToSeparateSurface( return true; } + // If the layer has blending. + // TODO(rosca): this is temporary, until blending is implemented for other + // types of quads than RenderPassDrawQuad. Layers having descendants that draw + // content will still create a separate rendering surface. + if (!layer->uses_default_blend_mode()) { + TRACE_EVENT_INSTANT0( + "cc", + "LayerTreeHostCommon::SubtreeShouldRenderToSeparateSurface blending", + TRACE_EVENT_SCOPE_THREAD); + DCHECK(!is_root); + return true; + } + // If the layer clips its descendants but it is not axis-aligned with respect // to its parent. bool layer_clips_external_content = LayerClipsSubtree(layer) || layer->HasDelegatedContent(); if (layer_clips_external_content && !axis_aligned_with_respect_to_parent && - !layer->draw_properties().descendants_can_clip_selves) { + num_descendants_that_draw_content > 0) { TRACE_EVENT_INSTANT0( "cc", "LayerTreeHostCommon::SubtreeShouldRenderToSeparateSurface clipping", @@ -623,6 +642,19 @@ static bool SubtreeShouldRenderToSeparateSurface( // be used as a contributing surface in order to apply correctly. // + // If the layer has isolation. + // TODO(rosca): to be optimized - create separate rendering surface only when + // the blending descendants might have access to the content behind this layer + // (layer has transparent background or descendants overflow). + // https://code.google.com/p/chromium/issues/detail?id=301738 + if (layer->is_root_for_isolated_group()) { + TRACE_EVENT_INSTANT0( + "cc", + "LayerTreeHostCommon::SubtreeShouldRenderToSeparateSurface isolation", + TRACE_EVENT_SCOPE_THREAD); + return true; + } + // If we force it. if (layer->force_render_surface()) return true; @@ -815,19 +847,29 @@ gfx::Transform ComputeScrollCompensationMatrixForChildren( // render_surfaces. // + // Scroll compensation restarts from identity under two possible conditions: + // - the current layer is a container for fixed-position descendants + // - the current layer is fixed-position itself, so any fixed-position + // descendants are positioned with respect to this layer. Thus, any + // fixed position descendants only need to compensate for scrollDeltas + // that occur below this layer. + bool current_layer_resets_scroll_compensation_for_descendants = + layer->IsContainerForFixedPositionLayers() || + layer->position_constraint().is_fixed_position(); + // Avoid the overheads (including stack allocation and matrix // initialization/copy) if we know that the scroll compensation doesn't need // to be reset or adjusted. - if (!layer->IsContainerForFixedPositionLayers() && + if (!current_layer_resets_scroll_compensation_for_descendants && scroll_delta.IsZero() && !layer->render_surface()) return current_scroll_compensation_matrix; // Start as identity matrix. gfx::Transform next_scroll_compensation_matrix; - // If this layer is not a container, then it inherits the existing scroll - // compensations. - if (!layer->IsContainerForFixedPositionLayers()) + // If this layer does not reset scroll compensation, then it inherits the + // existing scroll compensations. + if (!current_layer_resets_scroll_compensation_for_descendants) next_scroll_compensation_matrix = current_scroll_compensation_matrix; // If the current layer has a non-zero scroll_delta, then we should compute @@ -980,10 +1022,10 @@ static inline RenderSurfaceImpl* CreateOrReuseRenderSurface(LayerImpl* layer) { return layer->render_surface(); } -template <typename LayerType, typename LayerList> +template <typename LayerType> static inline void RemoveSurfaceForEarlyExit( LayerType* layer_to_remove, - LayerList* render_surface_layer_list) { + typename LayerType::RenderSurfaceListType* render_surface_layer_list) { DCHECK(layer_to_remove->render_surface()); // Technically, we know that the layer we want to remove should be // at the back of the render_surface_layer_list. However, we have had @@ -1024,7 +1066,6 @@ static void PreCalculateMetaInformation( PreCalculateMetaInformationRecursiveData* recursive_data) { bool has_delegated_content = layer->HasDelegatedContent(); int num_descendants_that_draw_content = 0; - bool descendants_can_clip_selves = true; if (has_delegated_content) { // Layers with delegated content need to be treated as if they have as @@ -1032,9 +1073,11 @@ static void PreCalculateMetaInformation( // Since we don't know this number right now, we choose one that acts like // infinity for our purposes. num_descendants_that_draw_content = 1000; - descendants_can_clip_selves = false; } + layer->draw_properties().sorted_for_recursion = false; + layer->draw_properties().has_child_with_a_scroll_parent = false; + if (layer->clip_parent()) recursive_data->num_unclipped_descendants++; @@ -1045,21 +1088,12 @@ static void PreCalculateMetaInformation( PreCalculateMetaInformationRecursiveData data_for_child; PreCalculateMetaInformation(child_layer, &data_for_child); - if (!has_delegated_content) { - bool sublayer_transform_prevents_clip = - !layer->sublayer_transform().IsPositiveScaleOrTranslation(); - - num_descendants_that_draw_content += child_layer->DrawsContent() ? 1 : 0; - num_descendants_that_draw_content += - child_layer->draw_properties().num_descendants_that_draw_content; - - if ((child_layer->DrawsContent() && !child_layer->CanClipSelf()) || - !child_layer->draw_properties().descendants_can_clip_selves || - sublayer_transform_prevents_clip || - !child_layer->transform().IsPositiveScaleOrTranslation()) - descendants_can_clip_selves = false; - } + num_descendants_that_draw_content += child_layer->DrawsContent() ? 1 : 0; + num_descendants_that_draw_content += + child_layer->draw_properties().num_descendants_that_draw_content; + if (child_layer->scroll_parent()) + layer->draw_properties().has_child_with_a_scroll_parent = true; recursive_data->Merge(data_for_child); } @@ -1076,17 +1110,13 @@ static void PreCalculateMetaInformation( num_descendants_that_draw_content; layer->draw_properties().num_unclipped_descendants = recursive_data->num_unclipped_descendants; - layer->draw_properties().descendants_can_clip_selves = - descendants_can_clip_selves; layer->draw_properties().layer_or_descendant_has_copy_request = recursive_data->layer_or_descendant_has_copy_request; } static void RoundTranslationComponents(gfx::Transform* transform) { - transform->matrix(). - setDouble(0, 3, MathUtil::Round(transform->matrix().getDouble(0, 3))); - transform->matrix(). - setDouble(1, 3, MathUtil::Round(transform->matrix().getDouble(1, 3))); + transform->matrix().set(0, 3, MathUtil::Round(transform->matrix().get(0, 3))); + transform->matrix().set(1, 3, MathUtil::Round(transform->matrix().get(1, 3))); } template <typename LayerType> @@ -1095,11 +1125,12 @@ struct SubtreeGlobals { int max_texture_size; float device_scale_factor; float page_scale_factor; - LayerType* page_scale_application_layer; + const LayerType* page_scale_application_layer; bool can_adjust_raster_scales; + bool can_render_to_separate_surface; }; -template<typename LayerType, typename RenderSurfaceType> +template<typename LayerType> struct DataForRecursion { // The accumulated sequence of transforms a layer will use to determine its // own draw transform. @@ -1132,23 +1163,140 @@ struct DataForRecursion { gfx::Rect clip_rect_of_target_surface_in_target_space; bool ancestor_clips_subtree; - RenderSurfaceType* nearest_ancestor_surface_that_moves_pixels; + typename LayerType::RenderSurfaceType* + nearest_occlusion_immune_ancestor_surface; bool in_subtree_of_page_scale_application_layer; bool subtree_can_use_lcd_text; bool subtree_is_visible_from_ancestor; }; +template <typename LayerType> +static LayerType* GetChildContainingLayer(const LayerType& parent, + LayerType* layer) { + for (LayerType* ancestor = layer; ancestor; ancestor = ancestor->parent()) { + if (ancestor->parent() == &parent) + return ancestor; + } + NOTREACHED(); + return 0; +} + +template <typename LayerType> +static void AddScrollParentChain(std::vector<LayerType*>* out, + const LayerType& parent, + LayerType* layer) { + // At a high level, this function walks up the chain of scroll parents + // recursively, and once we reach the end of the chain, we add the child + // of |parent| containing each scroll ancestor as we unwind. The result is + // an ordering of parent's children that ensures that scroll parents are + // visited before their descendants. + // Take for example this layer tree: + // + // + stacking_context + // + scroll_child (1) + // + scroll_parent_graphics_layer (*) + // | + scroll_parent_scrolling_layer + // | + scroll_parent_scrolling_content_layer (2) + // + scroll_grandparent_graphics_layer (**) + // + scroll_grandparent_scrolling_layer + // + scroll_grandparent_scrolling_content_layer (3) + // + // The scroll child is (1), its scroll parent is (2) and its scroll + // grandparent is (3). Note, this doesn't mean that (2)'s scroll parent is + // (3), it means that (*)'s scroll parent is (3). We don't want our list to + // look like [ (3), (2), (1) ], even though that does have the ancestor chain + // in the right order. Instead, we want [ (**), (*), (1) ]. That is, only want + // (1)'s siblings in the list, but we want them to appear in such an order + // that the scroll ancestors get visited in the correct order. + // + // So our first task at this step of the recursion is to determine the layer + // that we will potentionally add to the list. That is, the child of parent + // containing |layer|. + LayerType* child = GetChildContainingLayer(parent, layer); + if (child->draw_properties().sorted_for_recursion) + return; + + if (LayerType* scroll_parent = child->scroll_parent()) + AddScrollParentChain(out, parent, scroll_parent); + + out->push_back(child); + child->draw_properties().sorted_for_recursion = true; +} + +template <typename LayerType> +static bool SortChildrenForRecursion(std::vector<LayerType*>* out, + const LayerType& parent) { + out->reserve(parent.children().size()); + bool order_changed = false; + for (size_t i = 0; i < parent.children().size(); ++i) { + LayerType* current = + LayerTreeHostCommon::get_child_as_raw_ptr(parent.children(), i); + + if (current->draw_properties().sorted_for_recursion) { + order_changed = true; + continue; + } + + AddScrollParentChain(out, parent, current); + } + + DCHECK_EQ(parent.children().size(), out->size()); + return order_changed; +} + +template <typename LayerType> +static void GetNewDescendantsStartIndexAndCount(LayerType* layer, + size_t* start_index, + size_t* count) { + *start_index = layer->draw_properties().index_of_first_descendants_addition; + *count = layer->draw_properties().num_descendants_added; +} + +template <typename LayerType> +static void GetNewRenderSurfacesStartIndexAndCount(LayerType* layer, + size_t* start_index, + size_t* count) { + *start_index = layer->draw_properties() + .index_of_first_render_surface_layer_list_addition; + *count = layer->draw_properties().num_render_surfaces_added; +} + +template <typename LayerType, + typename GetIndexAndCountType> +static void SortLayerListContributions( + const LayerType& parent, + typename LayerType::RenderSurfaceListType* unsorted, + size_t start_index_for_all_contributions, + GetIndexAndCountType get_index_and_count) { + + typename LayerType::LayerListType buffer; + for (size_t i = 0; i < parent.children().size(); ++i) { + LayerType* child = + LayerTreeHostCommon::get_child_as_raw_ptr(parent.children(), i); + + size_t start_index = 0; + size_t count = 0; + get_index_and_count(child, &start_index, &count); + for (size_t j = start_index; j < start_index + count; ++j) + buffer.push_back(unsorted->at(j)); + } + + DCHECK_EQ(buffer.size(), + unsorted->size() - start_index_for_all_contributions); + + for (size_t i = 0; i < buffer.size(); ++i) + (*unsorted)[i + start_index_for_all_contributions] = buffer[i]; +} + // Recursively walks the layer tree starting at the given node and computes all // the necessary transformations, clip rects, render surfaces, etc. -template <typename LayerType, - typename LayerListType, - typename RenderSurfaceType> +template <typename LayerType> static void CalculateDrawPropertiesInternal( LayerType* layer, const SubtreeGlobals<LayerType>& globals, - const DataForRecursion<LayerType, RenderSurfaceType>& data_from_ancestor, - LayerListType* render_surface_layer_list, - LayerListType* layer_list, + const DataForRecursion<LayerType>& data_from_ancestor, + typename LayerType::RenderSurfaceListType* render_surface_layer_list, + typename LayerType::RenderSurfaceListType* layer_list, std::vector<AccumulatedSurfaceState<LayerType> >* accumulated_surface_state) { // This function computes the new matrix transformations recursively for this @@ -1278,9 +1426,10 @@ static void CalculateDrawPropertiesInternal( DCHECK(globals.page_scale_application_layer || (globals.page_scale_factor == 1.f)); - DataForRecursion<LayerType, RenderSurfaceType> data_for_children; - RenderSurfaceType* nearest_ancestor_surface_that_moves_pixels = - data_from_ancestor.nearest_ancestor_surface_that_moves_pixels; + DataForRecursion<LayerType> data_for_children; + typename LayerType::RenderSurfaceType* + nearest_occlusion_immune_ancestor_surface = + data_from_ancestor.nearest_occlusion_immune_ancestor_surface; data_for_children.in_subtree_of_page_scale_application_layer = data_from_ancestor.in_subtree_of_page_scale_application_layer; data_for_children.subtree_can_use_lcd_text = @@ -1313,15 +1462,14 @@ static void CalculateDrawPropertiesInternal( // Update our clipping state. If we have a clip parent we will need to pull // from the clip state cache rather than using the clip state passed from our // immediate ancestor. - UpdateClipRectsForClipChild<LayerType, RenderSurfaceType>( + UpdateClipRectsForClipChild<LayerType>( layer, &ancestor_clip_rect_in_target_space, &ancestor_clips_subtree); // As this function proceeds, these are the properties for the current // layer that actually get computed. To avoid unnecessary copies // (particularly for matrices), we do computations directly on these values // when possible. - DrawProperties<LayerType, RenderSurfaceType>& layer_draw_properties = - layer->draw_properties(); + DrawProperties<LayerType>& layer_draw_properties = layer->draw_properties(); gfx::Rect clip_rect_in_target_space; bool layer_or_ancestor_clips_descendants = false; @@ -1464,8 +1612,14 @@ static void CalculateDrawPropertiesInternal( ? combined_transform_scales : gfx::Vector2dF(layer_scale_factors, layer_scale_factors); - if (SubtreeShouldRenderToSeparateSurface( - layer, combined_transform.Preserves2dAxisAlignment())) { + bool render_to_separate_surface; + if (globals.can_render_to_separate_surface) { + render_to_separate_surface = SubtreeShouldRenderToSeparateSurface( + layer, combined_transform.Preserves2dAxisAlignment()); + } else { + render_to_separate_surface = IsRootLayer(layer); + } + if (render_to_separate_surface) { // Check back-face visibility before continuing with this surface and its // subtree if (!layer->double_sided() && TransformToParentIsKnown(layer) && @@ -1474,7 +1628,8 @@ static void CalculateDrawPropertiesInternal( return; } - RenderSurfaceType* render_surface = CreateOrReuseRenderSurface(layer); + typename LayerType::RenderSurfaceType* render_surface = + CreateOrReuseRenderSurface(layer); if (IsRootLayer(layer)) { // The root layer's render surface size is predetermined and so the root @@ -1543,7 +1698,7 @@ static void CalculateDrawPropertiesInternal( render_surface->draw_transform()); if (layer->mask_layer()) { - DrawProperties<LayerType, RenderSurfaceType>& mask_layer_draw_properties = + DrawProperties<LayerType>& mask_layer_draw_properties = layer->mask_layer()->draw_properties(); mask_layer_draw_properties.render_target = layer; mask_layer_draw_properties.visible_content_rect = @@ -1551,21 +1706,28 @@ static void CalculateDrawPropertiesInternal( } if (layer->replica_layer() && layer->replica_layer()->mask_layer()) { - DrawProperties<LayerType, RenderSurfaceType>& - replica_mask_draw_properties = + DrawProperties<LayerType>& replica_mask_draw_properties = layer->replica_layer()->mask_layer()->draw_properties(); replica_mask_draw_properties.render_target = layer; replica_mask_draw_properties.visible_content_rect = gfx::Rect(layer->content_bounds()); } + // Ignore occlusion from outside the surface when surface contents need to + // be fully drawn. Layers with copy-request need to be complete. + // We could be smarter about layers with replica and exclude regions + // where both layer and the replica are occluded, but this seems like an + // overkill. The same is true for layers with filters that move pixels. // TODO(senorblanco): make this smarter for the SkImageFilter case (check // for pixel-moving filters) - if (layer->filters().HasFilterThatMovesPixels() || layer->filter()) - nearest_ancestor_surface_that_moves_pixels = render_surface; - - render_surface->SetNearestAncestorThatMovesPixels( - nearest_ancestor_surface_that_moves_pixels); + if (layer->HasCopyRequest() || + layer->has_replica() || + layer->filters().HasReferenceFilter() || + layer->filters().HasFilterThatMovesPixels()) { + nearest_occlusion_immune_ancestor_surface = render_surface; + } + render_surface->SetNearestOcclusionImmuneAncestor( + nearest_occlusion_immune_ancestor_surface); layer_or_ancestor_clips_descendants = false; bool subtree_is_clipped_by_surface_bounds = false; @@ -1663,21 +1825,6 @@ static void CalculateDrawPropertiesInternal( layer_draw_properties.render_target = layer->parent()->render_target(); } - // Mark whether a layer could be drawn directly to the back buffer, for - // example when it could use LCD text even though it's in a non-contents - // opaque layer. This means that it can't be drawn to an intermediate - // render target and also that no blending is applied to the layer as a whole - // (meaning that its contents don't have to be pre-composited into a bitmap or - // a render target). - // - // Ignoring animations is an optimization, - // as it means that we're going to need some retained resources for this - // layer in the near future even if its opacity is 1 now. - layer_draw_properties.can_draw_directly_to_backbuffer = - IsRootLayer(layer_draw_properties.render_target) && - layer->draw_properties().opacity == 1.f && - !animating_opacity_to_screen; - if (adjust_text_aa) layer_draw_properties.can_use_lcd_text = layer_can_use_lcd_text; @@ -1710,7 +1857,7 @@ static void CalculateDrawPropertiesInternal( layer_draw_properties.clip_rect = rect_in_target_space; } - LayerListType& descendants = + typename LayerType::RenderSurfaceListType& descendants = (layer->render_surface() ? layer->render_surface()->layer_list() : *layer_list); @@ -1721,6 +1868,12 @@ static void CalculateDrawPropertiesInternal( if (!LayerShouldBeSkipped(layer, layer_is_visible)) descendants.push_back(layer); + // Any layers that are appended after this point may need to be sorted if we + // visit the children out of order. + size_t render_surface_layer_list_child_sorting_start_index = + render_surface_layer_list->size(); + size_t layer_list_child_sorting_start_index = descendants.size(); + if (!layer->children().empty()) { if (layer == globals.page_scale_application_layer) { data_for_children.parent_matrix.Scale( @@ -1760,29 +1913,64 @@ static void CalculateDrawPropertiesInternal( clip_rect_of_target_surface_in_target_space; data_for_children.ancestor_clips_subtree = layer_or_ancestor_clips_descendants; - data_for_children.nearest_ancestor_surface_that_moves_pixels = - nearest_ancestor_surface_that_moves_pixels; + data_for_children.nearest_occlusion_immune_ancestor_surface = + nearest_occlusion_immune_ancestor_surface; data_for_children.subtree_is_visible_from_ancestor = layer_is_visible; } + std::vector<LayerType*> sorted_children; + bool child_order_changed = false; + if (layer_draw_properties.has_child_with_a_scroll_parent) + child_order_changed = SortChildrenForRecursion(&sorted_children, *layer); + for (size_t i = 0; i < layer->children().size(); ++i) { + // If one of layer's children has a scroll parent, then we may have to + // visit the children out of order. The new order is stored in + // sorted_children. Otherwise, we'll grab the child directly from the + // layer's list of children. LayerType* child = - LayerTreeHostCommon::get_child_as_raw_ptr(layer->children(), i); - gfx::Rect drawable_content_rect_of_child_subtree; - gfx::Transform identity_matrix; - CalculateDrawPropertiesInternal<LayerType, - LayerListType, - RenderSurfaceType>( - child, - globals, - data_for_children, - render_surface_layer_list, - &descendants, - accumulated_surface_state); + layer_draw_properties.has_child_with_a_scroll_parent + ? sorted_children[i] + : LayerTreeHostCommon::get_child_as_raw_ptr(layer->children(), i); + + child->draw_properties().index_of_first_descendants_addition = + descendants.size(); + child->draw_properties().index_of_first_render_surface_layer_list_addition = + render_surface_layer_list->size(); + + CalculateDrawPropertiesInternal<LayerType>(child, + globals, + data_for_children, + render_surface_layer_list, + &descendants, + accumulated_surface_state); if (child->render_surface() && !child->render_surface()->content_rect().IsEmpty()) { descendants.push_back(child); } + + child->draw_properties().num_descendants_added = + descendants.size() - + child->draw_properties().index_of_first_descendants_addition; + child->draw_properties().num_render_surfaces_added = + render_surface_layer_list->size() - + child->draw_properties() + .index_of_first_render_surface_layer_list_addition; + } + + // Add the unsorted layer list contributions, if necessary. + if (child_order_changed) { + SortLayerListContributions( + *layer, + render_surface_layer_list, + render_surface_layer_list_child_sorting_start_index, + &GetNewRenderSurfacesStartIndexAndCount<LayerType>); + + SortLayerListContributions( + *layer, + &descendants, + layer_list_child_sorting_start_index, + &GetNewDescendantsStartIndexAndCount<LayerType>); } // Compute the total drawable_content_rect for this subtree (the rect is in @@ -1800,19 +1988,16 @@ static void CalculateDrawPropertiesInternal( return; } - if (layer->DrawsContent()) { - gfx::Rect local_drawable_content_rect = rect_in_target_space; - if (layer_or_ancestor_clips_descendants) - local_drawable_content_rect.Intersect(clip_rect_in_target_space); - local_drawable_content_rect_of_subtree.Union(local_drawable_content_rect); - } - // Compute the layer's drawable content rect (the rect is in target surface // space). layer_draw_properties.drawable_content_rect = rect_in_target_space; if (layer_or_ancestor_clips_descendants) { - layer_draw_properties.drawable_content_rect. - Intersect(clip_rect_in_target_space); + layer_draw_properties.drawable_content_rect.Intersect( + clip_rect_in_target_space); + } + if (layer->DrawsContent()) { + local_drawable_content_rect_of_subtree.Union( + layer_draw_properties.drawable_content_rect); } // Compute the layer's visible content rect (the rect is in content space). @@ -1826,8 +2011,9 @@ static void CalculateDrawPropertiesInternal( DCHECK(layer->render_surface()); layer->render_surface()->SetContentRect( ancestor_clip_rect_in_target_space); - } else if (layer->render_surface() && !IsRootLayer(layer)) { - RenderSurfaceType* render_surface = layer->render_surface(); + } else if (layer->render_surface()) { + typename LayerType::RenderSurfaceType* render_surface = + layer->render_surface(); gfx::Rect clipped_content_rect = local_drawable_content_rect_of_subtree; // Don't clip if the layer is reflected as the reflection shouldn't be @@ -1859,6 +2045,16 @@ static void CalculateDrawPropertiesInternal( return; } + // Layers having a non-default blend mode will blend with the content + // inside its parent's render target. This render target should be + // either root_for_isolated_group, or the root of the layer tree. + // Otherwise, this layer will use an incomplete backdrop, limited to its + // render target and the blending result will be incorrect. + DCHECK(layer->uses_default_blend_mode() || IsRootLayer(layer) || + !layer->parent()->render_target() || + IsRootLayer(layer->parent()->render_target()) || + layer->parent()->render_target()->is_root_for_isolated_group()); + render_surface->SetContentRect(clipped_content_rect); // The owning layer's screen_space_transform has a scale from content to @@ -1905,7 +2101,6 @@ static void CalculateDrawPropertiesInternal( } } - UpdateTilePrioritiesForLayer(layer); SavePaintPropertiesLayer(layer); // If neither this layer nor any of its children were added, early out. @@ -1925,7 +2120,7 @@ static void CalculateDrawPropertiesInternal( globals.layer_sorter); } - UpdateAccumulatedSurfaceState<LayerType, RenderSurfaceType>( + UpdateAccumulatedSurfaceState<LayerType>( layer, local_drawable_content_rect_of_subtree, accumulated_surface_state); if (layer->HasContributingDelegatedRenderPasses()) { @@ -1955,9 +2150,11 @@ void LayerTreeHostCommon::CalculateDrawProperties( globals.device_scale_factor = inputs->device_scale_factor; globals.page_scale_factor = inputs->page_scale_factor; globals.page_scale_application_layer = inputs->page_scale_application_layer; + globals.can_render_to_separate_surface = + inputs->can_render_to_separate_surface; globals.can_adjust_raster_scales = inputs->can_adjust_raster_scales; - DataForRecursion<Layer, RenderSurface> data_for_recursion; + DataForRecursion<Layer> data_for_recursion; data_for_recursion.parent_matrix = scaled_device_transform; data_for_recursion.full_hierarchy_matrix = identity_matrix; data_for_recursion.scroll_compensation_matrix = identity_matrix; @@ -1966,7 +2163,7 @@ void LayerTreeHostCommon::CalculateDrawProperties( data_for_recursion.clip_rect_of_target_surface_in_target_space = device_viewport_rect; data_for_recursion.ancestor_clips_subtree = true; - data_for_recursion.nearest_ancestor_surface_that_moves_pixels = NULL; + data_for_recursion.nearest_occlusion_immune_ancestor_surface = NULL; data_for_recursion.in_subtree_of_page_scale_application_layer = false; data_for_recursion.subtree_can_use_lcd_text = inputs->can_use_lcd_text; data_for_recursion.subtree_is_visible_from_ancestor = true; @@ -1974,13 +2171,12 @@ void LayerTreeHostCommon::CalculateDrawProperties( PreCalculateMetaInformationRecursiveData recursive_data; PreCalculateMetaInformation(inputs->root_layer, &recursive_data); std::vector<AccumulatedSurfaceState<Layer> > accumulated_surface_state; - CalculateDrawPropertiesInternal<Layer, RenderSurfaceLayerList, RenderSurface>( - inputs->root_layer, - globals, - data_for_recursion, - inputs->render_surface_layer_list, - &dummy_layer_list, - &accumulated_surface_state); + CalculateDrawPropertiesInternal<Layer>(inputs->root_layer, + globals, + data_for_recursion, + inputs->render_surface_layer_list, + &dummy_layer_list, + &accumulated_surface_state); // The dummy layer list should not have been used. DCHECK_EQ(0u, dummy_layer_list.size()); @@ -2012,9 +2208,11 @@ void LayerTreeHostCommon::CalculateDrawProperties( globals.device_scale_factor = inputs->device_scale_factor; globals.page_scale_factor = inputs->page_scale_factor; globals.page_scale_application_layer = inputs->page_scale_application_layer; + globals.can_render_to_separate_surface = + inputs->can_render_to_separate_surface; globals.can_adjust_raster_scales = inputs->can_adjust_raster_scales; - DataForRecursion<LayerImpl, RenderSurfaceImpl> data_for_recursion; + DataForRecursion<LayerImpl> data_for_recursion; data_for_recursion.parent_matrix = scaled_device_transform; data_for_recursion.full_hierarchy_matrix = identity_matrix; data_for_recursion.scroll_compensation_matrix = identity_matrix; @@ -2023,7 +2221,7 @@ void LayerTreeHostCommon::CalculateDrawProperties( data_for_recursion.clip_rect_of_target_surface_in_target_space = device_viewport_rect; data_for_recursion.ancestor_clips_subtree = true; - data_for_recursion.nearest_ancestor_surface_that_moves_pixels = NULL; + data_for_recursion.nearest_occlusion_immune_ancestor_surface = NULL; data_for_recursion.in_subtree_of_page_scale_application_layer = false; data_for_recursion.subtree_can_use_lcd_text = inputs->can_use_lcd_text; data_for_recursion.subtree_is_visible_from_ancestor = true; @@ -2032,13 +2230,12 @@ void LayerTreeHostCommon::CalculateDrawProperties( PreCalculateMetaInformation(inputs->root_layer, &recursive_data); std::vector<AccumulatedSurfaceState<LayerImpl> > accumulated_surface_state; - CalculateDrawPropertiesInternal<LayerImpl, LayerImplList, RenderSurfaceImpl>( - inputs->root_layer, - globals, - data_for_recursion, - inputs->render_surface_layer_list, - &dummy_layer_list, - &accumulated_surface_state); + CalculateDrawPropertiesInternal<LayerImpl>(inputs->root_layer, + globals, + data_for_recursion, + inputs->render_surface_layer_list, + &dummy_layer_list, + &accumulated_surface_state); // The dummy layer list should not have been used. DCHECK_EQ(0u, dummy_layer_list.size()); @@ -2186,34 +2383,21 @@ LayerImpl* LayerTreeHostCommon::FindLayerThatIsHitByPoint( LayerImpl* LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion( gfx::PointF screen_space_point, const LayerImplList& render_surface_layer_list) { - LayerImpl* found_layer = NULL; - - typedef LayerIterator<LayerImpl, - LayerImplList, - RenderSurfaceImpl, - LayerIteratorActions::FrontToBack> LayerIteratorType; - LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list); - - for (LayerIteratorType - it = LayerIteratorType::Begin(&render_surface_layer_list); - it != end; - ++it) { - // We don't want to consider render_surfaces for hit testing. - if (!it.represents_itself()) - continue; - - LayerImpl* current_layer = (*it); - - if (!LayerHasTouchEventHandlersAt(screen_space_point, current_layer)) - continue; - - found_layer = current_layer; - break; + // First find out which layer was hit from the saved list of visible layers + // in the most recent frame. + LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint( + screen_space_point, + render_surface_layer_list); + + // Walk up the hierarchy and look for a layer with a touch event handler + // region that the given point hits. + // This walk may not be necessary anymore: http://crbug.com/310817 + for (; layer_impl; layer_impl = layer_impl->parent()) { + if (LayerTreeHostCommon::LayerHasTouchEventHandlersAt(screen_space_point, + layer_impl)) + break; } - - // This can potentially return NULL, which means the screen_space_point did - // not successfully hit test any layers, not even the root layer. - return found_layer; + return layer_impl; } bool LayerTreeHostCommon::LayerHasTouchEventHandlersAt( diff --git a/chromium/cc/trees/layer_tree_host_common.h b/chromium/cc/trees/layer_tree_host_common.h index 05affee8f31..727244864ee 100644 --- a/chromium/cc/trees/layer_tree_host_common.h +++ b/chromium/cc/trees/layer_tree_host_common.h @@ -36,9 +36,10 @@ class CC_EXPORT LayerTreeHostCommon { const gfx::Transform& device_transform, float device_scale_factor, float page_scale_factor, - LayerType* page_scale_application_layer, + const LayerType* page_scale_application_layer, int max_texture_size, bool can_use_lcd_text, + bool can_render_to_separate_surface, bool can_adjust_raster_scales, RenderSurfaceLayerListType* render_surface_layer_list) : root_layer(root_layer), @@ -49,6 +50,7 @@ class CC_EXPORT LayerTreeHostCommon { page_scale_application_layer(page_scale_application_layer), max_texture_size(max_texture_size), can_use_lcd_text(can_use_lcd_text), + can_render_to_separate_surface(can_render_to_separate_surface), can_adjust_raster_scales(can_adjust_raster_scales), render_surface_layer_list(render_surface_layer_list) {} @@ -57,9 +59,10 @@ class CC_EXPORT LayerTreeHostCommon { const gfx::Transform& device_transform; float device_scale_factor; float page_scale_factor; - LayerType* page_scale_application_layer; + const LayerType* page_scale_application_layer; int max_texture_size; bool can_use_lcd_text; + bool can_render_to_separate_surface; bool can_adjust_raster_scales; RenderSurfaceLayerListType* render_surface_layer_list; }; @@ -220,6 +223,7 @@ LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType, NULL, std::numeric_limits<int>::max() / 2, false, + true, false, render_surface_layer_list) { DCHECK(root_layer); @@ -242,6 +246,7 @@ LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType, NULL, std::numeric_limits<int>::max() / 2, false, + true, false, render_surface_layer_list) { DCHECK(root_layer); diff --git a/chromium/cc/trees/layer_tree_host_common_perftest.cc b/chromium/cc/trees/layer_tree_host_common_perftest.cc new file mode 100644 index 00000000000..7b63b2a0c51 --- /dev/null +++ b/chromium/cc/trees/layer_tree_host_common_perftest.cc @@ -0,0 +1,198 @@ +// Copyright 2013 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 "cc/trees/layer_tree_host_common.h" + +#include <sstream> + +#include "base/file_util.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "base/strings/string_piece.h" +#include "base/threading/thread.h" +#include "base/time/time.h" +#include "cc/layers/layer.h" +#include "cc/test/fake_content_layer_client.h" +#include "cc/test/fake_layer_tree_host_client.h" +#include "cc/test/lap_timer.h" +#include "cc/test/layer_tree_json_parser.h" +#include "cc/test/layer_tree_test.h" +#include "cc/test/paths.h" +#include "cc/trees/layer_tree_impl.h" +#include "testing/perf/perf_test.h" + +namespace cc { +namespace { + +static const int kTimeLimitMillis = 2000; +static const int kWarmupRuns = 5; +static const int kTimeCheckInterval = 10; + +class LayerTreeHostCommonPerfTest : public LayerTreeTest { + public: + LayerTreeHostCommonPerfTest() + : timer_(kWarmupRuns, + base::TimeDelta::FromMilliseconds(kTimeLimitMillis), + kTimeCheckInterval) {} + + void ReadTestFile(const std::string& name) { + base::FilePath test_data_dir; + ASSERT_TRUE(PathService::Get(CCPaths::DIR_TEST_DATA, &test_data_dir)); + base::FilePath json_file = test_data_dir.AppendASCII(name + ".json"); + ASSERT_TRUE(base::ReadFileToString(json_file, &json_)); + } + + virtual void SetupTree() OVERRIDE { + gfx::Size viewport = gfx::Size(720, 1038); + layer_tree_host()->SetViewportSize(viewport); + scoped_refptr<Layer> root = + ParseTreeFromJson(json_, &content_layer_client_); + ASSERT_TRUE(root.get()); + layer_tree_host()->SetRootLayer(root); + } + + void SetTestName(const std::string& name) { test_name_ = name; } + + virtual void AfterTest() OVERRIDE { + CHECK(!test_name_.empty()) << "Must SetTestName() before TearDown()."; + perf_test::PrintResult("calc_draw_props_time", + "", + test_name_, + 1000 * timer_.MsPerLap(), + "us", + true); + } + + protected: + FakeContentLayerClient content_layer_client_; + LapTimer timer_; + std::string test_name_; + std::string json_; +}; + +class CalcDrawPropsMainTest : public LayerTreeHostCommonPerfTest { + public: + void RunCalcDrawProps() { + RunTest(false, false, false); + } + + virtual void BeginTest() OVERRIDE { + timer_.Reset(); + + do { + bool can_render_to_separate_surface = true; + int max_texture_size = 8096; + RenderSurfaceLayerList update_list; + LayerTreeHostCommon::CalcDrawPropsMainInputs inputs( + layer_tree_host()->root_layer(), + layer_tree_host()->device_viewport_size(), + gfx::Transform(), + layer_tree_host()->device_scale_factor(), + layer_tree_host()->page_scale_factor(), + layer_tree_host()->page_scale_layer(), + max_texture_size, + layer_tree_host()->settings().can_use_lcd_text, + can_render_to_separate_surface, + layer_tree_host() + ->settings() + .layer_transforms_should_scale_layer_contents, + &update_list); + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + timer_.NextLap(); + } while (!timer_.HasTimeLimitExpired()); + + EndTest(); + } +}; + +class CalcDrawPropsImplTest : public LayerTreeHostCommonPerfTest { + public: + void RunCalcDrawProps() { + RunTestWithImplSidePainting(); + } + + virtual void BeginTest() OVERRIDE { + PostSetNeedsCommitToMainThread(); + } + + virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + timer_.Reset(); + LayerTreeImpl* active_tree = host_impl->active_tree(); + + do { + bool can_render_to_separate_surface = true; + int max_texture_size = 8096; + LayerImplList update_list; + LayerTreeHostCommon::CalcDrawPropsImplInputs inputs( + active_tree->root_layer(), + active_tree->DrawViewportSize(), + host_impl->DrawTransform(), + active_tree->device_scale_factor(), + active_tree->total_page_scale_factor(), + active_tree->RootContainerLayer(), + max_texture_size, + host_impl->settings().can_use_lcd_text, + can_render_to_separate_surface, + host_impl->settings().layer_transforms_should_scale_layer_contents, + &update_list); + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + timer_.NextLap(); + } while (!timer_.HasTimeLimitExpired()); + + EndTest(); + } +}; + +TEST_F(CalcDrawPropsMainTest, TenTen) { + SetTestName("10_10"); + ReadTestFile("10_10_layer_tree"); + RunCalcDrawProps(); +} + +TEST_F(CalcDrawPropsMainTest, HeavyPage) { + SetTestName("heavy_page"); + ReadTestFile("heavy_layer_tree"); + RunCalcDrawProps(); +} + +TEST_F(CalcDrawPropsMainTest, TouchRegionLight) { + SetTestName("touch_region_light"); + ReadTestFile("touch_region_light"); + RunCalcDrawProps(); +} + +TEST_F(CalcDrawPropsMainTest, TouchRegionHeavy) { + SetTestName("touch_region_heavy"); + ReadTestFile("touch_region_heavy"); + RunCalcDrawProps(); +} + +TEST_F(CalcDrawPropsImplTest, TenTen) { + SetTestName("10_10"); + ReadTestFile("10_10_layer_tree"); + RunCalcDrawProps(); +} + +TEST_F(CalcDrawPropsImplTest, HeavyPage) { + SetTestName("heavy_page"); + ReadTestFile("heavy_layer_tree"); + RunCalcDrawProps(); +} + +TEST_F(CalcDrawPropsImplTest, TouchRegionLight) { + SetTestName("touch_region_light"); + ReadTestFile("touch_region_light"); + RunCalcDrawProps(); +} + +TEST_F(CalcDrawPropsImplTest, TouchRegionHeavy) { + SetTestName("touch_region_heavy"); + ReadTestFile("touch_region_heavy"); + RunCalcDrawProps(); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc index a5546192365..58d82ceda4a 100644 --- a/chromium/cc/trees/layer_tree_host_common_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_common_unittest.cc @@ -4,12 +4,15 @@ #include "cc/trees/layer_tree_host_common.h" +#include <set> + #include "cc/animation/layer_animation_controller.h" #include "cc/base/math_util.h" #include "cc/layers/content_layer.h" #include "cc/layers/content_layer_client.h" #include "cc/layers/heads_up_display_layer_impl.h" #include "cc/layers/layer.h" +#include "cc/layers/layer_client.h" #include "cc/layers/layer_impl.h" #include "cc/layers/render_surface.h" #include "cc/layers/render_surface_impl.h" @@ -186,23 +189,8 @@ class LayerWithForcedDrawsContent : public Layer { virtual ~LayerWithForcedDrawsContent() {} }; -class LayerCanClipSelf : public Layer { - public: - LayerCanClipSelf() : Layer() {} - - virtual bool DrawsContent() const OVERRIDE; - virtual bool CanClipSelf() const OVERRIDE; - - private: - virtual ~LayerCanClipSelf() {} -}; - bool LayerWithForcedDrawsContent::DrawsContent() const { return true; } -bool LayerCanClipSelf::DrawsContent() const { return true; } - -bool LayerCanClipSelf::CanClipSelf() const { return true; } - class MockContentLayerClient : public ContentLayerClient { public: MockContentLayerClient() {} @@ -343,7 +331,7 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) { // Case 4: A change in actual position affects both the draw transform and // screen space transform. gfx::Transform position_transform; - position_transform.Translate(0.0, 1.2); + position_transform.Translate(0.f, 1.2f); SetLayerPropertiesForTesting(layer.get(), identity_matrix, identity_matrix, @@ -551,7 +539,7 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSimpleHierarchy) { // Case 2: parent's position affects child and grand_child. gfx::Transform parent_position_transform; - parent_position_transform.Translate(0.0, 1.2); + parent_position_transform.Translate(0.f, 1.2f); SetLayerPropertiesForTesting(parent.get(), identity_matrix, identity_matrix, @@ -629,7 +617,7 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSimpleHierarchy) { // does not preserve3D. When it gives its hierarchy to the grand_child, it // should be flattened to 2D. gfx::Transform parent_sublayer_matrix; - parent_sublayer_matrix.Scale3d(10.0, 10.0, 3.3); + parent_sublayer_matrix.Scale3d(10.f, 10.f, 3.3f); // Sublayer matrix is applied to the anchor point of the parent layer. parent_composite_transform = parent_translation_to_anchor * parent_layer_transform * @@ -730,11 +718,11 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) { child->SetForceRenderSurface(true); gfx::Transform parent_layer_transform; - parent_layer_transform.Scale3d(1.0, 0.9, 1.0); + parent_layer_transform.Scale3d(1.f, 0.9f, 1.f); gfx::Transform parent_translation_to_anchor; parent_translation_to_anchor.Translate(25.0, 30.0); gfx::Transform parent_sublayer_matrix; - parent_sublayer_matrix.Scale3d(0.9, 1.0, 3.3); + parent_sublayer_matrix.Scale3d(0.9f, 1.f, 3.3f); gfx::Transform parent_composite_transform = parent_translation_to_anchor * parent_layer_transform * @@ -850,147 +838,6 @@ TEST_F(LayerTreeHostCommonTest, SublayerTransformWithAnchorPoint) { child->draw_transform()); } -TEST_F(LayerTreeHostCommonTest, SeparateRenderTargetRequirementWithClipping) { - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> parent = Layer::Create(); - scoped_refptr<Layer> child = Layer::Create(); - scoped_refptr<Layer> grand_child = make_scoped_refptr(new LayerCanClipSelf()); - root->AddChild(parent); - parent->AddChild(child); - child->AddChild(grand_child); - parent->SetMasksToBounds(true); - child->SetMasksToBounds(true); - - scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); - host->SetRootLayer(root); - - gfx::Transform identity_matrix; - gfx::Transform parent_layer_transform; - gfx::Transform parent_sublayer_matrix; - gfx::Transform child_layer_matrix; - - // No render surface should exist yet. - EXPECT_FALSE(root->render_surface()); - EXPECT_FALSE(parent->render_surface()); - EXPECT_FALSE(child->render_surface()); - EXPECT_FALSE(grand_child->render_surface()); - - // One-time setup of root layer - parent_layer_transform.Scale3d(1.0, 0.9, 1.0); - parent_sublayer_matrix.Scale3d(0.9, 1.0, 3.3); - child_layer_matrix.Rotate(20.0); - - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - identity_matrix, - gfx::PointF(), - gfx::PointF(), - gfx::Size(1, 2), - false); - SetLayerPropertiesForTesting(parent.get(), - parent_layer_transform, - parent_sublayer_matrix, - gfx::PointF(0.25f, 0.25f), - gfx::PointF(), - gfx::Size(100, 120), - false); - SetLayerPropertiesForTesting(child.get(), - child_layer_matrix, - identity_matrix, - gfx::PointF(), - gfx::PointF(), - gfx::Size(16, 18), - false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - identity_matrix, - gfx::PointF(), - gfx::PointF(), - gfx::Size(8, 10), - false); - - ExecuteCalculateDrawProperties(root.get()); - - // Render surfaces should have been created according to clipping rules now - // (grandchild can clip self). - EXPECT_TRUE(root->render_surface()); - EXPECT_FALSE(parent->render_surface()); - EXPECT_FALSE(child->render_surface()); - EXPECT_FALSE(grand_child->render_surface()); -} - -TEST_F(LayerTreeHostCommonTest, - SeparateRenderTargetRequirementWithoutClipping) { - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> parent = Layer::Create(); - scoped_refptr<Layer> child = Layer::Create(); - // This layer cannot clip itself, a feature we are testing here. - scoped_refptr<Layer> grand_child = - make_scoped_refptr(new LayerWithForcedDrawsContent()); - root->AddChild(parent); - parent->AddChild(child); - child->AddChild(grand_child); - parent->SetMasksToBounds(true); - child->SetMasksToBounds(true); - - scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); - host->SetRootLayer(root); - - gfx::Transform identity_matrix; - gfx::Transform parent_layer_transform; - gfx::Transform parent_sublayer_matrix; - gfx::Transform child_layer_matrix; - - // No render surface should exist yet. - EXPECT_FALSE(root->render_surface()); - EXPECT_FALSE(parent->render_surface()); - EXPECT_FALSE(child->render_surface()); - EXPECT_FALSE(grand_child->render_surface()); - - // One-time setup of root layer - parent_layer_transform.Scale3d(1.0, 0.9, 1.0); - parent_sublayer_matrix.Scale3d(0.9, 1.0, 3.3); - child_layer_matrix.Rotate(20.0); - - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - identity_matrix, - gfx::PointF(), - gfx::PointF(), - gfx::Size(1, 2), - false); - SetLayerPropertiesForTesting(parent.get(), - parent_layer_transform, - parent_sublayer_matrix, - gfx::PointF(0.25f, 0.25f), - gfx::PointF(), - gfx::Size(100, 120), - false); - SetLayerPropertiesForTesting(child.get(), - child_layer_matrix, - identity_matrix, - gfx::PointF(), - gfx::PointF(), - gfx::Size(16, 18), - false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - identity_matrix, - gfx::PointF(), - gfx::PointF(), - gfx::Size(8, 10), - false); - - ExecuteCalculateDrawProperties(root.get()); - - // Render surfaces should have been created according to clipping rules now - // (grandchild can't clip self). - EXPECT_TRUE(root->render_surface()); - EXPECT_FALSE(parent->render_surface()); - EXPECT_TRUE(child->render_surface()); - EXPECT_FALSE(grand_child->render_surface()); -} - TEST_F(LayerTreeHostCommonTest, TransformsForReplica) { scoped_refptr<Layer> root = Layer::Create(); scoped_refptr<Layer> parent = Layer::Create(); @@ -1024,7 +871,7 @@ TEST_F(LayerTreeHostCommonTest, TransformsForReplica) { gfx::Transform parent_translation_to_anchor; parent_translation_to_anchor.Translate(2.5, 3.0); gfx::Transform parent_sublayer_matrix; - parent_sublayer_matrix.Scale3d(10.0, 10.0, 3.3); + parent_sublayer_matrix.Scale3d(10.f, 10.f, 3.3f); gfx::Transform parent_composite_transform = parent_translation_to_anchor * parent_layer_transform * Inverse(parent_translation_to_anchor) * parent_translation_to_anchor * @@ -5454,6 +5301,121 @@ TEST_F(LayerTreeHostCommonTest, HitTestingForMultipleLayerLists) { EXPECT_EQ(4, result_layer->id()); } +TEST_F(LayerTreeHostCommonTest, HitTestingForEmptyLayers) { + FakeImplProxy proxy; + FakeLayerTreeHostImpl host_impl(&proxy); + + // Layer 1 - root + scoped_ptr<LayerImpl> root = + LayerImpl::Create(host_impl.active_tree(), 1); + gfx::Transform identity_matrix; + gfx::PointF anchor; + gfx::PointF position; + gfx::Size bounds(100, 100); + SetLayerPropertiesForTesting(root.get(), + identity_matrix, + identity_matrix, + anchor, + position, + bounds, + false); + root->SetDrawsContent(true); + + { + // Layer 2 - empty: drawsContent=false + gfx::PointF position(10.f, 10.f); + gfx::Size bounds(30, 30); + scoped_ptr<LayerImpl> empty_layer = + LayerImpl::Create(host_impl.active_tree(), 2); + SetLayerPropertiesForTesting(empty_layer.get(), + identity_matrix, + identity_matrix, + anchor, + position, + bounds, + false); + + empty_layer->SetDrawsContent(false); + root->AddChild(empty_layer.Pass()); + } + + { + // Layer 3 - empty, but has touch handler + gfx::PointF position(10.f, 60.f); + gfx::Size bounds(30, 30); + scoped_ptr<LayerImpl> test_layer = + LayerImpl::Create(host_impl.active_tree(), 3); + SetLayerPropertiesForTesting(test_layer.get(), + identity_matrix, + identity_matrix, + anchor, + position, + bounds, + false); + + test_layer->SetDrawsContent(false); + Region touch_handler_region(gfx::Rect(10, 10, 10, 10)); + test_layer->SetTouchEventHandlerRegion(touch_handler_region); + root->AddChild(test_layer.Pass()); + } + + { + // Layer 4 - empty, but has mousewheel handler + gfx::PointF position(60.f, 60.f); + gfx::Size bounds(30, 30); + scoped_ptr<LayerImpl> test_layer = + LayerImpl::Create(host_impl.active_tree(), 4); + SetLayerPropertiesForTesting(test_layer.get(), + identity_matrix, + identity_matrix, + anchor, + position, + bounds, + false); + + test_layer->SetDrawsContent(false); + test_layer->SetHaveWheelEventHandlers(true); + root->AddChild(test_layer.Pass()); + } + + LayerImplList render_surface_layer_list; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root.get(), root->bounds(), &render_surface_layer_list); + inputs.can_adjust_raster_scales = true; + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + // Verify that the root layer and empty layers with touch/wheel handlers + // (but not the empty layer without a touch handler) are in the RSSL. + ASSERT_EQ(1u, render_surface_layer_list.size()); + EXPECT_EQ(1, render_surface_layer_list[0]->id()); + ASSERT_EQ(3u, root->render_surface()->layer_list().size()); + EXPECT_EQ(1, root->render_surface()->layer_list().at(0)->id()); + EXPECT_EQ(3, root->render_surface()->layer_list().at(1)->id()); + EXPECT_EQ(4, root->render_surface()->layer_list().at(2)->id()); + + // Hit testing for a point inside the empty no-handlers layer should return + // the root layer. + gfx::Point test_point = gfx::Point(15, 15); + LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint( + test_point, render_surface_layer_list); + ASSERT_TRUE(result_layer); + EXPECT_EQ(1, result_layer->id()); + + // Hit testing for a point inside the touch handler layer should return it. + test_point = gfx::Point(15, 75); + result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint( + test_point, render_surface_layer_list); + ASSERT_TRUE(result_layer); + EXPECT_EQ(3, result_layer->id()); + + // Hit testing for a point inside the mousewheel layer should return it. + test_point = gfx::Point(75, 75); + result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint( + test_point, render_surface_layer_list); + ASSERT_TRUE(result_layer); + EXPECT_EQ(4, result_layer->id()); +} + TEST_F(LayerTreeHostCommonTest, HitCheckingTouchHandlerRegionsForEmptyLayerList) { // Hit checking on an empty render_surface_layer_list should return a null @@ -6063,6 +6025,90 @@ TEST_F(LayerTreeHostCommonTest, EXPECT_EQ(456, result_layer->id()); } +TEST_F(LayerTreeHostCommonTest, + HitCheckingTouchHandlerOverlappingRegions) { + gfx::Transform identity_matrix; + gfx::PointF anchor; + + FakeImplProxy proxy; + FakeLayerTreeHostImpl host_impl(&proxy); + scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1); + SetLayerPropertiesForTesting(root.get(), + identity_matrix, + identity_matrix, + anchor, + gfx::PointF(), + gfx::Size(100, 100), + false); + { + scoped_ptr<LayerImpl> touch_layer = + LayerImpl::Create(host_impl.active_tree(), 123); + // this layer is positioned, and hit testing should correctly know where the + // layer is located. + gfx::PointF position; + gfx::Size bounds(50, 50); + SetLayerPropertiesForTesting(touch_layer.get(), + identity_matrix, + identity_matrix, + anchor, + position, + bounds, + false); + touch_layer->SetDrawsContent(true); + touch_layer->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 50, 50)); + root->AddChild(touch_layer.Pass()); + } + + { + scoped_ptr<LayerImpl> notouch_layer = + LayerImpl::Create(host_impl.active_tree(), 1234); + // this layer is positioned, and hit testing should correctly know where the + // layer is located. + gfx::PointF position(0, 25); + gfx::Size bounds(50, 50); + SetLayerPropertiesForTesting(notouch_layer.get(), + identity_matrix, + identity_matrix, + anchor, + position, + bounds, + false); + notouch_layer->SetDrawsContent(true); + root->AddChild(notouch_layer.Pass()); + } + + LayerImplList render_surface_layer_list; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root.get(), root->bounds(), &render_surface_layer_list); + inputs.can_adjust_raster_scales = true; + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + // Sanity check the scenario we just created. + ASSERT_EQ(1u, render_surface_layer_list.size()); + ASSERT_EQ(2u, root->render_surface()->layer_list().size()); + ASSERT_EQ(123, root->render_surface()->layer_list().at(0)->id()); + ASSERT_EQ(1234, root->render_surface()->layer_list().at(1)->id()); + + gfx::Point test_point(35, 35); + LayerImpl* result_layer = + LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion( + test_point, render_surface_layer_list); + EXPECT_FALSE(result_layer); + + test_point = gfx::Point(35, 15); + result_layer = + LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion( + test_point, render_surface_layer_list); + ASSERT_TRUE(result_layer); + EXPECT_EQ(123, result_layer->id()); + + test_point = gfx::Point(35, 65); + result_layer = + LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion( + test_point, render_surface_layer_list); + EXPECT_FALSE(result_layer); +} + class NoScaleContentLayer : public ContentLayer { public: static scoped_refptr<NoScaleContentLayer> Create(ContentLayerClient* client) { @@ -6245,7 +6291,7 @@ TEST_F(LayerTreeHostCommonTest, SurfaceLayerTransformsInHighDPI) { perspective_matrix.ApplyPerspectiveDepth(2.0); gfx::Transform scale_small_matrix; - scale_small_matrix.Scale(1.0 / 10.0, 1.0 / 12.0); + scale_small_matrix.Scale(SK_MScalar1 / 10.f, SK_MScalar1 / 12.f); scoped_refptr<Layer> root = Layer::Create(); @@ -8883,6 +8929,84 @@ TEST_F(LayerTreeHostCommonTest, EXPECT_EQ(0, render_surface2->num_unclipped_descendants()); } +TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) { + FakeImplProxy proxy; + FakeLayerTreeHostImpl host_impl(&proxy); + scoped_ptr<LayerImpl> root = + LayerImpl::Create(host_impl.active_tree(), 12345); + scoped_ptr<LayerImpl> child1 = + LayerImpl::Create(host_impl.active_tree(), 123456); + scoped_ptr<LayerImpl> child2 = + LayerImpl::Create(host_impl.active_tree(), 1234567); + scoped_ptr<LayerImpl> child3 = + LayerImpl::Create(host_impl.active_tree(), 12345678); + + gfx::Transform identity_matrix; + gfx::PointF anchor; + gfx::PointF position; + gfx::Size bounds(100, 100); + SetLayerPropertiesForTesting(root.get(), + identity_matrix, + identity_matrix, + anchor, + position, + bounds, + false); + root->SetDrawsContent(true); + + // This layer structure normally forces render surface due to preserves3d + // behavior. + bool preserves3d = true; + SetLayerPropertiesForTesting(child1.get(), + identity_matrix, + identity_matrix, + anchor, + position, + bounds, + preserves3d); + child1->SetDrawsContent(true); + SetLayerPropertiesForTesting(child2.get(), + identity_matrix, + identity_matrix, + anchor, + position, + bounds, + false); + child2->SetDrawsContent(true); + SetLayerPropertiesForTesting(child3.get(), + identity_matrix, + identity_matrix, + anchor, + position, + bounds, + false); + child3->SetDrawsContent(true); + + child2->AddChild(child3.Pass()); + child1->AddChild(child2.Pass()); + root->AddChild(child1.Pass()); + + { + LayerImplList render_surface_layer_list; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root.get(), root->bounds(), &render_surface_layer_list); + inputs.can_render_to_separate_surface = true; + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + EXPECT_EQ(2u, render_surface_layer_list.size()); + } + + { + LayerImplList render_surface_layer_list; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root.get(), root->bounds(), &render_surface_layer_list); + inputs.can_render_to_separate_surface = false; + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + EXPECT_EQ(1u, render_surface_layer_list.size()); + } +} + TEST_F(LayerTreeHostCommonTest, DoNotIncludeBackfaceInvisibleSurfaces) { scoped_refptr<Layer> root = Layer::Create(); scoped_refptr<Layer> render_surface = Layer::Create(); @@ -8945,6 +9069,569 @@ TEST_F(LayerTreeHostCommonTest, DoNotIncludeBackfaceInvisibleSurfaces) { ->render_surface()->layer_list().size()); } +TEST_F(LayerTreeHostCommonTest, ClippedByScrollParent) { + // Checks that the simple case (being clipped by a scroll parent that would + // have been processed before you anyhow) results in the right clips. + // + // + root + // + scroll_parent_border + // | + scroll_parent_clip + // | + scroll_parent + // + scroll_child + // + scoped_refptr<Layer> root = Layer::Create(); + scoped_refptr<Layer> scroll_parent_border = Layer::Create(); + scoped_refptr<Layer> scroll_parent_clip = Layer::Create(); + scoped_refptr<LayerWithForcedDrawsContent> scroll_parent = + make_scoped_refptr(new LayerWithForcedDrawsContent); + scoped_refptr<LayerWithForcedDrawsContent> scroll_child = + make_scoped_refptr(new LayerWithForcedDrawsContent); + + root->AddChild(scroll_child); + + root->AddChild(scroll_parent_border); + scroll_parent_border->AddChild(scroll_parent_clip); + scroll_parent_clip->AddChild(scroll_parent); + + scroll_parent_clip->SetMasksToBounds(true); + + scroll_child->SetScrollParent(scroll_parent.get()); + + gfx::Transform identity_transform; + SetLayerPropertiesForTesting(root.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_parent_border.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(40, 40), + false); + SetLayerPropertiesForTesting(scroll_parent_clip.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(30, 30), + false); + SetLayerPropertiesForTesting(scroll_parent.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_child.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + + scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); + host->SetRootLayer(root); + + ExecuteCalculateDrawProperties(root.get()); + + EXPECT_TRUE(root->render_surface()); + + EXPECT_EQ(gfx::Rect(0, 0, 30, 30).ToString(), + scroll_child->clip_rect().ToString()); + EXPECT_TRUE(scroll_child->is_clipped()); +} + +TEST_F(LayerTreeHostCommonTest, ClippedByOutOfOrderScrollParent) { + // Checks that clipping by a scroll parent that follows you in paint order + // still results in correct clipping. + // + // + root + // + scroll_child + // + scroll_parent_border + // + scroll_parent_clip + // + scroll_parent + // + scoped_refptr<Layer> root = Layer::Create(); + scoped_refptr<Layer> scroll_parent_border = Layer::Create(); + scoped_refptr<Layer> scroll_parent_clip = Layer::Create(); + scoped_refptr<LayerWithForcedDrawsContent> scroll_parent = + make_scoped_refptr(new LayerWithForcedDrawsContent); + scoped_refptr<LayerWithForcedDrawsContent> scroll_child = + make_scoped_refptr(new LayerWithForcedDrawsContent); + + root->AddChild(scroll_parent_border); + scroll_parent_border->AddChild(scroll_parent_clip); + scroll_parent_clip->AddChild(scroll_parent); + + root->AddChild(scroll_child); + + scroll_parent_clip->SetMasksToBounds(true); + + scroll_child->SetScrollParent(scroll_parent.get()); + + gfx::Transform identity_transform; + SetLayerPropertiesForTesting(root.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_parent_border.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(40, 40), + false); + SetLayerPropertiesForTesting(scroll_parent_clip.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(30, 30), + false); + SetLayerPropertiesForTesting(scroll_parent.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_child.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + + scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); + host->SetRootLayer(root); + + ExecuteCalculateDrawProperties(root.get()); + + EXPECT_TRUE(root->render_surface()); + + EXPECT_EQ(gfx::Rect(0, 0, 30, 30).ToString(), + scroll_child->clip_rect().ToString()); + EXPECT_TRUE(scroll_child->is_clipped()); +} + +TEST_F(LayerTreeHostCommonTest, ClippedByOutOfOrderScrollGrandparent) { + // Checks that clipping by a scroll parent and scroll grandparent that follow + // you in paint order still results in correct clipping. + // + // + root + // + scroll_child + // + scroll_parent_border + // | + scroll_parent_clip + // | + scroll_parent + // + scroll_grandparent_border + // + scroll_grandparent_clip + // + scroll_grandparent + // + scoped_refptr<Layer> root = Layer::Create(); + scoped_refptr<Layer> scroll_parent_border = Layer::Create(); + scoped_refptr<Layer> scroll_parent_clip = Layer::Create(); + scoped_refptr<LayerWithForcedDrawsContent> scroll_parent = + make_scoped_refptr(new LayerWithForcedDrawsContent); + + scoped_refptr<Layer> scroll_grandparent_border = Layer::Create(); + scoped_refptr<Layer> scroll_grandparent_clip = Layer::Create(); + scoped_refptr<LayerWithForcedDrawsContent> scroll_grandparent = + make_scoped_refptr(new LayerWithForcedDrawsContent); + + scoped_refptr<LayerWithForcedDrawsContent> scroll_child = + make_scoped_refptr(new LayerWithForcedDrawsContent); + + root->AddChild(scroll_child); + + root->AddChild(scroll_parent_border); + scroll_parent_border->AddChild(scroll_parent_clip); + scroll_parent_clip->AddChild(scroll_parent); + + root->AddChild(scroll_grandparent_border); + scroll_grandparent_border->AddChild(scroll_grandparent_clip); + scroll_grandparent_clip->AddChild(scroll_grandparent); + + scroll_parent_clip->SetMasksToBounds(true); + scroll_grandparent_clip->SetMasksToBounds(true); + + scroll_child->SetScrollParent(scroll_parent.get()); + scroll_parent_border->SetScrollParent(scroll_grandparent.get()); + + gfx::Transform identity_transform; + SetLayerPropertiesForTesting(root.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_grandparent_border.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(40, 40), + false); + SetLayerPropertiesForTesting(scroll_grandparent_clip.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(20, 20), + false); + SetLayerPropertiesForTesting(scroll_grandparent.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_parent_border.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(40, 40), + false); + SetLayerPropertiesForTesting(scroll_parent_clip.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(30, 30), + false); + SetLayerPropertiesForTesting(scroll_parent.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_child.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + + scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); + host->SetRootLayer(root); + + ExecuteCalculateDrawProperties(root.get()); + + EXPECT_TRUE(root->render_surface()); + + EXPECT_EQ(gfx::Rect(0, 0, 20, 20).ToString(), + scroll_child->clip_rect().ToString()); + EXPECT_TRUE(scroll_child->is_clipped()); + + // Despite the fact that we visited the above layers out of order to get the + // correct clip, the layer lists should be unaffected. + EXPECT_EQ(3u, root->render_surface()->layer_list().size()); + EXPECT_EQ(scroll_child.get(), + root->render_surface()->layer_list().at(0)); + EXPECT_EQ(scroll_parent.get(), + root->render_surface()->layer_list().at(1)); + EXPECT_EQ(scroll_grandparent.get(), + root->render_surface()->layer_list().at(2)); +} + +TEST_F(LayerTreeHostCommonTest, OutOfOrderClippingRequiresRSLLSorting) { + // Ensures that even if we visit layers out of order, we still produce a + // correctly ordered render surface layer list. + // + root + // + scroll_child + // + scroll_parent_border + // + scroll_parent_clip + // + scroll_parent + // + render_surface1 + // + scroll_grandparent_border + // + scroll_grandparent_clip + // + scroll_grandparent + // + render_surface2 + // + scoped_refptr<LayerWithForcedDrawsContent> root = + make_scoped_refptr(new LayerWithForcedDrawsContent); + + scoped_refptr<Layer> scroll_parent_border = Layer::Create(); + scoped_refptr<Layer> scroll_parent_clip = Layer::Create(); + scoped_refptr<LayerWithForcedDrawsContent> scroll_parent = + make_scoped_refptr(new LayerWithForcedDrawsContent); + scoped_refptr<LayerWithForcedDrawsContent> render_surface1 = + make_scoped_refptr(new LayerWithForcedDrawsContent); + + scoped_refptr<Layer> scroll_grandparent_border = Layer::Create(); + scoped_refptr<Layer> scroll_grandparent_clip = Layer::Create(); + scoped_refptr<LayerWithForcedDrawsContent> scroll_grandparent = + make_scoped_refptr(new LayerWithForcedDrawsContent); + scoped_refptr<LayerWithForcedDrawsContent> render_surface2 = + make_scoped_refptr(new LayerWithForcedDrawsContent); + + scoped_refptr<LayerWithForcedDrawsContent> scroll_child = + make_scoped_refptr(new LayerWithForcedDrawsContent); + + root->AddChild(scroll_child); + + root->AddChild(scroll_parent_border); + scroll_parent_border->AddChild(scroll_parent_clip); + scroll_parent_clip->AddChild(scroll_parent); + scroll_parent->AddChild(render_surface2); + + root->AddChild(scroll_grandparent_border); + scroll_grandparent_border->AddChild(scroll_grandparent_clip); + scroll_grandparent_clip->AddChild(scroll_grandparent); + scroll_grandparent->AddChild(render_surface1); + + scroll_parent_clip->SetMasksToBounds(true); + scroll_grandparent_clip->SetMasksToBounds(true); + + scroll_child->SetScrollParent(scroll_parent.get()); + scroll_parent_border->SetScrollParent(scroll_grandparent.get()); + + render_surface1->SetForceRenderSurface(true); + render_surface2->SetForceRenderSurface(true); + + gfx::Transform identity_transform; + SetLayerPropertiesForTesting(root.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_grandparent_border.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(40, 40), + false); + SetLayerPropertiesForTesting(scroll_grandparent_clip.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(20, 20), + false); + SetLayerPropertiesForTesting(scroll_grandparent.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(render_surface1.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_parent_border.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(40, 40), + false); + SetLayerPropertiesForTesting(scroll_parent_clip.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(30, 30), + false); + SetLayerPropertiesForTesting(scroll_parent.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(render_surface2.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_child.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + + scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); + host->SetRootLayer(root); + + RenderSurfaceLayerList render_surface_layer_list; + LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( + root.get(), + root->bounds(), + identity_transform, + &render_surface_layer_list); + + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + EXPECT_TRUE(root->render_surface()); + + EXPECT_EQ(gfx::Rect(0, 0, 20, 20).ToString(), + scroll_child->clip_rect().ToString()); + EXPECT_TRUE(scroll_child->is_clipped()); + + // Despite the fact that we had to process the layers out of order to get the + // right clip, our render_surface_layer_list's order should be unaffected. + EXPECT_EQ(3u, render_surface_layer_list.size()); + EXPECT_EQ(root.get(), render_surface_layer_list.at(0)); + EXPECT_EQ(render_surface2.get(), render_surface_layer_list.at(1)); + EXPECT_EQ(render_surface1.get(), render_surface_layer_list.at(2)); + EXPECT_TRUE(render_surface_layer_list.at(0)->render_surface()); + EXPECT_TRUE(render_surface_layer_list.at(1)->render_surface()); + EXPECT_TRUE(render_surface_layer_list.at(2)->render_surface()); +} + +TEST_F(LayerTreeHostCommonTest, DoNotClobberSorting) { + // We rearrange layer list contributions if we have to visit children out of + // order, but it should be a 'stable' rearrangement. That is, the layer list + // additions for a single layer should not be reordered, though their position + // wrt to the contributions due to a sibling may vary. + // + // + root + // + scroll_child + // + top_content + // + bottom_content + // + scroll_parent_border + // + scroll_parent_clip + // + scroll_parent + // + FakeImplProxy proxy; + FakeLayerTreeHostImpl host_impl(&proxy); + host_impl.CreatePendingTree(); + scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1); + scoped_ptr<LayerImpl> scroll_parent_border = + LayerImpl::Create(host_impl.active_tree(), 2); + scoped_ptr<LayerImpl> scroll_parent_clip = + LayerImpl::Create(host_impl.active_tree(), 3); + scoped_ptr<LayerImpl> scroll_parent = + LayerImpl::Create(host_impl.active_tree(), 4); + scoped_ptr<LayerImpl> scroll_child = + LayerImpl::Create(host_impl.active_tree(), 5); + scoped_ptr<LayerImpl> bottom_content = + LayerImpl::Create(host_impl.active_tree(), 6); + scoped_ptr<LayerImpl> top_content = + LayerImpl::Create(host_impl.active_tree(), 7); + + scroll_parent_clip->SetMasksToBounds(true); + + scroll_child->SetScrollParent(scroll_parent.get()); + scoped_ptr<std::set<LayerImpl*> > scroll_children(new std::set<LayerImpl*>); + scroll_children->insert(scroll_child.get()); + scroll_parent->SetScrollChildren(scroll_children.release()); + + scroll_child->SetDrawsContent(true); + scroll_parent->SetDrawsContent(true); + top_content->SetDrawsContent(true); + bottom_content->SetDrawsContent(true); + + gfx::Transform identity_transform; + gfx::Transform top_transform; + top_transform.Translate3d(0.0, 0.0, 5.0); + gfx::Transform bottom_transform; + bottom_transform.Translate3d(0.0, 0.0, 3.0); + + SetLayerPropertiesForTesting(root.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_parent_border.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(40, 40), + false); + SetLayerPropertiesForTesting(scroll_parent_clip.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(30, 30), + false); + SetLayerPropertiesForTesting(scroll_parent.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(scroll_child.get(), + identity_transform, + identity_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(top_content.get(), + top_transform, + top_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + SetLayerPropertiesForTesting(bottom_content.get(), + bottom_transform, + bottom_transform, + gfx::PointF(), + gfx::PointF(), + gfx::Size(50, 50), + false); + + scroll_child->SetPreserves3d(true); + + scroll_child->AddChild(top_content.Pass()); + scroll_child->AddChild(bottom_content.Pass()); + root->AddChild(scroll_child.Pass()); + + scroll_parent_clip->AddChild(scroll_parent.Pass()); + scroll_parent_border->AddChild(scroll_parent_clip.Pass()); + root->AddChild(scroll_parent_border.Pass()); + + LayerImplList render_surface_layer_list; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root.get(), root->bounds(), &render_surface_layer_list); + + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + EXPECT_TRUE(root->render_surface()); + + // If we don't sort by depth and let the layers get added in the order they + // would normally be visited in, then layers 6 and 7 will be out of order. In + // other words, although we've had to shift 5, 6, and 7 to appear before 4 + // in the list (because of the scroll parent relationship), this should not + // have an effect on the the order of 5, 6, and 7 (which had been reordered + // due to layer sorting). + EXPECT_EQ(4u, root->render_surface()->layer_list().size()); + EXPECT_EQ(5, root->render_surface()->layer_list().at(0)->id()); + EXPECT_EQ(6, root->render_surface()->layer_list().at(1)->id()); + EXPECT_EQ(7, root->render_surface()->layer_list().at(2)->id()); + EXPECT_EQ(4, root->render_surface()->layer_list().at(3)->id()); +} + TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) { // This test verifies that a scrolling layer that gets snapped to // integer coordinates doesn't move a fixed position child. diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc index a854dff2894..e4d1b735765 100644 --- a/chromium/cc/trees/layer_tree_host_impl.cc +++ b/chromium/cc/trees/layer_tree_host_impl.cc @@ -15,9 +15,12 @@ #include "base/strings/stringprintf.h" #include "cc/animation/scrollbar_animation_controller.h" #include "cc/animation/timing_function.h" +#include "cc/base/latency_info_swap_promise_monitor.h" #include "cc/base/math_util.h" #include "cc/base/util.h" +#include "cc/debug/benchmark_instrumentation.h" #include "cc/debug/debug_rect_history.h" +#include "cc/debug/devtools_instrumentation.h" #include "cc/debug/frame_rate_counter.h" #include "cc/debug/overdraw_metrics.h" #include "cc/debug/paint_time_counter.h" @@ -31,6 +34,7 @@ #include "cc/layers/layer_iterator.h" #include "cc/layers/painted_scrollbar_layer_impl.h" #include "cc/layers/render_surface_impl.h" +#include "cc/layers/scrollbar_layer_impl_base.h" #include "cc/output/compositor_frame_metadata.h" #include "cc/output/copy_output_request.h" #include "cc/output/delegating_renderer.h" @@ -54,6 +58,8 @@ #include "cc/trees/quad_culler.h" #include "cc/trees/single_thread_proxy.h" #include "cc/trees/tree_synchronizer.h" +#include "gpu/GLES2/gl2extchromium.h" +#include "ui/gfx/frame_time.h" #include "ui/gfx/size_conversions.h" #include "ui/gfx/vector2d_conversions.h" @@ -73,24 +79,47 @@ void DidVisibilityChange(cc::LayerTreeHostImpl* id, bool visible) { } size_t GetMaxTransferBufferUsageBytes(cc::ContextProvider* context_provider) { - if (context_provider) { - // We want to make sure the default transfer buffer size is equal to the - // amount of data that can be uploaded by the compositor to avoid stalling - // the pipeline. - // For reference Chromebook Pixel can upload 1MB in about 0.5ms. - const size_t kMaxBytesUploadedPerMs = 1024 * 1024 * 2; - // Assuming a two frame deep pipeline between CPU and GPU and we are - // drawing 60 frames per second which would require us to draw one - // frame in 16 milliseconds. - const size_t kMaxTransferBufferUsageBytes = 16 * 2 * kMaxBytesUploadedPerMs; - return std::min( - context_provider->ContextCapabilities().max_transfer_buffer_usage_bytes, - kMaxTransferBufferUsageBytes); - } else { - // Software compositing should not use this value in production. Just use a - // default value when testing uploads with the software compositor. + // Software compositing should not use this value in production. Just use a + // default value when testing uploads with the software compositor. + if (!context_provider) return std::numeric_limits<size_t>::max(); - } + + // We want to make sure the default transfer buffer size is equal to the + // amount of data that can be uploaded by the compositor to avoid stalling + // the pipeline. + // For reference Chromebook Pixel can upload 1MB in about 0.5ms. + const size_t kMaxBytesUploadedPerMs = 1024 * 1024 * 2; + // Assuming a two frame deep pipeline between CPU and GPU and we are + // drawing 60 frames per second which would require us to draw one + // frame in 16 milliseconds. + const size_t kMaxTransferBufferUsageBytes = 16 * 2 * kMaxBytesUploadedPerMs; + return std::min( + context_provider->ContextCapabilities().max_transfer_buffer_usage_bytes, + kMaxTransferBufferUsageBytes); +} + +size_t GetMaxRasterTasksUsageBytes(cc::ContextProvider* context_provider) { + // Transfer-buffer/raster-tasks limits are different but related. We make + // equal here, as this is ideal when using transfer buffers. When not using + // transfer buffers we should still limit raster to something similar, to + // preserve caching behavior (and limit memory waste when priorities change). + return GetMaxTransferBufferUsageBytes(context_provider); +} + +GLenum GetMapImageTextureTarget(cc::ContextProvider* context_provider) { + if (!context_provider) + return GL_TEXTURE_2D; + + // TODO(reveman): Determine if GL_TEXTURE_EXTERNAL_OES works well on + // Android before we enable this. crbug.com/322780 +#if !defined(OS_ANDROID) + if (context_provider->ContextCapabilities().egl_image_external) + return GL_TEXTURE_EXTERNAL_OES; + if (context_provider->ContextCapabilities().texture_rectangle) + return GL_TEXTURE_RECTANGLE_ARB; +#endif + + return GL_TEXTURE_2D; } } // namespace @@ -178,36 +207,38 @@ scoped_ptr<LayerTreeHostImpl> LayerTreeHostImpl::Create( const LayerTreeSettings& settings, LayerTreeHostImplClient* client, Proxy* proxy, - RenderingStatsInstrumentation* rendering_stats_instrumentation) { - return make_scoped_ptr( - new LayerTreeHostImpl(settings, - client, - proxy, - rendering_stats_instrumentation)); + RenderingStatsInstrumentation* rendering_stats_instrumentation, + SharedBitmapManager* manager, + int id) { + return make_scoped_ptr(new LayerTreeHostImpl( + settings, client, proxy, rendering_stats_instrumentation, manager, id)); } LayerTreeHostImpl::LayerTreeHostImpl( const LayerTreeSettings& settings, LayerTreeHostImplClient* client, Proxy* proxy, - RenderingStatsInstrumentation* rendering_stats_instrumentation) + RenderingStatsInstrumentation* rendering_stats_instrumentation, + SharedBitmapManager* manager, + int id) : client_(client), proxy_(proxy), input_handler_client_(NULL), did_lock_scrolling_layer_(false), should_bubble_scrolls_(false), + last_scroll_did_bubble_(false), wheel_scrolling_(false), + scroll_layer_id_when_mouse_over_scrollbar_(0), tile_priorities_dirty_(false), root_layer_scroll_offset_delegate_(NULL), settings_(settings), visible_(true), cached_managed_memory_policy_( PrioritizedResourceManager::DefaultMemoryAllocationLimit(), - ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING, - 0, - ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING, + gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING, ManagedMemoryPolicy::kDefaultNumResourcesLimit), pinch_gesture_active_(false), + pinch_gesture_end_should_clear_scrolling_layer_(false), fps_counter_(FrameRateCounter::Create(proxy_->HasImplThread())), paint_time_counter_(PaintTimeCounter::Create()), memory_history_(MemoryHistory::Create()), @@ -225,7 +256,13 @@ LayerTreeHostImpl::LayerTreeHostImpl( external_stencil_test_enabled_(false), animation_registrar_(AnimationRegistrar::Create()), rendering_stats_instrumentation_(rendering_stats_instrumentation), - need_to_update_visible_tiles_before_draw_(false) { + micro_benchmark_controller_(this), + need_to_update_visible_tiles_before_draw_(false), +#ifndef NDEBUG + did_lose_called_(false), +#endif + shared_bitmap_manager_(manager), + id_(id) { DCHECK(proxy_->IsImplThread()); DidVisibilityChange(this, visible_); @@ -266,6 +303,16 @@ LayerTreeHostImpl::~LayerTreeHostImpl() { active_tree_.reset(); } +void LayerTreeHostImpl::BeginMainFrameAborted(bool did_handle) { + // If the begin frame data was handled, then scroll and scale set was applied + // by the main thread, so the active tree needs to be updated as if these sent + // values were applied and committed. + if (did_handle) { + active_tree_->ApplySentScrollAndScaleDeltasFromAbortedCommit(); + active_tree_->ResetContentsTexturesPurged(); + } +} + void LayerTreeHostImpl::BeginCommit() {} void LayerTreeHostImpl::CommitComplete() { @@ -275,7 +322,7 @@ void LayerTreeHostImpl::CommitComplete() { // Impl-side painting needs an update immediately post-commit to have the // opportunity to create tilings. Other paths can call UpdateDrawProperties // more lazily when needed prior to drawing. - pending_tree()->ApplyScrollDeltasSinceBeginFrame(); + pending_tree()->ApplyScrollDeltasSinceBeginMainFrame(); pending_tree_->set_needs_update_draw_properties(); pending_tree_->UpdateDrawProperties(); // Start working on newly created tiles immediately if needed. @@ -290,6 +337,8 @@ void LayerTreeHostImpl::CommitComplete() { } client_->SendManagedMemoryStats(); + + micro_benchmark_controller_.DidCompleteCommit(); } bool LayerTreeHostImpl::CanDraw() const { @@ -363,7 +412,7 @@ void LayerTreeHostImpl::ManageTiles() { return; tile_priorities_dirty_ = false; - tile_manager_->ManageTiles(); + tile_manager_->ManageTiles(global_tile_state_); size_t memory_required_bytes; size_t memory_nice_to_have_bytes; @@ -413,42 +462,36 @@ void LayerTreeHostImpl::StartPageScaleAnimation(gfx::Vector2d target_offset, duration.InSecondsF()); } - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); client_->SetNeedsCommitOnImplThread(); client_->RenewTreePriority(); } void LayerTreeHostImpl::ScheduleAnimation() { - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); } bool LayerTreeHostImpl::HaveTouchEventHandlersAt(gfx::Point viewport_point) { + if (!settings_.touch_hit_testing) + return true; if (!EnsureRenderSurfaceLayerList()) return false; gfx::PointF device_viewport_point = gfx::ScalePoint(viewport_point, device_scale_factor_); - // First find out which layer was hit from the saved list of visible layers - // in the most recent frame. - LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint( - device_viewport_point, - active_tree_->RenderSurfaceLayerList()); - - // Walk up the hierarchy and look for a layer with a touch event handler - // region that the given point hits. - for (; layer_impl; layer_impl = layer_impl->parent()) { - if (LayerTreeHostCommon::LayerHasTouchEventHandlersAt(device_viewport_point, - layer_impl)) - return true; - } - - return false; + LayerImpl* layer_impl = + LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion( + device_viewport_point, + active_tree_->RenderSurfaceLayerList()); + return layer_impl != NULL; } -void LayerTreeHostImpl::SetLatencyInfoForInputEvent( - const ui::LatencyInfo& latency_info) { - active_tree()->SetLatencyInfo(latency_info); +scoped_ptr<SwapPromiseMonitor> +LayerTreeHostImpl::CreateLatencyInfoSwapPromiseMonitor( + ui::LatencyInfo* latency) { + return scoped_ptr<SwapPromiseMonitor>( + new LatencyInfoSwapPromiseMonitor(latency, NULL, this)); } void LayerTreeHostImpl::TrackDamageForAllSurfaces( @@ -471,8 +514,7 @@ void LayerTreeHostImpl::TrackDamageForAllSurfaces( render_surface->SurfacePropertyChangedOnlyFromDescendant(), render_surface->content_rect(), render_surface_layer->mask_layer(), - render_surface_layer->filters(), - render_surface_layer->filter().get()); + render_surface_layer->filters()); } } @@ -507,7 +549,8 @@ static DrawMode GetDrawMode(OutputSurface* output_surface) { } else if (output_surface->context_provider()) { return DRAW_MODE_HARDWARE; } else { - DCHECK(output_surface->software_device()); + DCHECK_EQ(!output_surface->software_device(), + output_surface->capabilities().delegated_rendering); return DRAW_MODE_SOFTWARE; } } @@ -557,8 +600,9 @@ static void AppendQuadsForRenderSurfaceLayer( } static void AppendQuadsToFillScreen( - ResourceProvider::ResourceId resource_id, - gfx::SizeF resource_scaled_size, + ResourceProvider::ResourceId overhang_resource_id, + gfx::SizeF overhang_resource_scaled_size, + gfx::Rect root_scroll_layer_rect, RenderPass* target_render_pass, LayerImpl* root_layer, SkColor screen_background_color, @@ -570,6 +614,16 @@ static void AppendQuadsToFillScreen( if (fill_region.IsEmpty()) return; + // Divide the fill region into the part to be filled with the overhang + // resource and the part to be filled with the background color. + Region screen_background_color_region = fill_region; + Region overhang_region; + if (overhang_resource_id) { + overhang_region = fill_region; + overhang_region.Subtract(root_scroll_layer_rect); + screen_background_color_region.Intersect(root_scroll_layer_rect); + } + bool for_surface = false; QuadCuller quad_culler(&target_render_pass->quad_list, &target_render_pass->shared_quad_state_list, @@ -592,7 +646,8 @@ static void AppendQuadsToFillScreen( root_target_rect, root_target_rect, false, - opacity); + opacity, + SkXfermode::kSrcOver_Mode); AppendQuadsData append_quads_data; @@ -600,38 +655,44 @@ static void AppendQuadsToFillScreen( bool did_invert = root_layer->screen_space_transform().GetInverse( &transform_to_layer_space); DCHECK(did_invert); - for (Region::Iterator fill_rects(fill_region); + for (Region::Iterator fill_rects(screen_background_color_region); fill_rects.has_rect(); fill_rects.next()) { // The root layer transform is composed of translations and scales only, // no perspective, so mapping is sufficient (as opposed to projecting). gfx::Rect layer_rect = MathUtil::MapClippedRect(transform_to_layer_space, fill_rects.rect()); - if (resource_id) { - scoped_ptr<TextureDrawQuad> tex_quad = TextureDrawQuad::Create(); - const float vertex_opacity[4] = {1.f, 1.f, 1.f, 1.f}; - tex_quad->SetNew( - shared_quad_state, - layer_rect, - layer_rect, - resource_id, - false, - gfx::PointF(layer_rect.x() / resource_scaled_size.width(), - layer_rect.y() / resource_scaled_size.height()), - gfx::PointF(layer_rect.right() / resource_scaled_size.width(), - layer_rect.bottom() / resource_scaled_size.height()), - screen_background_color, - vertex_opacity, - false); - quad_culler.Append(tex_quad.PassAs<DrawQuad>(), &append_quads_data); - } else { - // Skip the quad culler and just append the quads directly to avoid - // occlusion checks. - scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create(); - quad->SetNew( - shared_quad_state, layer_rect, screen_background_color, false); - quad_culler.Append(quad.PassAs<DrawQuad>(), &append_quads_data); - } + // Skip the quad culler and just append the quads directly to avoid + // occlusion checks. + scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create(); + quad->SetNew( + shared_quad_state, layer_rect, screen_background_color, false); + quad_culler.Append(quad.PassAs<DrawQuad>(), &append_quads_data); + } + for (Region::Iterator fill_rects(overhang_region); + fill_rects.has_rect(); + fill_rects.next()) { + DCHECK(overhang_resource_id); + gfx::Rect layer_rect = + MathUtil::MapClippedRect(transform_to_layer_space, fill_rects.rect()); + scoped_ptr<TextureDrawQuad> tex_quad = TextureDrawQuad::Create(); + const float vertex_opacity[4] = {1.f, 1.f, 1.f, 1.f}; + tex_quad->SetNew( + shared_quad_state, + layer_rect, + layer_rect, + overhang_resource_id, + false, + gfx::PointF(layer_rect.x() / overhang_resource_scaled_size.width(), + layer_rect.y() / overhang_resource_scaled_size.height()), + gfx::PointF(layer_rect.right() / + overhang_resource_scaled_size.width(), + layer_rect.bottom() / + overhang_resource_scaled_size.height()), + screen_background_color, + vertex_opacity, + false); + quad_culler.Append(tex_quad.PassAs<DrawQuad>(), &append_quads_data); } } @@ -737,8 +798,7 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { RenderPass* target_render_pass = frame->render_passes_by_id[target_render_pass_id]; - bool prevent_occlusion = it.target_render_surface_layer()->HasCopyRequest(); - occlusion_tracker.EnterLayer(it, prevent_occlusion); + occlusion_tracker.EnterLayer(it); AppendQuadsData append_quads_data(target_render_pass_id); @@ -759,21 +819,15 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { contributing_render_pass, occlusion_tracker, &append_quads_data); - } else if (it.represents_itself() && + } else if (it.represents_itself() && it->DrawsContent() && !it->visible_content_rect().IsEmpty()) { - bool has_occlusion_from_outside_target_surface; bool impl_draw_transform_is_unknown = false; - if (occlusion_tracker.Occluded( + bool occluded = occlusion_tracker.Occluded( it->render_target(), it->visible_content_rect(), it->draw_transform(), - impl_draw_transform_is_unknown, - it->is_clipped(), - it->clip_rect(), - &has_occlusion_from_outside_target_surface)) { - append_quads_data.had_occlusion_from_outside_target_surface |= - has_occlusion_from_outside_target_surface; - } else if (it->WillDraw(draw_mode, resource_provider_.get())) { + impl_draw_transform_is_unknown); + if (!occluded && it->WillDraw(draw_mode, resource_provider_.get())) { DCHECK_EQ(active_tree_, it->layer_tree_impl()); frame->will_draw_layers.push_back(*it); @@ -806,12 +860,7 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { ++layers_drawn; } - if (append_quads_data.had_occlusion_from_outside_target_surface) - target_render_pass->has_occlusion_from_outside_target_surface = true; - if (append_quads_data.num_missing_tiles) { - rendering_stats_instrumentation_->AddMissingTiles( - append_quads_data.num_missing_tiles); bool layer_has_animating_transform = it->screen_space_transform_is_animating() || it->draw_transform_is_animating(); @@ -829,8 +878,6 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { output_surface_->capabilities().draw_and_swap_full_viewport_every_frame) draw_frame = true; - rendering_stats_instrumentation_->AddLayersDrawn(layers_drawn); - #ifndef NDEBUG for (size_t i = 0; i < frame->render_passes.size(); ++i) { for (size_t j = 0; j < frame->render_passes[i]->quad_list.size(); ++j) @@ -843,13 +890,14 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { if (!active_tree_->has_transparent_background()) { frame->render_passes.back()->has_transparent_background = false; - AppendQuadsToFillScreen(ResourceIdForUIResource(overhang_ui_resource_id_), - gfx::ScaleSize(overhang_ui_resource_size_, - device_scale_factor_), - frame->render_passes.back(), - active_tree_->root_layer(), - active_tree_->background_color(), - occlusion_tracker); + AppendQuadsToFillScreen( + ResourceIdForUIResource(overhang_ui_resource_id_), + gfx::ScaleSize(overhang_ui_resource_size_, device_scale_factor_), + active_tree_->RootScrollLayerDeviceViewportBounds(), + frame->render_passes.back(), + active_tree_->root_layer(), + active_tree_->background_color(), + occlusion_tracker); } if (draw_frame) @@ -858,10 +906,7 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { DCHECK(!have_copy_request); RemoveRenderPasses(CullRenderPassesWithNoQuads(), frame); - if (!output_surface_->ForcedDrawToSoftwareDevice()) - renderer_->DecideRenderPassAllocationsForFrame(frame->render_passes); - RemoveRenderPasses(CullRenderPassesWithCachedTextures(renderer_.get()), - frame); + renderer_->DecideRenderPassAllocationsForFrame(frame->render_passes); // Any copy requests left in the tree are not going to get serviced, and // should be aborted. @@ -875,6 +920,11 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { // If we're making a frame to draw, it better have at least one render pass. DCHECK(!frame->render_passes.empty()); + + // Should only have one render pass in resourceless software mode. + if (output_surface_->ForcedDrawToSoftwareDevice()) + DCHECK_EQ(1u, frame->render_passes.size()); + return draw_frame; } @@ -906,6 +956,11 @@ void LayerTreeHostImpl::UpdateBackgroundAnimateTicking( time_source_client_adapter_->SetActive(enabled); } +void LayerTreeHostImpl::DidAnimateScrollOffset() { + client_->SetNeedsCommitOnImplThread(); + client_->RenewTreePriority(); +} + void LayerTreeHostImpl::SetViewportDamage(gfx::Rect damage_rect) { viewport_damage_rect_.Union(damage_rect); } @@ -954,24 +1009,6 @@ static void RemoveRenderPassesRecursive(RenderPass::Id remove_render_pass_id, } } -bool LayerTreeHostImpl::CullRenderPassesWithCachedTextures:: - ShouldRemoveRenderPass(const RenderPassDrawQuad& quad, - const FrameData& frame) const { - DCHECK(renderer_); - bool quad_has_damage = !quad.contents_changed_since_last_frame.IsEmpty(); - bool quad_has_cached_resource = - renderer_->HaveCachedResourcesForRenderPassId(quad.render_pass_id); - if (quad_has_damage) { - TRACE_EVENT0("cc", "CullRenderPassesWithCachedTextures have damage"); - return false; - } else if (!quad_has_cached_resource) { - TRACE_EVENT0("cc", "CullRenderPassesWithCachedTextures have no texture"); - return false; - } - TRACE_EVENT0("cc", "CullRenderPassesWithCachedTextures dropped!"); - return true; -} - bool LayerTreeHostImpl::CullRenderPassesWithNoQuads::ShouldRemoveRenderPass( const RenderPassDrawQuad& quad, const FrameData& frame) const { const RenderPass* render_pass = @@ -1000,9 +1037,6 @@ bool LayerTreeHostImpl::CullRenderPassesWithNoQuads::ShouldRemoveRenderPass( // Defined for linking tests. template CC_EXPORT void LayerTreeHostImpl::RemoveRenderPasses< - LayerTreeHostImpl::CullRenderPassesWithCachedTextures>( - CullRenderPassesWithCachedTextures culler, FrameData* frame); -template CC_EXPORT void LayerTreeHostImpl::RemoveRenderPasses< LayerTreeHostImpl::CullRenderPassesWithNoQuads>( CullRenderPassesWithNoQuads culler, FrameData*); @@ -1100,11 +1134,10 @@ void LayerTreeHostImpl::EnforceManagedMemoryPolicy( const ManagedMemoryPolicy& policy) { bool evicted_resources = client_->ReduceContentsTextureMemoryOnImplThread( - visible_ ? policy.bytes_limit_when_visible - : policy.bytes_limit_when_not_visible, + visible_ ? policy.bytes_limit_when_visible : 0, ManagedMemoryPolicy::PriorityCutoffToValue( visible_ ? policy.priority_cutoff_when_visible - : policy.priority_cutoff_when_not_visible)); + : gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING)); if (evicted_resources) { active_tree_->SetContentsTexturesPurged(); if (pending_tree_) @@ -1123,23 +1156,21 @@ void LayerTreeHostImpl::UpdateTileManagerMemoryPolicy( if (!tile_manager_) return; - GlobalStateThatImpactsTilePriority new_state(tile_manager_->GlobalState()); - new_state.memory_limit_in_bytes = visible_ ? - policy.bytes_limit_when_visible : - policy.bytes_limit_when_not_visible; // TODO(reveman): We should avoid keeping around unused resources if // possible. crbug.com/224475 - new_state.unused_memory_limit_in_bytes = static_cast<size_t>( - (static_cast<int64>(new_state.memory_limit_in_bytes) * + global_tile_state_.memory_limit_in_bytes = + visible_ ? + policy.bytes_limit_when_visible : 0; + global_tile_state_.unused_memory_limit_in_bytes = static_cast<size_t>( + (static_cast<int64>(global_tile_state_.memory_limit_in_bytes) * settings_.max_unused_resource_memory_percentage) / 100); - new_state.memory_limit_policy = + global_tile_state_.memory_limit_policy = ManagedMemoryPolicy::PriorityCutoffToTileMemoryLimitPolicy( visible_ ? policy.priority_cutoff_when_visible : - policy.priority_cutoff_when_not_visible); - new_state.num_resources_limit = policy.num_resources_limit; + gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING); + global_tile_state_.num_resources_limit = policy.num_resources_limit; - tile_manager_->SetGlobalState(new_state); DidModifyTilePriorities(); } @@ -1166,11 +1197,6 @@ void LayerTreeHostImpl::SetMemoryPolicy(const ManagedMemoryPolicy& policy) { SetManagedMemoryPolicy(policy, zero_budget_); } -void LayerTreeHostImpl::SetDiscardBackBufferWhenNotVisible(bool discard) { - DCHECK(renderer_); - renderer_->SetDiscardBackBufferWhenNotVisible(discard); -} - void LayerTreeHostImpl::SetTreeActivationCallback( const base::Closure& callback) { DCHECK(proxy_->IsImplThread()); @@ -1231,11 +1257,18 @@ void LayerTreeHostImpl::SetExternalDrawConstraints( } void LayerTreeHostImpl::SetNeedsRedrawRect(gfx::Rect damage_rect) { + if (damage_rect.IsEmpty()) + return; + NotifySwapPromiseMonitorsOfSetNeedsRedraw(); client_->SetNeedsRedrawRectOnImplThread(damage_rect); } -void LayerTreeHostImpl::BeginFrame(const BeginFrameArgs& args) { - client_->BeginFrameOnImplThread(args); +void LayerTreeHostImpl::BeginImplFrame(const BeginFrameArgs& args) { + client_->BeginImplFrame(args); +} + +void LayerTreeHostImpl::DidSwapBuffers() { + client_->DidSwapBuffersOnImplThread(); } void LayerTreeHostImpl::OnSwapBuffersComplete() { @@ -1261,7 +1294,6 @@ CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const { metadata.root_layer_size = active_tree_->ScrollableSize(); metadata.min_page_scale_factor = active_tree_->min_page_scale_factor(); metadata.max_page_scale_factor = active_tree_->max_page_scale_factor(); - metadata.latency_info = active_tree_->GetLatencyInfo(); if (top_controls_manager_) { metadata.location_bar_offset = gfx::Vector2dF(0.f, top_controls_manager_->controls_top_offset()); @@ -1296,15 +1328,12 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame, DCHECK(!frame->render_passes.empty()); - int old_dropped_frame_count = fps_counter_->dropped_frame_count(); fps_counter_->SaveTimeStamp(frame_begin_time, !output_surface_->context_provider()); bool on_main_thread = false; - rendering_stats_instrumentation_->IncrementScreenFrameCount( + rendering_stats_instrumentation_->IncrementFrameCount( 1, on_main_thread); - rendering_stats_instrumentation_->IncrementDroppedFrameCount( - fps_counter_->dropped_frame_count() - old_dropped_frame_count); if (tile_manager_) { memory_history_->SaveEntry( @@ -1347,16 +1376,26 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame, // Because the contents of the HUD depend on everything else in the frame, the // contents of its texture are updated as the last thing before the frame is // drawn. - if (active_tree_->hud_layer()) - active_tree_->hud_layer()->UpdateHudTexture(resource_provider_.get()); + if (active_tree_->hud_layer()) { + TRACE_EVENT0("cc", "DrawLayers.UpdateHudTexture"); + active_tree_->hud_layer()->UpdateHudTexture( + GetDrawMode(output_surface_.get()), resource_provider_.get()); + } if (output_surface_->ForcedDrawToSoftwareDevice()) { bool allow_partial_swap = false; + bool disable_picture_quad_image_filtering = + IsCurrentlyScrolling() || needs_animate_layers(); scoped_ptr<SoftwareRenderer> temp_software_renderer = SoftwareRenderer::Create(this, &settings_, output_surface_.get(), NULL); - temp_software_renderer->DrawFrame( - &frame->render_passes, NULL, device_scale_factor_, allow_partial_swap); + temp_software_renderer->DrawFrame(&frame->render_passes, + NULL, + device_scale_factor_, + DeviceViewport(), + DeviceClip(), + allow_partial_swap, + disable_picture_quad_image_filtering); } else { // We don't track damage on the HUD layer (it interacts with damage tracking // visualizations), so disable partial swaps to make the HUD layer display @@ -1366,7 +1405,10 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame, renderer_->DrawFrame(&frame->render_passes, offscreen_context_provider_.get(), device_scale_factor_, - allow_partial_swap); + DeviceViewport(), + DeviceClip(), + allow_partial_swap, + false); } // The render passes should be consumed by the renderer. DCHECK(frame->render_passes.empty()); @@ -1382,7 +1424,8 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame, } active_tree_->root_layer()->ResetAllChangeTrackingForSubtree(); - rendering_stats_instrumentation_->IssueTraceEventForImplThreadStats(); + BenchmarkInstrumentation::IssueImplThreadRenderingStatsEvent( + rendering_stats_instrumentation_->impl_thread_rendering_stats()); rendering_stats_instrumentation_->AccumulateAndClearImplThreadStats(); } @@ -1410,23 +1453,26 @@ const RendererCapabilities& LayerTreeHostImpl::GetRendererCapabilities() const { } bool LayerTreeHostImpl::SwapBuffers(const LayerTreeHostImpl::FrameData& frame) { - if (frame.has_no_damage) + if (frame.has_no_damage) { + active_tree()->BreakSwapPromises(SwapPromise::SWAP_FAILS); return false; - renderer_->SwapBuffers(); - active_tree_->ClearLatencyInfo(); + } + CompositorFrameMetadata metadata = MakeCompositorFrameMetadata(); + active_tree()->FinishSwapPromises(&metadata); + renderer_->SwapBuffers(metadata); return true; } -void LayerTreeHostImpl::SetNeedsBeginFrame(bool enable) { +void LayerTreeHostImpl::SetNeedsBeginImplFrame(bool enable) { if (output_surface_) - output_surface_->SetNeedsBeginFrame(enable); + output_surface_->SetNeedsBeginImplFrame(enable); } gfx::SizeF LayerTreeHostImpl::UnscaledScrollableViewportSize() const { - // The container layer bounds should be used if non-overlay scrollbars may - // exist since it adjusts for them. + // Use the root container layer bounds if it clips to them, otherwise, the + // true viewport size should be used. LayerImpl* container_layer = active_tree_->RootContainerLayer(); - if (!settings_.solid_color_scrollbars && container_layer) { + if (container_layer && container_layer->masks_to_bounds()) { DCHECK(!top_controls_manager_); DCHECK_EQ(0, overdraw_bottom_height_); return container_layer->bounds(); @@ -1442,11 +1488,16 @@ gfx::SizeF LayerTreeHostImpl::UnscaledScrollableViewportSize() const { } void LayerTreeHostImpl::DidLoseOutputSurface() { + if (resource_provider_) + resource_provider_->DidLoseOutputSurface(); // TODO(jamesr): The renderer_ check is needed to make some of the // LayerTreeHostContextTest tests pass, but shouldn't be necessary (or // important) in production. We should adjust the test to not need this. if (renderer_) client_->DidLoseOutputSurfaceOnImplThread(); +#ifndef NDEBUG + did_lose_called_ = true; +#endif } void LayerTreeHostImpl::Readback(void* pixels, @@ -1471,12 +1522,17 @@ LayerImpl* LayerTreeHostImpl::CurrentlyScrollingLayer() const { return active_tree_->CurrentlyScrollingLayer(); } +bool LayerTreeHostImpl::IsCurrentlyScrolling() const { + return CurrentlyScrollingLayer() || + (RootScrollLayer() && RootScrollLayer()->IsExternalFlingActive()); +} + // Content layers can be either directly scrollable or contained in an outer // scrolling layer which applies the scroll transform. Given a content layer, // this function returns the associated scroll layer if any. static LayerImpl* FindScrollLayerForContentLayer(LayerImpl* layer_impl) { if (!layer_impl) - return 0; + return NULL; if (layer_impl->scrollable()) return layer_impl; @@ -1486,7 +1542,7 @@ static LayerImpl* FindScrollLayerForContentLayer(LayerImpl* layer_impl) { layer_impl->parent()->scrollable()) return layer_impl->parent(); - return 0; + return NULL; } void LayerTreeHostImpl::CreatePendingTree() { @@ -1496,9 +1552,7 @@ void LayerTreeHostImpl::CreatePendingTree() { else pending_tree_ = LayerTreeImpl::create(this); client_->OnCanDrawStateChanged(CanDraw()); - TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree", pending_tree_.get()); - TRACE_EVENT_ASYNC_STEP0("cc", - "PendingTree", pending_tree_.get(), "waiting"); + TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree:waiting", pending_tree_.get()); } void LayerTreeHostImpl::UpdateVisibleTiles() { @@ -1509,7 +1563,7 @@ void LayerTreeHostImpl::UpdateVisibleTiles() { void LayerTreeHostImpl::ActivatePendingTree() { CHECK(pending_tree_); - TRACE_EVENT_ASYNC_END0("cc", "PendingTree", pending_tree_.get()); + TRACE_EVENT_ASYNC_END0("cc", "PendingTree:waiting", pending_tree_.get()); need_to_update_visible_tiles_before_draw_ = true; @@ -1537,24 +1591,20 @@ void LayerTreeHostImpl::ActivatePendingTree() { // next sync. pending_tree_.swap(recycle_tree_); + active_tree_->DidBecomeActive(); active_tree_->SetRootLayerScrollOffsetDelegate( root_layer_scroll_offset_delegate_); - active_tree_->DidBecomeActive(); - - // Reduce wasted memory now that unlinked resources are guaranteed not - // to be used. - client_->ReduceWastedContentsTextureMemoryOnImplThread(); client_->OnCanDrawStateChanged(CanDraw()); - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); client_->RenewTreePriority(); if (debug_state_.continuous_painting) { const RenderingStats& stats = rendering_stats_instrumentation_->GetRenderingStats(); - paint_time_counter_->SavePaintTime( - stats.main_stats.paint_time + stats.main_stats.record_time + - stats.impl_stats.rasterize_time_for_now_bins_on_pending_tree); + paint_time_counter_->SavePaintTime(stats.main_stats.paint_time + + stats.main_stats.record_time + + stats.impl_stats.rasterize_time); } client_->DidActivatePendingTree(); @@ -1563,6 +1613,8 @@ void LayerTreeHostImpl::ActivatePendingTree() { if (time_source_client_adapter_ && time_source_client_adapter_->Active()) DCHECK(active_tree_->root_layer()); + devtools_instrumentation::didActivateLayerTree(id_, + active_tree_->source_frame_number()); } void LayerTreeHostImpl::SetVisible(bool visible) { @@ -1588,18 +1640,20 @@ void LayerTreeHostImpl::SetVisible(bool visible) { renderer_->SetVisible(visible); } +void LayerTreeHostImpl::SetNeedsRedraw() { + NotifySwapPromiseMonitorsOfSetNeedsRedraw(); + client_->SetNeedsRedrawOnImplThread(); +} + ManagedMemoryPolicy LayerTreeHostImpl::ActualManagedMemoryPolicy() const { ManagedMemoryPolicy actual = cached_managed_memory_policy_; if (debug_state_.rasterize_only_visible_content) { - actual.priority_cutoff_when_not_visible = - ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING; actual.priority_cutoff_when_visible = - ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY; + gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY; } if (zero_budget_) { actual.bytes_limit_when_visible = 0; - actual.bytes_limit_when_not_visible = 0; } return actual; @@ -1639,8 +1693,7 @@ void LayerTreeHostImpl::CreateAndSetRenderer( output_surface, resource_provider, texture_mailbox_deleter_.get(), - settings_.highp_threshold_min, - settings_.force_direct_layer_drawing); + settings_.highp_threshold_min); } else if (output_surface->software_device()) { renderer_ = SoftwareRenderer::Create( this, &settings_, output_surface, resource_provider); @@ -1671,7 +1724,9 @@ void LayerTreeHostImpl::CreateAndSetTileManager( settings_.num_raster_threads, rendering_stats_instrumentation_, using_map_image, - GetMaxTransferBufferUsageBytes(context_provider)); + GetMaxTransferBufferUsageBytes(context_provider), + GetMaxRasterTasksUsageBytes(context_provider), + GetMapImageTextureTarget(context_provider)); UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy()); need_to_update_visible_tiles_before_draw_ = false; @@ -1683,12 +1738,14 @@ void LayerTreeHostImpl::EnforceZeroBudget(bool zero_budget) { bool LayerTreeHostImpl::InitializeRenderer( scoped_ptr<OutputSurface> output_surface) { +#ifndef NDEBUG + DCHECK(!renderer_ || did_lose_called_); +#endif + // Since we will create a new resource provider, we cannot continue to use // the old resources (i.e. render_surfaces and texture IDs). Clear them // before we destroy the old resource provider. ReleaseTreeResources(); - if (resource_provider_) - resource_provider_->DidLoseOutputSurface(); // Note: order is important here. renderer_.reset(); @@ -1699,10 +1756,12 @@ bool LayerTreeHostImpl::InitializeRenderer( if (!output_surface->BindToClient(this)) return false; - scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create( - output_surface.get(), - settings_.highp_threshold_min, - settings_.use_rgba_4444_textures); + scoped_ptr<ResourceProvider> resource_provider = + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_, + settings_.highp_threshold_min, + settings_.use_rgba_4444_textures, + settings_.texture_id_allocation_chunk_size); if (!resource_provider) return false; @@ -1722,14 +1781,14 @@ bool LayerTreeHostImpl::InitializeRenderer( GetRendererCapabilities().using_map_image); } - // Setup BeginFrameEmulation if it's not supported natively - if (!settings_.begin_frame_scheduling_enabled) { + // Setup BeginImplFrameEmulation if it's not supported natively + if (!settings_.begin_impl_frame_scheduling_enabled) { const base::TimeDelta display_refresh_interval = base::TimeDelta::FromMicroseconds( base::Time::kMicrosecondsPerSecond / settings_.refresh_rate); - output_surface->InitializeBeginFrameEmulation( + output_surface->InitializeBeginImplFrameEmulation( proxy_->ImplThreadTaskRunner(), settings_.throttle_frame_production, display_refresh_interval); @@ -1753,7 +1812,6 @@ bool LayerTreeHostImpl::DeferredInitialize( scoped_refptr<ContextProvider> offscreen_context_provider) { DCHECK(output_surface_->capabilities().deferred_gl_initialization); DCHECK(settings_.impl_side_painting); - DCHECK(settings_.solid_color_scrollbars); DCHECK(output_surface_->context_provider()); ReleaseTreeResources(); @@ -1810,7 +1868,6 @@ bool LayerTreeHostImpl::DeferredInitialize( void LayerTreeHostImpl::ReleaseGL() { DCHECK(output_surface_->capabilities().deferred_gl_initialization); DCHECK(settings_.impl_side_painting); - DCHECK(settings_.solid_color_scrollbars); DCHECK(output_surface_->context_provider()); ReleaseTreeResources(); @@ -1845,9 +1902,6 @@ void LayerTreeHostImpl::SetViewportSize(gfx::Size device_viewport_size) { UpdateMaxScrollOffset(); - if (renderer_) - renderer_->ViewportChanged(); - client_->OnCanDrawStateChanged(CanDraw()); SetFullRootLayerDamage(); } @@ -1873,9 +1927,6 @@ void LayerTreeHostImpl::SetDeviceScaleFactor(float device_scale_factor) { return; device_scale_factor_ = device_scale_factor; - if (renderer_) - renderer_->ViewportChanged(); - UpdateMaxScrollOffset(); SetFullRootLayerDamage(); } @@ -1907,7 +1958,7 @@ void LayerTreeHostImpl::UpdateMaxScrollOffset() { } void LayerTreeHostImpl::DidChangeTopControlsPosition() { - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); active_tree_->set_needs_update_draw_properties(); SetFullRootLayerDamage(); } @@ -1928,26 +1979,10 @@ static LayerImpl* NextScrollLayer(LayerImpl* layer) { return layer->parent(); } -InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( - gfx::Point viewport_point, InputHandler::ScrollInputType type) { - TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBegin"); - - if (top_controls_manager_) - top_controls_manager_->ScrollBegin(); - - DCHECK(!CurrentlyScrollingLayer()); - ClearCurrentlyScrollingLayer(); - - if (!EnsureRenderSurfaceLayerList()) - return ScrollIgnored; - - gfx::PointF device_viewport_point = gfx::ScalePoint(viewport_point, - device_scale_factor_); - - // First find out which layer was hit from the saved list of visible layers - // in the most recent frame. - LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint( - device_viewport_point, active_tree_->RenderSurfaceLayerList()); +LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint( + gfx::PointF device_viewport_point, InputHandler::ScrollInputType type, + LayerImpl* layer_impl, bool* scroll_on_main_thread) const { + DCHECK(scroll_on_main_thread); // Walk up the hierarchy and look for a scrollable layer. LayerImpl* potentially_scrolling_layer_impl = 0; @@ -1956,9 +1991,8 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( // thread. ScrollStatus status = layer_impl->TryScroll(device_viewport_point, type); if (status == ScrollOnMainThread) { - rendering_stats_instrumentation_->IncrementMainThreadScrolls(); - UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", true); - return ScrollOnMainThread; + *scroll_on_main_thread = true; + return NULL; } LayerImpl* scroll_layer_impl = FindScrollLayerForContentLayer(layer_impl); @@ -1966,12 +2000,10 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( continue; status = scroll_layer_impl->TryScroll(device_viewport_point, type); - // If any layer wants to divert the scroll event to the main thread, abort. if (status == ScrollOnMainThread) { - rendering_stats_instrumentation_->IncrementMainThreadScrolls(); - UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", true); - return ScrollOnMainThread; + *scroll_on_main_thread = true; + return NULL; } if (status == ScrollStarted && !potentially_scrolling_layer_impl) @@ -1987,12 +2019,47 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( potentially_scrolling_layer_impl = RootScrollLayer(); } + return potentially_scrolling_layer_impl; +} + +InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( + gfx::Point viewport_point, InputHandler::ScrollInputType type) { + TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBegin"); + + if (top_controls_manager_) + top_controls_manager_->ScrollBegin(); + + DCHECK(!CurrentlyScrollingLayer()); + ClearCurrentlyScrollingLayer(); + + if (!EnsureRenderSurfaceLayerList()) + return ScrollIgnored; + + gfx::PointF device_viewport_point = gfx::ScalePoint(viewport_point, + device_scale_factor_); + LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint( + device_viewport_point, + active_tree_->RenderSurfaceLayerList()); + bool scroll_on_main_thread = false; + LayerImpl* potentially_scrolling_layer_impl = + FindScrollLayerForDeviceViewportPoint(device_viewport_point, type, + layer_impl, &scroll_on_main_thread); + + if (scroll_on_main_thread) { + UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", true); + return ScrollOnMainThread; + } + + // If we want to send a DidOverscroll for this scroll it can't be ignored. + if (!potentially_scrolling_layer_impl && settings_.always_overscroll) + potentially_scrolling_layer_impl = RootScrollLayer(); + if (potentially_scrolling_layer_impl) { active_tree_->SetCurrentlyScrollingLayer( potentially_scrolling_layer_impl); should_bubble_scrolls_ = (type != NonBubblingGesture); + last_scroll_did_bubble_ = false; wheel_scrolling_ = (type == Wheel); - rendering_stats_instrumentation_->IncrementImplThreadScrolls(); client_->RenewTreePriority(); UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", false); return ScrollStarted; @@ -2095,6 +2162,7 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, bool did_scroll_y = false; bool consume_by_top_controls = top_controls_manager_ && (CurrentlyScrollingLayer() == RootScrollLayer() || scroll_delta.y() < 0); + last_scroll_did_bubble_ = false; for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); layer_impl; @@ -2135,10 +2203,15 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, did_scroll_x |= did_move_layer_x; did_scroll_y |= did_move_layer_y; if (!did_move_layer_x && !did_move_layer_y) { - if (should_bubble_scrolls_ || !did_lock_scrolling_layer_) + if (!did_lock_scrolling_layer_) + continue; + + if (should_bubble_scrolls_) { + last_scroll_did_bubble_ = true; continue; - else - break; + } + + break; } if (layer_impl == RootScrollLayer()) @@ -2172,7 +2245,7 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, bool did_scroll = did_scroll_x || did_scroll_y; if (did_scroll) { client_->SetNeedsCommitOnImplThread(); - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); client_->RenewTreePriority(); } @@ -2225,7 +2298,7 @@ bool LayerTreeHostImpl::ScrollVerticallyByPage(gfx::Point viewport_point, if (!applied_delta.IsZero()) { client_->SetNeedsCommitOnImplThread(); - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); client_->RenewTreePriority(); return true; } @@ -2273,6 +2346,9 @@ InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() { return ScrollIgnored; } + if (!wheel_scrolling_) + should_bubble_scrolls_ = last_scroll_did_bubble_; + return ScrollStarted; } @@ -2280,11 +2356,104 @@ void LayerTreeHostImpl::NotifyCurrentFlingVelocity(gfx::Vector2dF velocity) { current_fling_velocity_ = velocity; } +float LayerTreeHostImpl::DeviceSpaceDistanceToLayer( + gfx::PointF device_viewport_point, + LayerImpl* layer_impl) { + if (!layer_impl) + return std::numeric_limits<float>::max(); + + gfx::Rect layer_impl_bounds( + layer_impl->content_bounds()); + + gfx::RectF device_viewport_layer_impl_bounds = MathUtil::MapClippedRect( + layer_impl->screen_space_transform(), + layer_impl_bounds); + + return device_viewport_layer_impl_bounds.ManhattanDistanceToPoint( + device_viewport_point); +} + +void LayerTreeHostImpl::MouseMoveAt(gfx::Point viewport_point) { + if (!EnsureRenderSurfaceLayerList()) + return; + + gfx::PointF device_viewport_point = gfx::ScalePoint(viewport_point, + device_scale_factor_); + + LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint( + device_viewport_point, + active_tree_->RenderSurfaceLayerList()); + if (HandleMouseOverScrollbar(layer_impl, device_viewport_point)) + return; + + if (scroll_layer_id_when_mouse_over_scrollbar_) { + LayerImpl* scroll_layer_impl = active_tree_->LayerById( + scroll_layer_id_when_mouse_over_scrollbar_); + + ScrollbarAnimationController* animation_controller = + scroll_layer_impl->scrollbar_animation_controller(); + if (animation_controller) { + animation_controller->DidMouseMoveOffScrollbar( + CurrentPhysicalTimeTicks()); + StartScrollbarAnimation(); + } + scroll_layer_id_when_mouse_over_scrollbar_ = 0; + } + + bool scroll_on_main_thread = false; + LayerImpl* scroll_layer_impl = FindScrollLayerForDeviceViewportPoint( + device_viewport_point, InputHandler::Gesture, layer_impl, + &scroll_on_main_thread); + if (scroll_on_main_thread || !scroll_layer_impl) + return; + + ScrollbarAnimationController* animation_controller = + scroll_layer_impl->scrollbar_animation_controller(); + if (!animation_controller) + return; + + float distance_to_scrollbar = std::min( + DeviceSpaceDistanceToLayer(device_viewport_point, + scroll_layer_impl->horizontal_scrollbar_layer()), + DeviceSpaceDistanceToLayer(device_viewport_point, + scroll_layer_impl->vertical_scrollbar_layer())); + + bool should_animate = animation_controller->DidMouseMoveNear( + CurrentPhysicalTimeTicks(), distance_to_scrollbar / device_scale_factor_); + if (should_animate) + StartScrollbarAnimation(); +} + +bool LayerTreeHostImpl::HandleMouseOverScrollbar(LayerImpl* layer_impl, + gfx::PointF device_viewport_point) { + if (layer_impl && layer_impl->ToScrollbarLayer()) { + int scroll_layer_id = layer_impl->ToScrollbarLayer()->ScrollLayerId(); + layer_impl = active_tree_->LayerById(scroll_layer_id); + if (layer_impl && layer_impl->scrollbar_animation_controller()) { + scroll_layer_id_when_mouse_over_scrollbar_ = scroll_layer_id; + bool should_animate = + layer_impl->scrollbar_animation_controller()->DidMouseMoveNear( + CurrentPhysicalTimeTicks(), 0); + if (should_animate) + StartScrollbarAnimation(); + } else { + scroll_layer_id_when_mouse_over_scrollbar_ = 0; + } + + return true; + } + + return false; +} + void LayerTreeHostImpl::PinchGestureBegin() { pinch_gesture_active_ = true; previous_pinch_anchor_ = gfx::Point(); client_->RenewTreePriority(); + pinch_gesture_end_should_clear_scrolling_layer_ = !CurrentlyScrollingLayer(); active_tree_->SetCurrentlyScrollingLayer(RootScrollLayer()); + if (top_controls_manager_) + top_controls_manager_->PinchBegin(); } void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta, @@ -2312,12 +2481,18 @@ void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta, RootScrollLayer()->ScrollBy(move); client_->SetNeedsCommitOnImplThread(); - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); client_->RenewTreePriority(); } void LayerTreeHostImpl::PinchGestureEnd() { pinch_gesture_active_ = false; + if (pinch_gesture_end_should_clear_scrolling_layer_) { + pinch_gesture_end_should_clear_scrolling_layer_ = false; + ClearCurrentlyScrollingLayer(); + } + if (top_controls_manager_) + top_controls_manager_->PinchEnd(); client_->SetNeedsCommitOnImplThread(); } @@ -2372,7 +2547,7 @@ void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks time) { page_scale_animation_->ScrollOffsetAtTime(monotonic_time); RootScrollLayer()->ScrollBy(next_scroll - scroll_total); - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); if (page_scale_animation_->IsAnimationCompleteAtTime(monotonic_time)) { page_scale_animation_.reset(); @@ -2411,7 +2586,7 @@ void LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time, ++iter) (*iter).second->Animate(monotonic_seconds); - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); } void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) { @@ -2525,7 +2700,7 @@ void LayerTreeHostImpl::AnimateScrollbarsRecursive(LayerImpl* layer, TRACE_EVENT_INSTANT0( "cc", "LayerTreeHostImpl::SetNeedsRedraw due to AnimateScrollbars", TRACE_EVENT_SCOPE_THREAD); - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); } for (size_t i = 0; i < layer->children().size(); ++i) @@ -2549,7 +2724,7 @@ void LayerTreeHostImpl::StartScrollbarAnimationRecursive(LayerImpl* layer, if (delay > base::TimeDelta()) client_->RequestScrollbarAnimationOnImplThread(delay); else if (scrollbar_controller->Animate(time)) - client_->SetNeedsRedrawOnImplThread(); + SetNeedsRedraw(); } for (size_t i = 0; i < layer->children().size(); ++i) @@ -2560,12 +2735,9 @@ void LayerTreeHostImpl::SetTreePriority(TreePriority priority) { if (!tile_manager_) return; - GlobalStateThatImpactsTilePriority new_state(tile_manager_->GlobalState()); - if (new_state.tree_priority == priority) + if (global_tile_state_.tree_priority == priority) return; - - new_state.tree_priority = priority; - tile_manager_->SetGlobalState(new_state); + global_tile_state_.tree_priority = priority; DidModifyTilePriorities(); } @@ -2594,7 +2766,7 @@ base::Time LayerTreeHostImpl::CurrentFrameTime() { } base::TimeTicks LayerTreeHostImpl::CurrentPhysicalTimeTicks() const { - return base::TimeTicks::Now(); + return gfx::FrameTime::Now(); } scoped_ptr<base::Value> LayerTreeHostImpl::AsValueWithFrame( @@ -2630,13 +2802,13 @@ void LayerTreeHostImpl::SetDebugState( paint_time_counter_->ClearHistory(); debug_state_ = new_debug_state; + UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy()); SetFullRootLayerDamage(); } void LayerTreeHostImpl::CreateUIResource(UIResourceId uid, const UIResourceBitmap& bitmap) { DCHECK_GT(uid, 0); - DCHECK_EQ(bitmap.GetFormat(), UIResourceBitmap::RGBA8); GLint wrap_mode = 0; switch (bitmap.GetWrapMode()) { @@ -2653,13 +2825,22 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid, ResourceProvider::ResourceId id = ResourceIdForUIResource(uid); if (id) DeleteUIResource(uid); + + ResourceFormat format = resource_provider_->best_texture_format(); + if (bitmap.GetFormat() == UIResourceBitmap::ETC1) + format = ETC1; id = resource_provider_->CreateResource( bitmap.GetSize(), wrap_mode, ResourceProvider::TextureUsageAny, - resource_provider_->best_texture_format()); + format); + + UIResourceData data; + data.resource_id = id; + data.size = bitmap.GetSize(); + data.opaque = bitmap.GetOpaque(); - ui_resource_map_[uid] = id; + ui_resource_map_[uid] = data; AutoLockUIResourceBitmap bitmap_lock(bitmap); resource_provider_->SetPixels(id, @@ -2687,7 +2868,7 @@ void LayerTreeHostImpl::EvictAllUIResources() { iter != ui_resource_map_.end(); ++iter) { evicted_ui_resources_.insert(iter->first); - resource_provider_->DeleteResource(iter->second); + resource_provider_->DeleteResource(iter->second.resource_id); } ui_resource_map_.clear(); @@ -2700,10 +2881,16 @@ ResourceProvider::ResourceId LayerTreeHostImpl::ResourceIdForUIResource( UIResourceId uid) const { UIResourceMap::const_iterator iter = ui_resource_map_.find(uid); if (iter != ui_resource_map_.end()) - return iter->second; + return iter->second.resource_id; return 0; } +bool LayerTreeHostImpl::IsUIResourceOpaque(UIResourceId uid) const { + UIResourceMap::const_iterator iter = ui_resource_map_.find(uid); + DCHECK(iter != ui_resource_map_.end()); + return iter->second.opaque; +} + bool LayerTreeHostImpl::EvictedUIResourcesExist() const { return !evicted_ui_resources_.empty(); } @@ -2718,4 +2905,23 @@ void LayerTreeHostImpl::MarkUIResourceNotEvicted(UIResourceId uid) { client_->OnCanDrawStateChanged(CanDraw()); } +void LayerTreeHostImpl::ScheduleMicroBenchmark( + scoped_ptr<MicroBenchmarkImpl> benchmark) { + micro_benchmark_controller_.ScheduleRun(benchmark.Pass()); +} + +void LayerTreeHostImpl::InsertSwapPromiseMonitor(SwapPromiseMonitor* monitor) { + swap_promise_monitor_.insert(monitor); +} + +void LayerTreeHostImpl::RemoveSwapPromiseMonitor(SwapPromiseMonitor* monitor) { + swap_promise_monitor_.erase(monitor); +} + +void LayerTreeHostImpl::NotifySwapPromiseMonitorsOfSetNeedsRedraw() { + std::set<SwapPromiseMonitor*>::iterator it = swap_promise_monitor_.begin(); + for (; it != swap_promise_monitor_.end(); it++) + (*it)->OnSetNeedsRedrawOnImpl(); +} + } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h index 6d969012deb..531384f6fdb 100644 --- a/chromium/cc/trees/layer_tree_host_impl.h +++ b/chromium/cc/trees/layer_tree_host_impl.h @@ -17,6 +17,7 @@ #include "cc/animation/animation_events.h" #include "cc/animation/animation_registrar.h" #include "cc/base/cc_export.h" +#include "cc/debug/micro_benchmark_controller_impl.h" #include "cc/input/input_handler.h" #include "cc/input/layer_scroll_offset_delegate.h" #include "cc/input/top_controls_manager_client.h" @@ -47,6 +48,7 @@ class PaintTimeCounter; class MemoryHistory; class RenderingStatsInstrumentation; class RenderPassDrawQuad; +class ScrollbarLayerImplBase; class TextureMailboxDeleter; class TopControlsManager; class UIResourceBitmap; @@ -57,10 +59,13 @@ struct RendererCapabilities; class LayerTreeHostImplClient { public: virtual void DidLoseOutputSurfaceOnImplThread() = 0; + virtual void DidSwapBuffersOnImplThread() = 0; virtual void OnSwapBuffersCompleteOnImplThread() = 0; - virtual void BeginFrameOnImplThread(const BeginFrameArgs& args) = 0; + virtual void BeginImplFrame(const BeginFrameArgs& args) = 0; virtual void OnCanDrawStateChanged(bool can_draw) = 0; virtual void NotifyReadyToActivate() = 0; + // Please call these 2 functions through + // LayerTreeHostImpl's SetNeedsRedraw() and SetNeedsRedrawRect(). virtual void SetNeedsRedrawOnImplThread() = 0; virtual void SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) = 0; virtual void DidInitializeVisibleTileOnImplThread() = 0; @@ -73,12 +78,12 @@ class LayerTreeHostImplClient { virtual bool ReduceContentsTextureMemoryOnImplThread( size_t limit_bytes, int priority_cutoff) = 0; - virtual void ReduceWastedContentsTextureMemoryOnImplThread() = 0; virtual void SendManagedMemoryStats() = 0; virtual bool IsInsideDraw() = 0; virtual void RenewTreePriority() = 0; virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay) = 0; virtual void DidActivatePendingTree() = 0; + virtual void DidManageTiles() = 0; protected: virtual ~LayerTreeHostImplClient() {} @@ -98,7 +103,9 @@ class CC_EXPORT LayerTreeHostImpl const LayerTreeSettings& settings, LayerTreeHostImplClient* client, Proxy* proxy, - RenderingStatsInstrumentation* rendering_stats_instrumentation); + RenderingStatsInstrumentation* rendering_stats_instrumentation, + SharedBitmapManager* manager, + int id); virtual ~LayerTreeHostImpl(); // InputHandler implementation @@ -116,6 +123,7 @@ class CC_EXPORT LayerTreeHostImpl virtual void ScrollEnd() OVERRIDE; virtual InputHandler::ScrollStatus FlingScrollBegin() OVERRIDE; virtual void NotifyCurrentFlingVelocity(gfx::Vector2dF velocity) OVERRIDE; + virtual void MouseMoveAt(gfx::Point viewport_point) OVERRIDE; virtual void PinchGestureBegin() OVERRIDE; virtual void PinchGestureUpdate(float magnify_delta, gfx::Point anchor) OVERRIDE; @@ -126,8 +134,8 @@ class CC_EXPORT LayerTreeHostImpl base::TimeDelta duration) OVERRIDE; virtual void ScheduleAnimation() OVERRIDE; virtual bool HaveTouchEventHandlersAt(gfx::Point viewport_port) OVERRIDE; - virtual void SetLatencyInfoForInputEvent(const ui::LatencyInfo& latency_info) - OVERRIDE; + virtual scoped_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor( + ui::LatencyInfo* latency) OVERRIDE; // TopControlsManagerClient implementation. virtual void DidChangeTopControlsPosition() OVERRIDE; @@ -153,6 +161,7 @@ class CC_EXPORT LayerTreeHostImpl virtual void AppendRenderPass(scoped_ptr<RenderPass> render_pass) OVERRIDE; }; + virtual void BeginMainFrameAborted(bool did_handle); virtual void BeginCommit(); virtual void CommitComplete(); virtual void Animate(base::TimeTicks monotonic_time, @@ -160,6 +169,7 @@ class CC_EXPORT LayerTreeHostImpl virtual void UpdateAnimationState(bool start_ready_animations); void MainThreadHasStoppedFlinging(); void UpdateBackgroundAnimateTicking(bool should_background_tick); + void DidAnimateScrollOffset(); void SetViewportDamage(gfx::Rect damage_rect); virtual void ManageTiles(); @@ -200,15 +210,8 @@ class CC_EXPORT LayerTreeHostImpl // invariant relative to page scale). gfx::SizeF UnscaledScrollableViewportSize() const; - // RendererClient implementation - - // Viewport rectangle and clip in nonflipped window space. These rects - // should only be used by Renderer subclasses to populate glViewport/glClip - // and their software-mode equivalents. - virtual gfx::Rect DeviceViewport() const OVERRIDE; - virtual gfx::Rect DeviceClip() const OVERRIDE; + // RendererClient implementation. virtual void SetFullRootLayerDamage() OVERRIDE; - virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const OVERRIDE; // TileManagerClient implementation. virtual void NotifyReadyToActivate() OVERRIDE; @@ -218,17 +221,17 @@ class CC_EXPORT LayerTreeHostImpl scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE; virtual void ReleaseGL() OVERRIDE; virtual void SetNeedsRedrawRect(gfx::Rect rect) OVERRIDE; - virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE; + virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE; virtual void SetExternalDrawConstraints( const gfx::Transform& transform, gfx::Rect viewport, gfx::Rect clip, bool valid_for_tile_management) OVERRIDE; virtual void DidLoseOutputSurface() OVERRIDE; + virtual void DidSwapBuffers() OVERRIDE; virtual void OnSwapBuffersComplete() OVERRIDE; virtual void ReclaimResources(const CompositorFrameAck* ack) OVERRIDE; virtual void SetMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE; - virtual void SetDiscardBackBufferWhenNotVisible(bool discard) OVERRIDE; virtual void SetTreeActivationCallback(const base::Closure& callback) OVERRIDE; @@ -257,7 +260,7 @@ class CC_EXPORT LayerTreeHostImpl const RendererCapabilities& GetRendererCapabilities() const; virtual bool SwapBuffers(const FrameData& frame); - void SetNeedsBeginFrame(bool enable); + void SetNeedsBeginImplFrame(bool enable); void DidModifyTilePriorities(); void Readback(void* pixels, gfx::Rect rect_in_device_viewport); @@ -276,11 +279,17 @@ class CC_EXPORT LayerTreeHostImpl LayerImpl* RootScrollLayer() const; LayerImpl* CurrentlyScrollingLayer() const; + int scroll_layer_id_when_mouse_over_scrollbar() { + return scroll_layer_id_when_mouse_over_scrollbar_; + } + + bool IsCurrentlyScrolling() const; + virtual void SetVisible(bool visible); bool visible() const { return visible_; } void SetNeedsCommit() { client_->SetNeedsCommitOnImplThread(); } - void SetNeedsRedraw() { client_->SetNeedsRedrawOnImplThread(); } + void SetNeedsRedraw(); ManagedMemoryPolicy ActualManagedMemoryPolicy() const; @@ -343,26 +352,6 @@ class CC_EXPORT LayerTreeHostImpl void SetDebugState(const LayerTreeDebugState& new_debug_state); const LayerTreeDebugState& debug_state() const { return debug_state_; } - class CC_EXPORT CullRenderPassesWithCachedTextures { - public: - bool ShouldRemoveRenderPass(const RenderPassDrawQuad& quad, - const FrameData& frame) const; - - // Iterates from the root first, in order to remove the surfaces closest - // to the root with cached textures, and all surfaces that draw into - // them. - size_t RenderPassListBegin(const RenderPassList& list) const { - return list.size() - 1; - } - size_t RenderPassListEnd(const RenderPassList& list) const { return 0 - 1; } - size_t RenderPassListNext(size_t it) const { return it - 1; } - - explicit CullRenderPassesWithCachedTextures(Renderer* renderer) - : renderer_(renderer) {} - private: - Renderer* renderer_; - }; - class CC_EXPORT CullRenderPassesWithNoQuads { public: bool ShouldRemoveRenderPass(const RenderPassDrawQuad& quad, @@ -413,12 +402,38 @@ class CC_EXPORT LayerTreeHostImpl virtual ResourceProvider::ResourceId ResourceIdForUIResource( UIResourceId uid) const; + virtual bool IsUIResourceOpaque(UIResourceId uid) const; + + struct UIResourceData { + ResourceProvider::ResourceId resource_id; + gfx::Size size; + bool opaque; + }; + + void ScheduleMicroBenchmark(scoped_ptr<MicroBenchmarkImpl> benchmark); + + CompositorFrameMetadata MakeCompositorFrameMetadata() const; + // Viewport rectangle and clip in nonflipped window space. These rects + // should only be used by Renderer subclasses to populate glViewport/glClip + // and their software-mode equivalents. + gfx::Rect DeviceViewport() const; + gfx::Rect DeviceClip() const; + + // When a SwapPromiseMonitor is created on the impl thread, it calls + // InsertSwapPromiseMonitor() to register itself with LayerTreeHostImpl. + // When the monitor is destroyed, it calls RemoveSwapPromiseMonitor() + // to unregister itself. + void InsertSwapPromiseMonitor(SwapPromiseMonitor* monitor); + void RemoveSwapPromiseMonitor(SwapPromiseMonitor* monitor); + protected: LayerTreeHostImpl( const LayerTreeSettings& settings, LayerTreeHostImplClient* client, Proxy* proxy, - RenderingStatsInstrumentation* rendering_stats_instrumentation); + RenderingStatsInstrumentation* rendering_stats_instrumentation, + SharedBitmapManager* manager, + int id); // Virtual for testing. virtual void AnimateLayers(base::TimeTicks monotonic_time, @@ -474,11 +489,21 @@ class CC_EXPORT LayerTreeHostImpl bool EnsureRenderSurfaceLayerList(); void ClearCurrentlyScrollingLayer(); + bool HandleMouseOverScrollbar(LayerImpl* layer_impl, + gfx::PointF device_viewport_point); + void AnimateScrollbarsRecursive(LayerImpl* layer, base::TimeTicks time); void UpdateCurrentFrameTime(base::TimeTicks* ticks, base::Time* now) const; + LayerImpl* FindScrollLayerForDeviceViewportPoint( + gfx::PointF device_viewport_point, + InputHandler::ScrollInputType type, + LayerImpl* layer_hit_by_point, + bool* scroll_on_main_thread) const; + float DeviceSpaceDistanceToLayer(gfx::PointF device_viewport_point, + LayerImpl* layer_impl); void StartScrollbarAnimationRecursive(LayerImpl* layer, base::TimeTicks time); void SetManagedMemoryPolicy(const ManagedMemoryPolicy& policy, bool zero_budget); @@ -488,7 +513,9 @@ class CC_EXPORT LayerTreeHostImpl void MarkUIResourceNotEvicted(UIResourceId uid); - typedef base::hash_map<UIResourceId, ResourceProvider::ResourceId> + void NotifySwapPromiseMonitorsOfSetNeedsRedraw(); + + typedef base::hash_map<UIResourceId, UIResourceData> UIResourceMap; UIResourceMap ui_resource_map_; @@ -506,6 +533,8 @@ class CC_EXPORT LayerTreeHostImpl scoped_ptr<TileManager> tile_manager_; scoped_ptr<Renderer> renderer_; + GlobalStateThatImpactsTilePriority global_tile_state_; + // Tree currently being drawn. scoped_ptr<LayerTreeImpl> active_tree_; @@ -520,7 +549,9 @@ class CC_EXPORT LayerTreeHostImpl InputHandlerClient* input_handler_client_; bool did_lock_scrolling_layer_; bool should_bubble_scrolls_; + bool last_scroll_did_bubble_; bool wheel_scrolling_; + int scroll_layer_id_when_mouse_over_scrollbar_; bool tile_priorities_dirty_; @@ -535,6 +566,7 @@ class CC_EXPORT LayerTreeHostImpl gfx::Vector2dF current_fling_velocity_; bool pinch_gesture_active_; + bool pinch_gesture_end_should_clear_scrolling_layer_; gfx::Point previous_pinch_anchor_; // This is set by AnimateLayers() and used by UpdateAnimationState() @@ -606,12 +638,21 @@ class CC_EXPORT LayerTreeHostImpl scoped_ptr<AnimationRegistrar> animation_registrar_; RenderingStatsInstrumentation* rendering_stats_instrumentation_; + MicroBenchmarkControllerImpl micro_benchmark_controller_; bool need_to_update_visible_tiles_before_draw_; +#ifndef NDEBUG + bool did_lose_called_; +#endif // Optional callback to notify of new tree activations. base::Closure tree_activation_callback_; + SharedBitmapManager* shared_bitmap_manager_; + int id_; + + std::set<SwapPromiseMonitor*> swap_promise_monitor_; + DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl); }; diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc index 6bd815b9424..4630adc555d 100644 --- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc @@ -10,8 +10,9 @@ #include "base/command_line.h" #include "base/containers/hash_tables.h" #include "base/containers/scoped_ptr_hash_map.h" +#include "cc/animation/scrollbar_animation_controller_thinning.h" +#include "cc/base/latency_info_swap_promise.h" #include "cc/base/math_util.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/input/top_controls_manager.h" #include "cc/layers/delegated_renderer_layer_impl.h" #include "cc/layers/heads_up_display_layer_impl.h" @@ -34,6 +35,7 @@ #include "cc/quads/solid_color_draw_quad.h" #include "cc/quads/texture_draw_quad.h" #include "cc/quads/tile_draw_quad.h" +#include "cc/resources/etc1_pixel_ref.h" #include "cc/resources/layer_tiling_data.h" #include "cc/test/animation_test_common.h" #include "cc/test/fake_layer_tree_host_impl.h" @@ -47,11 +49,13 @@ #include "cc/test/geometry_test_utils.h" #include "cc/test/layer_test_common.h" #include "cc/test/render_pass_test_common.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "cc/trees/layer_tree_impl.h" #include "cc/trees/single_thread_proxy.h" #include "media/base/media.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/frame_time.h" #include "ui/gfx/rect_conversions.h" #include "ui/gfx/size_conversions.h" #include "ui/gfx/vector2d_conversions.h" @@ -79,35 +83,30 @@ class LayerTreeHostImplTest : public testing::Test, did_request_redraw_(false), did_request_manage_tiles_(false), did_upload_visible_tile_(false), - did_lose_output_surface_(false), reduce_memory_result_(true), current_limit_bytes_(0), current_priority_cutoff_value_(0) { media::InitializeMediaLibraryForTesting(); } - virtual void SetUp() OVERRIDE { + LayerTreeSettings DefaultSettings() { LayerTreeSettings settings; settings.minimum_occlusion_tracking_size = gfx::Size(); settings.impl_side_painting = true; - settings.solid_color_scrollbars = true; + settings.texture_id_allocation_chunk_size = 1; + return settings; + } - host_impl_ = LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - host_impl_->InitializeRenderer(CreateOutputSurface()); - host_impl_->SetViewportSize(gfx::Size(10, 10)); + virtual void SetUp() OVERRIDE { + CreateHostImpl(DefaultSettings(), CreateOutputSurface()); } virtual void TearDown() OVERRIDE {} - virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE { - did_lose_output_surface_ = true; - } + virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE {} + virtual void DidSwapBuffersOnImplThread() OVERRIDE {} virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {} - virtual void BeginFrameOnImplThread(const BeginFrameArgs& args) - OVERRIDE {} + virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE {} virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE { on_can_draw_state_changed_called_ = true; } @@ -139,31 +138,25 @@ class LayerTreeHostImplTest : public testing::Test, current_priority_cutoff_value_ = priority_cutoff; return reduce_memory_result_; } - virtual void ReduceWastedContentsTextureMemoryOnImplThread() OVERRIDE {} virtual void SendManagedMemoryStats() OVERRIDE {} virtual bool IsInsideDraw() OVERRIDE { return false; } virtual void RenewTreePriority() OVERRIDE {} virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay) OVERRIDE { requested_scrollbar_animation_delay_ = delay; } virtual void DidActivatePendingTree() OVERRIDE {} + virtual void DidManageTiles() OVERRIDE {} void set_reduce_memory_result(bool reduce_memory_result) { reduce_memory_result_ = reduce_memory_result; } - void CreateLayerTreeHost(bool partial_swap, - scoped_ptr<OutputSurface> output_surface) { - LayerTreeSettings settings; - settings.minimum_occlusion_tracking_size = gfx::Size(); - settings.partial_swap_enabled = partial_swap; - - host_impl_ = LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - - host_impl_->InitializeRenderer(output_surface.Pass()); + bool CreateHostImpl(const LayerTreeSettings& settings, + scoped_ptr<OutputSurface> output_surface) { + host_impl_ = LayerTreeHostImpl::Create( + settings, this, &proxy_, &stats_instrumentation_, NULL, 0); + bool init = host_impl_->InitializeRenderer(output_surface.Pass()); host_impl_->SetViewportSize(gfx::Size(10, 10)); + return init; } void SetupRootLayerImpl(scoped_ptr<LayerImpl> root) { @@ -194,7 +187,7 @@ class LayerTreeHostImplTest : public testing::Test, times_encountered++; } - ASSERT_EQ(times_encountered, 1); + ASSERT_EQ(1, times_encountered); } static void ExpectNone(const ScrollAndScaleSet& scroll_info, int id) { @@ -209,16 +202,17 @@ class LayerTreeHostImplTest : public testing::Test, ASSERT_EQ(0, times_encountered); } - LayerImpl* SetupScrollAndContentsLayers(gfx::Size content_size) { + LayerImpl* CreateScrollAndContentsLayers(LayerTreeImpl* layer_tree_impl, + gfx::Size content_size) { scoped_ptr<LayerImpl> root = - LayerImpl::Create(host_impl_->active_tree(), 1); + LayerImpl::Create(layer_tree_impl, 1); root->SetBounds(content_size); root->SetContentBounds(content_size); root->SetPosition(gfx::PointF()); root->SetAnchorPoint(gfx::PointF()); scoped_ptr<LayerImpl> scroll = - LayerImpl::Create(host_impl_->active_tree(), 2); + LayerImpl::Create(layer_tree_impl, 2); LayerImpl* scroll_layer = scroll.get(); scroll->SetScrollable(true); scroll->SetScrollOffset(gfx::Vector2d()); @@ -230,7 +224,7 @@ class LayerTreeHostImplTest : public testing::Test, scroll->SetAnchorPoint(gfx::PointF()); scoped_ptr<LayerImpl> contents = - LayerImpl::Create(host_impl_->active_tree(), 3); + LayerImpl::Create(layer_tree_impl, 3); contents->SetDrawsContent(true); contents->SetBounds(content_size); contents->SetContentBounds(content_size); @@ -240,7 +234,13 @@ class LayerTreeHostImplTest : public testing::Test, scroll->AddChild(contents.Pass()); root->AddChild(scroll.Pass()); - host_impl_->active_tree()->SetRootLayer(root.Pass()); + layer_tree_impl->SetRootLayer(root.Pass()); + return scroll_layer; + } + + LayerImpl* SetupScrollAndContentsLayers(gfx::Size content_size) { + LayerImpl* scroll_layer = CreateScrollAndContentsLayers( + host_impl_->active_tree(), content_size); host_impl_->active_tree()->DidBecomeActive(); return scroll_layer; } @@ -257,15 +257,10 @@ class LayerTreeHostImplTest : public testing::Test, return layer.Pass(); } - void InitializeRendererAndDrawFrame() { - host_impl_->InitializeRenderer(CreateOutputSurface()); - DrawFrame(); - } - void DrawFrame() { LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -319,7 +314,6 @@ class LayerTreeHostImplTest : public testing::Test, set_reduce_memory_result(false); host_impl_->SetMemoryPolicy(ManagedMemoryPolicy( host_impl_->memory_allocation_limit_bytes() - 1)); - host_impl_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_TRUE(host_impl_->CanDraw()); EXPECT_FALSE(on_can_draw_state_changed_called_); on_can_draw_state_changed_called_ = false; @@ -328,7 +322,6 @@ class LayerTreeHostImplTest : public testing::Test, set_reduce_memory_result(true); host_impl_->SetMemoryPolicy(ManagedMemoryPolicy( host_impl_->memory_allocation_limit_bytes() - 1)); - host_impl_->SetDiscardBackBufferWhenNotVisible(true); if (always_draw) { EXPECT_TRUE(host_impl_->CanDraw()); } else { @@ -343,6 +336,8 @@ class LayerTreeHostImplTest : public testing::Test, on_can_draw_state_changed_called_ = false; } + void SetupMouseMoveAtWithDeviceScale(float device_scale_factor); + protected: virtual scoped_ptr<OutputSurface> CreateOutputSurface() { return CreateFakeOutputSurface(); @@ -366,7 +361,6 @@ class LayerTreeHostImplTest : public testing::Test, bool did_request_redraw_; bool did_request_manage_tiles_; bool did_upload_visible_tile_; - bool did_lose_output_surface_; bool reduce_memory_result_; base::TimeDelta requested_scrollbar_animation_delay_; size_t current_limit_bytes_; @@ -379,17 +373,9 @@ TEST_F(LayerTreeHostImplTest, NotifyIfCanDrawChanged) { } TEST_F(LayerTreeHostImplTest, CanDrawIncompleteFrames) { - LayerTreeSettings settings; - settings.impl_side_painting = true; - host_impl_ = LayerTreeHostImpl::Create( - settings, this, &proxy_, &stats_instrumentation_); - scoped_ptr<FakeOutputSurface> output_surface( FakeOutputSurface::CreateAlwaysDrawAndSwap3d()); - - host_impl_->InitializeRenderer( - output_surface.PassAs<OutputSurface>()); - host_impl_->SetViewportSize(gfx::Size(10, 10)); + CreateHostImpl(DefaultSettings(), output_surface.PassAs<OutputSurface>()); bool always_draw = true; CheckNotifyCalledIfCanDrawChanged(always_draw); @@ -467,7 +453,7 @@ TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) { TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); @@ -484,21 +470,16 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutRootLayer) { } TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) { - LayerTreeSettings settings; - host_impl_ = LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); scoped_ptr<TestWebGraphicsContext3D> context_owned = TestWebGraphicsContext3D::Create(); - context_owned->set_times_make_current_succeeds(0); + context_owned->set_context_lost(true); scoped_ptr<FakeOutputSurface> output_surface(FakeOutputSurface::Create3d( context_owned.Pass())); - // Initialization will fail here. - host_impl_->InitializeRenderer(output_surface.PassAs<OutputSurface>()); - host_impl_->SetViewportSize(gfx::Size(10, 10)); + // Initialization will fail. + EXPECT_FALSE(CreateHostImpl(DefaultSettings(), + output_surface.PassAs<OutputSurface>())); SetupScrollAndContentsLayers(gfx::Size(100, 100)); @@ -511,7 +492,7 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) { TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) { LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); // We should not crash if the tree is replaced while we are scrolling. EXPECT_EQ(InputHandler::ScrollStarted, @@ -532,7 +513,7 @@ TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) { TEST_F(LayerTreeHostImplTest, ClearRootRenderSurfaceAndScroll) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); // We should be able to scroll even if the root layer loses its render surface // after the most recent render. @@ -546,7 +527,7 @@ TEST_F(LayerTreeHostImplTest, ClearRootRenderSurfaceAndScroll) { TEST_F(LayerTreeHostImplTest, WheelEventHandlers) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); LayerImpl* root = host_impl_->active_tree()->root_layer(); root->SetHaveWheelEventHandlers(true); @@ -564,7 +545,7 @@ TEST_F(LayerTreeHostImplTest, WheelEventHandlers) { TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchscreen) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); // Ignore the fling since no layer is being scrolled EXPECT_EQ(InputHandler::ScrollIgnored, @@ -582,7 +563,7 @@ TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchscreen) { TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchpad) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); // Ignore the fling since no layer is being scrolled EXPECT_EQ(InputHandler::ScrollIgnored, @@ -600,7 +581,7 @@ TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchpad) { TEST_F(LayerTreeHostImplTest, NoFlingWhenScrollingOnMain) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); LayerImpl* root = host_impl_->active_tree()->root_layer(); root->SetShouldScrollOnMainThread(true); @@ -617,7 +598,7 @@ TEST_F(LayerTreeHostImplTest, NoFlingWhenScrollingOnMain) { TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); LayerImpl* root = host_impl_->active_tree()->root_layer(); root->SetShouldScrollOnMainThread(true); @@ -636,7 +617,7 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) { root->SetContentsScale(2.f, 2.f); root->SetNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); // All scroll types inside the non-fast scrollable region should fail. EXPECT_EQ(InputHandler::ScrollOnMainThread, @@ -668,7 +649,7 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) { root->SetNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50)); root->SetPosition(gfx::PointF(-25.f, 0.f)); - InitializeRendererAndDrawFrame(); + DrawFrame(); // This point would fall into the non-fast scrollable region except that we've // moved the layer down by 25 pixels. @@ -688,7 +669,7 @@ TEST_F(LayerTreeHostImplTest, ScrollByReturnsCorrectValue) { SetupScrollAndContentsLayers(gfx::Size(200, 200)); host_impl_->SetViewportSize(gfx::Size(100, 100)); - InitializeRendererAndDrawFrame(); + DrawFrame(); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); @@ -721,7 +702,7 @@ TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) { SetupScrollAndContentsLayers(gfx::Size(200, 2000)); host_impl_->SetViewportSize(gfx::Size(100, 1000)); - InitializeRendererAndDrawFrame(); + DrawFrame(); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(), @@ -750,11 +731,68 @@ TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) { gfx::Point(), SCROLL_BACKWARD)); } +// The user-scrollability breaks for zoomed-in pages. So disable this. +// http://crbug.com/322223 +TEST_F(LayerTreeHostImplTest, DISABLED_ScrollWithUserUnscrollableLayers) { + LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(200, 200)); + host_impl_->SetViewportSize(gfx::Size(100, 100)); + + gfx::Size overflow_size(400, 400); + ASSERT_EQ(1u, scroll_layer->children().size()); + LayerImpl* overflow = scroll_layer->children()[0]; + overflow->SetBounds(overflow_size); + overflow->SetContentBounds(overflow_size); + overflow->SetScrollable(true); + overflow->SetMaxScrollOffset(gfx::Vector2d(overflow_size.width(), + overflow_size.height())); + overflow->SetScrollOffset(gfx::Vector2d()); + overflow->SetPosition(gfx::PointF()); + overflow->SetAnchorPoint(gfx::PointF()); + + DrawFrame(); + gfx::Point scroll_position(10, 10); + + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(scroll_position, InputHandler::Wheel)); + EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->TotalScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(), overflow->TotalScrollOffset()); + + gfx::Vector2dF scroll_delta(10, 10); + host_impl_->ScrollBy(scroll_position, scroll_delta); + host_impl_->ScrollEnd(); + EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->TotalScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->TotalScrollOffset()); + + overflow->set_user_scrollable_horizontal(false); + + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(scroll_position, InputHandler::Wheel)); + EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->TotalScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->TotalScrollOffset()); + + host_impl_->ScrollBy(scroll_position, scroll_delta); + host_impl_->ScrollEnd(); + EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 0), scroll_layer->TotalScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->TotalScrollOffset()); + + overflow->set_user_scrollable_vertical(false); + + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(scroll_position, InputHandler::Wheel)); + EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 0), scroll_layer->TotalScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->TotalScrollOffset()); + + host_impl_->ScrollBy(scroll_position, scroll_delta); + host_impl_->ScrollEnd(); + EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 10), scroll_layer->TotalScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->TotalScrollOffset()); +} + TEST_F(LayerTreeHostImplTest, ClearRootRenderSurfaceAndHitTestTouchHandlerRegion) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); // We should be able to hit test for touch event handlers even if the root // layer loses its render surface after the most recent render. @@ -767,7 +805,7 @@ TEST_F(LayerTreeHostImplTest, TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); EXPECT_EQ(scroll_layer, host_impl_->RootScrollLayer()); @@ -831,7 +869,7 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { TEST_F(LayerTreeHostImplTest, PinchGesture) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); LayerImpl* scroll_layer = host_impl_->RootScrollLayer(); DCHECK(scroll_layer); @@ -974,7 +1012,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); LayerImpl* scroll_layer = host_impl_->RootScrollLayer(); DCHECK(scroll_layer); @@ -1044,7 +1082,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); - InitializeRendererAndDrawFrame(); + DrawFrame(); LayerImpl* scroll_layer = host_impl_->RootScrollLayer(); DCHECK(scroll_layer); @@ -1088,8 +1126,9 @@ class LayerTreeHostImplOverridePhysicalTime : public LayerTreeHostImpl { : LayerTreeHostImpl(settings, client, proxy, - rendering_stats_instrumentation) {} - + rendering_stats_instrumentation, + NULL, + 0) {} virtual base::TimeTicks CurrentPhysicalTimeTicks() const OVERRIDE { return fake_current_physical_time_; @@ -1103,7 +1142,7 @@ class LayerTreeHostImplOverridePhysicalTime : public LayerTreeHostImpl { base::TimeTicks fake_current_physical_time_; }; -TEST_F(LayerTreeHostImplTest, DISABLED_ScrollbarLinearFadeScheduling) { +TEST_F(LayerTreeHostImplTest, ScrollbarLinearFadeScheduling) { LayerTreeSettings settings; settings.scrollbar_animator = LayerTreeSettings::LinearFade; settings.scrollbar_linear_fade_delay_ms = 20; @@ -1115,7 +1154,7 @@ TEST_F(LayerTreeHostImplTest, DISABLED_ScrollbarLinearFadeScheduling) { LayerTreeHostImplOverridePhysicalTime* host_impl_override_time = new LayerTreeHostImplOverridePhysicalTime( settings, this, &proxy_, &stats_instrumentation_); - host_impl_ = make_scoped_ptr<LayerTreeHostImpl>(host_impl_override_time); + host_impl_ = make_scoped_ptr(host_impl_override_time); host_impl_->InitializeRenderer(CreateOutputSurface()); host_impl_->SetViewportSize(viewport_size); @@ -1148,9 +1187,9 @@ TEST_F(LayerTreeHostImplTest, DISABLED_ScrollbarLinearFadeScheduling) { host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->active_tree()->DidBecomeActive(); - InitializeRendererAndDrawFrame(); + DrawFrame(); - base::TimeTicks fake_now = base::TimeTicks::Now(); + base::TimeTicks fake_now = gfx::FrameTime::Now(); host_impl_override_time->SetCurrentPhysicalTimeTicksForTest(fake_now); // If no scroll happened recently, StartScrollbarAnimation should have no @@ -1211,11 +1250,99 @@ TEST_F(LayerTreeHostImplTest, DISABLED_ScrollbarLinearFadeScheduling) { EXPECT_EQ(fake_now, host_impl_->CurrentFrameTimeTicks()); } +void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale( + float device_scale_factor) { + LayerTreeSettings settings; + settings.scrollbar_animator = LayerTreeSettings::Thinning; + + gfx::Size viewport_size(300, 200); + gfx::Size device_viewport_size = gfx::ToFlooredSize( + gfx::ScaleSize(viewport_size, device_scale_factor)); + gfx::Size content_size(1000, 1000); + + CreateHostImpl(settings, CreateOutputSurface()); + host_impl_->SetDeviceScaleFactor(device_scale_factor); + host_impl_->SetViewportSize(device_viewport_size); + + scoped_ptr<LayerImpl> root = + LayerImpl::Create(host_impl_->active_tree(), 1); + root->SetBounds(viewport_size); + + scoped_ptr<LayerImpl> scroll = + LayerImpl::Create(host_impl_->active_tree(), 2); + scroll->SetScrollable(true); + scroll->SetScrollOffset(gfx::Vector2d()); + scroll->SetMaxScrollOffset(gfx::Vector2d(content_size.width(), + content_size.height())); + scroll->SetBounds(content_size); + scroll->SetContentBounds(content_size); + + scoped_ptr<LayerImpl> contents = + LayerImpl::Create(host_impl_->active_tree(), 3); + contents->SetDrawsContent(true); + contents->SetBounds(content_size); + contents->SetContentBounds(content_size); + + // The scrollbar is on the right side. + scoped_ptr<PaintedScrollbarLayerImpl> scrollbar = + PaintedScrollbarLayerImpl::Create(host_impl_->active_tree(), 5, VERTICAL); + scrollbar->SetDrawsContent(true); + scrollbar->SetBounds(gfx::Size(15, viewport_size.height())); + scrollbar->SetContentBounds(gfx::Size(15, viewport_size.height())); + scrollbar->SetPosition(gfx::Point(285, 0)); + scroll->SetVerticalScrollbarLayer(scrollbar.get()); + + scroll->AddChild(contents.Pass()); + root->AddChild(scroll.Pass()); + root->AddChild(scrollbar.PassAs<LayerImpl>()); + + host_impl_->active_tree()->SetRootLayer(root.Pass()); + host_impl_->active_tree()->DidBecomeActive(); + DrawFrame(); + + LayerImpl* root_scroll = host_impl_->active_tree()->RootScrollLayer(); + ASSERT_TRUE(root_scroll->scrollbar_animation_controller()); + ScrollbarAnimationControllerThinning* scrollbar_animation_controller = + static_cast<ScrollbarAnimationControllerThinning*>( + root_scroll->scrollbar_animation_controller()); + scrollbar_animation_controller->set_mouse_move_distance_for_test(100.f); + + host_impl_->MouseMoveAt(gfx::Point(1, 1)); + EXPECT_FALSE(scrollbar_animation_controller->mouse_is_near_scrollbar()); + + host_impl_->MouseMoveAt(gfx::Point(200, 50)); + EXPECT_TRUE(scrollbar_animation_controller->mouse_is_near_scrollbar()); + + host_impl_->MouseMoveAt(gfx::Point(184, 100)); + EXPECT_FALSE(scrollbar_animation_controller->mouse_is_near_scrollbar()); + + scrollbar_animation_controller->set_mouse_move_distance_for_test(102.f); + host_impl_->MouseMoveAt(gfx::Point(184, 100)); + EXPECT_TRUE(scrollbar_animation_controller->mouse_is_near_scrollbar()); + + did_request_redraw_ = false; + EXPECT_EQ(0, host_impl_->scroll_layer_id_when_mouse_over_scrollbar()); + host_impl_->MouseMoveAt(gfx::Point(290, 100)); + EXPECT_EQ(2, host_impl_->scroll_layer_id_when_mouse_over_scrollbar()); + host_impl_->MouseMoveAt(gfx::Point(290, 120)); + EXPECT_EQ(2, host_impl_->scroll_layer_id_when_mouse_over_scrollbar()); + host_impl_->MouseMoveAt(gfx::Point(150, 120)); + EXPECT_EQ(0, host_impl_->scroll_layer_id_when_mouse_over_scrollbar()); +} + +TEST_F(LayerTreeHostImplTest, MouseMoveAtWithDeviceScaleOf1) { + SetupMouseMoveAtWithDeviceScale(1.f); +} + +TEST_F(LayerTreeHostImplTest, MouseMoveAtWithDeviceScaleOf2) { + SetupMouseMoveAtWithDeviceScale(2.f); +} + TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f); - InitializeRendererAndDrawFrame(); + DrawFrame(); { CompositorFrameMetadata metadata = host_impl_->MakeCompositorFrameMetadata(); @@ -1356,7 +1483,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawReturningFalseDoesNotCall) { { LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect(10, 10))); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); EXPECT_TRUE(layer->will_draw_called()); @@ -1371,7 +1498,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawReturningFalseDoesNotCall) { layer->ClearDidDrawCheck(); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect(10, 10))); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); EXPECT_TRUE(layer->will_draw_called()); @@ -1403,7 +1530,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) { EXPECT_FALSE(layer->did_draw_called()); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); EXPECT_FALSE(layer->will_draw_called()); @@ -1418,7 +1545,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) { EXPECT_FALSE(layer->did_draw_called()); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); EXPECT_TRUE(layer->will_draw_called()); @@ -1457,7 +1584,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawNotCalledOnOccludedLayer) { EXPECT_FALSE(top_layer->did_draw_called()); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); EXPECT_FALSE(occluded_layer->will_draw_called()); @@ -1489,7 +1616,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) { LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); EXPECT_TRUE(root->did_draw_called()); @@ -1562,7 +1689,7 @@ TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) { LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); // When a texture is missing and we're not animating, we draw as usual with @@ -1580,7 +1707,7 @@ TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) { host_impl_->resource_provider())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); // When a texture is missing and we're animating, we don't want to draw @@ -1598,7 +1725,7 @@ TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) { host_impl_->resource_provider())); EXPECT_FALSE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); // When the layer skips draw and we're animating, we still draw the frame. @@ -1615,7 +1742,7 @@ TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) { host_impl_->resource_provider())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -1623,7 +1750,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) { scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); root->SetScrollable(false); host_impl_->active_tree()->SetRootLayer(root.Pass()); - InitializeRendererAndDrawFrame(); + DrawFrame(); // Scroll event is ignored because layer is not scrollable. EXPECT_EQ(InputHandler::ScrollIgnored, @@ -1637,12 +1764,7 @@ TEST_F(LayerTreeHostImplTest, ScrollNonScrollableRootWithTopControls) { settings.calculate_top_controls_position = true; settings.top_controls_height = 50; - host_impl_ = LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - host_impl_->InitializeRenderer(CreateOutputSurface()); - host_impl_->SetViewportSize(gfx::Size(10, 10)); + CreateHostImpl(settings, CreateOutputSurface()); gfx::Size layer_size(5, 5); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); @@ -1656,7 +1778,7 @@ TEST_F(LayerTreeHostImplTest, ScrollNonScrollableRootWithTopControls) { root->SetDrawsContent(false); host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->active_tree()->FindRootScrollLayer(); - InitializeRendererAndDrawFrame(); + DrawFrame(); EXPECT_EQ(InputHandler::ScrollIgnored, host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); @@ -1699,7 +1821,7 @@ TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) { host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass()); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(5, 5), @@ -1718,7 +1840,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildCallsCommitAndRedraw) { root->AddChild(CreateScrollableLayer(2, surface_size)); host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(5, 5), @@ -1735,7 +1857,7 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesChild) { root->AddChild(CreateScrollableLayer(2, surface_size)); host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); // Scroll event is ignored because the input coordinate is outside the layer // boundaries. @@ -1759,7 +1881,7 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) { root->AddChild(child.Pass()); host_impl_->active_tree()->SetRootLayer(root.Pass()); - InitializeRendererAndDrawFrame(); + DrawFrame(); // Scroll event is ignored because the scrollable layer is not facing the // viewer and there is nothing scrollable behind it. @@ -1781,7 +1903,7 @@ TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) { host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass()); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); // Scrolling fails because the content layer is asking to be scrolled on the // main thread. @@ -1799,7 +1921,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); LayerImpl* root_scroll = host_impl_->active_tree()->RootScrollLayer(); @@ -1838,7 +1960,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, page_scale); - InitializeRendererAndDrawFrame(); + DrawFrame(); LayerImpl* root_scroll = host_impl_->active_tree()->RootScrollLayer(); @@ -1911,7 +2033,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) { // the page scale delta on the root layer is applied hierarchically. LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); EXPECT_EQ(1.f, root->draw_transform().matrix().getDouble(0, 0)); @@ -1943,7 +2065,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) { host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); gfx::Vector2d scroll_delta(0, 10); gfx::Vector2d expected_scroll_delta(scroll_delta); @@ -1991,7 +2113,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) { host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); { gfx::Vector2d scroll_delta(-8, -7); EXPECT_EQ(InputHandler::ScrollStarted, @@ -2032,7 +2154,7 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); { gfx::Vector2d scroll_delta(0, -10); EXPECT_EQ(InputHandler::ScrollStarted, @@ -2124,7 +2246,7 @@ TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) { host_impl_->SetViewportSize(surface_size); host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->active_tree()->DidBecomeActive(); - InitializeRendererAndDrawFrame(); + DrawFrame(); { gfx::Vector2d scroll_delta(0, 4); EXPECT_EQ(InputHandler::ScrollStarted, @@ -2153,7 +2275,7 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) { // Draw one frame and then immediately rebuild the layer tree to mimic a tree // synchronization. - InitializeRendererAndDrawFrame(); + DrawFrame(); host_impl_->active_tree()->DetachLayerTree(); host_impl_->active_tree()->SetRootLayer( CreateScrollableLayer(2, surface_size)); @@ -2175,7 +2297,7 @@ TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) { gfx::Size surface_size(50, 50); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); // Scroll to the right in screen coordinates with a gesture. gfx::Vector2d gesture_scroll_delta(10, 0); @@ -2228,7 +2350,7 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { gfx::Size surface_size(50, 50); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); { // Scroll down in screen coordinates with a gesture. gfx::Vector2d gesture_scroll_delta(0, 10); @@ -2297,7 +2419,7 @@ TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) { gfx::Size surface_size(50, 50); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); // Scroll down in screen coordinates with a gesture. gfx::Vector2d scroll_delta(0, 10); @@ -2330,9 +2452,14 @@ TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) { class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate { public: - TestScrollOffsetDelegate() {} + TestScrollOffsetDelegate() : page_scale_factor_(0.f) {} + virtual ~TestScrollOffsetDelegate() {} + virtual void SetMaxScrollOffset(gfx::Vector2dF max_scroll_offset) OVERRIDE { + max_scroll_offset_ = max_scroll_offset; + } + virtual void SetTotalScrollOffset(gfx::Vector2dF new_value) OVERRIDE { last_set_scroll_offset_ = new_value; } @@ -2341,6 +2468,16 @@ class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate { return getter_return_value_; } + virtual bool IsExternalFlingActive() const OVERRIDE { return false; } + + virtual void SetTotalPageScaleFactor(float page_scale_factor) OVERRIDE { + page_scale_factor_ = page_scale_factor; + } + + virtual void SetScrollableSize(gfx::SizeF scrollable_size) OVERRIDE { + scrollable_size_ = scrollable_size; + } + gfx::Vector2dF last_set_scroll_offset() { return last_set_scroll_offset_; } @@ -2349,13 +2486,29 @@ class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate { getter_return_value_ = value; } + gfx::Vector2dF max_scroll_offset() const { + return max_scroll_offset_; + } + + gfx::SizeF scrollable_size() const { + return scrollable_size_; + } + + float page_scale_factor() const { + return page_scale_factor_; + } + private: gfx::Vector2dF last_set_scroll_offset_; gfx::Vector2dF getter_return_value_; + gfx::Vector2dF max_scroll_offset_; + gfx::SizeF scrollable_size_; + float page_scale_factor_; }; TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { TestScrollOffsetDelegate scroll_delegate; + host_impl_->SetViewportSize(gfx::Size(10, 20)); LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); // Setting the delegate results in the current scroll offset being set. @@ -2366,6 +2519,21 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { EXPECT_EQ(initial_scroll_delta.ToString(), scroll_delegate.last_set_scroll_offset().ToString()); + // Setting the delegate results in the scrollable_size, max_scroll_offset and + // page_scale being set. + EXPECT_EQ(gfx::SizeF(100, 100), scroll_delegate.scrollable_size()); + EXPECT_EQ(gfx::Vector2dF(90, 80), scroll_delegate.max_scroll_offset()); + EXPECT_EQ(1.f, scroll_delegate.page_scale_factor()); + + // Updating page scale immediately updates the delegate. + host_impl_->active_tree()->SetPageScaleFactorAndLimits(2.f, 0.5f, 4.f); + EXPECT_EQ(2.f, scroll_delegate.page_scale_factor()); + host_impl_->active_tree()->SetPageScaleDelta(1.5f); + EXPECT_EQ(3.f, scroll_delegate.page_scale_factor()); + host_impl_->active_tree()->SetPageScaleDelta(1.f); + host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f); + EXPECT_EQ(1.f, scroll_delegate.page_scale_factor()); + // Scrolling should be relative to the offset as returned by the delegate. gfx::Vector2dF scroll_delta(0.f, 10.f); gfx::Vector2dF current_offset(7.f, 8.f); @@ -2385,6 +2553,14 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { scroll_delegate.last_set_scroll_offset()); host_impl_->ScrollEnd(); + // Forces a full tree synchronization and ensures that the scroll delegate + // sees the correct size of the new tree. + gfx::Size new_size(42, 24); + host_impl_->CreatePendingTree(); + CreateScrollAndContentsLayers(host_impl_->pending_tree(), new_size); + host_impl_->ActivatePendingTree(); + EXPECT_EQ(new_size, scroll_delegate.scrollable_size()); + // Un-setting the delegate should propagate the delegate's current offset to // the root scrollable layer. current_offset = gfx::Vector2dF(13.f, 12.f); @@ -2399,7 +2575,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollRoot) { SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f); - InitializeRendererAndDrawFrame(); + DrawFrame(); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity()); @@ -2470,7 +2646,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) { host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); - InitializeRendererAndDrawFrame(); + DrawFrame(); { gfx::Vector2d scroll_delta(0, -10); EXPECT_EQ(InputHandler::ScrollStarted, @@ -2528,7 +2704,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) { host_impl_->SetViewportSize(surface_size); host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->active_tree()->DidBecomeActive(); - InitializeRendererAndDrawFrame(); + DrawFrame(); { gfx::Vector2d scroll_delta(0, 8); EXPECT_EQ(InputHandler::ScrollStarted, @@ -2544,26 +2720,25 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) { } } +TEST_F(LayerTreeHostImplTest, OverscrollAlways) { + LayerTreeSettings settings; + settings.always_overscroll = true; + CreateHostImpl(settings, CreateOutputSurface()); -class BlendStateTrackerContext: public TestWebGraphicsContext3D { - public: - BlendStateTrackerContext() : blend_(false) {} - - virtual void enable(WebKit::WGC3Denum cap) OVERRIDE { - if (cap == GL_BLEND) - blend_ = true; - } - - virtual void disable(WebKit::WGC3Denum cap) OVERRIDE { - if (cap == GL_BLEND) - blend_ = false; - } - - bool blend() const { return blend_; } + SetupScrollAndContentsLayers(gfx::Size(50, 50)); + host_impl_->SetViewportSize(gfx::Size(50, 50)); + host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f); + DrawFrame(); + EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); + EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity()); - private: - bool blend_; -}; + // Even though the layer can't scroll the overscroll still happens. + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); + EXPECT_EQ(gfx::Vector2dF(0, 10), host_impl_->accumulated_root_overscroll()); + EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity()); +} class BlendStateCheckLayer : public LayerImpl { public: @@ -2672,7 +2847,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetExpectation(false, false); layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2681,7 +2856,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetExpectation(true, false); layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2691,7 +2866,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetExpectation(true, false); layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2701,7 +2876,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetExpectation(true, false); layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2723,7 +2898,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetExpectation(false, false); layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2736,7 +2911,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetExpectation(false, false); layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2750,7 +2925,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetExpectation(false, false); layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2767,7 +2942,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetExpectation(false, false); layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2783,7 +2958,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetExpectation(true, false); layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2798,7 +2973,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetExpectation(true, false); layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2814,7 +2989,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetExpectation(false, false); layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2827,7 +3002,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetExpectation(true, false); layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2839,7 +3014,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetExpectation(true, false); layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2851,7 +3026,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetExpectation(true, false); layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -2864,33 +3039,24 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetExpectation(false, false); layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); } class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest { - public: + protected: LayerTreeHostImplViewportCoveredTest() : gutter_quad_material_(DrawQuad::SOLID_COLOR), child_(NULL), did_activate_pending_tree_(false) {} - void CreateLayerTreeHostImpl(bool always_draw) { - LayerTreeSettings settings; - settings.minimum_occlusion_tracking_size = gfx::Size(); - settings.impl_side_painting = true; - host_impl_ = LayerTreeHostImpl::Create( - settings, this, &proxy_, &stats_instrumentation_); - - scoped_ptr<FakeOutputSurface> output_surface; - if (always_draw) - output_surface = FakeOutputSurface::CreateAlwaysDrawAndSwap3d().Pass(); - else - output_surface = FakeOutputSurface::Create3d().Pass(); - - host_impl_->InitializeRenderer(output_surface.PassAs<OutputSurface>()); - viewport_size_ = gfx::Size(1000, 1000); + scoped_ptr<OutputSurface> CreateFakeOutputSurface(bool always_draw) { + if (always_draw) { + return FakeOutputSurface::CreateAlwaysDrawAndSwap3d() + .PassAs<OutputSurface>(); + } + return FakeOutputSurface::Create3d().PassAs<OutputSurface>(); } void SetupActiveTreeLayers() { @@ -3049,8 +3215,10 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest { }; TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCovered) { + viewport_size_ = gfx::Size(1000, 1000); + bool always_draw = false; - CreateLayerTreeHostImpl(always_draw); + CreateHostImpl(DefaultSettings(), CreateFakeOutputSurface(always_draw)); host_impl_->SetViewportSize(DipSizeToPixelSize(viewport_size_)); SetupActiveTreeLayers(); @@ -3061,8 +3229,10 @@ TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCovered) { } TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCoveredScaled) { + viewport_size_ = gfx::Size(1000, 1000); + bool always_draw = false; - CreateLayerTreeHostImpl(always_draw); + CreateHostImpl(DefaultSettings(), CreateFakeOutputSurface(always_draw)); host_impl_->SetDeviceScaleFactor(2.f); host_impl_->SetViewportSize(DipSizeToPixelSize(viewport_size_)); @@ -3074,8 +3244,10 @@ TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCoveredScaled) { } TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCoveredOverhangBitmap) { + viewport_size_ = gfx::Size(1000, 1000); + bool always_draw = false; - CreateLayerTreeHostImpl(always_draw); + CreateHostImpl(DefaultSettings(), CreateFakeOutputSurface(always_draw)); host_impl_->SetViewportSize(DipSizeToPixelSize(viewport_size_)); SetupActiveTreeLayers(); @@ -3086,7 +3258,8 @@ TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCoveredOverhangBitmap) { skbitmap.setImmutable(); // Specify an overhang bitmap to use. - UIResourceBitmap ui_resource_bitmap(skbitmap, UIResourceBitmap::REPEAT); + UIResourceBitmap ui_resource_bitmap(skbitmap); + ui_resource_bitmap.SetWrapMode(UIResourceBitmap::REPEAT); UIResourceId ui_resource_id = 12345; host_impl_->CreateUIResource(ui_resource_id, ui_resource_bitmap); host_impl_->SetOverhangUIResource(ui_resource_id, gfx::Size(32, 32)); @@ -3118,8 +3291,10 @@ TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCoveredOverhangBitmap) { } TEST_F(LayerTreeHostImplViewportCoveredTest, ActiveTreeGrowViewportInvalid) { + viewport_size_ = gfx::Size(1000, 1000); + bool always_draw = true; - CreateLayerTreeHostImpl(always_draw); + CreateHostImpl(DefaultSettings(), CreateFakeOutputSurface(always_draw)); // Pending tree to force active_tree size invalid. Not used otherwise. host_impl_->CreatePendingTree(); @@ -3133,8 +3308,10 @@ TEST_F(LayerTreeHostImplViewportCoveredTest, ActiveTreeGrowViewportInvalid) { } TEST_F(LayerTreeHostImplViewportCoveredTest, ActiveTreeShrinkViewportInvalid) { + viewport_size_ = gfx::Size(1000, 1000); + bool always_draw = true; - CreateLayerTreeHostImpl(always_draw); + CreateHostImpl(DefaultSettings(), CreateFakeOutputSurface(always_draw)); // Set larger viewport and activate it to active tree. host_impl_->CreatePendingTree(); @@ -3157,36 +3334,6 @@ TEST_F(LayerTreeHostImplViewportCoveredTest, ActiveTreeShrinkViewportInvalid) { TestLayerIsLargerThanViewport(); } -class ReshapeTrackerContext: public TestWebGraphicsContext3D { - public: - ReshapeTrackerContext() - : reshape_called_(false), - last_reshape_width_(-1), - last_reshape_height_(-1), - last_reshape_scale_factor_(-1.f) { - } - - virtual void reshapeWithScaleFactor( - int width, int height, float scale_factor) OVERRIDE { - reshape_called_ = true; - last_reshape_width_ = width; - last_reshape_height_ = height; - last_reshape_scale_factor_ = scale_factor; - } - - bool reshape_called() const { return reshape_called_; } - void clear_reshape_called() { reshape_called_ = false; } - int last_reshape_width() { return last_reshape_width_; } - int last_reshape_height() { return last_reshape_height_; } - int last_reshape_scale_factor() { return last_reshape_scale_factor_; } - - private: - bool reshape_called_; - int last_reshape_width_; - int last_reshape_height_; - float last_reshape_scale_factor_; -}; - class FakeDrawableLayerImpl: public LayerImpl { public: static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) { @@ -3201,12 +3348,10 @@ class FakeDrawableLayerImpl: public LayerImpl { // can leave the window at the wrong size if we never draw and the proper // viewport size is never set. TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) { - scoped_ptr<ReshapeTrackerContext> owned_reshape_tracker( - new ReshapeTrackerContext); - ReshapeTrackerContext* reshape_tracker = owned_reshape_tracker.get(); - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - owned_reshape_tracker.PassAs<TestWebGraphicsContext3D>())); - host_impl_->InitializeRenderer(output_surface.Pass()); + scoped_refptr<TestContextProvider> provider(TestContextProvider::Create()); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(provider)); + CreateHostImpl(DefaultSettings(), output_surface.Pass()); scoped_ptr<LayerImpl> root = FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 1); @@ -3215,96 +3360,60 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) { root->SetContentBounds(gfx::Size(10, 10)); root->SetDrawsContent(true); host_impl_->active_tree()->SetRootLayer(root.Pass()); - EXPECT_FALSE(reshape_tracker->reshape_called()); - reshape_tracker->clear_reshape_called(); + EXPECT_FALSE(provider->TestContext3d()->reshape_called()); + provider->TestContext3d()->clear_reshape_called(); LayerTreeHostImpl::FrameData frame; host_impl_->SetViewportSize(gfx::Size(10, 10)); host_impl_->SetDeviceScaleFactor(1.f); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); - EXPECT_TRUE(reshape_tracker->reshape_called()); - EXPECT_EQ(reshape_tracker->last_reshape_width(), 10); - EXPECT_EQ(reshape_tracker->last_reshape_height(), 10); - EXPECT_EQ(reshape_tracker->last_reshape_scale_factor(), 1.f); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); + EXPECT_TRUE(provider->TestContext3d()->reshape_called()); + EXPECT_EQ(provider->TestContext3d()->width(), 10); + EXPECT_EQ(provider->TestContext3d()->height(), 10); + EXPECT_EQ(provider->TestContext3d()->scale_factor(), 1.f); host_impl_->DidDrawAllLayers(frame); - reshape_tracker->clear_reshape_called(); + provider->TestContext3d()->clear_reshape_called(); host_impl_->SetViewportSize(gfx::Size(20, 30)); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); - EXPECT_TRUE(reshape_tracker->reshape_called()); - EXPECT_EQ(reshape_tracker->last_reshape_width(), 20); - EXPECT_EQ(reshape_tracker->last_reshape_height(), 30); - EXPECT_EQ(reshape_tracker->last_reshape_scale_factor(), 1.f); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); + EXPECT_TRUE(provider->TestContext3d()->reshape_called()); + EXPECT_EQ(provider->TestContext3d()->width(), 20); + EXPECT_EQ(provider->TestContext3d()->height(), 30); + EXPECT_EQ(provider->TestContext3d()->scale_factor(), 1.f); host_impl_->DidDrawAllLayers(frame); - reshape_tracker->clear_reshape_called(); + provider->TestContext3d()->clear_reshape_called(); host_impl_->SetDeviceScaleFactor(2.f); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); - EXPECT_TRUE(reshape_tracker->reshape_called()); - EXPECT_EQ(reshape_tracker->last_reshape_width(), 20); - EXPECT_EQ(reshape_tracker->last_reshape_height(), 30); - EXPECT_EQ(reshape_tracker->last_reshape_scale_factor(), 2.f); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); + EXPECT_TRUE(provider->TestContext3d()->reshape_called()); + EXPECT_EQ(provider->TestContext3d()->width(), 20); + EXPECT_EQ(provider->TestContext3d()->height(), 30); + EXPECT_EQ(provider->TestContext3d()->scale_factor(), 2.f); host_impl_->DidDrawAllLayers(frame); - reshape_tracker->clear_reshape_called(); + provider->TestContext3d()->clear_reshape_called(); } -class SwapTrackerContext : public TestWebGraphicsContext3D { - public: - SwapTrackerContext() - : last_update_type_(NoUpdate) { - test_capabilities_.post_sub_buffer = true; - test_capabilities_.set_visibility = true; - } - - virtual void prepareTexture() OVERRIDE { - update_rect_ = gfx::Rect(width_, height_); - last_update_type_ = PrepareTexture; - } - - virtual void postSubBufferCHROMIUM(int x, int y, int width, int height) - OVERRIDE { - update_rect_ = gfx::Rect(x, y, width, height); - last_update_type_ = PostSubBuffer; - } - - gfx::Rect update_rect() const { return update_rect_; } - - enum UpdateType { - NoUpdate = 0, - PrepareTexture, - PostSubBuffer - }; - - UpdateType last_update_type() { - return last_update_type_; - } - - private: - gfx::Rect update_rect_; - UpdateType last_update_type_; -}; - // Make sure damage tracking propagates all the way to the graphics context, // where it should request to swap only the sub-buffer that is damaged. TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { - scoped_ptr<SwapTrackerContext> context(new SwapTrackerContext); - SwapTrackerContext* swap_tracker = context.get(); + scoped_refptr<TestContextProvider> context_provider( + TestContextProvider::Create()); + context_provider->BindToCurrentThread(); + context_provider->TestContext3d()->set_have_post_sub_buffer(true); - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_provider)); // This test creates its own LayerTreeHostImpl, so // that we can force partial swap enabled. LayerTreeSettings settings; settings.partial_swap_enabled = true; scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl = - LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); + LayerTreeHostImpl::Create( + settings, this, &proxy_, &stats_instrumentation_, NULL, 0); layer_tree_host_impl->InitializeRenderer(output_surface.Pass()); layer_tree_host_impl->SetViewportSize(gfx::Size(500, 500)); @@ -3328,17 +3437,12 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { // First frame, the entire screen should get swapped. EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect())); - layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); + layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now()); layer_tree_host_impl->DidDrawAllLayers(frame); layer_tree_host_impl->SwapBuffers(frame); - gfx::Rect actual_swap_rect = swap_tracker->update_rect(); - gfx::Rect expected_swap_rect = gfx::Rect(0, 0, 500, 500); - EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x()); - EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y()); - EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width()); - EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height()); - EXPECT_EQ(swap_tracker->last_update_type(), - SwapTrackerContext::PrepareTexture); + EXPECT_EQ(TestContextSupport::SWAP, + context_provider->support()->last_swap_type()); + // Second frame, only the damaged area should get swapped. Damage should be // the union of old and new child rects. // expected damage rect: gfx::Rect(26, 28); @@ -3346,37 +3450,31 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { layer_tree_host_impl->active_tree()->root_layer()->children()[0]->SetPosition( gfx::PointF()); EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect())); - layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); + layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); layer_tree_host_impl->SwapBuffers(frame); - actual_swap_rect = swap_tracker->update_rect(); - expected_swap_rect = gfx::Rect(0, 500-28, 26, 28); - EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x()); - EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y()); - EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width()); - EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height()); - EXPECT_EQ(swap_tracker->last_update_type(), - SwapTrackerContext::PostSubBuffer); // Make sure that partial swap is constrained to the viewport dimensions // expected damage rect: gfx::Rect(500, 500); // expected swap rect: flipped damage rect, but also clamped to viewport + EXPECT_EQ(TestContextSupport::PARTIAL_SWAP, + context_provider->support()->last_swap_type()); + gfx::Rect expected_swap_rect(0, 500-28, 26, 28); + EXPECT_EQ(expected_swap_rect.ToString(), + context_provider->support()-> + last_partial_swap_rect().ToString()); + layer_tree_host_impl->SetViewportSize(gfx::Size(10, 10)); // This will damage everything. layer_tree_host_impl->active_tree()->root_layer()->SetBackgroundColor( SK_ColorBLACK); EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect())); - layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); + layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); layer_tree_host_impl->SwapBuffers(frame); - actual_swap_rect = swap_tracker->update_rect(); - expected_swap_rect = gfx::Rect(10, 10); - EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x()); - EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y()); - EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width()); - EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height()); - EXPECT_EQ(swap_tracker->last_update_type(), - SwapTrackerContext::PrepareTexture); + + EXPECT_EQ(TestContextSupport::SWAP, + context_provider->support()->last_swap_type()); } TEST_F(LayerTreeHostImplTest, RootLayerDoesntCreateExtraSurface) { @@ -3430,27 +3528,27 @@ class FakeLayerWithQuads : public LayerImpl { class MockContext : public TestWebGraphicsContext3D { public: - MOCK_METHOD1(useProgram, void(WebKit::WebGLId program)); - MOCK_METHOD5(uniform4f, void(WebKit::WGC3Dint location, - WebKit::WGC3Dfloat x, - WebKit::WGC3Dfloat y, - WebKit::WGC3Dfloat z, - WebKit::WGC3Dfloat w)); - MOCK_METHOD4(uniformMatrix4fv, void(WebKit::WGC3Dint location, - WebKit::WGC3Dsizei count, - WebKit::WGC3Dboolean transpose, - const WebKit::WGC3Dfloat* value)); - MOCK_METHOD4(drawElements, void(WebKit::WGC3Denum mode, - WebKit::WGC3Dsizei count, - WebKit::WGC3Denum type, - WebKit::WGC3Dintptr offset)); - MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebKit::WebString()); - MOCK_METHOD1(enable, void(WebKit::WGC3Denum cap)); - MOCK_METHOD1(disable, void(WebKit::WGC3Denum cap)); - MOCK_METHOD4(scissor, void(WebKit::WGC3Dint x, - WebKit::WGC3Dint y, - WebKit::WGC3Dsizei width, - WebKit::WGC3Dsizei height)); + MOCK_METHOD1(useProgram, void(blink::WebGLId program)); + MOCK_METHOD5(uniform4f, void(blink::WGC3Dint location, + blink::WGC3Dfloat x, + blink::WGC3Dfloat y, + blink::WGC3Dfloat z, + blink::WGC3Dfloat w)); + MOCK_METHOD4(uniformMatrix4fv, void(blink::WGC3Dint location, + blink::WGC3Dsizei count, + blink::WGC3Dboolean transpose, + const blink::WGC3Dfloat* value)); + MOCK_METHOD4(drawElements, void(blink::WGC3Denum mode, + blink::WGC3Dsizei count, + blink::WGC3Denum type, + blink::WGC3Dintptr offset)); + MOCK_METHOD0(getRequestableExtensionsCHROMIUM, blink::WebString()); + MOCK_METHOD1(enable, void(blink::WGC3Denum cap)); + MOCK_METHOD1(disable, void(blink::WGC3Denum cap)); + MOCK_METHOD4(scissor, void(blink::WGC3Dint x, + blink::WGC3Dint y, + blink::WGC3Dsizei width, + blink::WGC3Dsizei height)); }; class MockContextHarness { @@ -3525,7 +3623,9 @@ TEST_F(LayerTreeHostImplTest, NoPartialSwap) { MockContextHarness harness(mock_context); // Run test case - CreateLayerTreeHost(false, output_surface.Pass()); + LayerTreeSettings settings = DefaultSettings(); + settings.partial_swap_enabled = false; + CreateHostImpl(settings, output_surface.Pass()); SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1)); // Without partial swap, and no clipping, no scissor is set. @@ -3534,7 +3634,7 @@ TEST_F(LayerTreeHostImplTest, NoPartialSwap) { { LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } Mock::VerifyAndClearExpectations(&mock_context); @@ -3547,7 +3647,7 @@ TEST_F(LayerTreeHostImplTest, NoPartialSwap) { { LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } Mock::VerifyAndClearExpectations(&mock_context); @@ -3560,7 +3660,9 @@ TEST_F(LayerTreeHostImplTest, PartialSwap) { context_owned.PassAs<TestWebGraphicsContext3D>())); MockContextHarness harness(mock_context); - CreateLayerTreeHost(true, output_surface.Pass()); + LayerTreeSettings settings = DefaultSettings(); + settings.partial_swap_enabled = true; + CreateHostImpl(settings, output_surface.Pass()); SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1)); // The first frame is not a partially-swapped one. @@ -3569,7 +3671,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwap) { { LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } Mock::VerifyAndClearExpectations(&mock_context); @@ -3584,40 +3686,27 @@ TEST_F(LayerTreeHostImplTest, PartialSwap) { { LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } Mock::VerifyAndClearExpectations(&mock_context); } -class PartialSwapContext : public TestWebGraphicsContext3D { - public: - PartialSwapContext() { - test_capabilities_.post_sub_buffer = true; - } - - // Unlimited texture size. - virtual void getIntegerv(WebKit::WGC3Denum pname, WebKit::WGC3Dint* value) - OVERRIDE { - if (pname == GL_MAX_TEXTURE_SIZE) - *value = 8192; - else if (pname == GL_ACTIVE_TEXTURE) - *value = GL_TEXTURE0; - } -}; - static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity( bool partial_swap, LayerTreeHostImplClient* client, Proxy* proxy, RenderingStatsInstrumentation* stats_instrumentation) { - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext))); + scoped_refptr<TestContextProvider> provider(TestContextProvider::Create()); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(provider)); + provider->BindToCurrentThread(); + provider->TestContext3d()->set_have_post_sub_buffer(true); LayerTreeSettings settings; settings.partial_swap_enabled = partial_swap; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - LayerTreeHostImpl::Create(settings, client, proxy, stats_instrumentation); + scoped_ptr<LayerTreeHostImpl> my_host_impl = LayerTreeHostImpl::Create( + settings, client, proxy, stats_instrumentation, NULL, 0); my_host_impl->InitializeRenderer(output_surface.Pass()); my_host_impl->SetViewportSize(gfx::Size(100, 100)); @@ -3698,7 +3787,7 @@ TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorPartialSwap) { EXPECT_EQ(DrawQuad::RENDER_PASS, frame.render_passes[1]->quad_list[0]->material); - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); + my_host_impl->DrawLayers(&frame, gfx::FrameTime::Now()); my_host_impl->DidDrawAllLayers(frame); } } @@ -3719,51 +3808,18 @@ TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorNoPartialSwap) { EXPECT_EQ(DrawQuad::RENDER_PASS, frame.render_passes[1]->quad_list[0]->material); - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); + my_host_impl->DrawLayers(&frame, gfx::FrameTime::Now()); my_host_impl->DidDrawAllLayers(frame); } } -// Fake WebKit::WebGraphicsContext3D that tracks the number of textures in use. -class TrackingWebGraphicsContext3D : public TestWebGraphicsContext3D { - public: - TrackingWebGraphicsContext3D() - : TestWebGraphicsContext3D(), - num_textures_(0) { - test_capabilities_.iosurface = true; - test_capabilities_.texture_rectangle = true; - } - - virtual WebKit::WebGLId createTexture() OVERRIDE { - WebKit::WebGLId id = TestWebGraphicsContext3D::createTexture(); - - textures_[id] = true; - ++num_textures_; - return id; - } - - virtual void deleteTexture(WebKit::WebGLId id) OVERRIDE { - if (textures_.find(id) == textures_.end()) - return; - - textures_[id] = false; - --num_textures_; - } - - unsigned num_textures() const { return num_textures_; } - - private: - base::hash_map<WebKit::WebGLId, bool> textures_; - unsigned num_textures_; -}; - TEST_F(LayerTreeHostImplTest, LayersFreeTextures) { scoped_ptr<TestWebGraphicsContext3D> context = TestWebGraphicsContext3D::Create(); TestWebGraphicsContext3D* context3d = context.get(); scoped_ptr<OutputSurface> output_surface( FakeOutputSurface::Create3d(context.Pass())); - host_impl_->InitializeRenderer(output_surface.Pass()); + CreateHostImpl(DefaultSettings(), output_surface.Pass()); scoped_ptr<LayerImpl> root_layer = LayerImpl::Create(host_impl_->active_tree(), 1); @@ -3798,7 +3854,7 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) { LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); host_impl_->SwapBuffers(frame); @@ -3813,11 +3869,11 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) { class MockDrawQuadsToFillScreenContext : public TestWebGraphicsContext3D { public: - MOCK_METHOD1(useProgram, void(WebKit::WebGLId program)); - MOCK_METHOD4(drawElements, void(WebKit::WGC3Denum mode, - WebKit::WGC3Dsizei count, - WebKit::WGC3Denum type, - WebKit::WGC3Dintptr offset)); + MOCK_METHOD1(useProgram, void(blink::WebGLId program)); + MOCK_METHOD4(drawElements, void(blink::WGC3Denum mode, + blink::WGC3Dsizei count, + blink::WGC3Denum type, + blink::WGC3Dintptr offset)); }; TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { @@ -3829,7 +3885,9 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { mock_context_owned.PassAs<TestWebGraphicsContext3D>())); // Run test case - CreateLayerTreeHost(false, output_surface.Pass()); + LayerTreeSettings settings = DefaultSettings(); + settings.partial_swap_enabled = false; + CreateHostImpl(settings, output_surface.Pass()); SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1)); host_impl_->active_tree()->set_background_color(SK_ColorWHITE); @@ -3841,7 +3899,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { .Times(1); LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); Mock::VerifyAndClearExpectations(&mock_context); @@ -3849,1118 +3907,11 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { host_impl_->active_tree()->set_has_transparent_background(true); host_impl_->SetFullRootLayerDamage(); EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); Mock::VerifyAndClearExpectations(&mock_context); } -static void AddDrawingLayerTo(LayerImpl* parent, - int id, - gfx::Rect layer_rect, - LayerImpl** result) { - scoped_ptr<LayerImpl> layer = - FakeLayerWithQuads::Create(parent->layer_tree_impl(), id); - LayerImpl* layer_ptr = layer.get(); - layer_ptr->SetAnchorPoint(gfx::PointF()); - layer_ptr->SetPosition(gfx::PointF(layer_rect.origin())); - layer_ptr->SetBounds(layer_rect.size()); - layer_ptr->SetContentBounds(layer_rect.size()); - layer_ptr->SetDrawsContent(true); // only children draw content - layer_ptr->SetContentsOpaque(true); - parent->AddChild(layer.Pass()); - if (result) - *result = layer_ptr; -} - -static void SetupLayersForTextureCaching( - LayerTreeHostImpl* layer_tree_host_impl, - LayerImpl*& root_ptr, - LayerImpl*& intermediate_layer_ptr, - LayerImpl*& surface_layer_ptr, - LayerImpl*& child_ptr, - gfx::Size root_size) { - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext))); - - layer_tree_host_impl->InitializeRenderer(output_surface.Pass()); - layer_tree_host_impl->SetViewportSize(root_size); - - scoped_ptr<LayerImpl> root = - LayerImpl::Create(layer_tree_host_impl->active_tree(), 1); - root_ptr = root.get(); - - root->SetAnchorPoint(gfx::PointF()); - root->SetPosition(gfx::PointF()); - root->SetBounds(root_size); - root->SetContentBounds(root_size); - root->SetDrawsContent(true); - layer_tree_host_impl->active_tree()->SetRootLayer(root.Pass()); - - AddDrawingLayerTo(root_ptr, - 2, - gfx::Rect(10, 10, root_size.width(), root_size.height()), - &intermediate_layer_ptr); - // Only children draw content. - intermediate_layer_ptr->SetDrawsContent(false); - - // Surface layer is the layer that changes its opacity - // It will contain other layers that draw content. - AddDrawingLayerTo(intermediate_layer_ptr, - 3, - gfx::Rect(10, 10, root_size.width(), root_size.height()), - &surface_layer_ptr); - // Only children draw content. - surface_layer_ptr->SetDrawsContent(false); - surface_layer_ptr->SetOpacity(0.5f); - surface_layer_ptr->SetForceRenderSurface(true); - - // Child of the surface layer will produce some quads - AddDrawingLayerTo(surface_layer_ptr, - 4, - gfx::Rect(5, - 5, - root_size.width() - 25, - root_size.height() - 25), - &child_ptr); -} - -class GLRendererWithReleaseTextures : public GLRenderer { - public: - using GLRenderer::ReleaseRenderPassTextures; -}; - -TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusion) { - LayerTreeSettings settings; - settings.minimum_occlusion_tracking_size = gfx::Size(); - settings.cache_render_pass_contents = true; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - - // Layers are structure as follows: - // - // R +-- S1 +- L10 (owning) - // | +- L11 - // | +- L12 - // | - // +-- S2 +- L20 (owning) - // +- L21 - // - // Occlusion: - // L12 occludes L11 (internal) - // L20 occludes L10 (external) - // L21 occludes L20 (internal) - - LayerImpl* root_ptr; - LayerImpl* layer_s1_ptr; - LayerImpl* layer_s2_ptr; - - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext))); - - gfx::Size root_size(1000, 1000); - - my_host_impl->InitializeRenderer(output_surface.Pass()); - my_host_impl->SetViewportSize(root_size); - - scoped_ptr<LayerImpl> root = - LayerImpl::Create(my_host_impl->active_tree(), 1); - root_ptr = root.get(); - - root->SetAnchorPoint(gfx::PointF()); - root->SetPosition(gfx::PointF()); - root->SetBounds(root_size); - root->SetContentBounds(root_size); - root->SetDrawsContent(true); - root->SetMasksToBounds(true); - my_host_impl->active_tree()->SetRootLayer(root.Pass()); - - AddDrawingLayerTo(root_ptr, 2, gfx::Rect(300, 300, 300, 300), &layer_s1_ptr); - layer_s1_ptr->SetForceRenderSurface(true); - - AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(10, 10, 10, 10), 0); // L11 - AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 0, 30, 30), 0); // L12 - - AddDrawingLayerTo(root_ptr, 5, gfx::Rect(550, 250, 300, 400), &layer_s2_ptr); - layer_s2_ptr->SetForceRenderSurface(true); - - AddDrawingLayerTo(layer_s2_ptr, 6, gfx::Rect(20, 20, 5, 5), 0); // L21 - - // Initial draw - must receive all quads - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 3 render passes. - // For Root, there are 2 quads; for S1, there are 2 quads (1 is occluded); - // for S2, there is 2 quads. - ASSERT_EQ(3U, frame.render_passes.size()); - - EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); - EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // "Unocclude" surface S1 and repeat draw. - // Must remove S2's render pass since it's cached; - // Must keep S1 quads because texture contained external occlusion. - gfx::Transform transform = layer_s2_ptr->transform(); - transform.Translate(150.0, 150.0); - layer_s2_ptr->SetTransform(transform); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 2 render passes. - // For Root, there are 2 quads - // For S1, the number of quads depends on what got unoccluded, so not - // asserted beyond being positive. - // For S2, there is no render pass - ASSERT_EQ(2U, frame.render_passes.size()); - - EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U); - EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // "Re-occlude" surface S1 and repeat draw. - // Must remove S1's render pass since it is now available in full. - // S2 has no change so must also be removed. - transform = layer_s2_ptr->transform(); - transform.Translate(-15.0, -15.0); - layer_s2_ptr->SetTransform(transform); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 1 render pass - for the root. - ASSERT_EQ(1U, frame.render_passes.size()); - - EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } -} - -TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionEarlyOut) { - LayerTreeSettings settings; - settings.minimum_occlusion_tracking_size = gfx::Size(); - settings.cache_render_pass_contents = true; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - - // Layers are structure as follows: - // - // R +-- S1 +- L10 (owning, non drawing) - // | +- L11 (corner, unoccluded) - // | +- L12 (corner, unoccluded) - // | +- L13 (corner, unoccluded) - // | +- L14 (corner, entirely occluded) - // | - // +-- S2 +- L20 (owning, drawing) - // - - LayerImpl* root_ptr; - LayerImpl* layer_s1_ptr; - LayerImpl* layer_s2_ptr; - - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext))); - - gfx::Size root_size(1000, 1000); - - my_host_impl->InitializeRenderer(output_surface.Pass()); - my_host_impl->SetViewportSize(root_size); - - scoped_ptr<LayerImpl> root = - LayerImpl::Create(my_host_impl->active_tree(), 1); - root_ptr = root.get(); - - root->SetAnchorPoint(gfx::PointF()); - root->SetPosition(gfx::PointF()); - root->SetBounds(root_size); - root->SetContentBounds(root_size); - root->SetDrawsContent(true); - root->SetMasksToBounds(true); - my_host_impl->active_tree()->SetRootLayer(root.Pass()); - - AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 800, 800), &layer_s1_ptr); - layer_s1_ptr->SetForceRenderSurface(true); - layer_s1_ptr->SetDrawsContent(false); - - AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(0, 0, 300, 300), 0); // L11 - AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 500, 300, 300), 0); // L12 - AddDrawingLayerTo(layer_s1_ptr, 5, gfx::Rect(500, 0, 300, 300), 0); // L13 - AddDrawingLayerTo(layer_s1_ptr, 6, gfx::Rect(500, 500, 300, 300), 0); // L14 - AddDrawingLayerTo(layer_s1_ptr, 9, gfx::Rect(500, 500, 300, 300), 0); // L14 - - AddDrawingLayerTo(root_ptr, 7, gfx::Rect(450, 450, 450, 450), &layer_s2_ptr); - layer_s2_ptr->SetForceRenderSurface(true); - - // Initial draw - must receive all quads - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 3 render passes. - // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is - // 1 quad. - ASSERT_EQ(3U, frame.render_passes.size()); - - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - - // L14 is culled, so only 3 quads. - EXPECT_EQ(3U, frame.render_passes[1]->quad_list.size()); - EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // "Unocclude" surface S1 and repeat draw. - // Must remove S2's render pass since it's cached; - // Must keep S1 quads because texture contained external occlusion. - gfx::Transform transform = layer_s2_ptr->transform(); - transform.Translate(100.0, 100.0); - layer_s2_ptr->SetTransform(transform); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 2 render passes. - // For Root, there are 2 quads - // For S1, the number of quads depends on what got unoccluded, so not - // asserted beyond being positive. - // For S2, there is no render pass - ASSERT_EQ(2U, frame.render_passes.size()); - - EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U); - EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // "Re-occlude" surface S1 and repeat draw. - // Must remove S1's render pass since it is now available in full. - // S2 has no change so must also be removed. - transform = layer_s2_ptr->transform(); - transform.Translate(-15.0, -15.0); - layer_s2_ptr->SetTransform(transform); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 1 render pass - for the root. - ASSERT_EQ(1U, frame.render_passes.size()); - - EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } -} - -TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionExternalOverInternal) { - LayerTreeSettings settings; - settings.minimum_occlusion_tracking_size = gfx::Size(); - settings.cache_render_pass_contents = true; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - - // Layers are structured as follows: - // - // R +-- S1 +- L10 (owning, drawing) - // | +- L11 (corner, occluded by L12) - // | +- L12 (opposite corner) - // | - // +-- S2 +- L20 (owning, drawing) - // - - LayerImpl* root_ptr; - LayerImpl* layer_s1_ptr; - LayerImpl* layer_s2_ptr; - - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext))); - - gfx::Size root_size(1000, 1000); - - my_host_impl->InitializeRenderer(output_surface.Pass()); - my_host_impl->SetViewportSize(root_size); - - scoped_ptr<LayerImpl> root = - LayerImpl::Create(my_host_impl->active_tree(), 1); - root_ptr = root.get(); - - root->SetAnchorPoint(gfx::PointF()); - root->SetPosition(gfx::PointF()); - root->SetBounds(root_size); - root->SetContentBounds(root_size); - root->SetDrawsContent(true); - root->SetMasksToBounds(true); - my_host_impl->active_tree()->SetRootLayer(root.Pass()); - - AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 400, 400), &layer_s1_ptr); - layer_s1_ptr->SetForceRenderSurface(true); - - AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(0, 0, 300, 300), 0); // L11 - AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(100, 0, 300, 300), 0); // L12 - - AddDrawingLayerTo(root_ptr, 7, gfx::Rect(200, 0, 300, 300), &layer_s2_ptr); - layer_s2_ptr->SetForceRenderSurface(true); - - // Initial draw - must receive all quads - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 3 render passes. - // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is - // 1 quad. - ASSERT_EQ(3U, frame.render_passes.size()); - - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(3U, frame.render_passes[1]->quad_list.size()); - EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // "Unocclude" surface S1 and repeat draw. - // Must remove S2's render pass since it's cached; - // Must keep S1 quads because texture contained external occlusion. - gfx::Transform transform = layer_s2_ptr->transform(); - transform.Translate(300.0, 0.0); - layer_s2_ptr->SetTransform(transform); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 2 render passes. - // For Root, there are 2 quads - // For S1, the number of quads depends on what got unoccluded, so not - // asserted beyond being positive. - // For S2, there is no render pass - ASSERT_EQ(2U, frame.render_passes.size()); - - EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U); - EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } -} - -TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionExternalNotAligned) { - LayerTreeSettings settings; - settings.cache_render_pass_contents = true; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - - // Layers are structured as follows: - // - // R +-- S1 +- L10 (rotated, drawing) - // +- L11 (occupies half surface) - - LayerImpl* root_ptr; - LayerImpl* layer_s1_ptr; - - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext))); - - gfx::Size root_size(1000, 1000); - - my_host_impl->InitializeRenderer(output_surface.Pass()); - my_host_impl->SetViewportSize(root_size); - - scoped_ptr<LayerImpl> root = - LayerImpl::Create(my_host_impl->active_tree(), 1); - root_ptr = root.get(); - - root->SetAnchorPoint(gfx::PointF()); - root->SetPosition(gfx::PointF()); - root->SetBounds(root_size); - root->SetContentBounds(root_size); - root->SetDrawsContent(true); - root->SetMasksToBounds(true); - my_host_impl->active_tree()->SetRootLayer(root.Pass()); - - AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 400, 400), &layer_s1_ptr); - layer_s1_ptr->SetForceRenderSurface(true); - gfx::Transform transform = layer_s1_ptr->transform(); - transform.Translate(200.0, 200.0); - transform.Rotate(45.0); - transform.Translate(-200.0, -200.0); - layer_s1_ptr->SetTransform(transform); - - AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(200, 0, 200, 400), 0); // L11 - - // Initial draw - must receive all quads - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 2 render passes. - ASSERT_EQ(2U, frame.render_passes.size()); - - EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Change opacity and draw. Verify we used cached texture. - layer_s1_ptr->SetOpacity(0.2f); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // One render pass must be gone due to cached texture. - ASSERT_EQ(1U, frame.render_passes.size()); - - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } -} - -TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionPartialSwap) { - LayerTreeSettings settings; - settings.minimum_occlusion_tracking_size = gfx::Size(); - settings.partial_swap_enabled = true; - settings.cache_render_pass_contents = true; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - - // Layers are structure as follows: - // - // R +-- S1 +- L10 (owning) - // | +- L11 - // | +- L12 - // | - // +-- S2 +- L20 (owning) - // +- L21 - // - // Occlusion: - // L12 occludes L11 (internal) - // L20 occludes L10 (external) - // L21 occludes L20 (internal) - - LayerImpl* root_ptr; - LayerImpl* layer_s1_ptr; - LayerImpl* layer_s2_ptr; - - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext))); - - gfx::Size root_size(1000, 1000); - - my_host_impl->InitializeRenderer(output_surface.Pass()); - my_host_impl->SetViewportSize(root_size); - - scoped_ptr<LayerImpl> root = - LayerImpl::Create(my_host_impl->active_tree(), 1); - root_ptr = root.get(); - - root->SetAnchorPoint(gfx::PointF()); - root->SetPosition(gfx::PointF()); - root->SetBounds(root_size); - root->SetContentBounds(root_size); - root->SetDrawsContent(true); - root->SetMasksToBounds(true); - my_host_impl->active_tree()->SetRootLayer(root.Pass()); - - AddDrawingLayerTo(root_ptr, 2, gfx::Rect(300, 300, 300, 300), &layer_s1_ptr); - layer_s1_ptr->SetForceRenderSurface(true); - - AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(10, 10, 10, 10), 0); // L11 - AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 0, 30, 30), 0); // L12 - - AddDrawingLayerTo(root_ptr, 5, gfx::Rect(550, 250, 300, 400), &layer_s2_ptr); - layer_s2_ptr->SetForceRenderSurface(true); - - AddDrawingLayerTo(layer_s2_ptr, 6, gfx::Rect(20, 20, 5, 5), 0); // L21 - - // Initial draw - must receive all quads - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 3 render passes. - // For Root, there are 2 quads; for S1, there are 2 quads (one is occluded); - // for S2, there is 2 quads. - ASSERT_EQ(3U, frame.render_passes.size()); - - EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); - EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // "Unocclude" surface S1 and repeat draw. - // Must remove S2's render pass since it's cached; - // Must keep S1 quads because texture contained external occlusion. - gfx::Transform transform = layer_s2_ptr->transform(); - transform.Translate(150.0, 150.0); - layer_s2_ptr->SetTransform(transform); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive 2 render passes. - // For Root, there are 2 quads. - // For S1, there are 2 quads. - // For S2, there is no render pass - ASSERT_EQ(2U, frame.render_passes.size()); - - EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // "Re-occlude" surface S1 and repeat draw. - // Must remove S1's render pass since it is now available in full. - // S2 has no change so must also be removed. - transform = layer_s2_ptr->transform(); - transform.Translate(-15.0, -15.0); - layer_s2_ptr->SetTransform(transform); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Root render pass only. - ASSERT_EQ(1U, frame.render_passes.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } -} - -TEST_F(LayerTreeHostImplTest, TextureCachingWithScissor) { - LayerTreeSettings settings; - settings.minimum_occlusion_tracking_size = gfx::Size(); - settings.cache_render_pass_contents = true; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - - /* - Layers are created as follows: - - +--------------------+ - | 1 | - | +-----------+ | - | | 2 | | - | | +-------------------+ - | | | 3 | - | | +-------------------+ - | | | | - | +-----------+ | - | | - | | - +--------------------+ - - Layers 1, 2 have render surfaces - */ - scoped_ptr<LayerImpl> root = - LayerImpl::Create(my_host_impl->active_tree(), 1); - scoped_ptr<TiledLayerImpl> child = - TiledLayerImpl::Create(my_host_impl->active_tree(), 2); - scoped_ptr<LayerImpl> grand_child = - LayerImpl::Create(my_host_impl->active_tree(), 3); - - gfx::Rect root_rect(0, 0, 100, 100); - gfx::Rect child_rect(10, 10, 50, 50); - gfx::Rect grand_child_rect(5, 5, 150, 150); - - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext))); - my_host_impl->InitializeRenderer(output_surface.Pass()); - - root->SetAnchorPoint(gfx::PointF()); - root->SetPosition(gfx::PointF(root_rect.x(), root_rect.y())); - root->SetBounds(gfx::Size(root_rect.width(), root_rect.height())); - root->SetContentBounds(root->bounds()); - root->SetDrawsContent(true); - root->SetMasksToBounds(true); - - child->SetAnchorPoint(gfx::PointF()); - child->SetPosition(gfx::PointF(child_rect.x(), child_rect.y())); - child->SetOpacity(0.5f); - child->SetBounds(gfx::Size(child_rect.width(), child_rect.height())); - child->SetContentBounds(child->bounds()); - child->SetDrawsContent(true); - child->set_skips_draw(false); - - // child layer has 10x10 tiles. - scoped_ptr<LayerTilingData> tiler = - LayerTilingData::Create(gfx::Size(10, 10), - LayerTilingData::HAS_BORDER_TEXELS); - tiler->SetBounds(child->content_bounds()); - child->SetTilingData(*tiler.get()); - - grand_child->SetAnchorPoint(gfx::PointF()); - grand_child->SetPosition(grand_child_rect.origin()); - grand_child->SetBounds(grand_child_rect.size()); - grand_child->SetContentBounds(grand_child->bounds()); - grand_child->SetDrawsContent(true); - - TiledLayerImpl* child_ptr = child.get(); - RenderPass::Id child_pass_id(child_ptr->id(), 0); - - child->AddChild(grand_child.Pass()); - root->AddChild(child.PassAs<LayerImpl>()); - my_host_impl->active_tree()->SetRootLayer(root.Pass()); - my_host_impl->SetViewportSize(root_rect.size()); - - EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( - child_pass_id)); - { - LayerTreeHostImpl::FrameData frame; - host_impl_->SetFullRootLayerDamage(); - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // We should have cached textures for surface 2. - EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( - child_pass_id)); - { - LayerTreeHostImpl::FrameData frame; - host_impl_->SetFullRootLayerDamage(); - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // We should still have cached textures for surface 2 after drawing with no - // damage. - EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( - child_pass_id)); - - // Damage a single tile of surface 2. - child_ptr->set_update_rect(gfx::Rect(10, 10, 10, 10)); - { - LayerTreeHostImpl::FrameData frame; - host_impl_->SetFullRootLayerDamage(); - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // We should have a cached texture for surface 2 again even though it was - // damaged. - EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( - child_pass_id)); -} - -TEST_F(LayerTreeHostImplTest, SurfaceTextureCaching) { - LayerTreeSettings settings; - settings.minimum_occlusion_tracking_size = gfx::Size(); - settings.partial_swap_enabled = true; - settings.cache_render_pass_contents = true; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - - LayerImpl* root_ptr; - LayerImpl* intermediate_layer_ptr; - LayerImpl* surface_layer_ptr; - LayerImpl* child_ptr; - - SetupLayersForTextureCaching(my_host_impl.get(), - root_ptr, - intermediate_layer_ptr, - surface_layer_ptr, - child_ptr, - gfx::Size(100, 100)); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive two render passes, each with one quad - ASSERT_EQ(2U, frame.render_passes.size()); - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size()); - - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[1]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); - RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; - ASSERT_TRUE(target_pass); - EXPECT_FALSE(target_pass->damage_rect.IsEmpty()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Draw without any change - { - LayerTreeHostImpl::FrameData frame; - my_host_impl->SetFullRootLayerDamage(); - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive one render pass, as the other one should be culled - ASSERT_EQ(1U, frame.render_passes.size()); - - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[0]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); - EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == - frame.render_passes_by_id.end()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Change opacity and draw - surface_layer_ptr->SetOpacity(0.6f); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive one render pass, as the other one should be culled - ASSERT_EQ(1U, frame.render_passes.size()); - - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[0]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); - EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == - frame.render_passes_by_id.end()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Change less benign property and draw - should have contents changed flag - surface_layer_ptr->SetStackingOrderChanged(true); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive two render passes, each with one quad - ASSERT_EQ(2U, frame.render_passes.size()); - - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(DrawQuad::SOLID_COLOR, - frame.render_passes[0]->quad_list[0]->material); - - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[1]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); - RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; - ASSERT_TRUE(target_pass); - EXPECT_FALSE(target_pass->damage_rect.IsEmpty()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Change opacity again, and evict the cached surface texture. - surface_layer_ptr->SetOpacity(0.5f); - static_cast<GLRendererWithReleaseTextures*>( - my_host_impl->renderer())->ReleaseRenderPassTextures(); - - // Change opacity and draw - surface_layer_ptr->SetOpacity(0.6f); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive two render passes - ASSERT_EQ(2U, frame.render_passes.size()); - - // Even though not enough properties changed, the entire thing must be - // redrawn as we don't have cached textures - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size()); - - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[1]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); - RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; - ASSERT_TRUE(target_pass); - EXPECT_TRUE(target_pass->damage_rect.IsEmpty()); - - // Was our surface evicted? - EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( - target_pass->id)); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Draw without any change, to make sure the state is clear - { - LayerTreeHostImpl::FrameData frame; - my_host_impl->SetFullRootLayerDamage(); - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive one render pass, as the other one should be culled - ASSERT_EQ(1U, frame.render_passes.size()); - - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[0]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); - EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == - frame.render_passes_by_id.end()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Change location of the intermediate layer - gfx::Transform transform = intermediate_layer_ptr->transform(); - transform.matrix().setDouble(0, 3, 1.0001); - intermediate_layer_ptr->SetTransform(transform); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive one render pass, as the other one should be culled. - ASSERT_EQ(1U, frame.render_passes.size()); - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[0]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); - EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == - frame.render_passes_by_id.end()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } -} - -TEST_F(LayerTreeHostImplTest, SurfaceTextureCachingNoPartialSwap) { - LayerTreeSettings settings; - settings.minimum_occlusion_tracking_size = gfx::Size(); - settings.cache_render_pass_contents = true; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - - LayerImpl* root_ptr; - LayerImpl* intermediate_layer_ptr; - LayerImpl* surface_layer_ptr; - LayerImpl* child_ptr; - - SetupLayersForTextureCaching(my_host_impl.get(), - root_ptr, - intermediate_layer_ptr, - surface_layer_ptr, - child_ptr, - gfx::Size(100, 100)); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive two render passes, each with one quad - ASSERT_EQ(2U, frame.render_passes.size()); - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size()); - - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[1]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); - RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; - EXPECT_FALSE(target_pass->damage_rect.IsEmpty()); - - EXPECT_FALSE(frame.render_passes[0]->damage_rect.IsEmpty()); - EXPECT_FALSE(frame.render_passes[1]->damage_rect.IsEmpty()); - - EXPECT_FALSE( - frame.render_passes[0]->has_occlusion_from_outside_target_surface); - EXPECT_FALSE( - frame.render_passes[1]->has_occlusion_from_outside_target_surface); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Draw without any change - { - LayerTreeHostImpl::FrameData frame; - my_host_impl->SetFullRootLayerDamage(); - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Even though there was no change, we set the damage to entire viewport. - // One of the passes should be culled as a result, since contents didn't - // change and we have cached texture. - ASSERT_EQ(1U, frame.render_passes.size()); - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Change opacity and draw - surface_layer_ptr->SetOpacity(0.6f); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive one render pass, as the other one should be culled - ASSERT_EQ(1U, frame.render_passes.size()); - - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[0]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); - EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == - frame.render_passes_by_id.end()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Change less benign property and draw - should have contents changed flag - surface_layer_ptr->SetStackingOrderChanged(true); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive two render passes, each with one quad - ASSERT_EQ(2U, frame.render_passes.size()); - - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(DrawQuad::SOLID_COLOR, - frame.render_passes[0]->quad_list[0]->material); - - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[1]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); - RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; - ASSERT_TRUE(target_pass); - EXPECT_FALSE(target_pass->damage_rect.IsEmpty()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Change opacity again, and evict the cached surface texture. - surface_layer_ptr->SetOpacity(0.5f); - static_cast<GLRendererWithReleaseTextures*>( - my_host_impl->renderer())->ReleaseRenderPassTextures(); - - // Change opacity and draw - surface_layer_ptr->SetOpacity(0.6f); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive two render passes - ASSERT_EQ(2U, frame.render_passes.size()); - - // Even though not enough properties changed, the entire thing must be - // redrawn as we don't have cached textures - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size()); - - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[1]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); - RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; - ASSERT_TRUE(target_pass); - EXPECT_TRUE(target_pass->damage_rect.IsEmpty()); - - // Was our surface evicted? - EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( - target_pass->id)); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Draw without any change, to make sure the state is clear - { - LayerTreeHostImpl::FrameData frame; - my_host_impl->SetFullRootLayerDamage(); - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Even though there was no change, we set the damage to entire viewport. - // One of the passes should be culled as a result, since contents didn't - // change and we have cached texture. - ASSERT_EQ(1U, frame.render_passes.size()); - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } - - // Change location of the intermediate layer - gfx::Transform transform = intermediate_layer_ptr->transform(); - transform.matrix().setDouble(0, 3, 1.0001); - intermediate_layer_ptr->SetTransform(transform); - { - LayerTreeHostImpl::FrameData frame; - EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); - - // Must receive one render pass, as the other one should be culled. - ASSERT_EQ(1U, frame.render_passes.size()); - EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); - - EXPECT_EQ(DrawQuad::RENDER_PASS, - frame.render_passes[0]->quad_list[0]->material); - const RenderPassDrawQuad* quad = - RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); - EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == - frame.render_passes_by_id.end()); - - my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); - my_host_impl->DidDrawAllLayers(frame); - } -} - TEST_F(LayerTreeHostImplTest, ReleaseContentsTextureShouldTriggerCommit) { set_reduce_memory_result(false); @@ -4971,7 +3922,6 @@ TEST_F(LayerTreeHostImplTest, ReleaseContentsTextureShouldTriggerCommit) { host_impl_->memory_allocation_limit_bytes() - 1); host_impl_->SetMemoryPolicy(ManagedMemoryPolicy( host_impl_->memory_allocation_limit_bytes() - 1)); - host_impl_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_FALSE(did_request_commit_); did_request_commit_ = false; @@ -4983,7 +3933,6 @@ TEST_F(LayerTreeHostImplTest, ReleaseContentsTextureShouldTriggerCommit) { host_impl_->memory_allocation_limit_bytes()); host_impl_->SetMemoryPolicy(ManagedMemoryPolicy( host_impl_->memory_allocation_limit_bytes() - 1)); - host_impl_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_TRUE(did_request_commit_); did_request_commit_ = false; @@ -4993,7 +3942,6 @@ TEST_F(LayerTreeHostImplTest, ReleaseContentsTextureShouldTriggerCommit) { host_impl_->set_max_memory_needed_bytes(1); host_impl_->SetMemoryPolicy(ManagedMemoryPolicy( host_impl_->memory_allocation_limit_bytes() - 1)); - host_impl_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_TRUE(did_request_commit_); did_request_commit_ = false; @@ -5001,403 +3949,9 @@ TEST_F(LayerTreeHostImplTest, ReleaseContentsTextureShouldTriggerCommit) { // re-commit. host_impl_->SetMemoryPolicy(ManagedMemoryPolicy( host_impl_->memory_allocation_limit_bytes())); - host_impl_->SetDiscardBackBufferWhenNotVisible(true); EXPECT_FALSE(did_request_commit_); } -struct RenderPassRemovalTestData : public LayerTreeHostImpl::FrameData { - base::ScopedPtrHashMap<RenderPass::Id, TestRenderPass> render_pass_cache; - scoped_ptr<SharedQuadState> shared_quad_state; -}; - -class TestRenderer : public GLRenderer, public RendererClient { - public: - static scoped_ptr<TestRenderer> Create(const LayerTreeSettings* settings, - ResourceProvider* resource_provider, - OutputSurface* output_surface, - Proxy* proxy) { - scoped_ptr<TestRenderer> renderer( - new TestRenderer(settings, resource_provider, output_surface, proxy)); - if (!renderer->Initialize()) - return scoped_ptr<TestRenderer>(); - - return renderer.Pass(); - } - - void ClearCachedTextures() { textures_.clear(); } - void SetHaveCachedResourcesForRenderPassId(RenderPass::Id id) { - textures_.insert(id); - } - - virtual bool HaveCachedResourcesForRenderPassId(RenderPass::Id id) const - OVERRIDE { - return textures_.count(id); - } - - // RendererClient implementation. - virtual gfx::Rect DeviceViewport() const OVERRIDE { - return gfx::Rect(viewport_size_); - } - virtual gfx::Rect DeviceClip() const OVERRIDE { return DeviceViewport(); } - virtual void SetFullRootLayerDamage() OVERRIDE {} - virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const OVERRIDE { - return CompositorFrameMetadata(); - } - - protected: - TestRenderer(const LayerTreeSettings* settings, - ResourceProvider* resource_provider, - OutputSurface* output_surface, - Proxy* proxy) - : GLRenderer(this, settings, output_surface, resource_provider, NULL, 0) { - } - - private: - LayerTreeSettings settings_; - gfx::Size viewport_size_; - base::hash_set<RenderPass::Id> textures_; -}; - -static void ConfigureRenderPassTestData(const char* test_script, - RenderPassRemovalTestData* test_data, - TestRenderer* renderer) { - renderer->ClearCachedTextures(); - - // One shared state for all quads - we don't need the correct details - test_data->shared_quad_state = SharedQuadState::Create(); - test_data->shared_quad_state->SetAll(gfx::Transform(), - gfx::Size(), - gfx::Rect(), - gfx::Rect(), - false, - 1.f); - - const char* current_char = test_script; - - // Pre-create root pass - RenderPass::Id root_render_pass_id = - RenderPass::Id(test_script[0], test_script[1]); - scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); - pass->SetNew(root_render_pass_id, gfx::Rect(), gfx::Rect(), gfx::Transform()); - test_data->render_pass_cache.add(root_render_pass_id, pass.Pass()); - while (*current_char) { - int layer_id = *current_char; - current_char++; - ASSERT_TRUE(current_char); - int index = *current_char; - current_char++; - - RenderPass::Id render_pass_id = RenderPass::Id(layer_id, index); - - bool is_replica = false; - if (!test_data->render_pass_cache.contains(render_pass_id)) - is_replica = true; - - scoped_ptr<TestRenderPass> render_pass = - test_data->render_pass_cache.take(render_pass_id); - - // Cycle through quad data and create all quads. - while (*current_char && *current_char != '\n') { - if (*current_char == 's') { - // Solid color draw quad. - scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create(); - quad->SetNew(test_data->shared_quad_state.get(), - gfx::Rect(0, 0, 10, 10), - SK_ColorWHITE, - false); - - render_pass->AppendQuad(quad.PassAs<DrawQuad>()); - current_char++; - } else if ((*current_char >= 'A') && (*current_char <= 'Z')) { - // RenderPass draw quad. - int layer_id = *current_char; - current_char++; - ASSERT_TRUE(current_char); - int index = *current_char; - current_char++; - RenderPass::Id new_render_pass_id = RenderPass::Id(layer_id, index); - ASSERT_NE(root_render_pass_id, new_render_pass_id); - bool has_texture = false; - bool contents_changed = true; - - if (*current_char == '[') { - current_char++; - while (*current_char && *current_char != ']') { - switch (*current_char) { - case 'c': - contents_changed = false; - break; - case 't': - has_texture = true; - break; - } - current_char++; - } - if (*current_char == ']') - current_char++; - } - - if (test_data->render_pass_cache.find(new_render_pass_id) == - test_data->render_pass_cache.end()) { - if (has_texture) - renderer->SetHaveCachedResourcesForRenderPassId(new_render_pass_id); - - scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); - pass->SetNew(new_render_pass_id, - gfx::Rect(), - gfx::Rect(), - gfx::Transform()); - test_data->render_pass_cache.add(new_render_pass_id, pass.Pass()); - } - - gfx::Rect quad_rect = gfx::Rect(0, 0, 1, 1); - gfx::Rect contents_changed_rect = - contents_changed ? quad_rect : gfx::Rect(); - scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create(); - quad->SetNew(test_data->shared_quad_state.get(), - quad_rect, - new_render_pass_id, - is_replica, - 1, - contents_changed_rect, - gfx::RectF(0.f, 0.f, 1.f, 1.f), - FilterOperations(), - skia::RefPtr<SkImageFilter>(), - FilterOperations()); - render_pass->AppendQuad(quad.PassAs<DrawQuad>()); - } - } - test_data->render_passes_by_id[render_pass_id] = render_pass.get(); - test_data->render_passes.insert(test_data->render_passes.begin(), - render_pass.PassAs<RenderPass>()); - if (*current_char) - current_char++; - } -} - -void DumpRenderPassTestData(const RenderPassRemovalTestData& test_data, - char* buffer) { - char* pos = buffer; - for (RenderPassList::const_reverse_iterator it = - test_data.render_passes.rbegin(); - it != test_data.render_passes.rend(); - ++it) { - const RenderPass* current_pass = *it; - *pos = current_pass->id.layer_id; - pos++; - *pos = current_pass->id.index; - pos++; - - QuadList::const_iterator quad_list_iterator = - current_pass->quad_list.begin(); - while (quad_list_iterator != current_pass->quad_list.end()) { - DrawQuad* current_quad = *quad_list_iterator; - switch (current_quad->material) { - case DrawQuad::SOLID_COLOR: - *pos = 's'; - pos++; - break; - case DrawQuad::RENDER_PASS: - *pos = RenderPassDrawQuad::MaterialCast(current_quad)-> - render_pass_id.layer_id; - pos++; - *pos = RenderPassDrawQuad::MaterialCast(current_quad)-> - render_pass_id.index; - pos++; - break; - default: - *pos = 'x'; - pos++; - break; - } - - quad_list_iterator++; - } - *pos = '\n'; - pos++; - } - *pos = '\0'; -} - -// Each RenderPassList is represented by a string which describes the -// configuration. -// The syntax of the string is as follows: -// -// RsssssX[c]ssYsssZ[t]ssW[ct] -// Identifies the render pass------------------------^ ^^^ ^ ^ ^ ^ ^ -// These are solid color quads--------------------------+ | | | | | -// Identifies RenderPassDrawQuad's RenderPass--------------+ | | | | -// This quad's contents didn't change------------------------+ | | | -// This quad's contents changed and it has no texture------------+ | | -// This quad has texture but its contents changed----------------------+ | -// This quad's contents didn't change and it has texture - will be removed---+ -// -// Expected results have exactly the same syntax, except they do not use square -// brackets, since we only check the structure, not attributes. -// -// Test case configuration consists of initialization script and expected -// results, all in the same format. -struct TestCase { - const char* name; - const char* init_script; - const char* expected_result; -}; - -TestCase remove_render_passes_cases[] = { - { - "Single root pass", - "R0ssss\n", - "R0ssss\n" - }, { - "Single pass - no quads", - "R0\n", - "R0\n" - }, { - "Two passes, no removal", - "R0ssssA0sss\n" - "A0ssss\n", - "R0ssssA0sss\n" - "A0ssss\n" - }, { - "Two passes, remove last", - "R0ssssA0[ct]sss\n" - "A0ssss\n", - "R0ssssA0sss\n" - }, { - "Have texture but contents changed - leave pass", - "R0ssssA0[t]sss\n" - "A0ssss\n", - "R0ssssA0sss\n" - "A0ssss\n" - }, { - "Contents didn't change but no texture - leave pass", - "R0ssssA0[c]sss\n" - "A0ssss\n", - "R0ssssA0sss\n" - "A0ssss\n" - }, { - "Replica: two quads reference the same pass; remove", - "R0ssssA0[ct]A0[ct]sss\n" - "A0ssss\n", - "R0ssssA0A0sss\n" - }, { - "Replica: two quads reference the same pass; leave", - "R0ssssA0[c]A0[c]sss\n" - "A0ssss\n", - "R0ssssA0A0sss\n" - "A0ssss\n", - }, { - "Many passes, remove all", - "R0ssssA0[ct]sss\n" - "A0sssB0[ct]C0[ct]s\n" - "B0sssD0[ct]ssE0[ct]F0[ct]\n" - "E0ssssss\n" - "C0G0[ct]\n" - "D0sssssss\n" - "F0sssssss\n" - "G0sss\n", - - "R0ssssA0sss\n" - }, { - "Deep recursion, remove all", - - "R0sssssA0[ct]ssss\n" - "A0ssssB0sss\n" - "B0C0\n" - "C0D0\n" - "D0E0\n" - "E0F0\n" - "F0G0\n" - "G0H0\n" - "H0sssI0sss\n" - "I0J0\n" - "J0ssss\n", - - "R0sssssA0ssss\n" - }, { - "Wide recursion, remove all", - "R0A0[ct]B0[ct]C0[ct]D0[ct]E0[ct]F0[ct]G0[ct]H0[ct]I0[ct]J0[ct]\n" - "A0s\n" - "B0s\n" - "C0ssss\n" - "D0ssss\n" - "E0s\n" - "F0\n" - "G0s\n" - "H0s\n" - "I0s\n" - "J0ssss\n", - - "R0A0B0C0D0E0F0G0H0I0J0\n" - }, { - "Remove passes regardless of cache state", - "R0ssssA0[ct]sss\n" - "A0sssB0C0s\n" - "B0sssD0[c]ssE0[t]F0\n" - "E0ssssss\n" - "C0G0\n" - "D0sssssss\n" - "F0sssssss\n" - "G0sss\n", - - "R0ssssA0sss\n" - }, { - "Leave some passes, remove others", - - "R0ssssA0[c]sss\n" - "A0sssB0[t]C0[ct]s\n" - "B0sssD0[c]ss\n" - "C0G0\n" - "D0sssssss\n" - "G0sss\n", - - "R0ssssA0sss\n" - "A0sssB0C0s\n" - "B0sssD0ss\n" - "D0sssssss\n" - }, { - 0, 0, 0 - } -}; - -static void VerifyRenderPassTestData( - const TestCase& test_case, - const RenderPassRemovalTestData& test_data) { - char actual_result[1024]; - DumpRenderPassTestData(test_data, actual_result); - EXPECT_STREQ(test_case.expected_result, actual_result) << "In test case: " << - test_case.name; -} - -TEST_F(LayerTreeHostImplTest, TestRemoveRenderPasses) { - LayerTreeSettings settings; - FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(CreateOutputSurface()); - ASSERT_TRUE(output_surface->BindToClient(&output_surface_client)); - ASSERT_TRUE(output_surface->context_provider()); - - scoped_ptr<ResourceProvider> resource_provider = - ResourceProvider::Create(output_surface.get(), 0, false); - - scoped_ptr<TestRenderer> renderer = TestRenderer::Create( - &settings, resource_provider.get(), output_surface.get(), &proxy_); - - int test_case_index = 0; - while (remove_render_passes_cases[test_case_index].name) { - RenderPassRemovalTestData test_data; - ConfigureRenderPassTestData( - remove_render_passes_cases[test_case_index].init_script, - &test_data, - renderer.get()); - LayerTreeHostImpl::RemoveRenderPasses( - LayerTreeHostImpl::CullRenderPassesWithCachedTextures(renderer.get()), - &test_data); - VerifyRenderPassTestData(remove_render_passes_cases[test_case_index], - test_data); - test_case_index++; - } -} - class LayerTreeHostImplTestWithDelegatingRenderer : public LayerTreeHostImplTest { protected: @@ -5436,7 +3990,7 @@ class LayerTreeHostImplTestWithDelegatingRenderer root_render_pass->quad_list[1]->visible_rect); } - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); EXPECT_EQ(expect_to_draw, host_impl_->SwapBuffers(frame)); } @@ -5497,12 +4051,7 @@ class FakeMaskLayerImpl : public LayerImpl { TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) { LayerTreeSettings settings; settings.layer_transforms_should_scale_layer_contents = true; - host_impl_ = LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); - host_impl_->InitializeRenderer(CreateOutputSurface()); - host_impl_->SetViewportSize(gfx::Size(10, 10)); + CreateHostImpl(settings, CreateOutputSurface()); // Root // | @@ -5578,7 +4127,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), render_pass_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -5606,7 +4155,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), render_pass_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -5636,7 +4185,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), render_pass_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } } @@ -5699,7 +4248,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), render_pass_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -5726,7 +4275,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), render_pass_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -5756,7 +4305,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), render_pass_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -5781,7 +4330,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), render_pass_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } } @@ -5850,7 +4399,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), replica_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -5878,7 +4427,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), replica_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -5909,7 +4458,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), replica_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -5935,7 +4484,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), replica_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } } @@ -6026,7 +4575,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerForSurfaceWithUnclippedChild) { EXPECT_EQ(gfx::RectF(0.f, 0.f, 2.f, 1.f).ToString(), replica_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -6060,7 +4609,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerForSurfaceWithUnclippedChild) { EXPECT_EQ(gfx::RectF(-1.f, 0.f, 2.f, 1.f).ToString(), replica_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } } @@ -6156,7 +4705,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerForSurfaceWithClippedLayer) { 1.f / 50.f).ToString(), render_pass_quad->mask_uv_rect.ToString()); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } } @@ -6229,7 +4778,7 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { quad->quadTransform(), quad, &device_layer_quad, edge); EXPECT_FALSE(antialiased); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); } @@ -6279,13 +4828,14 @@ class CountingSoftwareDevice : public SoftwareOutputDevice { TEST_F(LayerTreeHostImplTest, ForcedDrawToSoftwareDeviceBasicRender) { // No main thread evictions in resourceless software mode. set_reduce_memory_result(false); - SetupScrollAndContentsLayers(gfx::Size(100, 100)); - host_impl_->SetViewportSize(gfx::Size(50, 50)); CountingSoftwareDevice* software_device = new CountingSoftwareDevice(); FakeOutputSurface* output_surface = FakeOutputSurface::CreateDeferredGL( scoped_ptr<SoftwareOutputDevice>(software_device)).release(); - EXPECT_TRUE(host_impl_->InitializeRenderer( - scoped_ptr<OutputSurface>(output_surface))); + EXPECT_TRUE(CreateHostImpl(DefaultSettings(), + scoped_ptr<OutputSurface>(output_surface))); + host_impl_->SetViewportSize(gfx::Size(50, 50)); + + SetupScrollAndContentsLayers(gfx::Size(100, 100)); output_surface->set_forced_draw_to_software_device(true); EXPECT_TRUE(output_surface->ForcedDrawToSoftwareDevice()); @@ -6308,8 +4858,8 @@ TEST_F(LayerTreeHostImplTest, set_reduce_memory_result(false); FakeOutputSurface* output_surface = FakeOutputSurface::CreateDeferredGL( scoped_ptr<SoftwareOutputDevice>(new CountingSoftwareDevice())).release(); - host_impl_->InitializeRenderer( - scoped_ptr<OutputSurface>(output_surface)); + EXPECT_TRUE(CreateHostImpl(DefaultSettings(), + scoped_ptr<OutputSurface>(output_surface))); output_surface->set_forced_draw_to_software_device(true); EXPECT_TRUE(output_surface->ForcedDrawToSoftwareDevice()); @@ -6330,7 +4880,7 @@ TEST_F(LayerTreeHostImplTest, LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); EXPECT_EQ(1u, frame.will_draw_layers.size()); @@ -6349,8 +4899,8 @@ class LayerTreeHostImplTestDeferredInitialize : public LayerTreeHostImplTest { scoped_ptr<SoftwareOutputDevice>(new CountingSoftwareDevice()))); output_surface_ = output_surface.get(); - EXPECT_TRUE(host_impl_->InitializeRenderer( - output_surface.PassAs<OutputSurface>())); + EXPECT_TRUE(CreateHostImpl(DefaultSettings(), + output_surface.PassAs<OutputSurface>())); scoped_ptr<SolidColorLayerImpl> root_layer = SolidColorLayerImpl::Create(host_impl_->active_tree(), 1); @@ -6399,12 +4949,10 @@ TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails_OnscreenContext_0) { // Fail initialization of the onscreen context before the OutputSurface binds // it to the thread. - onscreen_context_provider_->UnboundTestContext3d() - ->set_times_make_current_succeeds(0); + onscreen_context_provider_->UnboundTestContext3d()->set_context_lost(true); EXPECT_FALSE(host_impl_->output_surface()->context_provider()); EXPECT_FALSE(host_impl_->offscreen_context_provider()); - EXPECT_FALSE(did_lose_output_surface_); // DeferredInitialize fails. EXPECT_FALSE(output_surface_->InitializeAndSetContext3d( @@ -6420,78 +4968,58 @@ TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails_OnscreenContext_1) { // Software draw. DrawFrame(); - // Fail initialization of the onscreen context after the OutputSurface binds - // it to the thread. - onscreen_context_provider_->UnboundTestContext3d() - ->set_times_make_current_succeeds(2); - EXPECT_FALSE(host_impl_->output_surface()->context_provider()); EXPECT_FALSE(host_impl_->offscreen_context_provider()); - EXPECT_FALSE(did_lose_output_surface_); + onscreen_context_provider_->UnboundTestContext3d()->set_context_lost(true); + + EXPECT_FALSE(host_impl_->output_surface()->context_provider()); // DeferredInitialize fails. EXPECT_FALSE(output_surface_->InitializeAndSetContext3d( onscreen_context_provider_, offscreen_context_provider_)); EXPECT_FALSE(host_impl_->output_surface()->context_provider()); EXPECT_FALSE(host_impl_->offscreen_context_provider()); - - // We lose the output surface. - EXPECT_TRUE(did_lose_output_surface_); } TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails_OnscreenContext_2) { // Software draw. DrawFrame(); - // Fail initialization of the onscreen context after the OutputSurface binds - // it to the thread and during renderer initialization. - onscreen_context_provider_->UnboundTestContext3d() - ->set_times_make_current_succeeds(1); - EXPECT_FALSE(host_impl_->output_surface()->context_provider()); EXPECT_FALSE(host_impl_->offscreen_context_provider()); - EXPECT_FALSE(did_lose_output_surface_); + + onscreen_context_provider_->UnboundTestContext3d()->set_context_lost(true); // DeferredInitialize fails. EXPECT_FALSE(output_surface_->InitializeAndSetContext3d( onscreen_context_provider_, offscreen_context_provider_)); EXPECT_FALSE(host_impl_->output_surface()->context_provider()); EXPECT_FALSE(host_impl_->offscreen_context_provider()); - - // We lose the output surface. - EXPECT_TRUE(did_lose_output_surface_); } TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails_OffscreenContext) { // Software draw. DrawFrame(); - // Fail initialization of the offscreen context. - offscreen_context_provider_->UnboundTestContext3d() - ->set_times_make_current_succeeds(0); - EXPECT_FALSE(host_impl_->output_surface()->context_provider()); EXPECT_FALSE(host_impl_->offscreen_context_provider()); - EXPECT_FALSE(did_lose_output_surface_); + + // Fail initialization of the offscreen context. + onscreen_context_provider_->UnboundTestContext3d()->set_context_lost(true); // DeferredInitialize fails. EXPECT_FALSE(output_surface_->InitializeAndSetContext3d( onscreen_context_provider_, offscreen_context_provider_)); EXPECT_FALSE(host_impl_->output_surface()->context_provider()); EXPECT_FALSE(host_impl_->offscreen_context_provider()); - - // We lose the output surface. - EXPECT_TRUE(did_lose_output_surface_); } // Checks that we have a non-0 default allocation if we pass a context that // doesn't support memory management extensions. TEST_F(LayerTreeHostImplTest, DefaultMemoryAllocation) { LayerTreeSettings settings; - host_impl_ = LayerTreeHostImpl::Create(settings, - this, - &proxy_, - &stats_instrumentation_); + host_impl_ = LayerTreeHostImpl::Create( + settings, this, &proxy_, &stats_instrumentation_, NULL, 0); scoped_ptr<OutputSurface> output_surface( FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create())); @@ -6501,25 +5029,24 @@ TEST_F(LayerTreeHostImplTest, DefaultMemoryAllocation) { TEST_F(LayerTreeHostImplTest, MemoryPolicy) { ManagedMemoryPolicy policy1( - 456, ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING, - 123, ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE, 1000); - int visible_cutoff_value = ManagedMemoryPolicy::PriorityCutoffToValue( - policy1.priority_cutoff_when_visible); - int not_visible_cutoff_value = ManagedMemoryPolicy::PriorityCutoffToValue( - policy1.priority_cutoff_when_not_visible); + 456, gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING, 1000); + int everything_cutoff_value = ManagedMemoryPolicy::PriorityCutoffToValue( + gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING); + int nothing_cutoff_value = ManagedMemoryPolicy::PriorityCutoffToValue( + gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING); host_impl_->SetVisible(true); host_impl_->SetMemoryPolicy(policy1); EXPECT_EQ(policy1.bytes_limit_when_visible, current_limit_bytes_); - EXPECT_EQ(visible_cutoff_value, current_priority_cutoff_value_); + EXPECT_EQ(everything_cutoff_value, current_priority_cutoff_value_); host_impl_->SetVisible(false); - EXPECT_EQ(policy1.bytes_limit_when_not_visible, current_limit_bytes_); - EXPECT_EQ(not_visible_cutoff_value, current_priority_cutoff_value_); + EXPECT_EQ(0u, current_limit_bytes_); + EXPECT_EQ(nothing_cutoff_value, current_priority_cutoff_value_); host_impl_->SetVisible(true); EXPECT_EQ(policy1.bytes_limit_when_visible, current_limit_bytes_); - EXPECT_EQ(visible_cutoff_value, current_priority_cutoff_value_); + EXPECT_EQ(everything_cutoff_value, current_priority_cutoff_value_); } class LayerTreeHostImplTestManageTiles : public LayerTreeHostImplTest { @@ -6549,7 +5076,7 @@ TEST_F(LayerTreeHostImplTest, UIResourceManagement) { TestWebGraphicsContext3D::Create(); TestWebGraphicsContext3D* context3d = context.get(); scoped_ptr<OutputSurface> output_surface = CreateFakeOutputSurface(); - host_impl_->InitializeRenderer(output_surface.Pass()); + CreateHostImpl(DefaultSettings(), output_surface.Pass()); EXPECT_EQ(0u, context3d->NumTextures()); @@ -6593,6 +5120,28 @@ TEST_F(LayerTreeHostImplTest, UIResourceManagement) { EXPECT_EQ(0u, context3d->NumTextures()); } +TEST_F(LayerTreeHostImplTest, CreateETC1UIResource) { + scoped_ptr<TestWebGraphicsContext3D> context = + TestWebGraphicsContext3D::Create(); + TestWebGraphicsContext3D* context3d = context.get(); + scoped_ptr<OutputSurface> output_surface = CreateFakeOutputSurface(); + CreateHostImpl(DefaultSettings(), output_surface.Pass()); + + EXPECT_EQ(0u, context3d->NumTextures()); + + scoped_ptr<uint8_t[]> pixels(new uint8_t[8]); + skia::RefPtr<ETC1PixelRef> etc1_pixel_ref = + skia::AdoptRef(new ETC1PixelRef(pixels.Pass())); + UIResourceBitmap bitmap(etc1_pixel_ref, gfx::Size(4, 4)); + + UIResourceId ui_resource_id = 1; + host_impl_->CreateUIResource(ui_resource_id, bitmap); + EXPECT_EQ(1u, context3d->NumTextures()); + ResourceProvider::ResourceId id1 = + host_impl_->ResourceIdForUIResource(ui_resource_id); + EXPECT_NE(0u, id1); +} + void ShutdownReleasesContext_Callback(scoped_ptr<CopyOutputResult> result) { } @@ -6600,13 +5149,9 @@ TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) { scoped_refptr<TestContextProvider> context_provider = TestContextProvider::Create(); - host_impl_ = LayerTreeHostImpl::Create(LayerTreeSettings(), - this, - &proxy_, - &stats_instrumentation_); - host_impl_->InitializeRenderer( + CreateHostImpl( + DefaultSettings(), FakeOutputSurface::Create3d(context_provider).PassAs<OutputSurface>()); - host_impl_->SetViewportSize(gfx::Size(10, 10)); SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1)); @@ -6618,7 +5163,7 @@ TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) { LayerTreeHostImpl::FrameData frame; EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); - host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); host_impl_->DidDrawAllLayers(frame); // The CopyOutputResult's callback has a ref on the ContextProvider and a @@ -6634,5 +5179,241 @@ TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) { EXPECT_EQ(0u, context_provider->TestContext3d()->NumTextures()); } +TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) { + // When flinging via touch, only the child should scroll (we should not + // bubble). + gfx::Size surface_size(10, 10); + gfx::Size content_size(20, 20); + scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size); + scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size); + + root->AddChild(child.Pass()); + + host_impl_->SetViewportSize(surface_size); + host_impl_->active_tree()->SetRootLayer(root.Pass()); + host_impl_->active_tree()->DidBecomeActive(); + DrawFrame(); + { + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(gfx::Point(), + InputHandler::Gesture)); + + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->FlingScrollBegin()); + + gfx::Vector2d scroll_delta(0, 100); + host_impl_->ScrollBy(gfx::Point(), scroll_delta); + host_impl_->ScrollBy(gfx::Point(), scroll_delta); + + host_impl_->ScrollEnd(); + + scoped_ptr<ScrollAndScaleSet> scroll_info = + host_impl_->ProcessScrollDeltas(); + + // Only the child should have scrolled. + ASSERT_EQ(1u, scroll_info->scrolls.size()); + ExpectNone(*scroll_info.get(), + host_impl_->active_tree()->root_layer()->id()); + } +} + +TEST_F(LayerTreeHostImplTest, TouchFlingShouldBubbleIfPrecedingScrollBubbled) { + // When flinging via touch, bubble scrolls if the touch scroll + // immediately preceding the fling bubbled. + gfx::Size surface_size(10, 10); + gfx::Size root_content_size(10, 20); + gfx::Size child_content_size(40, 40); + scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, root_content_size); + scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, child_content_size); + + root->AddChild(child.Pass()); + + host_impl_->SetViewportSize(surface_size); + host_impl_->active_tree()->SetRootLayer(root.Pass()); + host_impl_->active_tree()->DidBecomeActive(); + DrawFrame(); + { + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(gfx::Point(), + InputHandler::Gesture)); + + // Touch scroll before starting the fling. The second scroll should bubble. + EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 100))); + EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 5))); + + scoped_ptr<ScrollAndScaleSet> scroll_info = + host_impl_->ProcessScrollDeltas(); + + // The root should have (partially) scrolled. + EXPECT_EQ(2u, scroll_info->scrolls.size()); + ExpectContains(*scroll_info.get(), + host_impl_->active_tree()->root_layer()->id(), + gfx::Vector2d(0, 5)); + + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->FlingScrollBegin()); + + EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 5))); + host_impl_->ScrollEnd(); + + // The root should have (fully) scrolled from the fling. + scroll_info = host_impl_->ProcessScrollDeltas(); + EXPECT_EQ(2u, scroll_info->scrolls.size()); + ExpectContains(*scroll_info.get(), + host_impl_->active_tree()->root_layer()->id(), + gfx::Vector2d(0, 10)); + } +} + +TEST_F(LayerTreeHostImplTest, WheelFlingShouldBubble) { + // When flinging via wheel, the root should eventually scroll (we should + // bubble). + gfx::Size surface_size(10, 10); + gfx::Size content_size(20, 20); + scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size); + scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size); + + root->AddChild(child.Pass()); + + host_impl_->SetViewportSize(surface_size); + host_impl_->active_tree()->SetRootLayer(root.Pass()); + host_impl_->active_tree()->DidBecomeActive(); + DrawFrame(); + { + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); + + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->FlingScrollBegin()); + + gfx::Vector2d scroll_delta(0, 100); + host_impl_->ScrollBy(gfx::Point(), scroll_delta); + host_impl_->ScrollBy(gfx::Point(), scroll_delta); + + host_impl_->ScrollEnd(); + + scoped_ptr<ScrollAndScaleSet> scroll_info = + host_impl_->ProcessScrollDeltas(); + + // The root should have scrolled. + ASSERT_EQ(2u, scroll_info->scrolls.size()); + ExpectContains(*scroll_info.get(), + host_impl_->active_tree()->root_layer()->id(), + gfx::Vector2d(0, 10)); + } +} + +// Make sure LatencyInfo carried by LatencyInfoSwapPromise are passed +// to CompositorFrameMetadata after SwapBuffers(); +TEST_F(LayerTreeHostImplTest, LatencyInfoPassedToCompositorFrameMetadata) { + scoped_ptr<SolidColorLayerImpl> root = + SolidColorLayerImpl::Create(host_impl_->active_tree(), 1); + root->SetAnchorPoint(gfx::PointF()); + root->SetPosition(gfx::PointF()); + root->SetBounds(gfx::Size(10, 10)); + root->SetContentBounds(gfx::Size(10, 10)); + root->SetDrawsContent(true); + + host_impl_->active_tree()->SetRootLayer(root.PassAs<LayerImpl>()); + + FakeOutputSurface* fake_output_surface = + static_cast<FakeOutputSurface*>(host_impl_->output_surface()); + + const ui::LatencyInfo& metadata_latency_before = + fake_output_surface->last_sent_frame().metadata.latency_info; + EXPECT_FALSE(metadata_latency_before.FindLatency( + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, NULL)); + + ui::LatencyInfo latency_info; + latency_info.AddLatencyNumber( + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, 0); + scoped_ptr<SwapPromise> swap_promise( + new LatencyInfoSwapPromise(latency_info)); + host_impl_->active_tree()->QueueSwapPromise(swap_promise.Pass()); + host_impl_->SetNeedsRedraw(); + + gfx::Rect full_frame_damage(host_impl_->DrawViewportSize()); + LayerTreeHostImpl::FrameData frame; + EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); + host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); + host_impl_->DidDrawAllLayers(frame); + EXPECT_TRUE(host_impl_->SwapBuffers(frame)); + + const ui::LatencyInfo& metadata_latency_after = + fake_output_surface->last_sent_frame().metadata.latency_info; + EXPECT_TRUE(metadata_latency_after.FindLatency( + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, NULL)); +} + +class SimpleSwapPromiseMonitor : public SwapPromiseMonitor { + public: + SimpleSwapPromiseMonitor(LayerTreeHost* layer_tree_host, + LayerTreeHostImpl* layer_tree_host_impl, + int* set_needs_commit_count, + int* set_needs_redraw_count) + : SwapPromiseMonitor(layer_tree_host, layer_tree_host_impl), + set_needs_commit_count_(set_needs_commit_count), + set_needs_redraw_count_(set_needs_redraw_count) {} + + virtual ~SimpleSwapPromiseMonitor() {} + + virtual void OnSetNeedsCommitOnMain() OVERRIDE { + (*set_needs_commit_count_)++; + } + + virtual void OnSetNeedsRedrawOnImpl() OVERRIDE { + (*set_needs_redraw_count_)++; + } + + private: + int* set_needs_commit_count_; + int* set_needs_redraw_count_; +}; + +TEST_F(LayerTreeHostImplTest, SimpleSwapPromiseMonitor) { + int set_needs_commit_count = 0; + int set_needs_redraw_count = 0; + + { + scoped_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( + new SimpleSwapPromiseMonitor(NULL, + host_impl_.get(), + &set_needs_commit_count, + &set_needs_redraw_count)); + host_impl_->SetNeedsRedraw(); + EXPECT_EQ(0, set_needs_commit_count); + EXPECT_EQ(1, set_needs_redraw_count); + } + + // Now the monitor is destroyed, SetNeedsRedraw() is no longer being + // monitored. + host_impl_->SetNeedsRedraw(); + EXPECT_EQ(0, set_needs_commit_count); + EXPECT_EQ(1, set_needs_redraw_count); + + { + scoped_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( + new SimpleSwapPromiseMonitor(NULL, + host_impl_.get(), + &set_needs_commit_count, + &set_needs_redraw_count)); + host_impl_->SetNeedsRedrawRect(gfx::Rect(10, 10)); + EXPECT_EQ(0, set_needs_commit_count); + EXPECT_EQ(2, set_needs_redraw_count); + } + + { + scoped_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( + new SimpleSwapPromiseMonitor(NULL, + host_impl_.get(), + &set_needs_commit_count, + &set_needs_redraw_count)); + // Empty damage rect won't signal the monitor. + host_impl_->SetNeedsRedrawRect(gfx::Rect()); + EXPECT_EQ(0, set_needs_commit_count); + EXPECT_EQ(2, set_needs_redraw_count); + } +} + } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_perftest.cc b/chromium/cc/trees/layer_tree_host_perftest.cc index 5ca78b64d49..1bfe1c49d9e 100644 --- a/chromium/cc/trees/layer_tree_host_perftest.cc +++ b/chromium/cc/trees/layer_tree_host_perftest.cc @@ -4,6 +4,8 @@ #include "cc/trees/layer_tree_host.h" +#include <sstream> + #include "base/file_util.h" #include "base/files/file_path.h" #include "base/path_service.h" @@ -12,6 +14,8 @@ #include "cc/layers/content_layer.h" #include "cc/layers/nine_patch_layer.h" #include "cc/layers/solid_color_layer.h" +#include "cc/layers/texture_layer.h" +#include "cc/resources/texture_mailbox.h" #include "cc/test/fake_content_layer_client.h" #include "cc/test/lap_timer.h" #include "cc/test/layer_tree_json_parser.h" @@ -40,6 +44,10 @@ class LayerTreeHostPerfTest : public LayerTreeTest { fake_content_layer_client_.set_paint_all_opaque(true); } + virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { + settings->throttle_frame_production = false; + } + virtual void BeginTest() OVERRIDE { BuildTree(); PostSetNeedsCommitToMainThread(); @@ -62,12 +70,11 @@ class LayerTreeHostPerfTest : public LayerTreeTest { } virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE { - if (TestEnded()) { + if (TestEnded() || CleanUpStarted()) return; - } draw_timer_.NextLap(); if (draw_timer_.HasTimeLimitExpired()) { - EndTest(); + CleanUpAndEndTest(impl); return; } if (!animation_driven_drawing_) @@ -76,17 +83,17 @@ class LayerTreeHostPerfTest : public LayerTreeTest { impl->SetFullRootLayerDamage(); } + virtual void CleanUpAndEndTest(LayerTreeHostImpl* host_impl) { EndTest(); } + + virtual bool CleanUpStarted() { return false; } + virtual void BuildTree() {} virtual void AfterTest() OVERRIDE { CHECK(!test_name_.empty()) << "Must SetTestName() before AfterTest()."; - perf_test::PrintResult("layer_tree_host_frame_count", "", test_name_, - draw_timer_.NumLaps(), "frame_count", true); perf_test::PrintResult("layer_tree_host_frame_time", "", test_name_, 1000 * draw_timer_.MsPerLap(), "us", true); if (measure_commit_cost_) { - perf_test::PrintResult("layer_tree_host_commit_count", "", test_name_, - commit_timer_.NumLaps(), "commit_count", true); perf_test::PrintResult("layer_tree_host_commit_time", "", test_name_, 1000 * commit_timer_.MsPerLap(), "us", true); } @@ -117,7 +124,7 @@ class LayerTreeHostPerfTestJsonReader : public LayerTreeHostPerfTest { void ReadTestFile(const std::string& name) { base::FilePath test_data_dir; - ASSERT_TRUE(PathService::Get(cc::DIR_TEST_DATA, &test_data_dir)); + ASSERT_TRUE(PathService::Get(CCPaths::DIR_TEST_DATA, &test_data_dir)); base::FilePath json_file = test_data_dir.AppendASCII(name + ".json"); ASSERT_TRUE(base::ReadFileToString(json_file, &json_)); } @@ -142,6 +149,12 @@ TEST_F(LayerTreeHostPerfTestJsonReader, TenTenSingleThread) { RunTest(false, false, false); } +TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreadedImplSide) { + SetTestName("10_10_threaded_impl_side"); + ReadTestFile("10_10_layer_tree"); + RunTestWithImplSidePainting(); +} + // Simulates a tab switcher scene with two stacks of 10 tabs each. TEST_F(LayerTreeHostPerfTestJsonReader, TenTenSingleThread_FullDamageEachFrame) { @@ -151,6 +164,14 @@ TEST_F(LayerTreeHostPerfTestJsonReader, RunTest(false, false, false); } +TEST_F(LayerTreeHostPerfTestJsonReader, + TenTenThreadedImplSide_FullDamageEachFrame) { + full_damage_each_frame_ = true; + SetTestName("10_10_threaded_impl_side_full_damage_each_frame"); + ReadTestFile("10_10_layer_tree"); + RunTestWithImplSidePainting(); +} + // Invalidates a leaf layer in the tree on the main thread after every commit. class LayerTreeHostPerfTestLeafInvalidates : public LayerTreeHostPerfTestJsonReader { @@ -185,6 +206,12 @@ TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenSingleThread) { RunTest(false, false, false); } +TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenThreadedImplSide) { + SetTestName("10_10_threaded_impl_side_leaf_invalidates"); + ReadTestFile("10_10_layer_tree"); + RunTestWithImplSidePainting(); +} + // Simulates main-thread scrolling on each frame. class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader { public: @@ -207,20 +234,93 @@ class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader { scoped_refptr<Layer> scrollable_; }; -TEST_F(ScrollingLayerTreePerfTest, LongScrollablePage) { +TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) { SetTestName("long_scrollable_page"); ReadTestFile("long_scrollable_page"); RunTest(false, false, false); } -class ImplSidePaintingPerfTest : public LayerTreeHostPerfTestJsonReader { - protected: - // Run test with impl-side painting. - void RunTestWithImplSidePainting() { RunTest(true, false, true); } +TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) { + SetTestName("long_scrollable_page_threaded_impl_side"); + ReadTestFile("long_scrollable_page"); + RunTestWithImplSidePainting(); +} + +static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {} + +// Simulates main-thread scrolling on each frame. +class BrowserCompositorInvalidateLayerTreePerfTest + : public LayerTreeHostPerfTestJsonReader { + public: + BrowserCompositorInvalidateLayerTreePerfTest() + : next_sync_point_(1), clean_up_started_(false) {} + + virtual void BuildTree() OVERRIDE { + LayerTreeHostPerfTestJsonReader::BuildTree(); + tab_contents_ = + static_cast<TextureLayer*>( + layer_tree_host()->root_layer()->children()[0]-> + children()[0]-> + children()[0]-> + children()[0].get()); + ASSERT_TRUE(tab_contents_.get()); + } + + virtual void WillCommit() OVERRIDE { + gpu::Mailbox gpu_mailbox; + std::ostringstream name_stream; + name_stream << "name" << next_sync_point_; + gpu_mailbox.SetName( + reinterpret_cast<const int8*>(name_stream.str().c_str())); + scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( + base::Bind(&EmptyReleaseCallback)); + TextureMailbox mailbox(gpu_mailbox, next_sync_point_); + next_sync_point_++; + + tab_contents_->SetTextureMailbox(mailbox, callback.Pass()); + } + + virtual void DidCommit() OVERRIDE { + if (CleanUpStarted()) + return; + layer_tree_host()->SetNeedsCommit(); + } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + if (CleanUpStarted()) + EndTest(); + } + + virtual void CleanUpAndEndTest(LayerTreeHostImpl* host_impl) OVERRIDE { + clean_up_started_ = true; + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&BrowserCompositorInvalidateLayerTreePerfTest:: + CleanUpAndEndTestOnMainThread, + base::Unretained(this))); + } + + void CleanUpAndEndTestOnMainThread() { + tab_contents_->SetTextureMailbox(TextureMailbox(), + scoped_ptr<SingleReleaseCallback>()); + } + + virtual bool CleanUpStarted() OVERRIDE { return clean_up_started_; } + + private: + scoped_refptr<TextureLayer> tab_contents_; + unsigned next_sync_point_; + bool clean_up_started_; }; +TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUI) { + SetTestName("dense_layer_tree"); + ReadTestFile("dense_layer_tree"); + RunTestWithImplSidePainting(); +} + // Simulates a page with several large, transformed and animated layers. -TEST_F(ImplSidePaintingPerfTest, HeavyPage) { +TEST_F(LayerTreeHostPerfTestJsonReader, HeavyPageThreadedImplSide) { animation_driven_drawing_ = true; measure_commit_cost_ = true; SetTestName("heavy_page"); @@ -228,7 +328,8 @@ TEST_F(ImplSidePaintingPerfTest, HeavyPage) { RunTestWithImplSidePainting(); } -class PageScaleImplSidePaintingPerfTest : public ImplSidePaintingPerfTest { +class PageScaleImplSidePaintingPerfTest + : public LayerTreeHostPerfTestJsonReader { public: PageScaleImplSidePaintingPerfTest() : max_scale_(16.f), min_scale_(1.f / max_scale_) {} diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc new file mode 100644 index 00000000000..7a492a1d5bf --- /dev/null +++ b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc @@ -0,0 +1,120 @@ +// Copyright 2013 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 "cc/layers/solid_color_layer.h" +#include "cc/layers/texture_layer.h" +#include "cc/test/layer_tree_pixel_test.h" + +#if !defined(OS_ANDROID) + +namespace cc { +namespace { + +SkXfermode::Mode const kBlendModes[] = { + SkXfermode::kSrcOver_Mode, SkXfermode::kScreen_Mode, + SkXfermode::kOverlay_Mode, SkXfermode::kDarken_Mode, + SkXfermode::kLighten_Mode, SkXfermode::kColorDodge_Mode, + SkXfermode::kColorBurn_Mode, SkXfermode::kHardLight_Mode, + SkXfermode::kSoftLight_Mode, SkXfermode::kDifference_Mode, + SkXfermode::kExclusion_Mode, SkXfermode::kMultiply_Mode, + SkXfermode::kHue_Mode, SkXfermode::kSaturation_Mode, + SkXfermode::kColor_Mode, SkXfermode::kLuminosity_Mode}; + +const int kBlendModesCount = arraysize(kBlendModes); + +class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest { + protected: + void RunBlendingWithRootPixelTestType(PixelTestType type) { + const int kLaneWidth = 15; + const int kLaneHeight = kBlendModesCount * kLaneWidth; + const int kRootSize = (kBlendModesCount + 2) * kLaneWidth; + + scoped_refptr<SolidColorLayer> background = + CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange); + + // Orange child layers will blend with the green background + for (int i = 0; i < kBlendModesCount; ++i) { + gfx::Rect child_rect( + (i + 1) * kLaneWidth, kLaneWidth, kLaneWidth, kLaneHeight); + scoped_refptr<SolidColorLayer> green_lane = + CreateSolidColorLayer(child_rect, kCSSGreen); + background->AddChild(green_lane); + green_lane->SetBlendMode(kBlendModes[i]); + } + + RunPixelTest(type, + background, + base::FilePath(FILE_PATH_LITERAL("blending_with_root.png"))); + } + + void RunBlendingWithTransparentPixelTestType(PixelTestType type) { + const int kLaneWidth = 15; + const int kLaneHeight = kBlendModesCount * kLaneWidth; + const int kRootSize = (kBlendModesCount + 2) * kLaneWidth; + + scoped_refptr<SolidColorLayer> root = + CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSBrown); + + scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( + gfx::Rect(0, kLaneWidth * 2, kRootSize, kLaneWidth), kCSSOrange); + + root->AddChild(background); + background->SetIsRootForIsolatedGroup(true); + + // Orange child layers will blend with the green background + for (int i = 0; i < kBlendModesCount; ++i) { + gfx::Rect child_rect( + (i + 1) * kLaneWidth, -kLaneWidth, kLaneWidth, kLaneHeight); + scoped_refptr<SolidColorLayer> green_lane = + CreateSolidColorLayer(child_rect, kCSSGreen); + background->AddChild(green_lane); + green_lane->SetBlendMode(kBlendModes[i]); + } + + RunPixelTest(type, + root, + base::FilePath(FILE_PATH_LITERAL("blending_transparent.png"))); + } +}; + +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) { + RunBlendingWithRootPixelTestType(GL_WITH_BITMAP); +} + +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) { + const int kLaneWidth = 15; + const int kLaneHeight = kBlendModesCount * kLaneWidth; + const int kRootSize = (kBlendModesCount + 2) * kLaneWidth; + + scoped_refptr<SolidColorLayer> background = + CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange); + + // Orange child layers have a background filter set and they will blend with + // the green background + for (int i = 0; i < kBlendModesCount; ++i) { + gfx::Rect child_rect( + (i + 1) * kLaneWidth, kLaneWidth, kLaneWidth, kLaneHeight); + scoped_refptr<SolidColorLayer> green_lane = + CreateSolidColorLayer(child_rect, kCSSGreen); + background->AddChild(green_lane); + + FilterOperations filters; + filters.Append(FilterOperation::CreateGrayscaleFilter(.75)); + green_lane->SetBackgroundFilters(filters); + green_lane->SetBlendMode(kBlendModes[i]); + } + + RunPixelTest(GL_WITH_BITMAP, + background, + base::FilePath(FILE_PATH_LITERAL("blending_and_filter.png"))); +} + +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_GL) { + RunBlendingWithTransparentPixelTestType(GL_WITH_BITMAP); +} + +} // namespace +} // namespace cc + +#endif // OS_ANDROID diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc index 7068b4b1047..d2a6507f940 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc @@ -129,8 +129,8 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) { blur->SetBackgroundFilters(filters); #if defined(OS_WIN) - // Windows has 151 pixels off by at most 2: crbug.com/225027 - float percentage_pixels_large_error = 0.3775f; // 151px / (200*200) + // Windows has 153 pixels off by at most 2: crbug.com/225027 + float percentage_pixels_large_error = 0.3825f; // 153px / (200*200) float percentage_pixels_small_error = 0.0f; float average_error_allowed_in_bad_pixels = 1.f; int large_error_allowed = 2; @@ -150,49 +150,58 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) { "background_filter_blur_off_axis.png"))); } -TEST_F(LayerTreeHostFiltersPixelTest, ImageFilterClipped) { - scoped_refptr<SolidColorLayer> root = CreateSolidColorLayer( - gfx::Rect(200, 200), SK_ColorBLACK); - - scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( - gfx::Rect(200, 200), SK_ColorYELLOW); - root->AddChild(background); - - scoped_refptr<SolidColorLayer> foreground = CreateSolidColorLayer( - gfx::Rect(200, 200), SK_ColorRED); - background->AddChild(foreground); - - SkScalar matrix[20]; - memset(matrix, 0, 20 * sizeof(matrix[0])); - // This filter does a red-blue swap, so the foreground becomes blue. - matrix[2] = matrix[6] = matrix[10] = matrix[18] = SK_Scalar1; - skia::RefPtr<SkColorFilter> colorFilter(skia::AdoptRef( - new SkColorMatrixFilter(matrix))); - // We filter only the bottom 200x100 pixels of the foreground. - SkIRect cropRect = SkIRect::MakeXYWH(0, 100, 200, 100); - skia::RefPtr<SkImageFilter> filter = - skia::AdoptRef(SkColorFilterImageFilter::Create( - colorFilter.get(), - NULL, - &cropRect)); - - // Make the foreground layer's render surface be clipped by the background - // layer. - background->SetMasksToBounds(true); - foreground->SetFilter(filter); - - // Then we translate the foreground up by 100 pixels in Y, so the cropped - // region is moved to to the top. This ensures that the crop rect is being - // correctly transformed in skia by the amount of clipping that the - // compositor performs. - gfx::Transform transform; - transform.Translate(0.0, -100.0); - foreground->SetTransform(transform); +class ImageFilterClippedPixelTest : public LayerTreeHostFiltersPixelTest { + protected: + void RunPixelTestType(PixelTestType test_type) { + scoped_refptr<SolidColorLayer> root = + CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK); + + scoped_refptr<SolidColorLayer> background = + CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorYELLOW); + root->AddChild(background); + + scoped_refptr<SolidColorLayer> foreground = + CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorRED); + background->AddChild(foreground); + + SkScalar matrix[20]; + memset(matrix, 0, 20 * sizeof(matrix[0])); + // This filter does a red-blue swap, so the foreground becomes blue. + matrix[2] = matrix[6] = matrix[10] = matrix[18] = SK_Scalar1; + skia::RefPtr<SkColorFilter> colorFilter( + skia::AdoptRef(new SkColorMatrixFilter(matrix))); + // We filter only the bottom 200x100 pixels of the foreground. + SkImageFilter::CropRect crop_rect(SkRect::MakeXYWH(0, 100, 200, 100)); + skia::RefPtr<SkImageFilter> filter = skia::AdoptRef( + SkColorFilterImageFilter::Create(colorFilter.get(), NULL, &crop_rect)); + FilterOperations filters; + filters.Append(FilterOperation::CreateReferenceFilter(filter)); + + // Make the foreground layer's render surface be clipped by the background + // layer. + background->SetMasksToBounds(true); + foreground->SetFilters(filters); + + // Then we translate the foreground up by 100 pixels in Y, so the cropped + // region is moved to to the top. This ensures that the crop rect is being + // correctly transformed in skia by the amount of clipping that the + // compositor performs. + gfx::Transform transform; + transform.Translate(0.0, -100.0); + foreground->SetTransform(transform); + + RunPixelTest(test_type, + background, + base::FilePath(FILE_PATH_LITERAL("blue_yellow.png"))); + } +}; + +TEST_F(ImageFilterClippedPixelTest, ImageFilterClipped_GL) { + RunPixelTestType(GL_WITH_BITMAP); +} - RunPixelTest(GL_WITH_BITMAP, - background, - base::FilePath(FILE_PATH_LITERAL( - "blue_yellow.png"))); +TEST_F(ImageFilterClippedPixelTest, ImageFilterClipped_Software) { + RunPixelTestType(SOFTWARE_WITH_BITMAP); } } // namespace diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc index 90570ec0b64..1d4f893d7d0 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc @@ -58,6 +58,7 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskOfLayer) { mask->SetIsMask(true); green->SetMaskLayer(mask.get()); + this->impl_side_painting_ = false; RunPixelTest(GL_WITH_BITMAP, background, base::FilePath(FILE_PATH_LITERAL("mask_of_layer.png"))); @@ -88,6 +89,7 @@ TEST_F(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) { green->SetMaskLayer(mask.get()); background->AddChild(green); + this->impl_side_painting_ = false; RunPixelTest(GL_WITH_BITMAP, background, base::FilePath(FILE_PATH_LITERAL("image_mask_of_layer.png"))); @@ -116,6 +118,7 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskOfClippedLayer) { mask->SetIsMask(true); green->SetMaskLayer(mask.get()); + this->impl_side_painting_ = false; RunPixelTest(GL_WITH_BITMAP, background, base::FilePath(FILE_PATH_LITERAL("mask_of_clipped_layer.png"))); @@ -145,6 +148,7 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskWithReplica) { replica->SetTransform(replica_transform); green->SetReplicaLayer(replica.get()); + this->impl_side_painting_ = false; RunPixelTest(GL_WITH_BITMAP, background, base::FilePath(FILE_PATH_LITERAL("mask_with_replica.png"))); @@ -183,6 +187,7 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskWithReplicaOfClippedLayer) { replica->SetTransform(replica_transform); green->SetReplicaLayer(replica.get()); + this->impl_side_painting_ = false; RunPixelTest(GL_WITH_BITMAP, background, base::FilePath(FILE_PATH_LITERAL( @@ -218,6 +223,7 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskOfReplica) { replica->SetMaskLayer(mask.get()); green->SetReplicaLayer(replica.get()); + this->impl_side_painting_ = false; RunPixelTest(GL_WITH_BITMAP, background, base::FilePath(FILE_PATH_LITERAL("mask_of_replica.png"))); @@ -260,6 +266,7 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskOfReplicaOfClippedLayer) { replica->SetMaskLayer(mask.get()); green->SetReplicaLayer(replica.get()); + this->impl_side_painting_ = false; RunPixelTest(GL_WITH_BITMAP, background, base::FilePath(FILE_PATH_LITERAL( diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc b/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc index a1990b01d5b..eaa97492c65 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc @@ -29,10 +29,8 @@ class LayerTreeHostOnDemandRasterPixelTest : public LayerTreePixelTest { virtual void BeginCommitOnThread(LayerTreeHostImpl* impl) OVERRIDE { // Not enough memory available. Enforce on-demand rasterization. impl->SetMemoryPolicy( - ManagedMemoryPolicy(1, ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING, - 1, ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING, + ManagedMemoryPolicy(1, gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING, 1000)); - impl->SetDiscardBackBufferWhenNotVisible(true); } virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc index d8e286183f5..e5bfcd24599 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc @@ -679,6 +679,7 @@ TEST_F(LayerTreeHostReadbackDeviceScalePixelTest, copy_subrect_ = gfx::Rect(25, 25, 50, 50); device_scale_factor_ = 2.f; + this->impl_side_painting_ = false; RunPixelTest(SOFTWARE_WITH_DEFAULT, background, base::FilePath(FILE_PATH_LITERAL( @@ -709,6 +710,7 @@ TEST_F(LayerTreeHostReadbackDeviceScalePixelTest, copy_subrect_ = gfx::Rect(25, 25, 50, 50); device_scale_factor_ = 2.f; + this->impl_side_painting_ = false; RunPixelTest(GL_WITH_DEFAULT, background, base::FilePath(FILE_PATH_LITERAL( @@ -740,6 +742,7 @@ TEST_F(LayerTreeHostReadbackDeviceScalePixelTest, copy_subrect_ = gfx::Rect(25, 25, 50, 50); device_scale_factor_ = 2.f; + this->impl_side_painting_ = false; RunPixelTestWithReadbackTarget(SOFTWARE_WITH_DEFAULT, background, green.get(), @@ -772,6 +775,7 @@ TEST_F(LayerTreeHostReadbackDeviceScalePixelTest, copy_subrect_ = gfx::Rect(25, 25, 50, 50); device_scale_factor_ = 2.f; + this->impl_side_painting_ = false; RunPixelTestWithReadbackTarget(GL_WITH_DEFAULT, background, green.get(), @@ -870,6 +874,7 @@ TEST_F(LayerTreeHostReadbackViaCompositeAndReadbackPixelTest, device_viewport_copy_subrect_ = gfx::Rect(50, 50, 100, 100); device_scale_factor_ = 1.f; + this->impl_side_painting_ = false; RunPixelTestWithReadbackTarget(SOFTWARE_WITH_DEFAULT, background, green.get(), @@ -901,6 +906,7 @@ TEST_F(LayerTreeHostReadbackViaCompositeAndReadbackPixelTest, device_viewport_copy_subrect_ = gfx::Rect(50, 50, 100, 100); device_scale_factor_ = 2.f; + this->impl_side_painting_ = false; RunPixelTestWithReadbackTarget(SOFTWARE_WITH_DEFAULT, background, green.get(), @@ -932,6 +938,7 @@ TEST_F(LayerTreeHostReadbackViaCompositeAndReadbackPixelTest, device_viewport_copy_subrect_ = gfx::Rect(50, 50, 100, 100); device_scale_factor_ = 1.f; + this->impl_side_painting_ = false; RunPixelTestWithReadbackTarget(GL_WITH_DEFAULT, background, green.get(), @@ -963,6 +970,7 @@ TEST_F(LayerTreeHostReadbackViaCompositeAndReadbackPixelTest, device_viewport_copy_subrect_ = gfx::Rect(50, 50, 100, 100); device_scale_factor_ = 2.f; + this->impl_side_painting_ = false; RunPixelTestWithReadbackTarget(GL_WITH_DEFAULT, background, green.get(), @@ -992,46 +1000,6 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerOutsideViewport) { "green_with_blue_corner.png"))); } -// TextureLayers are clipped differently than SolidColorLayers, verify they -// also can be copied when outside of the viewport. -TEST_F(LayerTreeHostReadbackPixelTest, - ReadbackNonRootTextureLayerOutsideViewport) { - scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( - gfx::Rect(200, 200), SK_ColorWHITE); - - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200); - bitmap.allocPixels(); - bitmap.eraseColor(SK_ColorGREEN); - { - SkBitmapDevice device(bitmap); - skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(new SkCanvas(&device)); - SkPaint paint; - paint.setStyle(SkPaint::kFill_Style); - paint.setColor(SK_ColorBLUE); - canvas->drawRect(SkRect::MakeXYWH(150, 150, 50, 50), paint); - } - - scoped_refptr<TextureLayer> texture = CreateTextureLayer( - gfx::Rect(200, 200), bitmap); - - // Tests with solid color layers verify correctness when CanClipSelf is false. - EXPECT_FALSE(background->CanClipSelf()); - // This test verifies correctness when CanClipSelf is true. - EXPECT_TRUE(texture->CanClipSelf()); - - // Only the top left quarter of the layer is inside the viewport, so the - // blue corner is entirely outside. - texture->SetPosition(gfx::Point(100, 100)); - background->AddChild(texture); - - RunPixelTestWithReadbackTarget(GL_WITH_DEFAULT, - background, - texture.get(), - base::FilePath(FILE_PATH_LITERAL( - "green_with_blue_corner.png"))); -} - } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_single_thread_client.h b/chromium/cc/trees/layer_tree_host_single_thread_client.h new file mode 100644 index 00000000000..cb6145048e6 --- /dev/null +++ b/chromium/cc/trees/layer_tree_host_single_thread_client.h @@ -0,0 +1,33 @@ +// Copyright 2013 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 CC_TREES_LAYER_TREE_HOST_SINGLE_THREAD_CLIENT_H_ +#define CC_TREES_LAYER_TREE_HOST_SINGLE_THREAD_CLIENT_H_ + +namespace cc { + +class LayerTreeHostSingleThreadClient { + public: + // Request that the client schedule a composite. + virtual void ScheduleComposite() = 0; + // Request that the client schedule a composite now, and calculate appropriate + // delay for potential future frame. + virtual void ScheduleAnimation() = 0; + + // Called whenever the compositor posts a SwapBuffers (either full or + // partial). After DidPostSwapBuffers(), exactly one of + // DidCompleteSwapBuffers() or DidAbortSwapBuffers() will be called, thus + // these functions can be used to keep track of pending swap buffers calls for + // rate limiting. + virtual void DidPostSwapBuffers() = 0; + virtual void DidCompleteSwapBuffers() = 0; + virtual void DidAbortSwapBuffers() = 0; + + protected: + virtual ~LayerTreeHostSingleThreadClient() {} +}; + +} // namespace cc + +#endif // CC_TREES_LAYER_TREE_HOST_SINGLE_THREAD_CLIENT_H_ diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc index 92cba325587..0ac203a9a9e 100644 --- a/chromium/cc/trees/layer_tree_host_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_unittest.cc @@ -9,8 +9,8 @@ #include "base/auto_reset.h" #include "base/synchronization/lock.h" #include "cc/animation/timing_function.h" +#include "cc/base/swap_promise.h" #include "cc/debug/frame_rate_counter.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/layers/content_layer.h" #include "cc/layers/content_layer_client.h" #include "cc/layers/io_surface_layer.h" @@ -29,6 +29,7 @@ #include "cc/scheduler/frame_rate_controller.h" #include "cc/test/fake_content_layer.h" #include "cc/test/fake_content_layer_client.h" +#include "cc/test/fake_content_layer_impl.h" #include "cc/test/fake_layer_tree_host_client.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_painted_scrollbar_layer.h" @@ -40,6 +41,7 @@ #include "cc/test/geometry_test_utils.h" #include "cc/test/layer_tree_test.h" #include "cc/test/occlusion_tracker_test_common.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/layer_tree_impl.h" #include "cc/trees/single_thread_proxy.h" @@ -50,6 +52,7 @@ #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "third_party/skia/include/core/SkPicture.h" +#include "ui/gfx/frame_time.h" #include "ui/gfx/point_conversions.h" #include "ui/gfx/size_conversions.h" #include "ui/gfx/vector2d_conversions.h" @@ -636,6 +639,194 @@ class LayerTreeHostTestCompositeAndReadbackAfterForcedDraw MULTI_THREAD_TEST_F(LayerTreeHostTestCompositeAndReadbackAfterForcedDraw); +class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest { + public: + LayerTreeHostTestSetNextCommitForcesRedraw() + : num_draws_(0), + bounds_(50, 50), + invalid_rect_(10, 10, 20, 20), + root_layer_(ContentLayer::Create(&client_)) { + } + + virtual void BeginTest() OVERRIDE { + root_layer_->SetIsDrawable(true); + root_layer_->SetBounds(bounds_); + layer_tree_host()->SetRootLayer(root_layer_); + layer_tree_host()->SetViewportSize(bounds_); + PostSetNeedsCommitToMainThread(); + } + + virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + if (num_draws_ == 3 && host_impl->settings().impl_side_painting) + host_impl->SetNeedsRedrawRect(invalid_rect_); + } + + virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, + LayerTreeHostImpl::FrameData* frame_data, + bool result) OVERRIDE { + EXPECT_TRUE(result); + + gfx::RectF root_damage_rect; + if (!frame_data->render_passes.empty()) + root_damage_rect = frame_data->render_passes.back()->damage_rect; + + switch (num_draws_) { + case 0: + EXPECT_RECT_EQ(gfx::Rect(bounds_), root_damage_rect); + break; + case 1: + case 2: + EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root_damage_rect); + break; + case 3: + EXPECT_RECT_EQ(invalid_rect_, root_damage_rect); + break; + case 4: + EXPECT_RECT_EQ(gfx::Rect(bounds_), root_damage_rect); + break; + default: + NOTREACHED(); + } + + return result; + } + + virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + switch (num_draws_) { + case 0: + case 1: + // Cycle through a couple of empty commits to ensure we're observing the + // right behavior + PostSetNeedsCommitToMainThread(); + break; + case 2: + // Should force full frame damage on the next commit + PostSetNextCommitForcesRedrawToMainThread(); + PostSetNeedsCommitToMainThread(); + if (host_impl->settings().impl_side_painting) + host_impl->BlockNotifyReadyToActivateForTesting(true); + else + num_draws_++; + break; + case 3: + host_impl->BlockNotifyReadyToActivateForTesting(false); + break; + default: + EndTest(); + break; + } + num_draws_++; + } + + virtual void AfterTest() OVERRIDE { + EXPECT_EQ(5, num_draws_); + } + + private: + int num_draws_; + const gfx::Size bounds_; + const gfx::Rect invalid_rect_; + FakeContentLayerClient client_; + scoped_refptr<ContentLayer> root_layer_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNextCommitForcesRedraw); + +// Tests that if a layer is not drawn because of some reason in the parent then +// its damage is preserved until the next time it is drawn. +class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest { + public: + LayerTreeHostTestUndrawnLayersDamageLater() + : root_layer_(ContentLayer::Create(&client_)) { + } + + virtual void SetupTree() OVERRIDE { + root_layer_->SetIsDrawable(true); + root_layer_->SetBounds(gfx::Size(50, 50)); + layer_tree_host()->SetRootLayer(root_layer_); + + // The initially transparent layer has a larger child layer, which is + // not initially drawn because of the this (parent) layer. + parent_layer_ = FakeContentLayer::Create(&client_); + parent_layer_->SetBounds(gfx::Size(15, 15)); + parent_layer_->SetOpacity(0.0f); + root_layer_->AddChild(parent_layer_); + + child_layer_ = FakeContentLayer::Create(&client_); + child_layer_->SetBounds(gfx::Size(25, 25)); + parent_layer_->AddChild(child_layer_); + + LayerTreeHostTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { + PostSetNeedsCommitToMainThread(); + } + + virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, + LayerTreeHostImpl::FrameData* frame_data, + bool result) OVERRIDE { + EXPECT_TRUE(result); + + gfx::RectF root_damage_rect; + if (!frame_data->render_passes.empty()) + root_damage_rect = frame_data->render_passes.back()->damage_rect; + + // The first time, the whole view needs be drawn. + // Afterwards, just the opacity of surface_layer1 is changed a few times, + // and each damage should be the bounding box of it and its child. If this + // was working improperly, the damage might not include its childs bounding + // box. + switch (layer_tree_host()->source_frame_number()) { + case 1: + EXPECT_RECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect); + break; + case 2: + case 3: + case 4: + EXPECT_RECT_EQ(gfx::Rect(child_layer_->bounds()), root_damage_rect); + break; + default: + NOTREACHED(); + } + + return result; + } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + switch (layer_tree_host()->source_frame_number()) { + case 1: + // Test not owning the surface. + parent_layer_->SetOpacity(1.0f); + break; + case 2: + parent_layer_->SetOpacity(0.0f); + break; + case 3: + // Test owning the surface. + parent_layer_->SetOpacity(0.5f); + parent_layer_->SetForceRenderSurface(true); + break; + case 4: + EndTest(); + break; + default: + NOTREACHED(); + } + } + + + virtual void AfterTest() OVERRIDE {} + + private: + FakeContentLayerClient client_; + scoped_refptr<ContentLayer> root_layer_; + scoped_refptr<FakeContentLayer> parent_layer_; + scoped_refptr<FakeContentLayer> child_layer_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUndrawnLayersDamageLater); + // If the layerTreeHost says it can't draw, Then we should not try to draw. class LayerTreeHostTestCanDrawBlocksDrawing : public LayerTreeHostTest { public: @@ -842,16 +1033,31 @@ class LayerTreeHostTestFrameTimeUpdatesAfterActivationFails PostSetNeedsCommitToMainThread(); } - virtual void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, + virtual void BeginCommitOnThread(LayerTreeHostImpl *impl) OVERRIDE { + EXPECT_EQ(frame_count_with_pending_tree_, 0); + impl->BlockNotifyReadyToActivateForTesting(true); + } + + virtual void WillBeginImplFrameOnThread(LayerTreeHostImpl* impl, const BeginFrameArgs& args) OVERRIDE { - if (host_impl->pending_tree()) + if (impl->pending_tree()) frame_count_with_pending_tree_++; - host_impl->BlockNotifyReadyToActivateForTesting( - frame_count_with_pending_tree_ <= 1); + + if (frame_count_with_pending_tree_ == 2) + impl->BlockNotifyReadyToActivateForTesting(false); + } + + virtual void DidBeginImplFrameOnThread(LayerTreeHostImpl* impl, + const BeginFrameArgs& args) OVERRIDE { + if (frame_count_with_pending_tree_ == 1) { + EXPECT_EQ(first_frame_time_.ToInternalValue(), 0); + first_frame_time_ = impl->CurrentFrameTimeTicks(); + } } virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE { if (frame_count_with_pending_tree_ > 1) { + EXPECT_NE(first_frame_time_.ToInternalValue(), 0); EXPECT_NE(first_frame_time_.ToInternalValue(), impl->CurrentFrameTimeTicks().ToInternalValue()); EndTest(); @@ -895,10 +1101,9 @@ class LayerTreeHostTestFrameTimeUpdatesAfterDraw : public LayerTreeHostTest { first_frame_time_ = impl->CurrentFrameTimeTicks(); impl->SetNeedsRedraw(); - // Since base::TimeTicks::Now() uses a low-resolution clock on - // Windows, we need to make sure that the clock has incremented past - // first_frame_time_. - while (first_frame_time_ == base::TimeTicks::Now()) {} + // Since we might use a low-resolution clock on Windows, we need to + // make sure that the clock has incremented past first_frame_time_. + while (first_frame_time_ == gfx::FrameTime::Now()) {} return; } @@ -935,10 +1140,19 @@ class LayerTreeHostTestStartPageScaleAnimation virtual void SetupTree() OVERRIDE { LayerTreeHostTest::SetupTree(); - scroll_layer_ = FakeContentLayer::Create(&client_); + if (layer_tree_host()->settings().impl_side_painting) { + scoped_refptr<FakePictureLayer> layer = + FakePictureLayer::Create(&client_); + layer->set_always_update_resources(true); + scroll_layer_ = layer; + } else { + scroll_layer_ = FakeContentLayer::Create(&client_); + } + scroll_layer_->SetScrollable(true); scroll_layer_->SetScrollOffset(gfx::Vector2d()); layer_tree_host()->root_layer()->AddChild(scroll_layer_); + layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.5f, 2.f); } virtual void BeginTest() OVERRIDE { @@ -953,7 +1167,6 @@ class LayerTreeHostTestStartPageScaleAnimation } virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE { - impl->ProcessScrollDeltas(); // We get one commit before the first draw, and the animation doesn't happen // until the second draw. switch (impl->active_tree()->source_frame_number()) { @@ -963,7 +1176,6 @@ class LayerTreeHostTestStartPageScaleAnimation break; case 1: EXPECT_EQ(1.f, impl->active_tree()->page_scale_factor()); - PostSetNeedsRedrawToMainThread(); break; case 2: EXPECT_EQ(1.25f, impl->active_tree()->page_scale_factor()); @@ -977,7 +1189,6 @@ class LayerTreeHostTestStartPageScaleAnimation virtual void DidCommitAndDrawFrame() OVERRIDE { switch (layer_tree_host()->source_frame_number()) { case 1: - layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.5f, 2.f); layer_tree_host()->StartPageScaleAnimation( gfx::Vector2d(), false, 1.25f, base::TimeDelta()); break; @@ -987,7 +1198,7 @@ class LayerTreeHostTestStartPageScaleAnimation virtual void AfterTest() OVERRIDE {} FakeContentLayerClient client_; - scoped_refptr<FakeContentLayer> scroll_layer_; + scoped_refptr<Layer> scroll_layer_; }; MULTI_THREAD_TEST_F(LayerTreeHostTestStartPageScaleAnimation); @@ -1236,6 +1447,7 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers); class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest { public: virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { + settings->texture_id_allocation_chunk_size = 1; // Make sure partial texture updates are turned off. settings->max_partial_texture_updates = 0; // Linear fade animator prevents scrollbars from drawing immediately. @@ -1337,7 +1549,7 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest { int drew_frame_; }; -MULTI_THREAD_DIRECT_RENDERER_TEST_F( +MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( LayerTreeHostTestDirectRendererAtomicCommit); class LayerTreeHostTestDelegatingRendererAtomicCommit @@ -1390,7 +1602,7 @@ class LayerTreeHostTestDelegatingRendererAtomicCommit } }; -MULTI_THREAD_DELEGATING_RENDERER_TEST_F( +MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F( LayerTreeHostTestDelegatingRendererAtomicCommit); static void SetLayerPropertiesForTesting(Layer* layer, @@ -1414,6 +1626,7 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate : public LayerTreeHostTest { public: virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { + settings->texture_id_allocation_chunk_size = 1; // Allow one partial texture update. settings->max_partial_texture_updates = 1; // No partial updates when impl side painting is enabled. @@ -1483,31 +1696,57 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate context->ResetUsedTextures(); break; case 1: - // Number of textures should be two for each content layer. - ASSERT_EQ(4u, context->NumTextures()); + if (HasImplThread()) { + // Number of textures should be two for each content layer. + ASSERT_EQ(4u, context->NumTextures()); + } else { + // In single thread we can always do partial updates, so the limit has + // no effect. + ASSERT_EQ(2u, context->NumTextures()); + } // Number of textures used for commit should be one for each content // layer. EXPECT_EQ(2u, context->NumUsedTextures()); - // First content textures should not have been used. - EXPECT_FALSE(context->UsedTexture(context->TextureAt(0))); - EXPECT_FALSE(context->UsedTexture(context->TextureAt(1))); - // New textures should have been used. - EXPECT_TRUE(context->UsedTexture(context->TextureAt(2))); - EXPECT_TRUE(context->UsedTexture(context->TextureAt(3))); + if (HasImplThread()) { + // First content textures should not have been used. + EXPECT_FALSE(context->UsedTexture(context->TextureAt(0))); + EXPECT_FALSE(context->UsedTexture(context->TextureAt(1))); + // New textures should have been used. + EXPECT_TRUE(context->UsedTexture(context->TextureAt(2))); + EXPECT_TRUE(context->UsedTexture(context->TextureAt(3))); + } else { + // In single thread we can always do partial updates, so the limit has + // no effect. + EXPECT_TRUE(context->UsedTexture(context->TextureAt(0))); + EXPECT_TRUE(context->UsedTexture(context->TextureAt(1))); + } context->ResetUsedTextures(); break; case 2: - // Number of textures should be two for each content layer. - ASSERT_EQ(4u, context->NumTextures()); + if (HasImplThread()) { + // Number of textures should be two for each content layer. + ASSERT_EQ(4u, context->NumTextures()); + } else { + // In single thread we can always do partial updates, so the limit has + // no effect. + ASSERT_EQ(2u, context->NumTextures()); + } // Number of textures used for commit should be one for each content // layer. EXPECT_EQ(2u, context->NumUsedTextures()); - // One content layer does a partial update also. - EXPECT_TRUE(context->UsedTexture(context->TextureAt(2))); - EXPECT_FALSE(context->UsedTexture(context->TextureAt(3))); + if (HasImplThread()) { + // One content layer does a partial update also. + EXPECT_TRUE(context->UsedTexture(context->TextureAt(2))); + EXPECT_FALSE(context->UsedTexture(context->TextureAt(3))); + } else { + // In single thread we can always do partial updates, so the limit has + // no effect. + EXPECT_TRUE(context->UsedTexture(context->TextureAt(0))); + EXPECT_TRUE(context->UsedTexture(context->TextureAt(1))); + } context->ResetUsedTextures(); break; @@ -1623,10 +1862,6 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestCompositeAndReadbackCleanup); class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit : public LayerTreeHostTest { protected: - virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { - settings->cache_render_pass_contents = true; - } - virtual void SetupTree() OVERRIDE { root_layer_ = FakeContentLayer::Create(&client_); root_layer_->SetBounds(gfx::Size(100, 100)); @@ -1667,21 +1902,20 @@ class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit switch (host_impl->active_tree()->source_frame_number()) { case 0: - EXPECT_TRUE(renderer->HaveCachedResourcesForRenderPassId( + EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting( surface1_render_pass_id)); - EXPECT_TRUE(renderer->HaveCachedResourcesForRenderPassId( + EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting( surface2_render_pass_id)); // Reduce the memory limit to only fit the root layer and one render // surface. This prevents any contents drawing into surfaces // from being allocated. host_impl->SetMemoryPolicy(ManagedMemoryPolicy(100 * 100 * 4 * 2)); - host_impl->SetDiscardBackBufferWhenNotVisible(true); break; case 1: - EXPECT_FALSE(renderer->HaveCachedResourcesForRenderPassId( + EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting( surface1_render_pass_id)); - EXPECT_FALSE(renderer->HaveCachedResourcesForRenderPassId( + EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting( surface2_render_pass_id)); EndTest(); @@ -1709,7 +1943,7 @@ class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit }; // Surfaces don't exist with a delegated renderer. -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit); class EvictionTestLayer : public Layer { @@ -1933,7 +2167,7 @@ class LayerTreeHostTestEvictTextures : public LayerTreeHostTest { int num_commits_; }; -MULTI_THREAD_TEST_F(LayerTreeHostTestEvictTextures); +MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostTestEvictTextures); class LayerTreeHostTestContinuousCommit : public LayerTreeHostTest { public: @@ -2024,7 +2258,7 @@ class LayerTreeHostTestContinuousInvalidate : public LayerTreeHostTest { int num_draw_layers_; }; -MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousInvalidate); +MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostTestContinuousInvalidate); class LayerTreeHostTestDeferCommits : public LayerTreeHostTest { public: @@ -2072,7 +2306,7 @@ class LayerTreeHostWithProxy : public LayerTreeHost { LayerTreeHostWithProxy(FakeLayerTreeHostClient* client, const LayerTreeSettings& settings, scoped_ptr<FakeProxy> proxy) - : LayerTreeHost(client, settings) { + : LayerTreeHost(client, NULL, settings) { proxy->SetLayerTreeHost(this); EXPECT_TRUE(InitializeForTesting(proxy.PassAs<Proxy>())); } @@ -2093,7 +2327,7 @@ TEST(LayerTreeHostTest, LimitPartialUpdates) { LayerTreeHostWithProxy host(&client, settings, proxy.Pass()); EXPECT_TRUE(host.InitializeOutputSurfaceIfNeeded()); - EXPECT_EQ(0u, host.settings().max_partial_texture_updates); + EXPECT_EQ(0u, host.MaxPartialTextureUpdates()); } // When partial updates are allowed, @@ -2111,7 +2345,7 @@ TEST(LayerTreeHostTest, LimitPartialUpdates) { LayerTreeHostWithProxy host(&client, settings, proxy.Pass()); EXPECT_TRUE(host.InitializeOutputSurfaceIfNeeded()); - EXPECT_EQ(5u, host.settings().max_partial_texture_updates); + EXPECT_EQ(5u, host.MaxPartialTextureUpdates()); } // When partial updates are allowed, @@ -2129,7 +2363,7 @@ TEST(LayerTreeHostTest, LimitPartialUpdates) { LayerTreeHostWithProxy host(&client, settings, proxy.Pass()); EXPECT_TRUE(host.InitializeOutputSurfaceIfNeeded()); - EXPECT_EQ(10u, host.settings().max_partial_texture_updates); + EXPECT_EQ(10u, host.MaxPartialTextureUpdates()); } } @@ -2140,7 +2374,7 @@ TEST(LayerTreeHostTest, PartialUpdatesWithGLRenderer) { settings.max_partial_texture_updates = 4; scoped_ptr<LayerTreeHost> host = - LayerTreeHost::Create(&client, settings, NULL); + LayerTreeHost::CreateSingleThreaded(&client, &client, NULL, settings); EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded()); EXPECT_EQ(4u, host->settings().max_partial_texture_updates); } @@ -2152,7 +2386,7 @@ TEST(LayerTreeHostTest, PartialUpdatesWithSoftwareRenderer) { settings.max_partial_texture_updates = 4; scoped_ptr<LayerTreeHost> host = - LayerTreeHost::Create(&client, settings, NULL); + LayerTreeHost::CreateSingleThreaded(&client, &client, NULL, settings); EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded()); EXPECT_EQ(4u, host->settings().max_partial_texture_updates); } @@ -2164,9 +2398,9 @@ TEST(LayerTreeHostTest, PartialUpdatesWithDelegatingRendererAndGLContent) { settings.max_partial_texture_updates = 4; scoped_ptr<LayerTreeHost> host = - LayerTreeHost::Create(&client, settings, NULL); + LayerTreeHost::CreateSingleThreaded(&client, &client, NULL, settings); EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded()); - EXPECT_EQ(0u, host->settings().max_partial_texture_updates); + EXPECT_EQ(0u, host->MaxPartialTextureUpdates()); } TEST(LayerTreeHostTest, @@ -2177,9 +2411,9 @@ TEST(LayerTreeHostTest, settings.max_partial_texture_updates = 4; scoped_ptr<LayerTreeHost> host = - LayerTreeHost::Create(&client, settings, NULL); + LayerTreeHost::CreateSingleThreaded(&client, &client, NULL, settings); EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded()); - EXPECT_EQ(0u, host->settings().max_partial_texture_updates); + EXPECT_EQ(0u, host->MaxPartialTextureUpdates()); } class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted @@ -2204,9 +2438,17 @@ class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl, bool visible) OVERRIDE { - // One backing should remain unevicted. - EXPECT_EQ(100u * 100u * 4u * 1u, - layer_tree_host()->contents_texture_manager()->MemoryUseBytes()); + if (visible) { + // One backing should remain unevicted. + EXPECT_EQ( + 100u * 100u * 4u * 1u, + layer_tree_host()->contents_texture_manager()->MemoryUseBytes()); + } else { + EXPECT_EQ( + 0u, + layer_tree_host()->contents_texture_manager()->MemoryUseBytes()); + } + // Make sure that contents textures are marked as having been // purged. EXPECT_TRUE(host_impl->active_tree()->ContentsTexturesPurged()); @@ -2226,11 +2468,8 @@ class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted // Because a resource was evicted, a commit will be kicked off. host_impl->SetMemoryPolicy( ManagedMemoryPolicy(100 * 100 * 4 * 2, - ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING, - 100 * 100 * 4 * 1, - ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING, + gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING, 1000)); - host_impl->SetDiscardBackBufferWhenNotVisible(true); break; case 2: // Only two backings should have memory. @@ -2259,7 +2498,7 @@ class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted int num_commits_; }; -SINGLE_AND_MULTI_THREAD_TEST_F( +SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F( LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted); class LayerTreeHostTestLCDNotification : public LayerTreeHostTest { @@ -2350,15 +2589,16 @@ class LayerTreeHostTestLCDNotification : public LayerTreeHostTest { SINGLE_THREAD_TEST_F(LayerTreeHostTestLCDNotification); -// Verify that the BeginFrame notification is used to initiate rendering. -class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest { +// Verify that the BeginImplFrame notification is used to initiate rendering. +class LayerTreeHostTestBeginImplFrameNotification : public LayerTreeHostTest { public: virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { - settings->begin_frame_scheduling_enabled = true; + settings->begin_impl_frame_scheduling_enabled = true; } virtual void BeginTest() OVERRIDE { - // This will trigger a SetNeedsBeginFrame which will trigger a BeginFrame. + // This will trigger a SetNeedsBeginImplFrame which will trigger a + // BeginImplFrame. PostSetNeedsCommitToMainThread(); } @@ -2376,24 +2616,24 @@ class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest { base::TimeTicks frame_time_; }; -MULTI_THREAD_TEST_F(LayerTreeHostTestBeginFrameNotification); +MULTI_THREAD_TEST_F(LayerTreeHostTestBeginImplFrameNotification); -class LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled +class LayerTreeHostTestBeginImplFrameNotificationShutdownWhileEnabled : public LayerTreeHostTest { public: virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { - settings->begin_frame_scheduling_enabled = true; + settings->begin_impl_frame_scheduling_enabled = true; settings->using_synchronous_renderer_compositor = true; } virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { - // The BeginFrame notification is turned off now but will get enabled + // The BeginImplFrame notification is turned off now but will get enabled // once we return. End test while it's enabled. ImplThreadTaskRunner()->PostTask( FROM_HERE, - base::Bind(&LayerTreeHostTestBeginFrameNotification::EndTest, + base::Bind(&LayerTreeHostTestBeginImplFrameNotification::EndTest, base::Unretained(this))); } @@ -2401,35 +2641,40 @@ class LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled }; MULTI_THREAD_TEST_F( - LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled); + LayerTreeHostTestBeginImplFrameNotificationShutdownWhileEnabled); -class LayerTreeHostTestAbortedCommitDoesntStallNextCommitWhenIdle - : public LayerTreeHostTest { +class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest { protected: - LayerTreeHostTestAbortedCommitDoesntStallNextCommitWhenIdle() - : commit_count_(0), commit_complete_count_(0) {} + LayerTreeHostTestAbortedCommitDoesntStall() + : commit_count_(0), commit_abort_count_(0), commit_complete_count_(0) {} virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { - settings->begin_frame_scheduling_enabled = true; - settings->using_synchronous_renderer_compositor = true; + settings->begin_impl_frame_scheduling_enabled = true; } virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } virtual void DidCommit() OVERRIDE { commit_count_++; - if (commit_count_ == 2) { - // A commit was just aborted, request a real commit now to make sure a + if (commit_count_ == 4) { + // After two aborted commits, request a real commit now to make sure a // real commit following an aborted commit will still complete and // end the test even when the Impl thread is idle. layer_tree_host()->SetNeedsCommit(); } } + virtual void BeginMainFrameAbortedOnThread( + LayerTreeHostImpl *host_impl, bool did_handle) OVERRIDE { + commit_abort_count_++; + // Initiate another abortable commit. + host_impl->SetNeedsCommit(); + } + virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { commit_complete_count_++; if (commit_complete_count_ == 1) { - // Initiate an aborted commit after the first commit. + // Initiate an abortable commit after the first commit. host_impl->SetNeedsCommit(); } else { EndTest(); @@ -2437,16 +2682,36 @@ class LayerTreeHostTestAbortedCommitDoesntStallNextCommitWhenIdle } virtual void AfterTest() OVERRIDE { - EXPECT_EQ(commit_count_, 3); + EXPECT_EQ(commit_count_, 5); + EXPECT_EQ(commit_abort_count_, 3); EXPECT_EQ(commit_complete_count_, 2); } int commit_count_; + int commit_abort_count_; int commit_complete_count_; }; +class LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor + : public LayerTreeHostTestAbortedCommitDoesntStall { + virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { + LayerTreeHostTestAbortedCommitDoesntStall::InitializeSettings(settings); + settings->using_synchronous_renderer_compositor = true; + } +}; + MULTI_THREAD_TEST_F( - LayerTreeHostTestAbortedCommitDoesntStallNextCommitWhenIdle); + LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor); + +class LayerTreeHostTestAbortedCommitDoesntStallDisabledVsync + : public LayerTreeHostTestAbortedCommitDoesntStall { + virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { + LayerTreeHostTestAbortedCommitDoesntStall::InitializeSettings(settings); + settings->throttle_frame_production = false; + } +}; + +MULTI_THREAD_TEST_F(LayerTreeHostTestAbortedCommitDoesntStallDisabledVsync); class LayerTreeHostTestUninvertibleTransformDoesNotBlockActivation : public LayerTreeHostTest { @@ -2544,26 +2809,26 @@ class MockIOSurfaceWebGraphicsContext3D : public TestWebGraphicsContext3D { test_capabilities_.texture_rectangle = true; } - virtual WebKit::WebGLId createTexture() OVERRIDE { + virtual blink::WebGLId createTexture() OVERRIDE { return 1; } - MOCK_METHOD1(activeTexture, void(WebKit::WGC3Denum texture)); - MOCK_METHOD2(bindTexture, void(WebKit::WGC3Denum target, - WebKit::WebGLId texture_id)); - MOCK_METHOD3(texParameteri, void(WebKit::WGC3Denum target, - WebKit::WGC3Denum pname, - WebKit::WGC3Dint param)); - MOCK_METHOD5(texImageIOSurface2DCHROMIUM, void(WebKit::WGC3Denum target, - WebKit::WGC3Dint width, - WebKit::WGC3Dint height, - WebKit::WGC3Duint ioSurfaceId, - WebKit::WGC3Duint plane)); - MOCK_METHOD4(drawElements, void(WebKit::WGC3Denum mode, - WebKit::WGC3Dsizei count, - WebKit::WGC3Denum type, - WebKit::WGC3Dintptr offset)); - MOCK_METHOD1(deleteTexture, void(WebKit::WGC3Denum texture)); + MOCK_METHOD1(activeTexture, void(blink::WGC3Denum texture)); + MOCK_METHOD2(bindTexture, void(blink::WGC3Denum target, + blink::WebGLId texture_id)); + MOCK_METHOD3(texParameteri, void(blink::WGC3Denum target, + blink::WGC3Denum pname, + blink::WGC3Dint param)); + MOCK_METHOD5(texImageIOSurface2DCHROMIUM, void(blink::WGC3Denum target, + blink::WGC3Dint width, + blink::WGC3Dint height, + blink::WGC3Duint ioSurfaceId, + blink::WGC3Duint plane)); + MOCK_METHOD4(drawElements, void(blink::WGC3Denum mode, + blink::WGC3Dsizei count, + blink::WGC3Denum type, + blink::WGC3Dintptr offset)); + MOCK_METHOD1(deleteTexture, void(blink::WGC3Denum texture)); }; @@ -2671,676 +2936,6 @@ class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest { SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( LayerTreeHostTestIOSurfaceDrawing); -class LayerTreeHostTestAsyncReadback : public LayerTreeHostTest { - protected: - virtual void SetupTree() OVERRIDE { - root = FakeContentLayer::Create(&client_); - root->SetBounds(gfx::Size(20, 20)); - - child = FakeContentLayer::Create(&client_); - child->SetBounds(gfx::Size(10, 10)); - root->AddChild(child); - - layer_tree_host()->SetRootLayer(root); - LayerTreeHostTest::SetupTree(); - } - - virtual void BeginTest() OVERRIDE { - PostSetNeedsCommitToMainThread(); - } - - virtual void DidCommitAndDrawFrame() OVERRIDE { - WaitForCallback(); - } - - void WaitForCallback() { - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind( - &LayerTreeHostTestAsyncReadback::NextStep, - base::Unretained(this))); - } - - void NextStep() { - int frame = layer_tree_host()->source_frame_number(); - switch (frame) { - case 1: - child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( - base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback, - base::Unretained(this)))); - EXPECT_EQ(0u, callbacks_.size()); - break; - case 2: - if (callbacks_.size() < 1u) { - WaitForCallback(); - return; - } - EXPECT_EQ(1u, callbacks_.size()); - EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[0].ToString()); - - child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( - base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback, - base::Unretained(this)))); - root->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( - base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback, - base::Unretained(this)))); - child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( - base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback, - base::Unretained(this)))); - EXPECT_EQ(1u, callbacks_.size()); - break; - case 3: - if (callbacks_.size() < 4u) { - WaitForCallback(); - return; - } - EXPECT_EQ(4u, callbacks_.size()); - // The child was copied to a bitmap and passed back twice. - EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[1].ToString()); - EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[2].ToString()); - // The root was copied to a bitmap and passed back also. - EXPECT_EQ(gfx::Size(20, 20).ToString(), callbacks_[3].ToString()); - EndTest(); - break; - } - } - - void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { - EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); - EXPECT_TRUE(result->HasBitmap()); - scoped_ptr<SkBitmap> bitmap = result->TakeBitmap().Pass(); - EXPECT_EQ(result->size().ToString(), - gfx::Size(bitmap->width(), bitmap->height()).ToString()); - callbacks_.push_back(result->size()); - } - - virtual void AfterTest() OVERRIDE { - EXPECT_EQ(4u, callbacks_.size()); - } - - virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) - OVERRIDE { - scoped_ptr<FakeOutputSurface> output_surface; - if (use_gl_renderer_) { - output_surface = FakeOutputSurface::Create3d().Pass(); - } else { - output_surface = FakeOutputSurface::CreateSoftware( - make_scoped_ptr(new SoftwareOutputDevice)).Pass(); - } - return output_surface.PassAs<OutputSurface>(); - } - - bool use_gl_renderer_; - std::vector<gfx::Size> callbacks_; - FakeContentLayerClient client_; - scoped_refptr<FakeContentLayer> root; - scoped_refptr<FakeContentLayer> child; -}; - -// Readback can't be done with a delegating renderer. -TEST_F(LayerTreeHostTestAsyncReadback, GLRenderer_RunSingleThread) { - use_gl_renderer_ = true; - RunTest(false, false, false); -} - -TEST_F(LayerTreeHostTestAsyncReadback, - GLRenderer_RunMultiThread_MainThreadPainting) { - use_gl_renderer_ = true; - RunTest(true, false, false); -} - -TEST_F(LayerTreeHostTestAsyncReadback, - GLRenderer_RunMultiThread_ImplSidePainting) { - use_gl_renderer_ = true; - RunTest(true, false, true); -} - -TEST_F(LayerTreeHostTestAsyncReadback, SoftwareRenderer_RunSingleThread) { - use_gl_renderer_ = false; - RunTest(false, false, false); -} - -TEST_F(LayerTreeHostTestAsyncReadback, - SoftwareRenderer_RunMultiThread_MainThreadPainting) { - use_gl_renderer_ = false; - RunTest(true, false, false); -} - -TEST_F(LayerTreeHostTestAsyncReadback, - SoftwareRenderer_RunMultiThread_ImplSidePainting) { - use_gl_renderer_ = false; - RunTest(true, false, true); -} - -class LayerTreeHostTestAsyncReadbackLayerDestroyed : public LayerTreeHostTest { - protected: - virtual void SetupTree() OVERRIDE { - root_ = FakeContentLayer::Create(&client_); - root_->SetBounds(gfx::Size(20, 20)); - - main_destroyed_ = FakeContentLayer::Create(&client_); - main_destroyed_->SetBounds(gfx::Size(15, 15)); - root_->AddChild(main_destroyed_); - - impl_destroyed_ = FakeContentLayer::Create(&client_); - impl_destroyed_->SetBounds(gfx::Size(10, 10)); - root_->AddChild(impl_destroyed_); - - layer_tree_host()->SetRootLayer(root_); - LayerTreeHostTest::SetupTree(); - } - - virtual void BeginTest() OVERRIDE { - callback_count_ = 0; - PostSetNeedsCommitToMainThread(); - } - - virtual void DidCommit() OVERRIDE { - int frame = layer_tree_host()->source_frame_number(); - switch (frame) { - case 1: - main_destroyed_->RequestCopyOfOutput( - CopyOutputRequest::CreateBitmapRequest(base::Bind( - &LayerTreeHostTestAsyncReadbackLayerDestroyed:: - CopyOutputCallback, - base::Unretained(this)))); - impl_destroyed_->RequestCopyOfOutput( - CopyOutputRequest::CreateBitmapRequest(base::Bind( - &LayerTreeHostTestAsyncReadbackLayerDestroyed:: - CopyOutputCallback, - base::Unretained(this)))); - EXPECT_EQ(0, callback_count_); - - // Destroy the main thread layer right away. - main_destroyed_->RemoveFromParent(); - main_destroyed_ = NULL; - - // Should callback with a NULL bitmap. - EXPECT_EQ(1, callback_count_); - - // Prevent drawing so we can't make a copy of the impl_destroyed layer. - layer_tree_host()->SetViewportSize(gfx::Size()); - break; - case 2: - // Flush the message loops and make sure the callbacks run. - layer_tree_host()->SetNeedsCommit(); - break; - case 3: - // No drawing means no readback yet. - EXPECT_EQ(1, callback_count_); - - // Destroy the impl thread layer. - impl_destroyed_->RemoveFromParent(); - impl_destroyed_ = NULL; - - // No callback yet because it's on the impl side. - EXPECT_EQ(1, callback_count_); - break; - case 4: - // Flush the message loops and make sure the callbacks run. - layer_tree_host()->SetNeedsCommit(); - break; - case 5: - // We should get another callback with a NULL bitmap. - EXPECT_EQ(2, callback_count_); - EndTest(); - break; - } - } - - void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { - EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); - EXPECT_TRUE(result->IsEmpty()); - ++callback_count_; - } - - virtual void AfterTest() OVERRIDE {} - - int callback_count_; - FakeContentLayerClient client_; - scoped_refptr<FakeContentLayer> root_; - scoped_refptr<FakeContentLayer> main_destroyed_; - scoped_refptr<FakeContentLayer> impl_destroyed_; -}; - -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestAsyncReadbackLayerDestroyed); - -class LayerTreeHostTestAsyncReadbackInHiddenSubtree : public LayerTreeHostTest { - protected: - virtual void SetupTree() OVERRIDE { - root_ = FakeContentLayer::Create(&client_); - root_->SetBounds(gfx::Size(20, 20)); - - grand_parent_layer_ = FakeContentLayer::Create(&client_); - grand_parent_layer_->SetBounds(gfx::Size(15, 15)); - root_->AddChild(grand_parent_layer_); - - // parent_layer_ owns a render surface. - parent_layer_ = FakeContentLayer::Create(&client_); - parent_layer_->SetBounds(gfx::Size(15, 15)); - parent_layer_->SetForceRenderSurface(true); - grand_parent_layer_->AddChild(parent_layer_); - - copy_layer_ = FakeContentLayer::Create(&client_); - copy_layer_->SetBounds(gfx::Size(10, 10)); - parent_layer_->AddChild(copy_layer_); - - layer_tree_host()->SetRootLayer(root_); - LayerTreeHostTest::SetupTree(); - } - - void AddCopyRequest(Layer* layer) { - layer->RequestCopyOfOutput( - CopyOutputRequest::CreateBitmapRequest(base::Bind( - &LayerTreeHostTestAsyncReadbackInHiddenSubtree::CopyOutputCallback, - base::Unretained(this)))); - } - - virtual void BeginTest() OVERRIDE { - callback_count_ = 0; - PostSetNeedsCommitToMainThread(); - - AddCopyRequest(copy_layer_.get()); - } - - void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { - EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); - EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()); - ++callback_count_; - - switch (callback_count_) { - case 1: - // Hide the copy request layer. - grand_parent_layer_->SetHideLayerAndSubtree(false); - parent_layer_->SetHideLayerAndSubtree(false); - copy_layer_->SetHideLayerAndSubtree(true); - AddCopyRequest(copy_layer_.get()); - break; - case 2: - // Hide the copy request layer's parent only. - grand_parent_layer_->SetHideLayerAndSubtree(false); - parent_layer_->SetHideLayerAndSubtree(true); - copy_layer_->SetHideLayerAndSubtree(false); - AddCopyRequest(copy_layer_.get()); - break; - case 3: - // Hide the copy request layer's grand parent only. - grand_parent_layer_->SetHideLayerAndSubtree(true); - parent_layer_->SetHideLayerAndSubtree(false); - copy_layer_->SetHideLayerAndSubtree(false); - AddCopyRequest(copy_layer_.get()); - break; - case 4: - // Hide the copy request layer's parent and grandparent. - grand_parent_layer_->SetHideLayerAndSubtree(true); - parent_layer_->SetHideLayerAndSubtree(true); - copy_layer_->SetHideLayerAndSubtree(false); - AddCopyRequest(copy_layer_.get()); - break; - case 5: - // Hide the copy request layer as well as its parent and grandparent. - grand_parent_layer_->SetHideLayerAndSubtree(true); - parent_layer_->SetHideLayerAndSubtree(true); - copy_layer_->SetHideLayerAndSubtree(true); - AddCopyRequest(copy_layer_.get()); - break; - case 6: - EndTest(); - break; - } - } - - virtual void AfterTest() OVERRIDE {} - - int callback_count_; - FakeContentLayerClient client_; - scoped_refptr<FakeContentLayer> root_; - scoped_refptr<FakeContentLayer> grand_parent_layer_; - scoped_refptr<FakeContentLayer> parent_layer_; - scoped_refptr<FakeContentLayer> copy_layer_; -}; - -// No output to copy for delegated renderers. -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostTestAsyncReadbackInHiddenSubtree); - -class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest - : public LayerTreeHostTest { - protected: - virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { - settings->cache_render_pass_contents = true; - } - - virtual void SetupTree() OVERRIDE { - root_ = FakeContentLayer::Create(&client_); - root_->SetBounds(gfx::Size(20, 20)); - - grand_parent_layer_ = FakeContentLayer::Create(&client_); - grand_parent_layer_->SetBounds(gfx::Size(15, 15)); - grand_parent_layer_->SetHideLayerAndSubtree(true); - root_->AddChild(grand_parent_layer_); - - // parent_layer_ owns a render surface. - parent_layer_ = FakeContentLayer::Create(&client_); - parent_layer_->SetBounds(gfx::Size(15, 15)); - parent_layer_->SetForceRenderSurface(true); - grand_parent_layer_->AddChild(parent_layer_); - - copy_layer_ = FakeContentLayer::Create(&client_); - copy_layer_->SetBounds(gfx::Size(10, 10)); - parent_layer_->AddChild(copy_layer_); - - layer_tree_host()->SetRootLayer(root_); - LayerTreeHostTest::SetupTree(); - } - - virtual void BeginTest() OVERRIDE { - did_draw_ = false; - PostSetNeedsCommitToMainThread(); - - copy_layer_->RequestCopyOfOutput( - CopyOutputRequest::CreateBitmapRequest(base::Bind( - &LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest:: - CopyOutputCallback, - base::Unretained(this)))); - } - - void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { - EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); - EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()); - EndTest(); - } - - virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { - Renderer* renderer = host_impl->renderer(); - - LayerImpl* root = host_impl->active_tree()->root_layer(); - LayerImpl* grand_parent = root->children()[0]; - LayerImpl* parent = grand_parent->children()[0]; - LayerImpl* copy_layer = parent->children()[0]; - - // |parent| owns a surface, but it was hidden and not part of the copy - // request so it should not allocate any resource. - EXPECT_FALSE(renderer->HaveCachedResourcesForRenderPassId( - parent->render_surface()->RenderPassId())); - - // |copy_layer| should have been rendered to a texture since it was needed - // for a copy request. - EXPECT_TRUE(renderer->HaveCachedResourcesForRenderPassId( - copy_layer->render_surface()->RenderPassId())); - - did_draw_ = true; - } - - virtual void AfterTest() OVERRIDE { EXPECT_TRUE(did_draw_); } - - FakeContentLayerClient client_; - bool did_draw_; - scoped_refptr<FakeContentLayer> root_; - scoped_refptr<FakeContentLayer> grand_parent_layer_; - scoped_refptr<FakeContentLayer> parent_layer_; - scoped_refptr<FakeContentLayer> copy_layer_; -}; - -// No output to copy for delegated renderers. -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest); - -class LayerTreeHostTestAsyncReadbackClippedOut : public LayerTreeHostTest { - protected: - virtual void SetupTree() OVERRIDE { - root_ = FakeContentLayer::Create(&client_); - root_->SetBounds(gfx::Size(20, 20)); - - parent_layer_ = FakeContentLayer::Create(&client_); - parent_layer_->SetBounds(gfx::Size(15, 15)); - parent_layer_->SetMasksToBounds(true); - root_->AddChild(parent_layer_); - - copy_layer_ = FakeContentLayer::Create(&client_); - copy_layer_->SetPosition(gfx::Point(15, 15)); - copy_layer_->SetBounds(gfx::Size(10, 10)); - parent_layer_->AddChild(copy_layer_); - - layer_tree_host()->SetRootLayer(root_); - LayerTreeHostTest::SetupTree(); - } - - virtual void BeginTest() OVERRIDE { - PostSetNeedsCommitToMainThread(); - - copy_layer_->RequestCopyOfOutput( - CopyOutputRequest::CreateBitmapRequest(base::Bind( - &LayerTreeHostTestAsyncReadbackClippedOut::CopyOutputCallback, - base::Unretained(this)))); - } - - void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { - // We should still get a callback with no output if the copy requested layer - // was completely clipped away. - EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); - EXPECT_EQ(gfx::Size().ToString(), result->size().ToString()); - EndTest(); - } - - virtual void AfterTest() OVERRIDE {} - - FakeContentLayerClient client_; - scoped_refptr<FakeContentLayer> root_; - scoped_refptr<FakeContentLayer> parent_layer_; - scoped_refptr<FakeContentLayer> copy_layer_; -}; - -// No output to copy for delegated renderers. -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostTestAsyncReadbackClippedOut); - -class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw : public LayerTreeHostTest { - protected: - virtual void SetupTree() OVERRIDE { - root_ = FakeContentLayer::Create(&client_); - root_->SetBounds(gfx::Size(20, 20)); - - copy_layer_ = FakeContentLayer::Create(&client_); - copy_layer_->SetBounds(gfx::Size(10, 10)); - root_->AddChild(copy_layer_); - - layer_tree_host()->SetRootLayer(root_); - LayerTreeHostTest::SetupTree(); - } - - void AddCopyRequest(Layer* layer) { - layer->RequestCopyOfOutput( - CopyOutputRequest::CreateBitmapRequest(base::Bind( - &LayerTreeHostTestAsyncTwoReadbacksWithoutDraw::CopyOutputCallback, - base::Unretained(this)))); - } - - virtual void BeginTest() OVERRIDE { - saw_copy_request_ = false; - callback_count_ = 0; - PostSetNeedsCommitToMainThread(); - - // Prevent drawing. - layer_tree_host()->SetViewportSize(gfx::Size(0, 0)); - - AddCopyRequest(copy_layer_.get()); - } - - virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE { - if (impl->active_tree()->source_frame_number() == 0) { - LayerImpl* root = impl->active_tree()->root_layer(); - EXPECT_TRUE(root->children()[0]->HasCopyRequest()); - saw_copy_request_ = true; - } - } - - virtual void DidCommit() OVERRIDE { - if (layer_tree_host()->source_frame_number() == 1) { - // Allow drawing. - layer_tree_host()->SetViewportSize(gfx::Size(root_->bounds())); - - AddCopyRequest(copy_layer_.get()); - } - } - - void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { - EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); - EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()); - ++callback_count_; - - if (callback_count_ == 2) - EndTest(); - } - - virtual void AfterTest() OVERRIDE { EXPECT_TRUE(saw_copy_request_); } - - bool saw_copy_request_; - int callback_count_; - FakeContentLayerClient client_; - scoped_refptr<FakeContentLayer> root_; - scoped_refptr<FakeContentLayer> copy_layer_; -}; - -// No output to copy for delegated renderers. -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostTestAsyncTwoReadbacksWithoutDraw); - -class LayerTreeHostTestAsyncReadbackLostOutputSurface - : public LayerTreeHostTest { - protected: - virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) - OVERRIDE { - if (!first_context_provider_.get()) { - first_context_provider_ = TestContextProvider::Create(); - return FakeOutputSurface::Create3d(first_context_provider_) - .PassAs<OutputSurface>(); - } - - EXPECT_FALSE(second_context_provider_.get()); - second_context_provider_ = TestContextProvider::Create(); - return FakeOutputSurface::Create3d(second_context_provider_) - .PassAs<OutputSurface>(); - } - - virtual void SetupTree() OVERRIDE { - root_ = FakeContentLayer::Create(&client_); - root_->SetBounds(gfx::Size(20, 20)); - - copy_layer_ = FakeContentLayer::Create(&client_); - copy_layer_->SetBounds(gfx::Size(10, 10)); - root_->AddChild(copy_layer_); - - layer_tree_host()->SetRootLayer(root_); - LayerTreeHostTest::SetupTree(); - } - - virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } - - void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { - EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); - EXPECT_EQ(gfx::Size(10, 10).ToString(), result->size().ToString()); - EXPECT_TRUE(result->HasTexture()); - - // Save the result for later. - EXPECT_FALSE(result_); - result_ = result.Pass(); - - // Post a commit to lose the output surface. - layer_tree_host()->SetNeedsCommit(); - } - - virtual void DidCommitAndDrawFrame() OVERRIDE { - switch (layer_tree_host()->source_frame_number()) { - case 1: - // The layers have been pushed to the impl side. The layer textures have - // been allocated. - - // Request a copy of the layer. This will use another texture. - copy_layer_->RequestCopyOfOutput( - CopyOutputRequest::CreateRequest(base::Bind( - &LayerTreeHostTestAsyncReadbackLostOutputSurface:: - CopyOutputCallback, - base::Unretained(this)))); - break; - case 4: - // With SingleThreadProxy it takes two commits to finally swap after a - // context loss. - case 5: - // Now destroy the CopyOutputResult, releasing the texture inside back - // to the compositor. - EXPECT_TRUE(result_); - result_.reset(); - - // Check that it is released. - ImplThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&LayerTreeHostTestAsyncReadbackLostOutputSurface:: - CheckNumTextures, - base::Unretained(this), - num_textures_after_loss_ - 1)); - break; - } - } - - virtual void SwapBuffersOnThread(LayerTreeHostImpl *impl, bool result) - OVERRIDE { - switch (impl->active_tree()->source_frame_number()) { - case 0: - // The layers have been drawn, so their textures have been allocated. - EXPECT_FALSE(result_); - num_textures_without_readback_ = - first_context_provider_->TestContext3d()->NumTextures(); - break; - case 1: - // We did a readback, so there will be a readback texture around now. - EXPECT_LT(num_textures_without_readback_, - first_context_provider_->TestContext3d()->NumTextures()); - break; - case 2: - // The readback texture is collected. - EXPECT_TRUE(result_); - - // Lose the output surface. - first_context_provider_->TestContext3d()->loseContextCHROMIUM( - GL_GUILTY_CONTEXT_RESET_ARB, - GL_INNOCENT_CONTEXT_RESET_ARB); - break; - case 3: - // With SingleThreadProxy it takes two commits to finally swap after a - // context loss. - case 4: - // The output surface has been recreated. - EXPECT_TRUE(second_context_provider_.get()); - - num_textures_after_loss_ = - first_context_provider_->TestContext3d()->NumTextures(); - break; - } - } - - void CheckNumTextures(size_t expected_num_textures) { - EXPECT_EQ(expected_num_textures, - first_context_provider_->TestContext3d()->NumTextures()); - EndTest(); - } - - virtual void AfterTest() OVERRIDE {} - - scoped_refptr<TestContextProvider> first_context_provider_; - scoped_refptr<TestContextProvider> second_context_provider_; - size_t num_textures_without_readback_; - size_t num_textures_after_loss_; - FakeContentLayerClient client_; - scoped_refptr<FakeContentLayer> root_; - scoped_refptr<FakeContentLayer> copy_layer_; - scoped_ptr<CopyOutputResult> result_; -}; - -// No output to copy for delegated renderers. -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostTestAsyncReadbackLostOutputSurface); - class LayerTreeHostTestNumFramesPending : public LayerTreeHostTest { public: virtual void BeginTest() OVERRIDE { @@ -3417,7 +3012,6 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest { virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { // PictureLayer can only be used with impl side painting enabled. settings->impl_side_painting = true; - settings->solid_color_scrollbars = true; } virtual void SetupTree() OVERRIDE { @@ -3440,7 +3034,6 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest { OVERRIDE { scoped_ptr<TestWebGraphicsContext3D> context3d( TestWebGraphicsContext3D::Create()); - context3d->set_support_swapbuffers_complete_callback(false); return FakeOutputSurface::CreateDeferredGL( scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)) @@ -3524,6 +3117,10 @@ class LayerTreeHostTestUIResource : public LayerTreeHostTest { public: LayerTreeHostTestUIResource() : num_ui_resources_(0), num_commits_(0) {} + virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { + settings->texture_id_allocation_chunk_size = 1; + } + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } virtual void DidCommit() OVERRIDE { @@ -3672,13 +3269,13 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest { child_ = PushPropertiesCountingLayer::Create(); child2_ = PushPropertiesCountingLayer::Create(); grandchild_ = PushPropertiesCountingLayer::Create(); - leaf_scrollbar_layer_ = - FakePaintedScrollbarLayer::Create(false, false, root_->id()); + leaf_always_pushing_layer_ = PushPropertiesCountingLayer::Create(); + leaf_always_pushing_layer_->set_persist_needs_push_properties(true); root_->AddChild(child_); root_->AddChild(child2_); child_->AddChild(grandchild_); - child2_->AddChild(leaf_scrollbar_layer_); + child2_->AddChild(leaf_always_pushing_layer_); other_root_ = PushPropertiesCountingLayer::Create(); @@ -3698,7 +3295,7 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest { EXPECT_EQ(expected_push_properties_other_root_, other_root_->push_properties_count()); EXPECT_EQ(expected_push_properties_leaf_layer_, - leaf_scrollbar_layer_->push_properties_count()); + leaf_always_pushing_layer_->push_properties_count()); // The scrollbar layer always needs to be pushed. if (root_->layer_tree_host()) { @@ -3709,9 +3306,10 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest { EXPECT_TRUE(child2_->descendant_needs_push_properties()); EXPECT_FALSE(child2_->needs_push_properties()); } - if (leaf_scrollbar_layer_->layer_tree_host()) { - EXPECT_FALSE(leaf_scrollbar_layer_->descendant_needs_push_properties()); - EXPECT_TRUE(leaf_scrollbar_layer_->needs_push_properties()); + if (leaf_always_pushing_layer_->layer_tree_host()) { + EXPECT_FALSE( + leaf_always_pushing_layer_->descendant_needs_push_properties()); + EXPECT_TRUE(leaf_always_pushing_layer_->needs_push_properties()); } // child_ and grandchild_ don't persist their need to push properties. @@ -3820,9 +3418,8 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest { break; } - // Content/Picture layers require PushProperties every commit that they are - // in the tree. - if (leaf_scrollbar_layer_->layer_tree_host()) + // The leaf layer always pushes. + if (leaf_always_pushing_layer_->layer_tree_host()) ++expected_push_properties_leaf_layer_; } @@ -3835,7 +3432,7 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest { scoped_refptr<PushPropertiesCountingLayer> child2_; scoped_refptr<PushPropertiesCountingLayer> grandchild_; scoped_refptr<PushPropertiesCountingLayer> other_root_; - scoped_refptr<FakePaintedScrollbarLayer> leaf_scrollbar_layer_; + scoped_refptr<PushPropertiesCountingLayer> leaf_always_pushing_layer_; size_t expected_push_properties_root_; size_t expected_push_properties_child_; size_t expected_push_properties_child2_; @@ -4578,7 +4175,7 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestUpdateLayerInEmptyViewport); class LayerTreeHostTestAbortEvictedTextures : public LayerTreeHostTest { public: LayerTreeHostTestAbortEvictedTextures() - : num_will_begin_frames_(0), num_impl_commits_(0) {} + : num_will_begin_main_frames_(0), num_impl_commits_(0) {} protected: virtual void SetupTree() OVERRIDE { @@ -4592,9 +4189,9 @@ class LayerTreeHostTestAbortEvictedTextures : public LayerTreeHostTest { virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } - virtual void WillBeginFrame() OVERRIDE { - num_will_begin_frames_++; - switch (num_will_begin_frames_) { + virtual void WillBeginMainFrame() OVERRIDE { + num_will_begin_main_frames_++; + switch (num_will_begin_main_frames_) { case 2: // Send a redraw to the compositor thread. This will (wrongly) be // ignored unless aborting resets the texture state. @@ -4624,12 +4221,12 @@ class LayerTreeHostTestAbortEvictedTextures : public LayerTreeHostTest { virtual void AfterTest() OVERRIDE { // Ensure that the commit was truly aborted. - EXPECT_EQ(2, num_will_begin_frames_); + EXPECT_EQ(2, num_will_begin_main_frames_); EXPECT_EQ(1, num_impl_commits_); } private: - int num_will_begin_frames_; + int num_will_begin_main_frames_; int num_impl_commits_; }; @@ -4640,6 +4237,7 @@ class LayerTreeHostTestMaxTransferBufferUsageBytes : public LayerTreeHostTest { protected: virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { settings->impl_side_painting = true; + settings->default_tile_size = gfx::Size(128, 128); } virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) @@ -4671,8 +4269,11 @@ class LayerTreeHostTestMaxTransferBufferUsageBytes : public LayerTreeHostTest { // Expect that the transfer buffer memory used is equal to the // MaxTransferBufferUsageBytes value set in CreateOutputSurface. - EXPECT_EQ(1024 * 1024u, - context->GetTransferBufferMemoryUsedBytes()); + // NOTE: This is now 1/2 due to raster memory limit in TileManager. + // Only half the limit will be reached unless the task set + // thrashes to a completly new set of tiles. + EXPECT_EQ(512 * 1024u, + context->GetPeakTransferBufferMemoryUsedBytes()); EndTest(); } @@ -4750,9 +4351,7 @@ class LayerTreeHostTestMemoryLimits : public LayerTreeHostTest { // This will trigger a commit because the priority cutoff has changed. impl->SetMemoryPolicy(ManagedMemoryPolicy( 16u*1024u*1024u, - ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE, - 0, - ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING, + gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE, 1000)); break; case 2: @@ -4760,9 +4359,7 @@ class LayerTreeHostTestMemoryLimits : public LayerTreeHostTest { // changed, and there is already enough memory for all allocations. impl->SetMemoryPolicy(ManagedMemoryPolicy( 32u*1024u*1024u, - ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE, - 0, - ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING, + gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE, 1000)); break; case 3: @@ -4777,8 +4374,402 @@ class LayerTreeHostTestMemoryLimits : public LayerTreeHostTest { int num_commits_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestMemoryLimits); +SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostTestMemoryLimits); + +class LayerSetsNeedsFilterContext : public Layer { + public: + static scoped_refptr<LayerSetsNeedsFilterContext> Create() { + return make_scoped_refptr(new LayerSetsNeedsFilterContext()); + } + + virtual bool Update(ResourceUpdateQueue* queue, + const OcclusionTracker* occlusion) OVERRIDE { + bool updated = Layer::Update(queue, occlusion); + if (needs_context_) { + layer_tree_host()->set_needs_filter_context(); + return true; + } + return updated; + } + + void set_needs_context(bool need) { needs_context_ = need; } + + private: + LayerSetsNeedsFilterContext() : needs_context_(false) {} + virtual ~LayerSetsNeedsFilterContext() {} + + bool needs_context_; +}; + +class LayerTreeHostTestOffscreenContext : public LayerTreeHostTest { + protected: + virtual void SetupTree() OVERRIDE { + scoped_refptr<LayerSetsNeedsFilterContext> root = + LayerSetsNeedsFilterContext::Create(); + root->SetIsDrawable(true); + root->SetAnchorPoint(gfx::PointF()); + root->SetBounds(gfx::Size(10, 10)); + root->set_needs_context(with_context_); + layer_tree_host()->SetRootLayer(root); + LayerTreeHostTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + bool expect_context = with_context_; + if (delegating_renderer()) + expect_context = false; + EXPECT_EQ(expect_context, !!host_impl->offscreen_context_provider()); + EndTest(); + } + + virtual void AfterTest() OVERRIDE {} + + bool with_context_; +}; + +class LayerTreeHostTestOffscreenContext_NoContext + : public LayerTreeHostTestOffscreenContext { + protected: + LayerTreeHostTestOffscreenContext_NoContext() { with_context_ = false; } +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestOffscreenContext_NoContext); + +class LayerTreeHostTestOffscreenContext_WithContext + : public LayerTreeHostTestOffscreenContext { + protected: + LayerTreeHostTestOffscreenContext_WithContext() { with_context_ = true; } +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestOffscreenContext_WithContext); + +class LayerTreeHostTestNoQuadsForEmptyLayer : public LayerTreeHostTest { + protected: + virtual void SetupTree() OVERRIDE { + LayerTreeHostTest::SetupTree(); + root_layer_ = FakeContentLayer::Create(&client_); + root_layer_->SetBounds(gfx::Size(10, 10)); + root_layer_->SetIsDrawable(false); + root_layer_->SetHaveWheelEventHandlers(true); + layer_tree_host()->SetRootLayer(root_layer_); + LayerTreeHostTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { + PostSetNeedsCommitToMainThread(); + } + + virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE { + FakeContentLayerImpl* layer_impl = + static_cast<FakeContentLayerImpl*>(impl->RootLayer()); + EXPECT_FALSE(layer_impl->DrawsContent()); + EXPECT_EQ(0u, layer_impl->append_quads_count()); + } + + virtual void DidCommit() OVERRIDE { + // The layer is not drawable, so it should not be updated. + EXPECT_EQ(0u, root_layer_->update_count()); + EndTest(); + } + virtual void AfterTest() OVERRIDE {} + + private: + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root_layer_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoQuadsForEmptyLayer); + } // namespace +class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface + : public LayerTreeHostTest { + protected: + LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface() + : first_output_surface_memory_limit_(4321234), + second_output_surface_memory_limit_(1234321) {} + + virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) + OVERRIDE { + if (!first_context_provider_) { + first_context_provider_ = TestContextProvider::Create(); + } else { + EXPECT_FALSE(second_context_provider_); + second_context_provider_ = TestContextProvider::Create(); + } + + scoped_ptr<FakeOutputSurface> output_surface( + FakeOutputSurface::Create3d( + second_context_provider_ ? + second_context_provider_ : + first_context_provider_)); + output_surface->SetMemoryPolicyToSetAtBind(make_scoped_ptr( + new ManagedMemoryPolicy( + second_context_provider_ ? + second_output_surface_memory_limit_ : + first_output_surface_memory_limit_, + gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE, + ManagedMemoryPolicy::kDefaultNumResourcesLimit))); + return output_surface.PassAs<OutputSurface>(); + } + + virtual void SetupTree() OVERRIDE { + root_ = FakeContentLayer::Create(&client_); + root_->SetBounds(gfx::Size(20, 20)); + layer_tree_host()->SetRootLayer(root_); + LayerTreeHostTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { + PostSetNeedsCommitToMainThread(); + } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + // Lost context sometimes takes two frames to recreate. The third frame + // is sometimes aborted, so wait until the fourth frame to verify that + // the memory has been set, and the fifth frame to end the test. + if (layer_tree_host()->source_frame_number() < 5) { + layer_tree_host()->SetNeedsCommit(); + } else if (layer_tree_host()->source_frame_number() == 5) { + EndTest(); + } + } + + virtual void SwapBuffersOnThread(LayerTreeHostImpl *impl, bool result) + OVERRIDE { + switch (impl->active_tree()->source_frame_number()) { + case 1: + EXPECT_EQ(first_output_surface_memory_limit_, + impl->memory_allocation_limit_bytes()); + // Lose the output surface. + first_context_provider_->TestContext3d()->loseContextCHROMIUM( + GL_GUILTY_CONTEXT_RESET_ARB, + GL_INNOCENT_CONTEXT_RESET_ARB); + break; + case 4: + EXPECT_EQ(second_output_surface_memory_limit_, + impl->memory_allocation_limit_bytes()); + break; + } + } + + virtual void AfterTest() OVERRIDE {} + + scoped_refptr<TestContextProvider> first_context_provider_; + scoped_refptr<TestContextProvider> second_context_provider_; + size_t first_output_surface_memory_limit_; + size_t second_output_surface_memory_limit_; + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root_; +}; + +// No output to copy for delegated renderers. +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface); + +struct TestSwapPromiseResult { + TestSwapPromiseResult() : did_swap_called(false), + did_not_swap_called(false), + dtor_called(false), + reason(SwapPromise::DID_NOT_SWAP_UNKNOWN) { + } + + bool did_swap_called; + bool did_not_swap_called; + bool dtor_called; + SwapPromise::DidNotSwapReason reason; + base::Lock lock; +}; + +class TestSwapPromise : public SwapPromise { + public: + explicit TestSwapPromise(TestSwapPromiseResult* result) + : result_(result) { + } + + virtual ~TestSwapPromise() { + base::AutoLock lock(result_->lock); + result_->dtor_called = true; + } + + virtual void DidSwap(CompositorFrameMetadata* metadata) OVERRIDE { + base::AutoLock lock(result_->lock); + EXPECT_FALSE(result_->did_swap_called); + EXPECT_FALSE(result_->did_not_swap_called); + result_->did_swap_called = true; + } + + virtual void DidNotSwap(DidNotSwapReason reason) OVERRIDE { + base::AutoLock lock(result_->lock); + EXPECT_FALSE(result_->did_swap_called); + EXPECT_FALSE(result_->did_not_swap_called); + result_->did_not_swap_called = true; + result_->reason = reason; + } + + private: + // Not owned. + TestSwapPromiseResult* result_; +}; + +class LayerTreeHostTestBreakSwapPromise + : public LayerTreeHostTest { + protected: + LayerTreeHostTestBreakSwapPromise() + : commit_count_(0), commit_complete_count_(0) { + } + + virtual void WillBeginMainFrame() OVERRIDE { + ASSERT_LE(commit_count_, 2); + scoped_ptr<SwapPromise> swap_promise(new TestSwapPromise( + &swap_promise_result_[commit_count_])); + layer_tree_host()->QueueSwapPromise(swap_promise.Pass()); + } + + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void DidCommit() OVERRIDE { + commit_count_++; + if (commit_count_ == 2) { + // This commit will finish. + layer_tree_host()->SetNeedsCommit(); + } + } + + virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + commit_complete_count_++; + if (commit_complete_count_ == 1) { + // This commit will be aborted because no actual update. + PostSetNeedsUpdateLayersToMainThread(); + } else { + EndTest(); + } + } + + virtual void AfterTest() OVERRIDE { + // 3 commits are scheduled. 2 completes. 1 is aborted. + EXPECT_EQ(commit_count_, 3); + EXPECT_EQ(commit_complete_count_, 2); + + { + // The first commit completes and causes swap buffer which finishes + // the promise. + base::AutoLock lock(swap_promise_result_[0].lock); + EXPECT_TRUE(swap_promise_result_[0].did_swap_called); + EXPECT_FALSE(swap_promise_result_[0].did_not_swap_called); + EXPECT_TRUE(swap_promise_result_[0].dtor_called); + } + + { + // The second commit aborts. + base::AutoLock lock(swap_promise_result_[1].lock); + EXPECT_FALSE(swap_promise_result_[1].did_swap_called); + EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called); + EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_[1].reason); + EXPECT_TRUE(swap_promise_result_[1].dtor_called); + } + + { + // The last commit completes but it does not cause swap buffer because + // there is no damage in the frame data. + base::AutoLock lock(swap_promise_result_[2].lock); + EXPECT_FALSE(swap_promise_result_[2].did_swap_called); + EXPECT_TRUE(swap_promise_result_[2].did_not_swap_called); + EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[2].reason); + EXPECT_TRUE(swap_promise_result_[2].dtor_called); + } + } + + int commit_count_; + int commit_complete_count_; + TestSwapPromiseResult swap_promise_result_[3]; +}; + +MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromise); + + +class SimpleSwapPromiseMonitor : public SwapPromiseMonitor { + public: + SimpleSwapPromiseMonitor(LayerTreeHost* layer_tree_host, + LayerTreeHostImpl* layer_tree_host_impl, + int* set_needs_commit_count, + int* set_needs_redraw_count) + : SwapPromiseMonitor(layer_tree_host, layer_tree_host_impl), + set_needs_commit_count_(set_needs_commit_count), + set_needs_redraw_count_(set_needs_redraw_count) {} + + virtual ~SimpleSwapPromiseMonitor() {} + + virtual void OnSetNeedsCommitOnMain() OVERRIDE { + (*set_needs_commit_count_)++; + } + + virtual void OnSetNeedsRedrawOnImpl() OVERRIDE { + (*set_needs_redraw_count_)++; + } + + private: + int* set_needs_commit_count_; + int* set_needs_redraw_count_; +}; + +class LayerTreeHostTestSimpleSwapPromiseMonitor + : public LayerTreeHostTest { + + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void WillBeginMainFrame() OVERRIDE { + int set_needs_commit_count = 0; + int set_needs_redraw_count = 0; + + { + scoped_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( + new SimpleSwapPromiseMonitor(layer_tree_host(), + NULL, + &set_needs_commit_count, + &set_needs_redraw_count)); + layer_tree_host()->SetNeedsCommit(); + EXPECT_EQ(1, set_needs_commit_count); + EXPECT_EQ(0, set_needs_redraw_count); + } + + // Now the monitor is destroyed, SetNeedsCommit() is no longer being + // monitored. + layer_tree_host()->SetNeedsCommit(); + EXPECT_EQ(1, set_needs_commit_count); + EXPECT_EQ(0, set_needs_redraw_count); + + { + scoped_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( + new SimpleSwapPromiseMonitor(layer_tree_host(), + NULL, + &set_needs_commit_count, + &set_needs_redraw_count)); + layer_tree_host()->SetNeedsUpdateLayers(); + EXPECT_EQ(2, set_needs_commit_count); + EXPECT_EQ(0, set_needs_redraw_count); + } + + { + scoped_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( + new SimpleSwapPromiseMonitor(layer_tree_host(), + NULL, + &set_needs_commit_count, + &set_needs_redraw_count)); + layer_tree_host()->SetNeedsAnimate(); + EXPECT_EQ(3, set_needs_commit_count); + EXPECT_EQ(0, set_needs_redraw_count); + } + + EndTest(); + } + + virtual void AfterTest() OVERRIDE {} +}; + +MULTI_THREAD_TEST_F(LayerTreeHostTestSimpleSwapPromiseMonitor); + } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_unittest_animation.cc b/chromium/cc/trees/layer_tree_host_unittest_animation.cc index 70e2a9ec6d8..22c8965a5fd 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc @@ -6,6 +6,7 @@ #include "cc/animation/animation_curve.h" #include "cc/animation/layer_animation_controller.h" +#include "cc/animation/scroll_offset_animation_curve.h" #include "cc/animation/timing_function.h" #include "cc/layers/layer.h" #include "cc/layers/layer_impl.h" @@ -115,8 +116,7 @@ class LayerTreeHostAnimationTestAddAnimation public: LayerTreeHostAnimationTestAddAnimation() : num_animates_(0), - received_animation_started_notification_(false), - start_time_(0.0) { + received_animation_started_notification_(false) { } virtual void BeginTest() OVERRIDE { @@ -135,7 +135,7 @@ class LayerTreeHostAnimationTestAddAnimation } if (received_animation_started_notification_) { - EXPECT_LT(0.0, start_time_); + EXPECT_LT(base::TimeTicks(), start_time_); LayerAnimationController* controller_impl = host_impl->active_tree()->root_layer()->layer_animation_controller(); @@ -148,11 +148,14 @@ class LayerTreeHostAnimationTestAddAnimation } } - virtual void NotifyAnimationStarted(double wall_clock_time) OVERRIDE { + virtual void NotifyAnimationStarted( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { received_animation_started_notification_ = true; - start_time_ = wall_clock_time; + start_time_ = monotonic_time; if (num_animates_) { - EXPECT_LT(0.0, start_time_); + EXPECT_LT(base::TimeTicks(), start_time_); LayerAnimationController* controller = layer_tree_host()->root_layer()->layer_animation_controller(); @@ -170,7 +173,7 @@ class LayerTreeHostAnimationTestAddAnimation private: int num_animates_; bool received_animation_started_notification_; - double start_time_; + base::TimeTicks start_time_; }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAddAnimation); @@ -239,7 +242,10 @@ class LayerTreeHostAnimationTestAnimationsGetDeleted EndTest(); } - virtual void NotifyAnimationFinished(double time) OVERRIDE { + virtual void NotifyAnimationFinished( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { // Animations on the impl-side controller only get deleted during a commit, // so we need to schedule a commit. layer_tree_host()->SetNeedsCommit(); @@ -261,7 +267,7 @@ class LayerTreeHostAnimationTestTickAnimationWhileBackgrounded : num_animates_(0) {} virtual void BeginTest() OVERRIDE { - PostAddAnimationToMainThread(layer_tree_host()->root_layer()); + PostAddLongAnimationToMainThread(layer_tree_host()->root_layer()); } // Use WillAnimateLayers to set visible false before the animation runs and @@ -309,7 +315,10 @@ class LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree PostAddAnimationToMainThread(layer_tree_host()->root_layer()); } - virtual void NotifyAnimationFinished(double time) OVERRIDE { + virtual void NotifyAnimationFinished( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { // Replace animated commits with an empty tree. layer_tree_host()->SetRootLayer(make_scoped_refptr<Layer>(NULL)); } @@ -375,14 +384,17 @@ class LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree // Verify that commits are actually alternating with empty / non-empty // trees. - switch (host_impl->active_tree()->source_frame_number()) { + int frame_number = host_impl->active_tree()->source_frame_number(); + switch (frame_number) { case 0: case 2: - EXPECT_TRUE(host_impl->active_tree()->root_layer()); + EXPECT_TRUE(host_impl->active_tree()->root_layer()) + << "frame: " << frame_number; break; case 1: case 3: - EXPECT_FALSE(host_impl->active_tree()->root_layer()); + EXPECT_FALSE(host_impl->active_tree()->root_layer()) + << "frame: " << frame_number; break; } @@ -496,7 +508,10 @@ class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes PostAddAnimationToMainThread(content_.get()); } - virtual void NotifyAnimationStarted(double time) OVERRIDE { + virtual void NotifyAnimationStarted( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { LayerAnimationController* controller = layer_tree_host()->root_layer()->children()[0]-> layer_animation_controller(); @@ -551,7 +566,10 @@ class LayerTreeHostAnimationTestAnimationFinishedEvents PostAddInstantAnimationToMainThread(layer_tree_host()->root_layer()); } - virtual void NotifyAnimationFinished(double time) OVERRIDE { + virtual void NotifyAnimationFinished( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { LayerAnimationController* controller = layer_tree_host()->root_layer()->layer_animation_controller(); Animation* animation = @@ -767,11 +785,17 @@ class LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw PostAddAnimationToMainThread(content_.get()); } - virtual void NotifyAnimationStarted(double wall_clock_time) OVERRIDE { + virtual void NotifyAnimationStarted( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { started_times_++; } - virtual void NotifyAnimationFinished(double wall_clock_time) OVERRIDE { + virtual void NotifyAnimationFinished( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { EndTest(); } @@ -813,12 +837,18 @@ class LayerTreeHostAnimationTestRunAnimationWhenNotVisible layer_tree_host()->SetVisible(false); } - virtual void NotifyAnimationStarted(double wall_clock_time) OVERRIDE { + virtual void NotifyAnimationStarted( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { EXPECT_FALSE(visible_); started_times_++; } - virtual void NotifyAnimationFinished(double wall_clock_time) OVERRIDE { + virtual void NotifyAnimationFinished( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { EXPECT_FALSE(visible_); EXPECT_EQ(1, started_times_); EndTest(); @@ -863,13 +893,6 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations PostSetNeedsCommitToMainThread(); } - virtual void DispatchAddInstantAnimation(Layer* layer_to_receive_animation) - OVERRIDE { - LayerTreeHostAnimationTest::DispatchAddInstantAnimation( - layer_to_receive_animation); - added_animations_++; - } - virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, LayerTreeHostImpl::FrameData* frame_data, bool result) OVERRIDE { @@ -897,13 +920,19 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations } } - virtual void NotifyAnimationStarted(double wall_clock_time) OVERRIDE { + virtual void NotifyAnimationStarted( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { if (TestEnded()) return; started_times_++; } - virtual void NotifyAnimationFinished(double wall_clock_time) OVERRIDE { + virtual void NotifyAnimationFinished( + double wall_clock_time, + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property) OVERRIDE { // We should be checkerboarding already, but it should still finish the // first animation. EXPECT_EQ(2, added_animations_); @@ -932,5 +961,57 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations MULTI_THREAD_TEST_F( LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations); +// Verifies that when scroll offset is animated on the impl thread, updates +// are sent back to the main thread. +class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated + : public LayerTreeHostAnimationTest { + public: + LayerTreeHostAnimationTestScrollOffsetChangesArePropagated() {} + + virtual void SetupTree() OVERRIDE { + LayerTreeHostAnimationTest::SetupTree(); + + scroll_layer_ = FakeContentLayer::Create(&client_); + scroll_layer_->SetScrollable(true); + scroll_layer_->SetBounds(gfx::Size(1000, 1000)); + scroll_layer_->SetScrollOffset(gfx::Vector2d(10, 20)); + layer_tree_host()->root_layer()->AddChild(scroll_layer_); + } + + virtual void BeginTest() OVERRIDE { + PostSetNeedsCommitToMainThread(); + } + + virtual void DidCommit() OVERRIDE { + switch (layer_tree_host()->source_frame_number()) { + case 1: { + scoped_ptr<ScrollOffsetAnimationCurve> curve( + ScrollOffsetAnimationCurve::Create( + gfx::Vector2dF(500.f, 550.f), + EaseInOutTimingFunction::Create())); + scoped_ptr<Animation> animation(Animation::Create( + curve.PassAs<AnimationCurve>(), 1, 0, Animation::ScrollOffset)); + animation->set_needs_synchronized_start_time(true); + scroll_layer_->AddAnimation(animation.Pass()); + break; + } + default: + if (scroll_layer_->scroll_offset().x() > 10 && + scroll_layer_->scroll_offset().y() > 20) + EndTest(); + } + } + + virtual void AfterTest() OVERRIDE {} + + private: + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> scroll_layer_; +}; + +// SingleThreadProxy doesn't send scroll updates from LayerTreeHostImpl to +// LayerTreeHost. +MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetChangesArePropagated); + } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc index 18683e826b6..7112436595d 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_context.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc @@ -5,9 +5,9 @@ #include "cc/trees/layer_tree_host.h" #include "base/basictypes.h" -#include "cc/debug/test_context_provider.h" -#include "cc/debug/test_web_graphics_context_3d.h" #include "cc/layers/content_layer.h" +#include "cc/layers/delegated_frame_provider.h" +#include "cc/layers/delegated_frame_resource_collection.h" #include "cc/layers/heads_up_display_layer.h" #include "cc/layers/io_surface_layer.h" #include "cc/layers/layer_impl.h" @@ -25,12 +25,15 @@ #include "cc/test/fake_delegated_renderer_layer_impl.h" #include "cc/test/fake_layer_tree_host_client.h" #include "cc/test/fake_output_surface.h" +#include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_painted_scrollbar_layer.h" #include "cc/test/fake_scoped_ui_resource.h" #include "cc/test/fake_scrollbar.h" #include "cc/test/fake_video_frame_provider.h" #include "cc/test/layer_tree_test.h" #include "cc/test/render_pass_test_common.h" +#include "cc/test/test_context_provider.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/layer_tree_impl.h" #include "cc/trees/single_thread_proxy.h" @@ -38,7 +41,7 @@ #include "media/base/media.h" using media::VideoFrame; -using WebKit::WebGraphicsContext3D; +using blink::WebGraphicsContext3D; namespace cc { namespace { @@ -50,13 +53,9 @@ class LayerTreeHostContextTest : public LayerTreeTest { : LayerTreeTest(), context3d_(NULL), times_to_fail_create_(0), - times_to_fail_initialize_(0), - times_to_lose_on_create_(0), times_to_lose_during_commit_(0), times_to_lose_during_draw_(0), times_to_fail_recreate_(0), - times_to_fail_reinitialize_(0), - times_to_lose_on_recreate_(0), times_to_fail_create_offscreen_(0), times_to_fail_recreate_offscreen_(0), times_to_expect_create_failed_(0), @@ -94,19 +93,6 @@ class LayerTreeHostContextTest : public LayerTreeTest { context3d_->set_have_extension_egl_image(true); } - if (times_to_fail_initialize_ && !(fallback && fallback_context_works_)) { - --times_to_fail_initialize_; - // Make the context get lost during reinitialization. - // The number of times MakeCurrent succeeds is not important, and - // can be changed if needed to make this pass with future changes. - context3d_->set_times_make_current_succeeds(2); - ExpectCreateToFail(); - } else if (times_to_lose_on_create_) { - --times_to_lose_on_create_; - LoseContext(); - ExpectCreateToFail(); - } - if (delegating_renderer()) { return FakeOutputSurface::CreateDelegating3d(context3d.Pass()) .PassAs<OutputSurface>(); @@ -135,35 +121,13 @@ class LayerTreeHostContextTest : public LayerTreeTest { return offscreen_context3d.Pass(); } - virtual scoped_refptr<cc::ContextProvider> - OffscreenContextProviderForMainThread() OVERRIDE { - DCHECK(!HasImplThread()); - - if (!offscreen_contexts_main_thread_.get() || - offscreen_contexts_main_thread_->DestroyedOnMainThread()) { - offscreen_contexts_main_thread_ = - TestContextProvider::Create( - base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d, - base::Unretained(this))); - if (offscreen_contexts_main_thread_ && - !offscreen_contexts_main_thread_->BindToCurrentThread()) - offscreen_contexts_main_thread_ = NULL; - } - return offscreen_contexts_main_thread_; - } - - virtual scoped_refptr<cc::ContextProvider> - OffscreenContextProviderForCompositorThread() OVERRIDE { - DCHECK(HasImplThread()); - - if (!offscreen_contexts_compositor_thread_.get() || - offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) { - offscreen_contexts_compositor_thread_ = - TestContextProvider::Create( - base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d, - base::Unretained(this))); + virtual scoped_refptr<ContextProvider> OffscreenContextProvider() OVERRIDE { + if (!offscreen_contexts_.get() || + offscreen_contexts_->DestroyedOnMainThread()) { + offscreen_contexts_ = + TestContextProvider::Create(CreateOffscreenContext3d()); } - return offscreen_contexts_compositor_thread_; + return offscreen_contexts_; } virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, @@ -174,14 +138,10 @@ class LayerTreeHostContextTest : public LayerTreeTest { return result; --times_to_lose_during_draw_; - context3d_->set_times_make_current_succeeds(0); + LoseContext(); times_to_fail_create_ = times_to_fail_recreate_; times_to_fail_recreate_ = 0; - times_to_fail_initialize_ = times_to_fail_reinitialize_; - times_to_fail_reinitialize_ = 0; - times_to_lose_on_create_ = times_to_lose_on_recreate_; - times_to_lose_on_recreate_ = 0; times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_; times_to_fail_recreate_offscreen_ = 0; @@ -198,10 +158,6 @@ class LayerTreeHostContextTest : public LayerTreeTest { times_to_fail_create_ = times_to_fail_recreate_; times_to_fail_recreate_ = 0; - times_to_fail_initialize_ = times_to_fail_reinitialize_; - times_to_fail_reinitialize_ = 0; - times_to_lose_on_create_ = times_to_lose_on_recreate_; - times_to_lose_on_recreate_ = 0; times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_; times_to_fail_recreate_offscreen_ = 0; } @@ -222,13 +178,9 @@ class LayerTreeHostContextTest : public LayerTreeTest { protected: TestWebGraphicsContext3D* context3d_; int times_to_fail_create_; - int times_to_fail_initialize_; - int times_to_lose_on_create_; int times_to_lose_during_commit_; int times_to_lose_during_draw_; int times_to_fail_recreate_; - int times_to_fail_reinitialize_; - int times_to_lose_on_recreate_; int times_to_fail_create_offscreen_; int times_to_fail_recreate_offscreen_; int times_to_expect_create_failed_; @@ -238,8 +190,7 @@ class LayerTreeHostContextTest : public LayerTreeTest { bool context_should_support_io_surface_; bool fallback_context_works_; - scoped_refptr<TestContextProvider> offscreen_contexts_main_thread_; - scoped_refptr<TestContextProvider> offscreen_contexts_compositor_thread_; + scoped_refptr<TestContextProvider> offscreen_contexts_; }; class LayerTreeHostContextTestLostContextSucceeds @@ -249,6 +200,7 @@ class LayerTreeHostContextTestLostContextSucceeds : LayerTreeHostContextTest(), test_case_(0), num_losses_(0), + num_losses_last_test_case_(-1), recovered_context_(true), first_initialized_(false) {} @@ -267,10 +219,7 @@ class LayerTreeHostContextTestLostContextSucceeds recovered_context_ = true; } - virtual void AfterTest() OVERRIDE { - EXPECT_EQ(11u, test_case_); - EXPECT_EQ(8 + 10 + 10 + 1, num_losses_); - } + virtual void AfterTest() OVERRIDE { EXPECT_EQ(9u, test_case_); } virtual void DidCommitAndDrawFrame() OVERRIDE { // If the last frame had a context loss, then we'll commit again to @@ -301,65 +250,37 @@ class LayerTreeHostContextTestLostContextSucceeds // immediately) a small number of times should succeed. { 1, // times_to_lose_during_commit 0, // times_to_lose_during_draw - 3, // times_to_fail_reinitialize 0, // times_to_fail_recreate - 0, // times_to_lose_on_recreate 0, // times_to_fail_recreate_offscreen false, // fallback_context_works }, { 0, // times_to_lose_during_commit 1, // times_to_lose_during_draw - 3, // times_to_fail_reinitialize 0, // times_to_fail_recreate - 0, // times_to_lose_on_recreate 0, // times_to_fail_recreate_offscreen false, // fallback_context_works }, { 1, // times_to_lose_during_commit 0, // times_to_lose_during_draw - 0, // times_to_fail_reinitialize 3, // times_to_fail_recreate - 0, // times_to_lose_on_recreate 0, // times_to_fail_recreate_offscreen false, // fallback_context_works }, { 0, // times_to_lose_during_commit 1, // times_to_lose_during_draw - 0, // times_to_fail_reinitialize 3, // times_to_fail_recreate - 0, // times_to_lose_on_recreate 0, // times_to_fail_recreate_offscreen false, // fallback_context_works }, { 1, // times_to_lose_during_commit 0, // times_to_lose_during_draw - 0, // times_to_fail_reinitialize - 0, // times_to_fail_recreate - 3, // times_to_lose_on_recreate - 0, // times_to_fail_recreate_offscreen - false, // fallback_context_works - }, - { 0, // times_to_lose_during_commit - 1, // times_to_lose_during_draw - 0, // times_to_fail_reinitialize 0, // times_to_fail_recreate - 3, // times_to_lose_on_recreate - 0, // times_to_fail_recreate_offscreen - false, // fallback_context_works - }, - { 1, // times_to_lose_during_commit - 0, // times_to_lose_during_draw - 0, // times_to_fail_reinitialize - 0, // times_to_fail_recreate - 0, // times_to_lose_on_recreate 3, // times_to_fail_recreate_offscreen false, // fallback_context_works }, { 0, // times_to_lose_during_commit 1, // times_to_lose_during_draw - 0, // times_to_fail_reinitialize 0, // times_to_fail_recreate - 0, // times_to_lose_on_recreate 3, // times_to_fail_recreate_offscreen false, // fallback_context_works }, @@ -367,17 +288,13 @@ class LayerTreeHostContextTestLostContextSucceeds // succeed. { 10, // times_to_lose_during_commit 0, // times_to_lose_during_draw - 0, // times_to_fail_reinitialize 0, // times_to_fail_recreate - 0, // times_to_lose_on_recreate 0, // times_to_fail_recreate_offscreen false, // fallback_context_works }, { 0, // times_to_lose_during_commit 10, // times_to_lose_during_draw - 0, // times_to_fail_reinitialize 0, // times_to_fail_recreate - 0, // times_to_lose_on_recreate 0, // times_to_fail_recreate_offscreen false, // fallback_context_works }, @@ -385,9 +302,7 @@ class LayerTreeHostContextTestLostContextSucceeds // context should work. { 0, // times_to_lose_during_commit 1, // times_to_lose_during_draw - 10, // times_to_fail_reinitialize 0, // times_to_fail_recreate - 0, // times_to_lose_on_recreate 0, // times_to_fail_recreate_offscreen true, // fallback_context_works }, @@ -395,14 +310,16 @@ class LayerTreeHostContextTestLostContextSucceeds if (test_case_ >= arraysize(kTests)) return false; + // Make sure that we lost our context at least once in the last test run so + // the test did something. + EXPECT_GT(num_losses_, num_losses_last_test_case_); + num_losses_last_test_case_ = num_losses_; times_to_lose_during_commit_ = kTests[test_case_].times_to_lose_during_commit; times_to_lose_during_draw_ = kTests[test_case_].times_to_lose_during_draw; - times_to_fail_reinitialize_ = kTests[test_case_].times_to_fail_reinitialize; times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate; - times_to_lose_on_recreate_ = kTests[test_case_].times_to_lose_on_recreate; times_to_fail_recreate_offscreen_ = kTests[test_case_].times_to_fail_recreate_offscreen; fallback_context_works_ = kTests[test_case_].fallback_context_works; @@ -413,9 +330,7 @@ class LayerTreeHostContextTestLostContextSucceeds struct TestCase { int times_to_lose_during_commit; int times_to_lose_during_draw; - int times_to_fail_reinitialize; int times_to_fail_recreate; - int times_to_lose_on_recreate; int times_to_fail_recreate_offscreen; bool fallback_context_works; }; @@ -423,6 +338,7 @@ class LayerTreeHostContextTestLostContextSucceeds protected: size_t test_case_; int num_losses_; + int num_losses_last_test_case_; bool recovered_context_; bool first_initialized_; }; @@ -476,7 +392,7 @@ class LayerTreeHostContextTestLostContextSucceedsWithContent // the active context. EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0)); - cc::ContextProvider* contexts = host_impl->offscreen_context_provider(); + ContextProvider* contexts = host_impl->offscreen_context_provider(); if (use_surface_) { ASSERT_TRUE(contexts); EXPECT_TRUE(contexts->Context3d()); @@ -491,13 +407,11 @@ class LayerTreeHostContextTestLostContextSucceedsWithContent LayerTreeHostContextTestLostContextSucceeds::AfterTest(); if (use_surface_) { // 1 create to start with + - // 6 from test cases that fail on initializing the renderer (after the - // offscreen context is created) + - // 6 from test cases that lose the offscreen context directly + - // 4 from test cases that create a fallback + + // 4 from test cases that lose the offscreen context directly + + // 2 from test cases that create a fallback + // All the test cases that recreate both contexts only once // per time it is lost. - EXPECT_EQ(6 + 6 + 1 + 4 + num_losses_, times_offscreen_created_); + EXPECT_EQ(4 + 1 + 2 + num_losses_, times_offscreen_created_); } else { EXPECT_EQ(0, times_offscreen_created_); } @@ -529,23 +443,11 @@ TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, } TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, - NoSurface_MultiThread_DirectRenderer_ImplSidePaint) { - use_surface_ = false; - RunTest(true, false, true); -} - -TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, NoSurface_MultiThread_DelegatingRenderer_MainThreadPaint) { use_surface_ = false; RunTest(true, true, false); } -TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, - NoSurface_MultiThread_DelegatingRenderer_ImplSidePaint) { - use_surface_ = false; - RunTest(true, true, true); -} - // Surfaces don't exist with a delegating renderer. TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, WithSurface_SingleThread_DirectRenderer) { @@ -559,12 +461,6 @@ TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, RunTest(true, false, false); } -TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent, - WithSurface_MultiThread_DirectRenderer_ImplSidePaint) { - use_surface_ = true; - RunTest(true, false, true); -} - class LayerTreeHostContextTestOffscreenContextFails : public LayerTreeHostContextTest { public: @@ -597,7 +493,7 @@ class LayerTreeHostContextTestOffscreenContextFails } virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { - cc::ContextProvider* contexts = host_impl->offscreen_context_provider(); + ContextProvider* contexts = host_impl->offscreen_context_provider(); EXPECT_FALSE(contexts); // This did not lead to create failure. @@ -663,180 +559,6 @@ class LayerTreeHostContextTestLostContextFails bool first_initialized_; }; -TEST_F(LayerTreeHostContextTestLostContextFails, - FailReinitialize100_SingleThread_DirectRenderer) { - times_to_fail_reinitialize_ = 100; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 0; - RunTest(false, false, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailReinitialize100_SingleThread_DelegatingRenderer) { - times_to_fail_reinitialize_ = 100; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 0; - RunTest(false, true, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailReinitialize100_MultiThread_DirectRenderer_MainThreadPaint) { - times_to_fail_reinitialize_ = 100; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 0; - RunTest(true, false, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailReinitialize100_MultiThread_DirectRenderer_ImplSidePaint) { - times_to_fail_reinitialize_ = 100; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 0; - RunTest(true, false, true); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailReinitialize100_MultiThread_DelegatingRenderer_MainThreadPaint) { - times_to_fail_reinitialize_ = 100; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 0; - RunTest(true, true, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailReinitialize100_MultiThread_DelegatingRenderer_ImplSidePaint) { - times_to_fail_reinitialize_ = 100; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 0; - RunTest(true, true, true); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailRecreate100_SingleThread_DirectRenderer) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 100; - times_to_lose_on_recreate_ = 0; - RunTest(false, false, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailRecreate100_SingleThread_DelegatingRenderer) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 100; - times_to_lose_on_recreate_ = 0; - RunTest(false, true, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailRecreate100_MultiThread_DirectRenderer_MainThreadPaint) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 100; - times_to_lose_on_recreate_ = 0; - RunTest(true, false, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailRecreate100_MultiThread_DirectRenderer_ImplSidePaint) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 100; - times_to_lose_on_recreate_ = 0; - RunTest(true, false, true); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailRecreate100_MultiThread_DelegatingRenderer_MainThreadPaint) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 100; - times_to_lose_on_recreate_ = 0; - RunTest(true, true, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - FailRecreate100_MultiThread_DelegatingRenderer_ImplSidePaint) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 100; - times_to_lose_on_recreate_ = 0; - RunTest(true, true, true); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - LoseOnRecreate100_SingleThread_DirectRenderer) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 100; - RunTest(false, false, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - LoseOnRecreate100_SingleThread_DelegatingRenderer) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 100; - RunTest(false, true, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - LoseOnRecreate100_MultiThread_DirectRenderer_MainThreadPaint) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 100; - RunTest(true, false, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - LoseOnRecreate100_MultiThread_DirectRenderer_ImplSidePaint) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 100; - RunTest(true, false, true); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - LoseOnRecreate100_MultiThread_DelegatingRenderer_MainThreadPaint) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 100; - RunTest(true, true, false); -} - -TEST_F(LayerTreeHostContextTestLostContextFails, - LoseOnRecreate100_MultiThread_DelegatingRenderer_ImplSidePaint) { - times_to_fail_reinitialize_ = 0; - times_to_fail_recreate_ = 0; - times_to_lose_on_recreate_ = 100; - RunTest(true, true, true); -} - -class LayerTreeHostContextTestFinishAllRenderingAfterLoss - : public LayerTreeHostContextTest { - public: - virtual void BeginTest() OVERRIDE { - // Lose the context until the compositor gives up on it. - first_initialized_ = false; - times_to_lose_during_commit_ = 1; - times_to_fail_reinitialize_ = 10; - PostSetNeedsCommitToMainThread(); - } - - virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE { - if (first_initialized_) { - EXPECT_FALSE(succeeded); - layer_tree_host()->FinishAllRendering(); - EndTest(); - } else { - first_initialized_ = true; - } - } - - virtual void AfterTest() OVERRIDE {} - - private: - bool first_initialized_; -}; - -SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostContextTestFinishAllRenderingAfterLoss); - class LayerTreeHostContextTestLostContextAndEvictTextures : public LayerTreeHostContextTest { public: @@ -927,19 +649,14 @@ TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, } TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, - LoseAfterEvict_MultiThread_DirectRenderer_ImplSidePaint) { - lose_after_evict_ = true; - RunTest(true, false, true); -} - -TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) { lose_after_evict_ = true; RunTest(true, true, false); } +// Flaky on all platforms, http://crbug.com/310979 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, - LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) { + DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) { lose_after_evict_ = true; RunTest(true, true, true); } @@ -1017,8 +734,8 @@ class LayerTreeHostContextTestLostContextWhileUpdatingResources PostSetNeedsCommitToMainThread(); } - virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE { - LayerTreeHostContextTest::CommitCompleteOnThread(impl); + virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + EXPECT_EQ(0, times_to_lose_on_end_query_); EndTest(); } @@ -1037,7 +754,7 @@ class LayerTreeHostContextTestLostContextWhileUpdatingResources int times_to_lose_on_end_query_; }; -SINGLE_AND_MULTI_THREAD_TEST_F( +SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F( LayerTreeHostContextTestLostContextWhileUpdatingResources); class LayerTreeHostContextTestLayersNotified @@ -1084,25 +801,9 @@ class LayerTreeHostContextTestLayersNotified times_to_fail_create_ = 1; break; case 2: - EXPECT_EQ(1u, root->lost_output_surface_count()); - EXPECT_EQ(1u, child->lost_output_surface_count()); - EXPECT_EQ(1u, grandchild->lost_output_surface_count()); - // Lose the context and again during recreate. - LoseContext(); - times_to_lose_on_create_ = 1; - break; - case 3: - EXPECT_EQ(3u, root->lost_output_surface_count()); - EXPECT_EQ(3u, child->lost_output_surface_count()); - EXPECT_EQ(3u, grandchild->lost_output_surface_count()); - // Lose the context and again during reinitialization. - LoseContext(); - times_to_fail_initialize_ = 1; - break; - case 4: - EXPECT_EQ(5u, root->lost_output_surface_count()); - EXPECT_EQ(5u, child->lost_output_surface_count()); - EXPECT_EQ(5u, grandchild->lost_output_surface_count()); + EXPECT_GE(1u, root->lost_output_surface_count()); + EXPECT_GE(1u, child->lost_output_surface_count()); + EXPECT_GE(1u, grandchild->lost_output_surface_count()); EndTest(); break; default: @@ -1126,72 +827,165 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified); class LayerTreeHostContextTestDontUseLostResources : public LayerTreeHostContextTest { public: - virtual void SetupTree() OVERRIDE { - scoped_refptr<Layer> root_ = Layer::Create(); - root_->SetBounds(gfx::Size(10, 10)); - root_->SetAnchorPoint(gfx::PointF()); - root_->SetIsDrawable(true); + LayerTreeHostContextTestDontUseLostResources() + : lost_context_(false) { + context_should_support_io_surface_ = true; - scoped_refptr<FakeDelegatedRendererLayer> delegated_ = - FakeDelegatedRendererLayer::Create(NULL); - delegated_->SetBounds(gfx::Size(10, 10)); - delegated_->SetAnchorPoint(gfx::PointF()); - delegated_->SetIsDrawable(true); - root_->AddChild(delegated_); + child_output_surface_ = FakeOutputSurface::Create3d(); + child_output_surface_->BindToClient(&output_surface_client_); + child_resource_provider_ = + ResourceProvider::Create(child_output_surface_.get(), + NULL, + 0, + false, + 1); + } - scoped_refptr<ContentLayer> content_ = ContentLayer::Create(&client_); - content_->SetBounds(gfx::Size(10, 10)); - content_->SetAnchorPoint(gfx::PointF()); - content_->SetIsDrawable(true); - root_->AddChild(content_); + static void EmptyReleaseCallback(unsigned sync_point, bool lost) {} - scoped_refptr<TextureLayer> texture_ = TextureLayer::Create(NULL); - texture_->SetBounds(gfx::Size(10, 10)); - texture_->SetAnchorPoint(gfx::PointF()); - texture_->SetIsDrawable(true); - root_->AddChild(texture_); + virtual void SetupTree() OVERRIDE { + blink::WebGraphicsContext3D* context3d = + child_output_surface_->context_provider()->Context3d(); + + scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); + + scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create(); + pass_for_quad->SetNew( + // AppendOneOfEveryQuadType() makes a RenderPass quad with this id. + RenderPass::Id(2, 1), + gfx::Rect(0, 0, 10, 10), + gfx::Rect(0, 0, 10, 10), + gfx::Transform()); + + scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); + pass->SetNew(RenderPass::Id(1, 1), + gfx::Rect(0, 0, 10, 10), + gfx::Rect(0, 0, 10, 10), + gfx::Transform()); + pass->AppendOneOfEveryQuadType(child_resource_provider_.get(), + RenderPass::Id(2, 1)); + + frame_data->render_pass_list.push_back(pass_for_quad.PassAs<RenderPass>()); + frame_data->render_pass_list.push_back(pass.PassAs<RenderPass>()); + + delegated_resource_collection_ = new DelegatedFrameResourceCollection; + delegated_frame_provider_ = new DelegatedFrameProvider( + delegated_resource_collection_.get(), frame_data.Pass()); + + ResourceProvider::ResourceId resource = + child_resource_provider_->CreateResource( + gfx::Size(4, 4), + GL_CLAMP_TO_EDGE, + ResourceProvider::TextureUsageAny, + RGBA_8888); + ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(), + resource); + + gpu::Mailbox mailbox; + context3d->genMailboxCHROMIUM(mailbox.name); + unsigned sync_point = context3d->insertSyncPoint(); - scoped_refptr<ContentLayer> mask_ = ContentLayer::Create(&client_); - mask_->SetBounds(gfx::Size(10, 10)); - mask_->SetAnchorPoint(gfx::PointF()); + scoped_refptr<Layer> root = Layer::Create(); + root->SetBounds(gfx::Size(10, 10)); + root->SetAnchorPoint(gfx::PointF()); + root->SetIsDrawable(true); - scoped_refptr<ContentLayer> content_with_mask_ = + scoped_refptr<FakeDelegatedRendererLayer> delegated = + FakeDelegatedRendererLayer::Create(delegated_frame_provider_.get()); + delegated->SetBounds(gfx::Size(10, 10)); + delegated->SetAnchorPoint(gfx::PointF()); + delegated->SetIsDrawable(true); + root->AddChild(delegated); + + scoped_refptr<ContentLayer> content = ContentLayer::Create(&client_); + content->SetBounds(gfx::Size(10, 10)); + content->SetAnchorPoint(gfx::PointF()); + content->SetIsDrawable(true); + root->AddChild(content); + + scoped_refptr<TextureLayer> texture = TextureLayer::CreateForMailbox(NULL); + texture->SetBounds(gfx::Size(10, 10)); + texture->SetAnchorPoint(gfx::PointF()); + texture->SetIsDrawable(true); + texture->SetTextureMailbox( + TextureMailbox(mailbox, sync_point), + SingleReleaseCallback::Create(base::Bind( + &LayerTreeHostContextTestDontUseLostResources:: + EmptyReleaseCallback))); + root->AddChild(texture); + + scoped_refptr<ContentLayer> mask = ContentLayer::Create(&client_); + mask->SetBounds(gfx::Size(10, 10)); + mask->SetAnchorPoint(gfx::PointF()); + + scoped_refptr<ContentLayer> content_with_mask = ContentLayer::Create(&client_); - content_with_mask_->SetBounds(gfx::Size(10, 10)); - content_with_mask_->SetAnchorPoint(gfx::PointF()); - content_with_mask_->SetIsDrawable(true); - content_with_mask_->SetMaskLayer(mask_.get()); - root_->AddChild(content_with_mask_); - - scoped_refptr<VideoLayer> video_color_ = VideoLayer::Create( - &color_frame_provider_); - video_color_->SetBounds(gfx::Size(10, 10)); - video_color_->SetAnchorPoint(gfx::PointF()); - video_color_->SetIsDrawable(true); - root_->AddChild(video_color_); - - scoped_refptr<VideoLayer> video_hw_ = VideoLayer::Create( - &hw_frame_provider_); - video_hw_->SetBounds(gfx::Size(10, 10)); - video_hw_->SetAnchorPoint(gfx::PointF()); - video_hw_->SetIsDrawable(true); - root_->AddChild(video_hw_); - - scoped_refptr<VideoLayer> video_scaled_hw_ = VideoLayer::Create( - &scaled_hw_frame_provider_); - video_scaled_hw_->SetBounds(gfx::Size(10, 10)); - video_scaled_hw_->SetAnchorPoint(gfx::PointF()); - video_scaled_hw_->SetIsDrawable(true); - root_->AddChild(video_scaled_hw_); + content_with_mask->SetBounds(gfx::Size(10, 10)); + content_with_mask->SetAnchorPoint(gfx::PointF()); + content_with_mask->SetIsDrawable(true); + content_with_mask->SetMaskLayer(mask.get()); + root->AddChild(content_with_mask); + + scoped_refptr<VideoLayer> video_color = + VideoLayer::Create(&color_frame_provider_); + video_color->SetBounds(gfx::Size(10, 10)); + video_color->SetAnchorPoint(gfx::PointF()); + video_color->SetIsDrawable(true); + root->AddChild(video_color); + + scoped_refptr<VideoLayer> video_hw = + VideoLayer::Create(&hw_frame_provider_); + video_hw->SetBounds(gfx::Size(10, 10)); + video_hw->SetAnchorPoint(gfx::PointF()); + video_hw->SetIsDrawable(true); + root->AddChild(video_hw); + + scoped_refptr<VideoLayer> video_scaled_hw = + VideoLayer::Create(&scaled_hw_frame_provider_); + video_scaled_hw->SetBounds(gfx::Size(10, 10)); + video_scaled_hw->SetAnchorPoint(gfx::PointF()); + video_scaled_hw->SetIsDrawable(true); + root->AddChild(video_scaled_hw); + + color_video_frame_ = VideoFrame::CreateColorFrame( + gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta()); + hw_video_frame_ = VideoFrame::WrapNativeTexture( + make_scoped_ptr(new VideoFrame::MailboxHolder( + mailbox, + sync_point, + VideoFrame::MailboxHolder::TextureNoLongerNeededCallback())), + GL_TEXTURE_2D, + gfx::Size(4, 4), + gfx::Rect(0, 0, 4, 4), + gfx::Size(4, 4), + base::TimeDelta(), + VideoFrame::ReadPixelsCB(), + base::Closure()); + scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture( + make_scoped_ptr(new VideoFrame::MailboxHolder( + mailbox, + sync_point, + VideoFrame::MailboxHolder::TextureNoLongerNeededCallback())), + GL_TEXTURE_2D, + gfx::Size(4, 4), + gfx::Rect(0, 0, 3, 2), + gfx::Size(4, 4), + base::TimeDelta(), + VideoFrame::ReadPixelsCB(), + base::Closure()); + + color_frame_provider_.set_frame(color_video_frame_); + hw_frame_provider_.set_frame(hw_video_frame_); + scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_); if (!delegating_renderer()) { // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335 - scoped_refptr<IOSurfaceLayer> io_surface_ = IOSurfaceLayer::Create(); - io_surface_->SetBounds(gfx::Size(10, 10)); - io_surface_->SetAnchorPoint(gfx::PointF()); - io_surface_->SetIsDrawable(true); - io_surface_->SetIOSurfaceProperties(1, gfx::Size(10, 10)); - root_->AddChild(io_surface_); + scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create(); + io_surface->SetBounds(gfx::Size(10, 10)); + io_surface->SetAnchorPoint(gfx::PointF()); + io_surface->SetIsDrawable(true); + io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10)); + root->AddChild(io_surface); } // Enable the hud. @@ -1199,109 +993,23 @@ class LayerTreeHostContextTestDontUseLostResources debug_state.show_property_changed_rects = true; layer_tree_host()->SetDebugState(debug_state); - scoped_refptr<PaintedScrollbarLayer> scrollbar_ = + scoped_refptr<PaintedScrollbarLayer> scrollbar = PaintedScrollbarLayer::Create( - scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content_->id()); - scrollbar_->SetBounds(gfx::Size(10, 10)); - scrollbar_->SetAnchorPoint(gfx::PointF()); - scrollbar_->SetIsDrawable(true); - root_->AddChild(scrollbar_); + scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content->id()); + scrollbar->SetBounds(gfx::Size(10, 10)); + scrollbar->SetAnchorPoint(gfx::PointF()); + scrollbar->SetIsDrawable(true); + root->AddChild(scrollbar); - layer_tree_host()->SetRootLayer(root_); + layer_tree_host()->SetRootLayer(root); LayerTreeHostContextTest::SetupTree(); } - virtual void BeginTest() OVERRIDE { - context_should_support_io_surface_ = true; - PostSetNeedsCommitToMainThread(); - } + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { LayerTreeHostContextTest::CommitCompleteOnThread(host_impl); - ResourceProvider* resource_provider = host_impl->resource_provider(); - ContextProvider* context_provider = - host_impl->output_surface()->context_provider(); - - DCHECK(context_provider); - - if (host_impl->active_tree()->source_frame_number() == 0) { - // Set up impl resources on the first commit. - - scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create(); - pass_for_quad->SetNew( - // AppendOneOfEveryQuadType() makes a RenderPass quad with this id. - RenderPass::Id(1, 1), - gfx::Rect(0, 0, 10, 10), - gfx::Rect(0, 0, 10, 10), - gfx::Transform()); - - scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); - pass->SetNew( - RenderPass::Id(2, 1), - gfx::Rect(0, 0, 10, 10), - gfx::Rect(0, 0, 10, 10), - gfx::Transform()); - pass->AppendOneOfEveryQuadType(resource_provider, RenderPass::Id(2, 1)); - - ScopedPtrVector<RenderPass> pass_list; - pass_list.push_back(pass_for_quad.PassAs<RenderPass>()); - pass_list.push_back(pass.PassAs<RenderPass>()); - - // First child is the delegated layer. - FakeDelegatedRendererLayerImpl* delegated_impl = - static_cast<FakeDelegatedRendererLayerImpl*>( - host_impl->active_tree()->root_layer()->children()[0]); - delegated_impl->SetFrameDataForRenderPasses(&pass_list); - EXPECT_TRUE(pass_list.empty()); - - // Third child is the texture layer. - TextureLayerImpl* texture_impl = - static_cast<TextureLayerImpl*>( - host_impl->active_tree()->root_layer()->children()[2]); - texture_impl->set_texture_id( - context_provider->Context3d()->createTexture()); - - ResourceProvider::ResourceId texture = resource_provider->CreateResource( - gfx::Size(4, 4), - GL_CLAMP_TO_EDGE, - ResourceProvider::TextureUsageAny, - RGBA_8888); - ResourceProvider::ScopedWriteLockGL lock(resource_provider, texture); - - gpu::Mailbox mailbox; - context_provider->Context3d()->genMailboxCHROMIUM(mailbox.name); - unsigned sync_point = context_provider->Context3d()->insertSyncPoint(); - - color_video_frame_ = VideoFrame::CreateColorFrame( - gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta()); - hw_video_frame_ = VideoFrame::WrapNativeTexture( - new VideoFrame::MailboxHolder( - mailbox, - sync_point, - VideoFrame::MailboxHolder::TextureNoLongerNeededCallback()), - GL_TEXTURE_2D, - gfx::Size(4, 4), gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), - base::TimeDelta(), - VideoFrame::ReadPixelsCB(), - base::Closure()); - scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture( - new VideoFrame::MailboxHolder( - mailbox, - sync_point, - VideoFrame::MailboxHolder::TextureNoLongerNeededCallback()), - GL_TEXTURE_2D, - gfx::Size(4, 4), gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), - base::TimeDelta(), - VideoFrame::ReadPixelsCB(), - base::Closure()); - - color_frame_provider_.set_frame(color_video_frame_); - hw_frame_provider_.set_frame(hw_video_frame_); - scaled_hw_frame_provider_.set_frame(scaled_hw_video_frame_); - return; - } - if (host_impl->active_tree()->source_frame_number() == 3) { // On the third commit we're recovering from context loss. Hardware // video frames should not be reused by the VideoFrameProvider, but @@ -1317,37 +1025,46 @@ class LayerTreeHostContextTestDontUseLostResources if (host_impl->active_tree()->source_frame_number() == 2) { // Lose the context during draw on the second commit. This will cause // a third commit to recover. - if (context3d_) - context3d_->set_times_bind_texture_succeeds(4); + context3d_->set_times_bind_texture_succeeds(0); } return true; } + virtual scoped_ptr<OutputSurface> CreateOutputSurface( + bool fallback) OVERRIDE { + if (layer_tree_host()) { + lost_context_ = true; + EXPECT_EQ(layer_tree_host()->source_frame_number(), 3); + } + return LayerTreeHostContextTest::CreateOutputSurface(fallback); + } + virtual void DidCommitAndDrawFrame() OVERRIDE { ASSERT_TRUE(layer_tree_host()->hud_layer()); // End the test once we know the 3nd frame drew. - if (layer_tree_host()->source_frame_number() == 4) - EndTest(); - else + if (layer_tree_host()->source_frame_number() < 4) { + layer_tree_host()->root_layer()->SetNeedsDisplay(); layer_tree_host()->SetNeedsCommit(); + } else { + EndTest(); + } } - virtual void AfterTest() OVERRIDE {} + virtual void AfterTest() OVERRIDE { + EXPECT_TRUE(lost_context_); + } private: FakeContentLayerClient client_; + bool lost_context_; - scoped_refptr<Layer> root_; - scoped_refptr<DelegatedRendererLayer> delegated_; - scoped_refptr<ContentLayer> content_; - scoped_refptr<TextureLayer> texture_; - scoped_refptr<ContentLayer> mask_; - scoped_refptr<ContentLayer> content_with_mask_; - scoped_refptr<VideoLayer> video_color_; - scoped_refptr<VideoLayer> video_hw_; - scoped_refptr<VideoLayer> video_scaled_hw_; - scoped_refptr<IOSurfaceLayer> io_surface_; - scoped_refptr<PaintedScrollbarLayer> scrollbar_; + FakeOutputSurfaceClient output_surface_client_; + scoped_ptr<FakeOutputSurface> child_output_surface_; + scoped_ptr<ResourceProvider> child_resource_provider_; + + scoped_refptr<DelegatedFrameResourceCollection> + delegated_resource_collection_; + scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_; scoped_refptr<VideoFrame> color_video_frame_; scoped_refptr<VideoFrame> hw_video_frame_; @@ -1360,73 +1077,6 @@ class LayerTreeHostContextTestDontUseLostResources SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources); -class LayerTreeHostContextTestLosesFirstOutputSurface - : public LayerTreeHostContextTest { - public: - LayerTreeHostContextTestLosesFirstOutputSurface() { - // Always fail. This needs to be set before LayerTreeHost is created. - times_to_lose_on_create_ = 1000; - } - - virtual void BeginTest() OVERRIDE { - PostSetNeedsCommitToMainThread(); - } - - virtual void AfterTest() OVERRIDE {} - - virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE { - EXPECT_FALSE(succeeded); - - // If we make it this far without crashing, we pass! - EndTest(); - } - - virtual void DidCommitAndDrawFrame() OVERRIDE { - EXPECT_TRUE(false); - } -}; - -SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostContextTestLosesFirstOutputSurface); - -class LayerTreeHostContextTestRetriesFirstInitializationAndSucceeds - : public LayerTreeHostContextTest { - public: - virtual void AfterTest() OVERRIDE {} - - virtual void BeginTest() OVERRIDE { - times_to_fail_initialize_ = 2; - PostSetNeedsCommitToMainThread(); - } - - virtual void DidCommitAndDrawFrame() OVERRIDE { - EndTest(); - } -}; - -SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostContextTestRetriesFirstInitializationAndSucceeds); - -class LayerTreeHostContextTestRetryWorksWithForcedInit - : public LayerTreeHostContextTestRetriesFirstInitializationAndSucceeds { - public: - virtual void DidFailToInitializeOutputSurface() OVERRIDE { - LayerTreeHostContextTestRetriesFirstInitializationAndSucceeds - ::DidFailToInitializeOutputSurface(); - - if (times_create_failed_ == 1) { - // CompositeAndReadback force recreates the output surface, which should - // fail. - char pixels[4]; - EXPECT_FALSE(layer_tree_host()->CompositeAndReadback( - &pixels, gfx::Rect(1, 1))); - } - } -}; - -SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostContextTestRetryWorksWithForcedInit); - class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit : public LayerTreeHostContextTest { public: @@ -1437,13 +1087,16 @@ class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit times_output_surface_created_ = 0; + // Post the SetNeedsCommit before the readback to make sure it is run + // on the main thread before the readback's replacement commit when + // we have a threaded compositor. + PostSetNeedsCommitToMainThread(); + char pixels[4]; bool result = layer_tree_host()->CompositeAndReadback( &pixels, gfx::Rect(1, 1)); EXPECT_EQ(!delegating_renderer(), result); EXPECT_EQ(1, times_output_surface_created_); - - PostSetNeedsCommitToMainThread(); } virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE { @@ -1576,7 +1229,6 @@ class LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit protected: static const int kFirstOutputSurfaceInitSourceFrameNumber = 0; static const int kReadbackSourceFrameNumber = 1; - static const int kReadbackReplacementSourceFrameNumber = 2; static const int kForcedDrawCommitSourceFrameNumber = 2; static const int kSecondOutputSurfaceInitSourceFrameNumber = 2; @@ -1753,42 +1405,6 @@ class ScrollbarLayerLostContext : public LayerTreeHostContextTest { SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext); -class LayerTreeHostContextTestFailsToCreateSurface - : public LayerTreeHostContextTest { - public: - LayerTreeHostContextTestFailsToCreateSurface() - : LayerTreeHostContextTest(), - failure_count_(0) { - times_to_lose_on_create_ = 10; - } - - virtual void BeginTest() OVERRIDE { - PostSetNeedsCommitToMainThread(); - } - - virtual void AfterTest() OVERRIDE {} - - virtual void DidInitializeOutputSurface(bool success) OVERRIDE { - EXPECT_FALSE(success); - EXPECT_EQ(0, failure_count_); - times_to_lose_on_create_ = 0; - failure_count_++; - // Normally, the embedder should stop trying to use the compositor at - // this point, but let's force it back into action when we shouldn't. - char pixels[4]; - EXPECT_FALSE( - layer_tree_host()->CompositeAndReadback(pixels, gfx::Rect(1, 1))); - // If we've made it this far without crashing, we've succeeded. - EndTest(); - } - - private: - int failure_count_; -}; - -SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostContextTestFailsToCreateSurface); - // Not reusing LayerTreeTest because it expects creating LTH to always succeed. class LayerTreeHostTestCannotCreateIfCannotCreateOutputSurface : public testing::Test, @@ -1806,20 +1422,20 @@ class LayerTreeHostTestCannotCreateIfCannotCreateOutputSurface void RunTest(bool threaded, bool delegating_renderer, bool impl_side_painting) { - scoped_ptr<base::Thread> impl_thread; + LayerTreeSettings settings; + settings.impl_side_painting = impl_side_painting; if (threaded) { - impl_thread.reset(new base::Thread("LayerTreeTest")); + scoped_ptr<base::Thread> impl_thread(new base::Thread("LayerTreeTest")); ASSERT_TRUE(impl_thread->Start()); ASSERT_TRUE(impl_thread->message_loop_proxy().get()); + scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::CreateThreaded( + this, NULL, settings, impl_thread->message_loop_proxy()); + EXPECT_FALSE(layer_tree_host); + } else { + scoped_ptr<LayerTreeHost> layer_tree_host = + LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings); + EXPECT_FALSE(layer_tree_host); } - - LayerTreeSettings settings; - settings.impl_side_painting = impl_side_painting; - scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::Create( - this, - settings, - impl_thread ? impl_thread->message_loop_proxy() : NULL); - EXPECT_FALSE(layer_tree_host); } }; @@ -1829,6 +1445,9 @@ SINGLE_AND_MULTI_THREAD_TEST_F( class UIResourceLostTest : public LayerTreeHostContextTest { public: UIResourceLostTest() : time_step_(0) {} + virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { + settings->texture_id_allocation_chunk_size = 1; + } virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } virtual void AfterTest() OVERRIDE {} @@ -2250,5 +1869,74 @@ class UIResourceLostEviction : public UIResourceLostTestSimple { SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction); +class LayerTreeHostContextTestSurfaceCreateCallback + : public LayerTreeHostContextTest { + public: + LayerTreeHostContextTestSurfaceCreateCallback() + : LayerTreeHostContextTest(), + layer_(FakeContentLayer::Create(&client_)), + num_commits_(0) {} + + virtual void SetupTree() OVERRIDE { + layer_->SetBounds(gfx::Size(10, 20)); + layer_tree_host()->SetRootLayer(layer_); + LayerTreeHostContextTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { + PostSetNeedsCommitToMainThread(); + } + + virtual void DidCommit() OVERRIDE { + switch (num_commits_) { + case 0: + EXPECT_EQ(1u, layer_->output_surface_created_count()); + layer_tree_host()->SetNeedsCommit(); + break; + case 1: + EXPECT_EQ(1u, layer_->output_surface_created_count()); + layer_tree_host()->SetNeedsCommit(); + break; + case 2: + EXPECT_EQ(1u, layer_->output_surface_created_count()); + break; + case 3: + EXPECT_EQ(2u, layer_->output_surface_created_count()); + layer_tree_host()->SetNeedsCommit(); + break; + } + ++num_commits_; + } + + virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE { + LayerTreeHostContextTest::CommitCompleteOnThread(impl); + switch (num_commits_) { + case 0: + break; + case 1: + break; + case 2: + LoseContext(); + break; + case 3: + EndTest(); + break; + } + } + + virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE { + EXPECT_TRUE(succeeded); + } + + virtual void AfterTest() OVERRIDE {} + + protected: + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> layer_; + int num_commits_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback); + } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc new file mode 100644 index 00000000000..c06f345ef17 --- /dev/null +++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc @@ -0,0 +1,908 @@ +// Copyright 2013 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 "cc/output/copy_output_request.h" +#include "cc/output/copy_output_result.h" +#include "cc/test/fake_content_layer.h" +#include "cc/test/fake_content_layer_client.h" +#include "cc/test/fake_output_surface.h" +#include "cc/test/layer_tree_test.h" +#include "cc/trees/layer_tree_impl.h" +#include "gpu/GLES2/gl2extchromium.h" + +namespace cc { +namespace { + +// These tests only use direct rendering, as there is no output to copy for +// delegated renderers. +class LayerTreeHostCopyRequestTest : public LayerTreeTest {}; + +class LayerTreeHostCopyRequestTestMultipleRequests + : public LayerTreeHostCopyRequestTest { + protected: + virtual void SetupTree() OVERRIDE { + root = FakeContentLayer::Create(&client_); + root->SetBounds(gfx::Size(20, 20)); + + child = FakeContentLayer::Create(&client_); + child->SetBounds(gfx::Size(10, 10)); + root->AddChild(child); + + layer_tree_host()->SetRootLayer(root); + LayerTreeHostCopyRequestTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void DidCommitAndDrawFrame() OVERRIDE { WaitForCallback(); } + + void WaitForCallback() { + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::NextStep, + base::Unretained(this))); + } + + void NextStep() { + int frame = layer_tree_host()->source_frame_number(); + switch (frame) { + case 1: + child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( + base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests:: + CopyOutputCallback, + base::Unretained(this)))); + EXPECT_EQ(0u, callbacks_.size()); + break; + case 2: + if (callbacks_.size() < 1u) { + WaitForCallback(); + return; + } + EXPECT_EQ(1u, callbacks_.size()); + EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[0].ToString()); + + child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( + base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests:: + CopyOutputCallback, + base::Unretained(this)))); + root->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( + base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests:: + CopyOutputCallback, + base::Unretained(this)))); + child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( + base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests:: + CopyOutputCallback, + base::Unretained(this)))); + EXPECT_EQ(1u, callbacks_.size()); + break; + case 3: + if (callbacks_.size() < 4u) { + WaitForCallback(); + return; + } + EXPECT_EQ(4u, callbacks_.size()); + // The child was copied to a bitmap and passed back twice. + EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[1].ToString()); + EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[2].ToString()); + // The root was copied to a bitmap and passed back also. + EXPECT_EQ(gfx::Size(20, 20).ToString(), callbacks_[3].ToString()); + EndTest(); + break; + } + } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); + EXPECT_TRUE(result->HasBitmap()); + scoped_ptr<SkBitmap> bitmap = result->TakeBitmap().Pass(); + EXPECT_EQ(result->size().ToString(), + gfx::Size(bitmap->width(), bitmap->height()).ToString()); + callbacks_.push_back(result->size()); + } + + virtual void AfterTest() OVERRIDE { EXPECT_EQ(4u, callbacks_.size()); } + + virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) + OVERRIDE { + scoped_ptr<FakeOutputSurface> output_surface; + if (use_gl_renderer_) { + output_surface = FakeOutputSurface::Create3d().Pass(); + } else { + output_surface = FakeOutputSurface::CreateSoftware( + make_scoped_ptr(new SoftwareOutputDevice)).Pass(); + } + return output_surface.PassAs<OutputSurface>(); + } + + bool use_gl_renderer_; + std::vector<gfx::Size> callbacks_; + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root; + scoped_refptr<FakeContentLayer> child; +}; + +// Readback can't be done with a delegating renderer. +TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, + GLRenderer_RunSingleThread) { + use_gl_renderer_ = true; + RunTest(false, false, false); +} + +TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, + GLRenderer_RunMultiThread_MainThreadPainting) { + use_gl_renderer_ = true; + RunTest(true, false, false); +} + +TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, + SoftwareRenderer_RunSingleThread) { + use_gl_renderer_ = false; + RunTest(false, false, false); +} + +TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, + SoftwareRenderer_RunMultiThread_MainThreadPainting) { + use_gl_renderer_ = false; + RunTest(true, false, false); +} + +class LayerTreeHostCopyRequestTestLayerDestroyed + : public LayerTreeHostCopyRequestTest { + protected: + virtual void SetupTree() OVERRIDE { + root_ = FakeContentLayer::Create(&client_); + root_->SetBounds(gfx::Size(20, 20)); + + main_destroyed_ = FakeContentLayer::Create(&client_); + main_destroyed_->SetBounds(gfx::Size(15, 15)); + root_->AddChild(main_destroyed_); + + impl_destroyed_ = FakeContentLayer::Create(&client_); + impl_destroyed_->SetBounds(gfx::Size(10, 10)); + root_->AddChild(impl_destroyed_); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeHostCopyRequestTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { + callback_count_ = 0; + PostSetNeedsCommitToMainThread(); + } + + virtual void DidCommit() OVERRIDE { + int frame = layer_tree_host()->source_frame_number(); + switch (frame) { + case 1: + main_destroyed_->RequestCopyOfOutput( + CopyOutputRequest::CreateBitmapRequest(base::Bind( + &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback, + base::Unretained(this)))); + impl_destroyed_->RequestCopyOfOutput( + CopyOutputRequest::CreateBitmapRequest(base::Bind( + &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback, + base::Unretained(this)))); + EXPECT_EQ(0, callback_count_); + + // Destroy the main thread layer right away. + main_destroyed_->RemoveFromParent(); + main_destroyed_ = NULL; + + // Should callback with a NULL bitmap. + EXPECT_EQ(1, callback_count_); + + // Prevent drawing so we can't make a copy of the impl_destroyed layer. + layer_tree_host()->SetViewportSize(gfx::Size()); + break; + case 2: + // Flush the message loops and make sure the callbacks run. + layer_tree_host()->SetNeedsCommit(); + break; + case 3: + // No drawing means no readback yet. + EXPECT_EQ(1, callback_count_); + + // Destroy the impl thread layer. + impl_destroyed_->RemoveFromParent(); + impl_destroyed_ = NULL; + + // No callback yet because it's on the impl side. + EXPECT_EQ(1, callback_count_); + break; + case 4: + // Flush the message loops and make sure the callbacks run. + layer_tree_host()->SetNeedsCommit(); + break; + case 5: + // We should get another callback with a NULL bitmap. + EXPECT_EQ(2, callback_count_); + EndTest(); + break; + } + } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); + EXPECT_TRUE(result->IsEmpty()); + ++callback_count_; + } + + virtual void AfterTest() OVERRIDE {} + + int callback_count_; + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root_; + scoped_refptr<FakeContentLayer> main_destroyed_; + scoped_refptr<FakeContentLayer> impl_destroyed_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestLayerDestroyed); + +class LayerTreeHostCopyRequestTestInHiddenSubtree + : public LayerTreeHostCopyRequestTest { + protected: + virtual void SetupTree() OVERRIDE { + root_ = FakeContentLayer::Create(&client_); + root_->SetBounds(gfx::Size(20, 20)); + + grand_parent_layer_ = FakeContentLayer::Create(&client_); + grand_parent_layer_->SetBounds(gfx::Size(15, 15)); + root_->AddChild(grand_parent_layer_); + + // parent_layer_ owns a render surface. + parent_layer_ = FakeContentLayer::Create(&client_); + parent_layer_->SetBounds(gfx::Size(15, 15)); + parent_layer_->SetForceRenderSurface(true); + grand_parent_layer_->AddChild(parent_layer_); + + copy_layer_ = FakeContentLayer::Create(&client_); + copy_layer_->SetBounds(gfx::Size(10, 10)); + parent_layer_->AddChild(copy_layer_); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeHostCopyRequestTest::SetupTree(); + } + + void AddCopyRequest(Layer* layer) { + layer->RequestCopyOfOutput( + CopyOutputRequest::CreateBitmapRequest(base::Bind( + &LayerTreeHostCopyRequestTestInHiddenSubtree::CopyOutputCallback, + base::Unretained(this)))); + } + + virtual void BeginTest() OVERRIDE { + callback_count_ = 0; + PostSetNeedsCommitToMainThread(); + + AddCopyRequest(copy_layer_.get()); + } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { + ++callback_count_; + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); + EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()) + << callback_count_; + switch (callback_count_) { + case 1: + // Hide the copy request layer. + grand_parent_layer_->SetHideLayerAndSubtree(false); + parent_layer_->SetHideLayerAndSubtree(false); + copy_layer_->SetHideLayerAndSubtree(true); + AddCopyRequest(copy_layer_.get()); + break; + case 2: + // Hide the copy request layer's parent only. + grand_parent_layer_->SetHideLayerAndSubtree(false); + parent_layer_->SetHideLayerAndSubtree(true); + copy_layer_->SetHideLayerAndSubtree(false); + AddCopyRequest(copy_layer_.get()); + break; + case 3: + // Hide the copy request layer's grand parent only. + grand_parent_layer_->SetHideLayerAndSubtree(true); + parent_layer_->SetHideLayerAndSubtree(false); + copy_layer_->SetHideLayerAndSubtree(false); + AddCopyRequest(copy_layer_.get()); + break; + case 4: + // Hide the copy request layer's parent and grandparent. + grand_parent_layer_->SetHideLayerAndSubtree(true); + parent_layer_->SetHideLayerAndSubtree(true); + copy_layer_->SetHideLayerAndSubtree(false); + AddCopyRequest(copy_layer_.get()); + break; + case 5: + // Hide the copy request layer as well as its parent and grandparent. + grand_parent_layer_->SetHideLayerAndSubtree(true); + parent_layer_->SetHideLayerAndSubtree(true); + copy_layer_->SetHideLayerAndSubtree(true); + AddCopyRequest(copy_layer_.get()); + break; + case 6: + EndTest(); + break; + } + } + + virtual void AfterTest() OVERRIDE {} + + int callback_count_; + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root_; + scoped_refptr<FakeContentLayer> grand_parent_layer_; + scoped_refptr<FakeContentLayer> parent_layer_; + scoped_refptr<FakeContentLayer> copy_layer_; +}; + +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( + LayerTreeHostCopyRequestTestInHiddenSubtree); + +class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest + : public LayerTreeHostCopyRequestTest { + protected: + virtual void SetupTree() OVERRIDE { + root_ = FakeContentLayer::Create(&client_); + root_->SetBounds(gfx::Size(20, 20)); + + grand_parent_layer_ = FakeContentLayer::Create(&client_); + grand_parent_layer_->SetBounds(gfx::Size(15, 15)); + grand_parent_layer_->SetHideLayerAndSubtree(true); + root_->AddChild(grand_parent_layer_); + + // parent_layer_ owns a render surface. + parent_layer_ = FakeContentLayer::Create(&client_); + parent_layer_->SetBounds(gfx::Size(15, 15)); + parent_layer_->SetForceRenderSurface(true); + grand_parent_layer_->AddChild(parent_layer_); + + copy_layer_ = FakeContentLayer::Create(&client_); + copy_layer_->SetBounds(gfx::Size(10, 10)); + parent_layer_->AddChild(copy_layer_); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeHostCopyRequestTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { + did_draw_ = false; + PostSetNeedsCommitToMainThread(); + + copy_layer_->RequestCopyOfOutput( + CopyOutputRequest::CreateBitmapRequest(base::Bind( + &LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest:: + CopyOutputCallback, + base::Unretained(this)))); + } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); + EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()); + EndTest(); + } + + virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + Renderer* renderer = host_impl->renderer(); + + LayerImpl* root = host_impl->active_tree()->root_layer(); + LayerImpl* grand_parent = root->children()[0]; + LayerImpl* parent = grand_parent->children()[0]; + LayerImpl* copy_layer = parent->children()[0]; + + // |parent| owns a surface, but it was hidden and not part of the copy + // request so it should not allocate any resource. + EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting( + parent->render_surface()->RenderPassId())); + + // |copy_layer| should have been rendered to a texture since it was needed + // for a copy request. + EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting( + copy_layer->render_surface()->RenderPassId())); + + did_draw_ = true; + } + + virtual void AfterTest() OVERRIDE { EXPECT_TRUE(did_draw_); } + + FakeContentLayerClient client_; + bool did_draw_; + scoped_refptr<FakeContentLayer> root_; + scoped_refptr<FakeContentLayer> grand_parent_layer_; + scoped_refptr<FakeContentLayer> parent_layer_; + scoped_refptr<FakeContentLayer> copy_layer_; +}; + +// No output to copy for delegated renderers. +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( + LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest); + +class LayerTreeHostCopyRequestTestClippedOut + : public LayerTreeHostCopyRequestTest { + protected: + virtual void SetupTree() OVERRIDE { + root_ = FakeContentLayer::Create(&client_); + root_->SetBounds(gfx::Size(20, 20)); + + parent_layer_ = FakeContentLayer::Create(&client_); + parent_layer_->SetBounds(gfx::Size(15, 15)); + parent_layer_->SetMasksToBounds(true); + root_->AddChild(parent_layer_); + + copy_layer_ = FakeContentLayer::Create(&client_); + copy_layer_->SetPosition(gfx::Point(15, 15)); + copy_layer_->SetBounds(gfx::Size(10, 10)); + parent_layer_->AddChild(copy_layer_); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeHostCopyRequestTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { + PostSetNeedsCommitToMainThread(); + + copy_layer_->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( + base::Bind(&LayerTreeHostCopyRequestTestClippedOut::CopyOutputCallback, + base::Unretained(this)))); + } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { + // We should still get a callback with no output if the copy requested layer + // was completely clipped away. + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); + EXPECT_EQ(gfx::Size().ToString(), result->size().ToString()); + EndTest(); + } + + virtual void AfterTest() OVERRIDE {} + + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root_; + scoped_refptr<FakeContentLayer> parent_layer_; + scoped_refptr<FakeContentLayer> copy_layer_; +}; + +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( + LayerTreeHostCopyRequestTestClippedOut); + +class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw + : public LayerTreeHostCopyRequestTest { + protected: + virtual void SetupTree() OVERRIDE { + root_ = FakeContentLayer::Create(&client_); + root_->SetBounds(gfx::Size(20, 20)); + + copy_layer_ = FakeContentLayer::Create(&client_); + copy_layer_->SetBounds(gfx::Size(10, 10)); + root_->AddChild(copy_layer_); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeHostCopyRequestTest::SetupTree(); + } + + void AddCopyRequest(Layer* layer) { + layer->RequestCopyOfOutput( + CopyOutputRequest::CreateBitmapRequest(base::Bind( + &LayerTreeHostTestAsyncTwoReadbacksWithoutDraw::CopyOutputCallback, + base::Unretained(this)))); + } + + virtual void BeginTest() OVERRIDE { + saw_copy_request_ = false; + callback_count_ = 0; + PostSetNeedsCommitToMainThread(); + + // Prevent drawing. + layer_tree_host()->SetViewportSize(gfx::Size(0, 0)); + + AddCopyRequest(copy_layer_.get()); + } + + virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE { + if (impl->active_tree()->source_frame_number() == 0) { + LayerImpl* root = impl->active_tree()->root_layer(); + EXPECT_TRUE(root->children()[0]->HasCopyRequest()); + saw_copy_request_ = true; + } + } + + virtual void DidCommit() OVERRIDE { + if (layer_tree_host()->source_frame_number() == 1) { + // Allow drawing. + layer_tree_host()->SetViewportSize(gfx::Size(root_->bounds())); + + AddCopyRequest(copy_layer_.get()); + } + } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); + EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()); + ++callback_count_; + + if (callback_count_ == 2) + EndTest(); + } + + virtual void AfterTest() OVERRIDE { EXPECT_TRUE(saw_copy_request_); } + + bool saw_copy_request_; + int callback_count_; + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root_; + scoped_refptr<FakeContentLayer> copy_layer_; +}; + +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( + LayerTreeHostTestAsyncTwoReadbacksWithoutDraw); + +class LayerTreeHostCopyRequestTestLostOutputSurface + : public LayerTreeHostCopyRequestTest { + protected: + virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) + OVERRIDE { + if (!first_context_provider_.get()) { + first_context_provider_ = TestContextProvider::Create(); + return FakeOutputSurface::Create3d(first_context_provider_) + .PassAs<OutputSurface>(); + } + + EXPECT_FALSE(second_context_provider_.get()); + second_context_provider_ = TestContextProvider::Create(); + return FakeOutputSurface::Create3d(second_context_provider_) + .PassAs<OutputSurface>(); + } + + virtual void SetupTree() OVERRIDE { + root_ = FakeContentLayer::Create(&client_); + root_->SetBounds(gfx::Size(20, 20)); + + copy_layer_ = FakeContentLayer::Create(&client_); + copy_layer_->SetBounds(gfx::Size(10, 10)); + root_->AddChild(copy_layer_); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeHostCopyRequestTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); + EXPECT_EQ(gfx::Size(10, 10).ToString(), result->size().ToString()); + EXPECT_TRUE(result->HasTexture()); + + // Save the result for later. + EXPECT_FALSE(result_); + result_ = result.Pass(); + + // Post a commit to lose the output surface. + layer_tree_host()->SetNeedsCommit(); + } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + switch (layer_tree_host()->source_frame_number()) { + case 1: + // The layers have been pushed to the impl side. The layer textures have + // been allocated. + + // Request a copy of the layer. This will use another texture. + copy_layer_->RequestCopyOfOutput(CopyOutputRequest::CreateRequest( + base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface:: + CopyOutputCallback, + base::Unretained(this)))); + break; + case 4: + // With SingleThreadProxy it takes two commits to finally swap after a + // context loss. + case 5: + // Now destroy the CopyOutputResult, releasing the texture inside back + // to the compositor. + EXPECT_TRUE(result_); + result_.reset(); + + // Check that it is released. + ImplThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface:: + CheckNumTextures, + base::Unretained(this), + num_textures_after_loss_ - 1)); + break; + } + } + + virtual void SwapBuffersOnThread(LayerTreeHostImpl* impl, + bool result) OVERRIDE { + switch (impl->active_tree()->source_frame_number()) { + case 0: + // The layers have been drawn, so their textures have been allocated. + EXPECT_FALSE(result_); + num_textures_without_readback_ = + first_context_provider_->TestContext3d()->NumTextures(); + break; + case 1: + // We did a readback, so there will be a readback texture around now. + EXPECT_LT(num_textures_without_readback_, + first_context_provider_->TestContext3d()->NumTextures()); + break; + case 2: + // The readback texture is collected. + EXPECT_TRUE(result_); + + // Lose the output surface. + first_context_provider_->TestContext3d()->loseContextCHROMIUM( + GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); + break; + case 3: + // With SingleThreadProxy it takes two commits to finally swap after a + // context loss. + case 4: + // The output surface has been recreated. + EXPECT_TRUE(second_context_provider_.get()); + + num_textures_after_loss_ = + first_context_provider_->TestContext3d()->NumTextures(); + break; + } + } + + void CheckNumTextures(size_t expected_num_textures) { + EXPECT_EQ(expected_num_textures, + first_context_provider_->TestContext3d()->NumTextures()); + EndTest(); + } + + virtual void AfterTest() OVERRIDE {} + + scoped_refptr<TestContextProvider> first_context_provider_; + scoped_refptr<TestContextProvider> second_context_provider_; + size_t num_textures_without_readback_; + size_t num_textures_after_loss_; + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root_; + scoped_refptr<FakeContentLayer> copy_layer_; + scoped_ptr<CopyOutputResult> result_; +}; + +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( + LayerTreeHostCopyRequestTestLostOutputSurface); + +class LayerTreeHostCopyRequestTestCountTextures + : public LayerTreeHostCopyRequestTest { + protected: + virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) + OVERRIDE { + context_provider_ = TestContextProvider::Create(); + return FakeOutputSurface::Create3d(context_provider_) + .PassAs<OutputSurface>(); + } + + virtual void SetupTree() OVERRIDE { + root_ = FakeContentLayer::Create(&client_); + root_->SetBounds(gfx::Size(20, 20)); + + copy_layer_ = FakeContentLayer::Create(&client_); + copy_layer_->SetBounds(gfx::Size(10, 10)); + root_->AddChild(copy_layer_); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeHostCopyRequestTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { + num_textures_without_readback_ = 0; + num_textures_with_readback_ = 0; + waited_sync_point_after_readback_ = 0; + PostSetNeedsCommitToMainThread(); + } + + virtual void RequestCopy(Layer* layer) = 0; + + virtual void DidCommitAndDrawFrame() OVERRIDE { + switch (layer_tree_host()->source_frame_number()) { + case 1: + // The layers have been pushed to the impl side. The layer textures have + // been allocated. + RequestCopy(copy_layer_.get()); + break; + } + } + + virtual void SwapBuffersOnThread(LayerTreeHostImpl* impl, + bool result) OVERRIDE { + switch (impl->active_tree()->source_frame_number()) { + case 0: + // The layers have been drawn, so their textures have been allocated. + num_textures_without_readback_ = + context_provider_->TestContext3d()->NumTextures(); + break; + case 1: + // We did a readback, so there will be a readback texture around now. + num_textures_with_readback_ = + context_provider_->TestContext3d()->NumTextures(); + waited_sync_point_after_readback_ = + context_provider_->TestContext3d()->last_waited_sync_point(); + + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&LayerTreeHostCopyRequestTestCountTextures::DoEndTest, + base::Unretained(this))); + break; + } + } + + virtual void DoEndTest() { EndTest(); } + + scoped_refptr<TestContextProvider> context_provider_; + size_t num_textures_without_readback_; + size_t num_textures_with_readback_; + unsigned waited_sync_point_after_readback_; + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root_; + scoped_refptr<FakeContentLayer> copy_layer_; +}; + +class LayerTreeHostCopyRequestTestCreatesTexture + : public LayerTreeHostCopyRequestTestCountTextures { + protected: + virtual void RequestCopy(Layer* layer) OVERRIDE { + // Request a normal texture copy. This should create a new texture. + copy_layer_->RequestCopyOfOutput( + CopyOutputRequest::CreateRequest(base::Bind( + &LayerTreeHostCopyRequestTestCreatesTexture::CopyOutputCallback, + base::Unretained(this)))); + } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { + EXPECT_FALSE(result->IsEmpty()); + EXPECT_TRUE(result->HasTexture()); + + TextureMailbox mailbox; + scoped_ptr<SingleReleaseCallback> release; + result->TakeTexture(&mailbox, &release); + EXPECT_TRUE(release); + + release->Run(0, false); + } + + virtual void AfterTest() OVERRIDE { + // No sync point was needed. + EXPECT_EQ(0u, waited_sync_point_after_readback_); + // Except the copy to have made another texture. + EXPECT_EQ(num_textures_without_readback_ + 1, num_textures_with_readback_); + } +}; + +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( + LayerTreeHostCopyRequestTestCreatesTexture); + +class LayerTreeHostCopyRequestTestProvideTexture + : public LayerTreeHostCopyRequestTestCountTextures { + protected: + virtual void BeginTest() OVERRIDE { + external_context_provider_ = TestContextProvider::Create(); + EXPECT_TRUE(external_context_provider_->BindToCurrentThread()); + LayerTreeHostCopyRequestTestCountTextures::BeginTest(); + } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { + EXPECT_FALSE(result->IsEmpty()); + EXPECT_TRUE(result->HasTexture()); + + TextureMailbox mailbox; + scoped_ptr<SingleReleaseCallback> release; + result->TakeTexture(&mailbox, &release); + EXPECT_FALSE(release); + } + + virtual void RequestCopy(Layer* layer) OVERRIDE { + // Request a copy to a provided texture. This should not create a new + // texture. + scoped_ptr<CopyOutputRequest> request = + CopyOutputRequest::CreateRequest(base::Bind( + &LayerTreeHostCopyRequestTestProvideTexture::CopyOutputCallback, + base::Unretained(this))); + + gpu::Mailbox mailbox; + external_context_provider_->Context3d()->genMailboxCHROMIUM(mailbox.name); + sync_point_ = external_context_provider_->Context3d()->insertSyncPoint(); + request->SetTextureMailbox(TextureMailbox(mailbox, sync_point_)); + EXPECT_TRUE(request->has_texture_mailbox()); + + copy_layer_->RequestCopyOfOutput(request.Pass()); + } + + virtual void AfterTest() OVERRIDE { + // Expect the compositor to have waited for the sync point in the provided + // TextureMailbox. + EXPECT_EQ(sync_point_, waited_sync_point_after_readback_); + // Except the copy to have *not* made another texture. + EXPECT_EQ(num_textures_without_readback_, num_textures_with_readback_); + } + + scoped_refptr<TestContextProvider> external_context_provider_; + unsigned sync_point_; +}; + +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( + LayerTreeHostCopyRequestTestProvideTexture); + +class LayerTreeHostCopyRequestTestDestroyBeforeCopy + : public LayerTreeHostCopyRequestTest { + protected: + virtual void SetupTree() OVERRIDE { + root_ = FakeContentLayer::Create(&client_); + root_->SetBounds(gfx::Size(20, 20)); + + copy_layer_ = FakeContentLayer::Create(&client_); + copy_layer_->SetBounds(gfx::Size(10, 10)); + root_->AddChild(copy_layer_); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeHostCopyRequestTest::SetupTree(); + } + + virtual void BeginTest() OVERRIDE { + callback_count_ = 0; + PostSetNeedsCommitToMainThread(); + } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { + EXPECT_TRUE(result->IsEmpty()); + ++callback_count_; + } + + virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE { + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&LayerTreeHostCopyRequestTestDestroyBeforeCopy::DidActivate, + base::Unretained(this))); + } + + void DidActivate() { + switch (layer_tree_host()->source_frame_number()) { + case 1: { + EXPECT_EQ(0, callback_count_); + // Put a copy request on the layer, but then don't allow any + // drawing to take place. + scoped_ptr<CopyOutputRequest> request = + CopyOutputRequest::CreateRequest( + base::Bind(&LayerTreeHostCopyRequestTestDestroyBeforeCopy:: + CopyOutputCallback, + base::Unretained(this))); + copy_layer_->RequestCopyOfOutput(request.Pass()); + + layer_tree_host()->SetViewportSize(gfx::Size()); + break; + } + case 2: + EXPECT_EQ(0, callback_count_); + // Remove the copy layer before we were able to draw. + copy_layer_->RemoveFromParent(); + break; + case 3: + EXPECT_EQ(1, callback_count_); + // Allow us to draw now. + layer_tree_host()->SetViewportSize( + layer_tree_host()->root_layer()->bounds()); + break; + case 4: + EXPECT_EQ(1, callback_count_); + // We should not have crashed. + EndTest(); + } + } + + virtual void AfterTest() OVERRIDE {} + + int callback_count_; + FakeContentLayerClient client_; + scoped_refptr<FakeContentLayer> root_; + scoped_refptr<FakeContentLayer> copy_layer_; +}; + +SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( + LayerTreeHostCopyRequestTestDestroyBeforeCopy); + +} // namespace +} // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_unittest_damage.cc b/chromium/cc/trees/layer_tree_host_unittest_damage.cc index 64c7d4b7c30..7f008b46808 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_damage.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_damage.cc @@ -23,103 +23,6 @@ namespace { // These tests deal with damage tracking. class LayerTreeHostDamageTest : public LayerTreeTest {}; -// Changing visibility alone does not cause drawing. -class LayerTreeHostDamageTestSetVisibleDoesNotDraw - : public LayerTreeHostDamageTest { - virtual void BeginTest() OVERRIDE { - step_ = 0; - PostSetNeedsCommitToMainThread(); - } - - virtual void SetupTree() OVERRIDE { - // Viewport is 10x10. - scoped_refptr<FakeContentLayer> root = FakeContentLayer::Create(&client_); - root->SetBounds(gfx::Size(10, 10)); - - layer_tree_host()->SetRootLayer(root); - LayerTreeHostDamageTest::SetupTree(); - } - - virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* impl, - LayerTreeHostImpl::FrameData* frame_data, - bool result) OVERRIDE { - EXPECT_TRUE(result); - - RenderSurfaceImpl* root_surface = - impl->active_tree()->root_layer()->render_surface(); - gfx::RectF root_damage = - root_surface->damage_tracker()->current_damage_rect(); - - switch (step_) { - case 0: - // The first frame has full damage. - EXPECT_EQ(gfx::RectF(10.f, 10.f).ToString(), root_damage.ToString()); - - // No evictions when we become not-visible. - impl->SetMemoryPolicy(ManagedMemoryPolicy( - 1000 * 1000 * 1000, - ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING, - 1000 * 1000 * 1000, - ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING, - ManagedMemoryPolicy::kDefaultNumResourcesLimit)); - - PostSetVisibleToMainThread(false); - break; - case 1: - // The compositor has been set not-visible. - EXPECT_FALSE(impl->visible()); - // This frame not visible, so not drawn. - NOTREACHED(); - break; - case 2: - // The compositor has been set visible again. - EXPECT_TRUE(impl->visible()); - // But it still does not draw. - NOTREACHED(); - break; - case 3: - // Finally we force a draw, but it will have no damage. - EXPECT_EQ(gfx::RectF().ToString(), root_damage.ToString()); - EndTest(); - break; - case 4: - NOTREACHED(); - } - return result; - } - - virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl, - bool visible) OVERRIDE { - if (!visible) { - EXPECT_EQ(0, step_); - PostSetVisibleToMainThread(true); - } else { - EXPECT_EQ(1, step_); - - base::MessageLoopProxy::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&LayerTreeHostDamageTestSetVisibleDoesNotDraw::Redraw, - base::Unretained(this), - impl), - base::TimeDelta::FromMilliseconds(10)); - } - ++step_; - } - - void Redraw(LayerTreeHostImpl* impl) { - EXPECT_EQ(2, step_); - impl->SetNeedsRedraw(); - ++step_; - } - - virtual void AfterTest() OVERRIDE {} - - int step_; - FakeContentLayerClient client_; -}; - -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetVisibleDoesNotDraw); - // LayerTreeHost::SetNeedsRedraw should damage the whole viewport. class LayerTreeHostDamageTestSetNeedsRedraw : public LayerTreeHostDamageTest { @@ -331,7 +234,8 @@ class LayerTreeHostDamageTestNoDamageDoesNotSwap int did_swap_and_succeed_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestNoDamageDoesNotSwap); +SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F( + LayerTreeHostDamageTestNoDamageDoesNotSwap); class LayerTreeHostDamageTestNoDamageReadbackDoesDraw : public LayerTreeHostDamageTest { @@ -459,18 +363,24 @@ class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest { child_damage_rect_ = gfx::RectF(10, 11, 12, 13); break; case 3: - if (!delegating_renderer() && - !host_impl->settings().impl_side_painting) { - // The update rect in the child should be damaged. - // TODO(danakj): Remove this when impl side painting is always on. - EXPECT_EQ(gfx::RectF(100+10, 100+11, 12, 13).ToString(), - root_damage.ToString()); - } else { + // The update rect in the child should be damaged and the damaged area + // should match the invalidation. + EXPECT_EQ(gfx::RectF(100+10, 100+11, 12, 13).ToString(), + root_damage.ToString()); + + // TODO(danakj): Remove this when impl side painting is always on. + if (delegating_renderer() || + host_impl->settings().impl_side_painting) { // When using a delegating renderer, or using impl side painting, the // entire child is considered damaged as we need to replace its - // resources with newly created ones. - EXPECT_EQ(gfx::RectF(child_->position(), child_->bounds()).ToString(), - root_damage.ToString()); + // resources with newly created ones. The damaged area is kept as it + // is, but entire child is painted. + + // The paint rect should match the layer bounds. + gfx::RectF paint_rect = child_->LastPaintRect(); + paint_rect.set_origin(child_->position()); + EXPECT_EQ(gfx::RectF(100, 100, 30, 30).ToString(), + paint_rect.ToString()); } EXPECT_FALSE(frame_data->has_no_damage); @@ -509,12 +419,13 @@ class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest { gfx::RectF child_damage_rect_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestForcedFullDamage); +SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostDamageTestForcedFullDamage); class LayerTreeHostScrollbarDamageTest : public LayerTreeHostDamageTest { virtual void SetupTree() OVERRIDE { scoped_refptr<Layer> root_layer = Layer::Create(); root_layer->SetBounds(gfx::Size(400, 400)); + root_layer->SetMasksToBounds(true); layer_tree_host()->SetRootLayer(root_layer); scoped_refptr<Layer> content_layer = FakeContentLayer::Create(&client_); @@ -614,7 +525,7 @@ class LayerTreeHostDamageTestScrollbarDoesDamage MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarDoesDamage); -class DISABLED_LayerTreeHostDamageTestScrollbarCommitDoesNoDamage +class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage : public LayerTreeHostScrollbarDamageTest { virtual void BeginTest() OVERRIDE { did_swaps_ = 0; @@ -687,8 +598,7 @@ class DISABLED_LayerTreeHostDamageTestScrollbarCommitDoesNoDamage int did_swaps_; }; -MULTI_THREAD_TEST_F( - DISABLED_LayerTreeHostDamageTestScrollbarCommitDoesNoDamage); +MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarCommitDoesNoDamage); class LayerTreeHostDamageTestVisibleTilesStillTriggerDraws : public LayerTreeHostDamageTest { diff --git a/chromium/cc/trees/layer_tree_host_unittest_delegated.cc b/chromium/cc/trees/layer_tree_host_unittest_delegated.cc index 012f6f82fdf..195a4acdfa5 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_delegated.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_delegated.cc @@ -11,8 +11,9 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "base/time/time.h" +#include "cc/layers/delegated_frame_provider.h" +#include "cc/layers/delegated_frame_resource_collection.h" #include "cc/layers/delegated_renderer_layer.h" -#include "cc/layers/delegated_renderer_layer_client.h" #include "cc/layers/delegated_renderer_layer_impl.h" #include "cc/output/compositor_frame.h" #include "cc/output/compositor_frame_ack.h" @@ -134,6 +135,7 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest { ResourceProvider::ResourceId resource_id) { TransferableResource resource; resource.id = resource_id; + resource.target = GL_TEXTURE_2D; frame->resource_list.push_back(resource); } @@ -183,18 +185,11 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest { damage_rect, gfx::Rect(0, 0, 1, 1), // mask_uv_rect filters, - skia::RefPtr<SkImageFilter>(), background_filters); frame->render_pass_list[0]->shared_quad_state_list.push_back(sqs.Pass()); frame->render_pass_list[0]->quad_list.push_back(quad.PassAs<DrawQuad>()); } - scoped_ptr<DelegatedFrameData> CreateEmptyFrameData() { - scoped_ptr<DelegatedFrameData> frame(new DelegatedFrameData); - return frame.Pass(); - } - - static ResourceProvider::ResourceId AppendResourceId( std::vector<ResourceProvider::ResourceId>* resources_in_last_sent_frame, ResourceProvider::ResourceId resource_id) { @@ -209,13 +204,9 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest { return; std::vector<ResourceProvider::ResourceId> resources_in_last_sent_frame; - for (size_t i = 0; i < delegated_frame_data->render_pass_list.size(); ++i) { - RenderPass* pass = delegated_frame_data->render_pass_list.at(i); - for (size_t j = 0; j < pass->quad_list.size(); ++j) { - DrawQuad* quad = pass->quad_list[j]; - quad->IterateResources(base::Bind(&AppendResourceId, - &resources_in_last_sent_frame)); - } + for (size_t i = 0; i < delegated_frame_data->resource_list.size(); ++i) { + resources_in_last_sent_frame.push_back( + delegated_frame_data->resource_list[i].id); } std::vector<ResourceProvider::ResourceId> resources_to_return; @@ -246,68 +237,80 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest { class LayerTreeHostDelegatedTestCaseSingleDelegatedLayer : public LayerTreeHostDelegatedTest, - public DelegatedRendererLayerClient { + public DelegatedFrameResourceCollectionClient { public: + LayerTreeHostDelegatedTestCaseSingleDelegatedLayer() + : resource_collection_(new DelegatedFrameResourceCollection), + available_(false) { + resource_collection_->SetClient(this); + } + virtual void SetupTree() OVERRIDE { root_ = Layer::Create(); root_->SetAnchorPoint(gfx::PointF()); root_->SetBounds(gfx::Size(10, 10)); - delegated_ = FakeDelegatedRendererLayer::Create(this); - delegated_->SetAnchorPoint(gfx::PointF()); - delegated_->SetBounds(gfx::Size(10, 10)); - delegated_->SetIsDrawable(true); - - root_->AddChild(delegated_); layer_tree_host()->SetRootLayer(root_); LayerTreeHostDelegatedTest::SetupTree(); } virtual void BeginTest() OVERRIDE { + resource_collection_->SetClient(this); PostSetNeedsCommitToMainThread(); } - virtual void AfterTest() OVERRIDE {} + void SetFrameData(scoped_ptr<DelegatedFrameData> frame_data) { + RenderPass* root_pass = frame_data->render_pass_list.back(); + gfx::Size frame_size = root_pass->output_rect.size(); - virtual void DidCommitFrameData() OVERRIDE {} - - protected: - scoped_refptr<Layer> root_; - scoped_refptr<DelegatedRendererLayer> delegated_; -}; + if (frame_provider_.get() && frame_size == frame_provider_->frame_size()) { + frame_provider_->SetFrameData(frame_data.Pass()); + return; + } -class LayerTreeHostDelegatedTestClientDidCommitCallback - : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer { - public: - LayerTreeHostDelegatedTestClientDidCommitCallback() - : LayerTreeHostDelegatedTestCaseSingleDelegatedLayer(), - num_did_commit_frame_data_(0) {} + if (delegated_.get()) { + delegated_->RemoveFromParent(); + delegated_ = NULL; + frame_provider_ = NULL; + } - virtual void DidCommit() OVERRIDE { - if (TestEnded()) - return; + frame_provider_ = new DelegatedFrameProvider(resource_collection_.get(), + frame_data.Pass()); - EXPECT_EQ(1, num_did_commit_frame_data_); - EndTest(); + delegated_ = CreateDelegatedLayer(frame_provider_.get()); } - virtual void BeginTest() OVERRIDE { - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 1, 1), - gfx::Rect(0, 0, 1, 1))); - PostSetNeedsCommitToMainThread(); + scoped_refptr<DelegatedRendererLayer> CreateDelegatedLayer( + DelegatedFrameProvider* frame_provider) { + scoped_refptr<DelegatedRendererLayer> delegated = + FakeDelegatedRendererLayer::Create(frame_provider); + delegated->SetAnchorPoint(gfx::PointF()); + delegated->SetBounds(gfx::Size(10, 10)); + delegated->SetIsDrawable(true); + + root_->AddChild(delegated); + return delegated; } - virtual void DidCommitFrameData() OVERRIDE { - num_did_commit_frame_data_++; + virtual void AfterTest() OVERRIDE { resource_collection_->SetClient(NULL); } + + // DelegatedFrameProviderClient implementation. + virtual void UnusedResourcesAreAvailable() OVERRIDE { available_ = true; } + + bool TestAndResetAvailable() { + bool available = available_; + available_ = false; + return available; } protected: - int num_did_commit_frame_data_; + scoped_refptr<DelegatedFrameResourceCollection> resource_collection_; + scoped_refptr<DelegatedFrameProvider> frame_provider_; + scoped_refptr<Layer> root_; + scoped_refptr<DelegatedRendererLayer> delegated_; + bool available_; }; -SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostDelegatedTestClientDidCommitCallback); - class LayerTreeHostDelegatedTestCreateChildId : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer { public: @@ -319,11 +322,13 @@ class LayerTreeHostDelegatedTestCreateChildId virtual void DidCommit() OVERRIDE { if (TestEnded()) return; - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 1, 1), - gfx::Rect(0, 0, 1, 1))); + SetFrameData(CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1))); } virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { + if (host_impl->active_tree()->source_frame_number() < 1) + return; + LayerImpl* root_impl = host_impl->active_tree()->root_layer(); FakeDelegatedRendererLayerImpl* delegated_impl = static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]); @@ -365,8 +370,6 @@ class LayerTreeHostDelegatedTestCreateChildId did_reset_child_id_ = true; } - virtual void AfterTest() OVERRIDE {} - protected: int num_activates_; bool did_reset_child_id_; @@ -381,7 +384,7 @@ class LayerTreeHostDelegatedTestOffscreenContext_NoFilters scoped_ptr<DelegatedFrameData> frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); PostSetNeedsCommitToMainThread(); } @@ -390,8 +393,6 @@ class LayerTreeHostDelegatedTestOffscreenContext_NoFilters EXPECT_FALSE(host_impl->offscreen_context_provider()); EndTest(); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F( @@ -413,7 +414,7 @@ class LayerTreeHostDelegatedTestOffscreenContext_Filters gfx::Rect(0, 0, 1, 1), filters, FilterOperations()); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); PostSetNeedsCommitToMainThread(); } @@ -423,8 +424,6 @@ class LayerTreeHostDelegatedTestOffscreenContext_Filters EXPECT_EQ(expect_context, !!host_impl->offscreen_context_provider()); EndTest(); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F( @@ -446,7 +445,7 @@ class LayerTreeHostDelegatedTestOffscreenContext_BackgroundFilters gfx::Rect(0, 0, 1, 1), FilterOperations(), filters); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); PostSetNeedsCommitToMainThread(); } @@ -456,8 +455,6 @@ class LayerTreeHostDelegatedTestOffscreenContext_BackgroundFilters EXPECT_EQ(expect_context, !!host_impl->offscreen_context_provider()); EndTest(); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F( @@ -467,21 +464,24 @@ class LayerTreeHostDelegatedTestOffscreenContext_Filters_AddedToTree : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer { protected: virtual void BeginTest() OVERRIDE { - scoped_ptr<DelegatedFrameData> frame = - CreateFrameData(gfx::Rect(0, 0, 1, 1), - gfx::Rect(0, 0, 1, 1)); + scoped_ptr<DelegatedFrameData> frame_no_filters = + CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + + scoped_ptr<DelegatedFrameData> frame_with_filters = + CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f)); - AddRenderPass(frame.get(), + AddRenderPass(frame_with_filters.get(), RenderPass::Id(2, 1), gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1), filters, FilterOperations()); + SetFrameData(frame_no_filters.Pass()); delegated_->RemoveFromParent(); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame_with_filters.Pass()); layer_tree_host()->root_layer()->AddChild(delegated_); PostSetNeedsCommitToMainThread(); @@ -492,8 +492,6 @@ class LayerTreeHostDelegatedTestOffscreenContext_Filters_AddedToTree EXPECT_EQ(expect_context, !!host_impl->offscreen_context_provider()); EndTest(); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F( @@ -512,101 +510,112 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage case 1: // The first time the layer gets a frame the whole layer should be // damaged. - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 1, 1), - gfx::Rect(0, 0, 1, 1))); + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1))); break; case 2: + // A different frame size will damage the whole layer. + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 20, 20), gfx::Rect(0, 0, 0, 0))); + break; + case 3: // Should create a total amount of gfx::Rect(2, 2, 10, 6) damage. // The frame size is 20x20 while the layer is 10x10, so this should // produce a gfx::Rect(1, 1, 5, 3) damage rect. - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 20, 20), - gfx::Rect(2, 2, 5, 5))); - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 20, 20), - gfx::Rect(7, 2, 5, 6))); + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 20, 20), gfx::Rect(2, 2, 5, 5))); + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 20, 20), gfx::Rect(7, 2, 5, 6))); break; - case 3: + case 4: // Should create zero damage. layer_tree_host()->SetNeedsCommit(); break; - case 4: + case 5: // Should damage the full viewport. delegated_->SetBounds(gfx::Size(2, 2)); break; - case 5: + case 6: // Should create zero damage. layer_tree_host()->SetNeedsCommit(); break; - case 6: - // Should damage the full layer. + case 7: + // Should damage the full layer, tho the frame size is not changing. delegated_->SetBounds(gfx::Size(6, 6)); - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 5, 5), - gfx::Rect(1, 1, 2, 2))); + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 20, 20), gfx::Rect(1, 1, 2, 2))); break; - case 7: + case 8: // Should create zero damage. layer_tree_host()->SetNeedsCommit(); break; - case 8: + case 9: // Should damage the full layer. delegated_->SetDisplaySize(gfx::Size(10, 10)); break; - case 9: + case 10: // Should create zero damage. layer_tree_host()->SetNeedsCommit(); break; - case 10: - // Setting an empty frame should damage the whole layer the - // first time. - delegated_->SetFrameData(CreateEmptyFrameData()); - break; case 11: - // Setting an empty frame shouldn't damage anything after the - // first time. - delegated_->SetFrameData(CreateEmptyFrameData()); + // Changing the frame size damages the full layer. + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 5, 5), gfx::Rect(4, 4, 1, 1))); break; case 12: - // Having valid content to display agains should damage the whole layer. - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 10, 10), - gfx::Rect(5, 5, 1, 1))); - break; - case 13: // An invalid frame isn't used, so it should not cause damage. - delegated_->SetFrameData(CreateInvalidFrameData(gfx::Rect(0, 0, 10, 10), - gfx::Rect(5, 5, 1, 1))); + SetFrameData(CreateInvalidFrameData(gfx::Rect(0, 0, 5, 5), + gfx::Rect(4, 4, 1, 1))); break; - case 14: + case 13: // Should create gfx::Rect(1, 1, 2, 2) of damage. The frame size is // 5x5 and the display size is now set to 10x10, so this should result // in a gfx::Rect(2, 2, 4, 4) damage rect. - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 5, 5), - gfx::Rect(1, 1, 2, 2))); + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 5, 5), gfx::Rect(1, 1, 2, 2))); break; - case 15: + case 14: // Should create zero damage. layer_tree_host()->SetNeedsCommit(); break; - case 16: + case 15: // Moving the layer out of the tree and back in will damage the whole // impl layer. delegated_->RemoveFromParent(); layer_tree_host()->root_layer()->AddChild(delegated_); break; - case 17: + case 16: // Make a larger frame with lots of damage. Then a frame smaller than // the first frame's damage. The entire layer should be damaged, but // nothing more. - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 10, 10), - gfx::Rect(0, 0, 10, 10))); - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 5, 5), - gfx::Rect(1, 1, 2, 2))); + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 10, 10), gfx::Rect(0, 0, 10, 10))); + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 5, 5), gfx::Rect(1, 1, 2, 2))); break; - case 18: - // Make a frame with lots of damage. Then replace it with an empty - // frame. The entire layer should be damaged, but nothing more. - delegated_->SetFrameData(CreateFrameData(gfx::Rect(0, 0, 10, 10), - gfx::Rect(0, 0, 10, 10))); - delegated_->SetFrameData(CreateEmptyFrameData()); + case 17: + // Make a frame with lots of damage. Then replace it with a frame with + // no damage. The entire layer should be damaged, but nothing more. + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 10, 10), gfx::Rect(0, 0, 10, 10))); + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 10, 10), gfx::Rect(0, 0, 0, 0))); break; + case 18: + // Make another layer that uses the same frame provider. The new layer + // should be damaged. + delegated_copy_ = CreateDelegatedLayer(frame_provider_); + delegated_copy_->SetPosition(gfx::Point(5, 0)); + + // Also set a new frame. + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 10, 10), gfx::Rect(4, 0, 1, 1))); + break; + case 19: + // Set another new frame, both layers should be damaged in the same + // ways. + SetFrameData( + CreateFrameData(gfx::Rect(0, 0, 10, 10), gfx::Rect(3, 3, 1, 1))); } first_draw_for_source_frame_ = true; } @@ -638,71 +647,76 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage damage_rect.ToString()); break; case 2: - EXPECT_EQ(gfx::RectF(1.f, 1.f, 5.f, 3.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(), damage_rect.ToString()); break; case 3: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), + EXPECT_EQ(gfx::RectF(1.f, 1.f, 5.f, 3.f).ToString(), damage_rect.ToString()); break; case 4: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), damage_rect.ToString()); break; case 5: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(), damage_rect.ToString()); break; case 6: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), damage_rect.ToString()); break; case 7: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(), damage_rect.ToString()); break; case 8: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), damage_rect.ToString()); break; case 9: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(), damage_rect.ToString()); break; case 10: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), damage_rect.ToString()); break; case 11: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(), damage_rect.ToString()); break; case 12: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), damage_rect.ToString()); break; case 13: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), + EXPECT_EQ(gfx::RectF(2.f, 2.f, 4.f, 4.f).ToString(), damage_rect.ToString()); break; case 14: - EXPECT_EQ(gfx::RectF(2.f, 2.f, 4.f, 4.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), damage_rect.ToString()); break; case 15: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(), damage_rect.ToString()); break; case 16: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(), damage_rect.ToString()); break; case 17: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(), + EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(), damage_rect.ToString()); break; case 18: - EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(), + EXPECT_EQ(gfx::UnionRects(gfx::RectF(5.f, 0.f, 10.f, 10.f), + gfx::RectF(4.f, 0.f, 1.f, 1.f)).ToString(), + damage_rect.ToString()); + break; + case 19: + EXPECT_EQ(gfx::RectF(3.f, 3.f, 6.f, 1.f).ToString(), damage_rect.ToString()); EndTest(); break; @@ -712,6 +726,7 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage } protected: + scoped_refptr<DelegatedRendererLayer> delegated_copy_; bool first_draw_for_source_frame_; }; @@ -728,7 +743,7 @@ class LayerTreeHostDelegatedTestMergeResources CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame1.get(), 999); AddTransferableResource(frame1.get(), 999); - delegated_->SetFrameData(frame1.Pass()); + SetFrameData(frame1.Pass()); // The second frame uses resource 999 still, but also adds 555. scoped_ptr<DelegatedFrameData> frame2 = @@ -737,15 +752,17 @@ class LayerTreeHostDelegatedTestMergeResources AddTransferableResource(frame2.get(), 999); AddTextureQuad(frame2.get(), 555); AddTransferableResource(frame2.get(), 555); - delegated_->SetFrameData(frame2.Pass()); + SetFrameData(frame2.Pass()); // The resource 999 from frame1 is returned since it is still on the main // thread. ReturnedResourceArray returned_resources; - delegated_->TakeUnusedResourcesForChildCompositor(&returned_resources); + resource_collection_->TakeUnusedResourcesForChildCompositor( + &returned_resources); { unsigned expected[] = {999}; EXPECT_RESOURCES(expected, returned_resources); + EXPECT_TRUE(TestAndResetAvailable()); } PostSetNeedsCommitToMainThread(); @@ -771,8 +788,6 @@ class LayerTreeHostDelegatedTestMergeResources EndTest(); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestMergeResources); @@ -788,7 +803,7 @@ class LayerTreeHostDelegatedTestRemapResourcesInQuads AddTransferableResource(frame.get(), 999); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); PostSetNeedsCommitToMainThread(); } @@ -822,8 +837,6 @@ class LayerTreeHostDelegatedTestRemapResourcesInQuads EndTest(); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestRemapResourcesInQuads); @@ -848,12 +861,13 @@ class LayerTreeHostDelegatedTestReturnUnusedResources AddTransferableResource(frame.get(), 999); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 2: // All of the resources are in use. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // Keep using 999 but stop using 555. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); @@ -861,19 +875,20 @@ class LayerTreeHostDelegatedTestReturnUnusedResources AddTransferableResource(frame.get(), 999); AddTextureQuad(frame.get(), 444); AddTransferableResource(frame.get(), 444); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 3: // 555 is no longer in use. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {555}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } // Stop using any resources. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 4: // Postpone collecting resources for a frame. They should still be there @@ -883,27 +898,28 @@ class LayerTreeHostDelegatedTestReturnUnusedResources case 5: // 444 and 999 are no longer in use. We sent two refs to 999, so we // should get two back. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {444, 999, 999}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } EndTest(); break; } - // Resource are never immediately released. + // Resources are never immediately released. ReturnedResourceArray empty_resources; - delegated_->TakeUnusedResourcesForChildCompositor(&empty_resources); - EXPECT_TRUE(empty_resources.empty()); + resource_collection_->TakeUnusedResourcesForChildCompositor( + &empty_resources); + EXPECT_EQ(0u, empty_resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); } virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) OVERRIDE { ReturnUnusedResourcesFromParent(host_impl); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F( @@ -931,22 +947,24 @@ class LayerTreeHostDelegatedTestReusedResources AddTransferableResource(frame.get(), 555); AddTextureQuad(frame.get(), 444); AddTransferableResource(frame.get(), 444); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 2: // All of the resources are in use. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // Keep using 999 but stop using 555 and 444. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 999); AddTransferableResource(frame.get(), 999); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); // Resource are not immediately released. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // Now using 555 and 444 again, but not 999. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); @@ -954,15 +972,16 @@ class LayerTreeHostDelegatedTestReusedResources AddTransferableResource(frame.get(), 555); AddTextureQuad(frame.get(), 444); AddTransferableResource(frame.get(), 444); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 3: // The 999 resource is the only unused one. Two references were sent, so // two should be returned. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {999, 999}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } EndTest(); break; @@ -973,8 +992,6 @@ class LayerTreeHostDelegatedTestReusedResources bool result) OVERRIDE { ReturnUnusedResourcesFromParent(host_impl); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestReusedResources); @@ -1001,30 +1018,33 @@ class LayerTreeHostDelegatedTestFrameBeforeAck AddTransferableResource(frame.get(), 555); AddTextureQuad(frame.get(), 444); AddTransferableResource(frame.get(), 444); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 2: // All of the resources are in use. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // Keep using 999 but stop using 555 and 444. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 999); AddTransferableResource(frame.get(), 999); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); // Resource are not immediately released. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // The parent compositor (this one) does a commit. break; case 3: - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {444, 555}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } // The child compositor sends a frame referring to resources not in the @@ -1033,7 +1053,7 @@ class LayerTreeHostDelegatedTestFrameBeforeAck AddTextureQuad(frame.get(), 999); AddTextureQuad(frame.get(), 555); AddTextureQuad(frame.get(), 444); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; } } @@ -1072,8 +1092,6 @@ class LayerTreeHostDelegatedTestFrameBeforeAck bool result) OVERRIDE { ReturnUnusedResourcesFromParent(host_impl); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestFrameBeforeAck); @@ -1100,22 +1118,24 @@ class LayerTreeHostDelegatedTestFrameBeforeTakeResources AddTransferableResource(frame.get(), 555); AddTextureQuad(frame.get(), 444); AddTransferableResource(frame.get(), 444); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 2: // All of the resources are in use. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // Keep using 999 but stop using 555 and 444. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 999); AddTransferableResource(frame.get(), 999); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); // Resource are not immediately released. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // The parent compositor (this one) does a commit. break; @@ -1130,19 +1150,21 @@ class LayerTreeHostDelegatedTestFrameBeforeTakeResources AddTransferableResource(frame.get(), 555); AddTextureQuad(frame.get(), 444); AddTransferableResource(frame.get(), 444); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); // The resources are used by the new frame but are returned anyway since // we passed them again. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {444, 555}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } break; case 4: - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); EndTest(); break; } @@ -1189,8 +1211,6 @@ class LayerTreeHostDelegatedTestFrameBeforeTakeResources bool result) OVERRIDE { ReturnUnusedResourcesFromParent(host_impl); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F( @@ -1216,12 +1236,13 @@ class LayerTreeHostDelegatedTestBadFrame AddTransferableResource(frame.get(), 999); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 2: // All of the resources are in use. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // Generate a bad frame with a resource the layer doesn't have. The // 885 and 775 resources are unknown, while ownership of the legit 444 @@ -1233,29 +1254,35 @@ class LayerTreeHostDelegatedTestBadFrame AddTextureQuad(frame.get(), 444); AddTransferableResource(frame.get(), 444); AddTextureQuad(frame.get(), 775); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); // The parent compositor (this one) does a commit. break; case 3: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Now send a good frame with 999 again. + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + AddTextureQuad(frame.get(), 999); + SetFrameData(frame.Pass()); + // The bad frame's resource is given back to the child compositor. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {444}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } - - // Now send a good frame with 999 again. - frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); - AddTextureQuad(frame.get(), 999); - delegated_->SetFrameData(frame.Pass()); break; case 4: // The unused 555 from the last good frame is now released. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {555}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } EndTest(); @@ -1339,8 +1366,6 @@ class LayerTreeHostDelegatedTestBadFrame } } } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestBadFrame); @@ -1364,14 +1389,23 @@ class LayerTreeHostDelegatedTestUnnamedResource AddTransferableResource(frame.get(), 999); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 2: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Now send an empty frame. + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + SetFrameData(frame.Pass()); + // The unused resource should be returned. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {999}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } EndTest(); @@ -1398,8 +1432,6 @@ class LayerTreeHostDelegatedTestUnnamedResource EXPECT_EQ(1u, delegated_impl->Resources().size()); EXPECT_EQ(1u, delegated_impl->Resources().count(555)); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestUnnamedResource); @@ -1424,33 +1456,35 @@ class LayerTreeHostDelegatedTestDontLeakResource AddTransferableResource(frame.get(), 999); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); // But then we immediately stop using 999. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 2: // The unused resources should be returned. 555 is still used, but it's // returned once to account for the first frame. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {555, 999}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } // Send a frame with no resources in it. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 3: // The now unused resource 555 should be returned. resources.clear(); - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {555}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } EndTest(); break; @@ -1481,8 +1515,6 @@ class LayerTreeHostDelegatedTestDontLeakResource bool result) OVERRIDE { ReturnUnusedResourcesFromParent(host_impl); } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestDontLeakResource); @@ -1503,23 +1535,25 @@ class LayerTreeHostDelegatedTestResourceSentToParent AddTransferableResource(frame.get(), 999); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 2: - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // 999 is in use in the grandparent compositor, generate a frame without // it present. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 3: // Since 999 is in the grandparent it is not returned. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // The impl side will get back the resource at some point. ImplThreadTaskRunner()->PostTask(FROM_HERE, @@ -1542,20 +1576,15 @@ class LayerTreeHostDelegatedTestResourceSentToParent output_surface()->ReturnResource(map.find(999)->second, &ack); host_impl->ReclaimResources(&ack); host_impl->OnSwapBuffersComplete(); - - // And then it should be released by the DelegatedRendererLayer. - MainThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&LayerTreeHostDelegatedTestResourceSentToParent:: - DidReceiveResourceOnMainThread, - base::Unretained(this))); } - void DidReceiveResourceOnMainThread() { + virtual void UnusedResourcesAreAvailable() OVERRIDE { + EXPECT_EQ(3, layer_tree_host()->source_frame_number()); + ReturnedResourceArray resources; // 999 was returned from the grandparent and could be released. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {999}; EXPECT_RESOURCES(expected, resources); @@ -1616,8 +1645,6 @@ class LayerTreeHostDelegatedTestResourceSentToParent } } - virtual void AfterTest() OVERRIDE {} - base::Closure receive_resource_on_thread_; }; @@ -1647,17 +1674,18 @@ class LayerTreeHostDelegatedTestCommitWithoutTake AddTransferableResource(frame.get(), 555); AddTextureQuad(frame.get(), 444); AddTransferableResource(frame.get(), 444); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 2: - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); // Stop using 999 and 444 in this frame and commit. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); // 999 and 444 will be returned for frame 1, but not 555 since it's in // the current frame. break; @@ -1668,27 +1696,29 @@ class LayerTreeHostDelegatedTestCommitWithoutTake AddTransferableResource(frame.get(), 999); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); break; case 4: // 555 from frame 1 and 2 isn't returned since it's still in use. 999 // from frame 1 is returned though. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {444, 999}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); // 555 will be returned 3 times for frames 1 2 and 3, and 999 will be // returned once for frame 3. break; case 5: - delegated_->TakeUnusedResourcesForChildCompositor(&resources); + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {555, 555, 555, 999}; EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); } EndTest(); @@ -1737,8 +1767,6 @@ class LayerTreeHostDelegatedTestCommitWithoutTake EXPECT_EQ(1u, delegated_impl->Resources().count(555)); } } - - virtual void AfterTest() OVERRIDE {} }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestCommitWithoutTake); @@ -1748,7 +1776,8 @@ class DelegatedFrameIsActivatedDuringCommit protected: DelegatedFrameIsActivatedDuringCommit() : wait_thread_("WAIT"), - wait_event_(false, false) { + wait_event_(false, false), + returned_resource_count_(0) { wait_thread_.Start(); } @@ -1759,7 +1788,7 @@ class DelegatedFrameIsActivatedDuringCommit CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 999); AddTransferableResource(frame.get(), 999); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); PostSetNeedsCommitToMainThread(); } @@ -1797,7 +1826,7 @@ class DelegatedFrameIsActivatedDuringCommit CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 555); AddTransferableResource(frame.get(), 555); - delegated_->SetFrameData(frame.Pass()); + SetFrameData(frame.Pass()); // So this commit number should complete after the second activate. EXPECT_EQ(1, layer_tree_host()->source_frame_number()); break; @@ -1810,9 +1839,6 @@ class DelegatedFrameIsActivatedDuringCommit // So this commit number should complete after the third activate. EXPECT_EQ(2, layer_tree_host()->source_frame_number()); break; - case 3: - EndTest(); - break; } } @@ -1828,22 +1854,433 @@ class DelegatedFrameIsActivatedDuringCommit // The activate to remove the layer should have happened before now. base::AutoLock lock(activate_lock_); EXPECT_EQ(3, activate_count_); + + scoped_ptr<DelegatedFrameData> frame = + CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + SetFrameData(frame.Pass()); break; } } } + virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, + bool result) OVERRIDE { + ReturnUnusedResourcesFromParent(host_impl); + } - virtual void AfterTest() OVERRIDE {} + virtual void UnusedResourcesAreAvailable() OVERRIDE { + LayerTreeHostDelegatedTestCaseSingleDelegatedLayer:: + UnusedResourcesAreAvailable(); + ReturnedResourceArray resources; + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_TRUE(TestAndResetAvailable()); + returned_resource_count_ += resources.size(); + if (returned_resource_count_ == 2) + EndTest(); + } base::Thread wait_thread_; base::WaitableEvent wait_event_; base::Lock activate_lock_; int activate_count_; + size_t returned_resource_count_; }; SINGLE_AND_MULTI_THREAD_TEST_F( DelegatedFrameIsActivatedDuringCommit); +class LayerTreeHostDelegatedTestTwoImplLayers + : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer { + public: + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + scoped_ptr<DelegatedFrameData> frame; + ReturnedResourceArray resources; + + int next_source_frame_number = layer_tree_host()->source_frame_number(); + switch (next_source_frame_number) { + case 1: + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + AddTextureQuad(frame.get(), 999); + AddTransferableResource(frame.get(), 999); + AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); + SetFrameData(frame.Pass()); + break; + case 2: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Remove the delegated layer and replace it with a new one. Use the + // same frame and resources for it. + delegated_->RemoveFromParent(); + delegated_ = CreateDelegatedLayer(frame_provider_.get()); + break; + case 3: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Use a frame with no resources in it. + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + SetFrameData(frame.Pass()); + break; + case 4: + // We gave one frame to the frame provider, so we should get one + // ref back for each resource. + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + { + unsigned expected[] = {555, 999}; + EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); + } + EndTest(); + break; + } + } + + virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, + bool result) OVERRIDE { + ReturnUnusedResourcesFromParent(host_impl); + } +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestTwoImplLayers); + +class LayerTreeHostDelegatedTestTwoImplLayersTwoFrames + : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer { + public: + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + scoped_ptr<DelegatedFrameData> frame; + ReturnedResourceArray resources; + + int next_source_frame_number = layer_tree_host()->source_frame_number(); + switch (next_source_frame_number) { + case 1: + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + AddTextureQuad(frame.get(), 999); + AddTransferableResource(frame.get(), 999); + AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); + SetFrameData(frame.Pass()); + break; + case 2: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + AddTextureQuad(frame.get(), 999); + AddTransferableResource(frame.get(), 999); + AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); + + // Remove the delegated layer and replace it with a new one. Make a new + // frame but with the same resources for it. + delegated_->RemoveFromParent(); + delegated_ = NULL; + + frame_provider_->SetFrameData(frame.Pass()); + delegated_ = CreateDelegatedLayer(frame_provider_.get()); + break; + case 3: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Use a frame with no resources in it. + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + SetFrameData(frame.Pass()); + break; + case 4: + // We gave two frames to the frame provider, so we should get two + // refs back for each resource. + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + { + unsigned expected[] = {555, 555, 999, 999}; + EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); + } + EndTest(); + break; + } + } + + virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, + bool result) OVERRIDE { + ReturnUnusedResourcesFromParent(host_impl); + } +}; + +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostDelegatedTestTwoImplLayersTwoFrames); + +class LayerTreeHostDelegatedTestTwoLayers + : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer { + public: + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + scoped_ptr<DelegatedFrameData> frame; + ReturnedResourceArray resources; + + int next_source_frame_number = layer_tree_host()->source_frame_number(); + switch (next_source_frame_number) { + case 1: + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + AddTextureQuad(frame.get(), 999); + AddTransferableResource(frame.get(), 999); + AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); + + // Create a DelegatedRendererLayer using the frame. + SetFrameData(frame.Pass()); + break; + case 2: + // Create a second DelegatedRendererLayer using the same frame provider. + delegated_thief_ = CreateDelegatedLayer(frame_provider_.get()); + root_->AddChild(delegated_thief_); + + // And drop our ref on the frame provider so only the layers keep it + // alive. + frame_provider_ = NULL; + break; + case 3: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Remove one delegated layer from the tree. No resources should be + // returned yet. + delegated_->RemoveFromParent(); + break; + case 4: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Put the first layer back, and remove the other layer and destroy it. + // No resources should be returned yet. + root_->AddChild(delegated_); + delegated_thief_->RemoveFromParent(); + delegated_thief_ = NULL; + break; + case 5: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Remove the first layer from the tree again. The resources are still + // held by the main thread layer. + delegated_->RemoveFromParent(); + break; + case 6: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Destroy the layer and the resources should be returned immediately. + delegated_ = NULL; + + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + { + unsigned expected[] = {555, 999}; + EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); + } + EndTest(); + break; + } + } + + virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, + bool result) OVERRIDE { + ReturnUnusedResourcesFromParent(host_impl); + } + + scoped_refptr<DelegatedRendererLayer> delegated_thief_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestTwoLayers); + +class LayerTreeHostDelegatedTestRemoveAndAddToTree + : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer { + public: + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + scoped_ptr<DelegatedFrameData> frame; + ReturnedResourceArray resources; + + int next_source_frame_number = layer_tree_host()->source_frame_number(); + switch (next_source_frame_number) { + case 1: + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + AddTextureQuad(frame.get(), 999); + AddTransferableResource(frame.get(), 999); + AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); + + // Create a DelegatedRendererLayer using the frame. + SetFrameData(frame.Pass()); + break; + case 2: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Remove the layer from the tree. The resources should not be returned + // since they are still on the main thread layer. + delegated_->RemoveFromParent(); + break; + case 3: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Add the layer back to the tree. + layer_tree_host()->root_layer()->AddChild(delegated_); + break; + case 4: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Set a new frame. Resources should be returned. + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + AddTextureQuad(frame.get(), 888); + AddTransferableResource(frame.get(), 888); + AddTextureQuad(frame.get(), 777); + AddTransferableResource(frame.get(), 777); + SetFrameData(frame.Pass()); + break; + case 5: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + { + unsigned expected[] = {555, 999}; + EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); + } + + // Destroy the layer. + delegated_->RemoveFromParent(); + delegated_ = NULL; + break; + case 6: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Destroy the frame provider. Resources should be returned. + frame_provider_ = NULL; + + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + { + unsigned expected[] = {777, 888}; + EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); + } + EndTest(); + break; + } + } + + virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, + bool result) OVERRIDE { + ReturnUnusedResourcesFromParent(host_impl); + } + + scoped_refptr<DelegatedRendererLayer> delegated_thief_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestRemoveAndAddToTree); + +class LayerTreeHostDelegatedTestRemoveAndChangeResources + : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer { + public: + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + scoped_ptr<DelegatedFrameData> frame; + ReturnedResourceArray resources; + + int next_source_frame_number = layer_tree_host()->source_frame_number(); + switch (next_source_frame_number) { + case 1: + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + AddTextureQuad(frame.get(), 999); + AddTransferableResource(frame.get(), 999); + AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); + + // Create a DelegatedRendererLayer using the frame. + SetFrameData(frame.Pass()); + break; + case 2: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Remove the layer from the tree. The resources should not be returned + // since they are still on the main thread layer. + delegated_->RemoveFromParent(); + break; + case 3: + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Set a new frame. Resources should be returned immediately. + frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); + AddTextureQuad(frame.get(), 888); + AddTransferableResource(frame.get(), 888); + AddTextureQuad(frame.get(), 777); + AddTransferableResource(frame.get(), 777); + SetFrameData(frame.Pass()); + + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + { + unsigned expected[] = {555, 999}; + EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); + resources.clear(); + } + + // Destroy the frame provider. + frame_provider_ = NULL; + + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + EXPECT_EQ(0u, resources.size()); + EXPECT_FALSE(TestAndResetAvailable()); + + // Destroy the layer. Resources should be returned. + delegated_ = NULL; + + resource_collection_->TakeUnusedResourcesForChildCompositor(&resources); + { + unsigned expected[] = {777, 888}; + EXPECT_RESOURCES(expected, resources); + EXPECT_TRUE(TestAndResetAvailable()); + } + EndTest(); + break; + } + } + + virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, + bool result) OVERRIDE { + ReturnUnusedResourcesFromParent(host_impl); + } + + scoped_refptr<DelegatedRendererLayer> delegated_thief_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostDelegatedTestRemoveAndChangeResources); + } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc b/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc index 155b8428dd8..621d23d360f 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc @@ -5,6 +5,8 @@ #include "cc/trees/layer_tree_host.h" #include "cc/layers/layer.h" +#include "cc/output/copy_output_request.h" +#include "cc/output/copy_output_result.h" #include "cc/test/layer_tree_test.h" #include "cc/test/occlusion_tracker_test_common.h" @@ -99,6 +101,10 @@ class LayerTreeHostOcclusionTest : public LayerTreeTest { } protected: + virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { + settings->minimum_occlusion_tracking_size = gfx::Size(); + } + scoped_refptr<TestLayer> root_; scoped_refptr<TestLayer> child_; scoped_refptr<TestLayer> child2_; @@ -340,6 +346,74 @@ class LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion); +class LayerTreeHostOcclusionTestOcclusionBlending + : public LayerTreeHostOcclusionTest { + public: + virtual void SetupTree() OVERRIDE { + // If the child layer has a blend mode, then it shouldn't + // contribute to occlusion on stuff below it + SetLayerPropertiesForTesting( + root_.get(), NULL, identity_matrix_, + gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true); + SetLayerPropertiesForTesting( + child2_.get(), root_.get(), identity_matrix_, + gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true); + SetLayerPropertiesForTesting( + child_.get(), root_.get(), identity_matrix_, + gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true); + SetLayerPropertiesForTesting( + grand_child_.get(), child_.get(), identity_matrix_, + gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true); + + child_->SetMasksToBounds(true); + child_->SetBlendMode(SkXfermode::kMultiply_Mode); + child_->SetForceRenderSurface(true); + + child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190)); + root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190)); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeTest::SetupTree(); + } +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionBlending); + +class LayerTreeHostOcclusionTestOcclusionBlendingBelowOcclusion + : public LayerTreeHostOcclusionTest { + public: + virtual void SetupTree() OVERRIDE { + // If the child layer with a blend mode is below child2, then + // child2 should contribute to occlusion on everything, and child shouldn't + // contribute to the root_. + SetLayerPropertiesForTesting( + root_.get(), NULL, identity_matrix_, + gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true); + SetLayerPropertiesForTesting( + child_.get(), root_.get(), identity_matrix_, + gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true); + SetLayerPropertiesForTesting( + grand_child_.get(), child_.get(), identity_matrix_, + gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true); + SetLayerPropertiesForTesting( + child2_.get(), root_.get(), identity_matrix_, + gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true); + + child_->SetMasksToBounds(true); + child_->SetBlendMode(SkXfermode::kMultiply_Mode); + + grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190)); + child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190)); + root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190)); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeTest::SetupTree(); + } +}; + +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostOcclusionTestOcclusionBlendingBelowOcclusion); + class LayerTreeHostOcclusionTestOcclusionOpacityFilter : public LayerTreeHostOcclusionTest { public: @@ -426,6 +500,78 @@ class LayerTreeHostOcclusionTestOcclusionBlurFilter SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostOcclusionTestOcclusionBlurFilter); +class LayerTreeHostOcclusionTestOcclusionCopyRequest + : public LayerTreeHostOcclusionTest { + public: + static void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {} + + virtual void SetupTree() OVERRIDE { + // If the child layer has copy request, and is below child2, + // then child should not inherit occlusion from outside its subtree. + // The child layer will still receive occlusion from inside, and + // the root layer will recive occlusion from child. + SetLayerPropertiesForTesting( + root_.get(), NULL, identity_matrix_, + gfx::PointF(), gfx::Size(100, 100), true); + SetLayerPropertiesForTesting( + child_.get(), root_.get(), identity_matrix_, + gfx::PointF(), gfx::Size(75, 75), true); + SetLayerPropertiesForTesting( + grand_child_.get(), child_.get(), identity_matrix_, + gfx::PointF(), gfx::Size(75, 50), true); + SetLayerPropertiesForTesting( + child2_.get(), root_.get(), identity_matrix_, + gfx::PointF(0.f, 25.f), gfx::Size(75, 75), true); + + child_->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( + base::Bind(&CopyOutputCallback))); + EXPECT_TRUE(child_->HasCopyRequest()); + + child_->set_expected_occlusion(gfx::Rect(0, 0, 75, 50)); + root_->set_expected_occlusion(gfx::Rect(0, 0, 75, 100)); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeTest::SetupTree(); + } +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionCopyRequest); + +class LayerTreeHostOcclusionTestOcclusionReplica + : public LayerTreeHostOcclusionTest { + public: + virtual void SetupTree() OVERRIDE { + // If the child layer has copy request, and is below child2, + // then child should not inherit occlusion from outside its subtree. + // The child layer will still receive occlusion from inside, and + // the root layer will recive occlusion from child. + SetLayerPropertiesForTesting( + root_.get(), NULL, identity_matrix_, + gfx::PointF(), gfx::Size(100, 100), true); + SetLayerPropertiesForTesting( + child_.get(), root_.get(), identity_matrix_, + gfx::PointF(), gfx::Size(75, 75), true); + SetLayerPropertiesForTesting( + grand_child_.get(), child_.get(), identity_matrix_, + gfx::PointF(), gfx::Size(75, 50), true); + SetLayerPropertiesForTesting( + child2_.get(), root_.get(), identity_matrix_, + gfx::PointF(0.f, 25.f), gfx::Size(75, 75), true); + + scoped_refptr<Layer> replica_layer(Layer::Create()); + child_->SetReplicaLayer(replica_layer.get()); + EXPECT_TRUE(child_->has_replica()); + + child_->set_expected_occlusion(gfx::Rect(0, 0, 75, 50)); + root_->set_expected_occlusion(gfx::Rect(0, 0, 75, 100)); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeTest::SetupTree(); + } +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionReplica); + class LayerTreeHostOcclusionTestManySurfaces : public LayerTreeHostOcclusionTest { public: diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc index ab87be1b5c5..38711545636 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc @@ -172,8 +172,8 @@ class LayerTreeHostScrollTestScrollAbortedCommit impl_scroll_(-3, 2), second_main_scroll_(14, -3), impl_scale_(2.f), - num_will_begin_frames_(0), - num_did_begin_frames_(0), + num_will_begin_main_frames_(0), + num_did_begin_main_frames_(0), num_will_commits_(0), num_did_commits_(0), num_impl_commits_(0), @@ -194,10 +194,10 @@ class LayerTreeHostScrollTestScrollAbortedCommit layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); } - virtual void WillBeginFrame() OVERRIDE { - num_will_begin_frames_++; + virtual void WillBeginMainFrame() OVERRIDE { + num_will_begin_main_frames_++; Layer* root_scroll_layer = layer_tree_host()->root_layer()->children()[0]; - switch (num_will_begin_frames_) { + switch (num_will_begin_main_frames_) { case 1: // This will not be aborted because of the initial prop changes. EXPECT_EQ(0, num_impl_scrolls_); @@ -239,7 +239,7 @@ class LayerTreeHostScrollTestScrollAbortedCommit } } - virtual void DidBeginFrame() OVERRIDE { num_did_begin_frames_++; } + virtual void DidBeginMainFrame() OVERRIDE { num_did_begin_main_frames_++; } virtual void WillCommit() OVERRIDE { num_will_commits_++; } @@ -317,8 +317,8 @@ class LayerTreeHostScrollTestScrollAbortedCommit virtual void AfterTest() OVERRIDE { EXPECT_EQ(3, num_impl_scrolls_); // Verify that the embedder sees aborted commits as real commits. - EXPECT_EQ(4, num_will_begin_frames_); - EXPECT_EQ(4, num_did_begin_frames_); + EXPECT_EQ(4, num_will_begin_main_frames_); + EXPECT_EQ(4, num_did_begin_main_frames_); EXPECT_EQ(4, num_will_commits_); EXPECT_EQ(4, num_did_commits_); // ...but the compositor thread only sees two real ones. @@ -330,8 +330,8 @@ class LayerTreeHostScrollTestScrollAbortedCommit gfx::Vector2d impl_scroll_; gfx::Vector2d second_main_scroll_; float impl_scale_; - int num_will_begin_frames_; - int num_did_begin_frames_; + int num_will_begin_main_frames_; + int num_did_begin_main_frames_; int num_will_commits_; int num_did_commits_; int num_impl_commits_; @@ -1012,8 +1012,8 @@ TEST(LayerTreeHostFlingTest, DidStopFlingingThread) { FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D); ASSERT_TRUE(impl_thread.message_loop_proxy().get()); - scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::Create( - &client, settings, impl_thread.message_loop_proxy()); + scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::CreateThreaded( + &client, NULL, settings, impl_thread.message_loop_proxy()); impl_thread.message_loop_proxy() ->PostTask(FROM_HERE, diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc index 280bdad8ee1..9f181cda458 100644 --- a/chromium/cc/trees/layer_tree_impl.cc +++ b/chromium/cc/trees/layer_tree_impl.cc @@ -7,11 +7,14 @@ #include "base/debug/trace_event.h" #include "cc/animation/keyframed_animation_curve.h" #include "cc/animation/scrollbar_animation_controller.h" +#include "cc/base/math_util.h" +#include "cc/base/util.h" #include "cc/debug/traced_value.h" #include "cc/layers/heads_up_display_layer_impl.h" #include "cc/layers/layer.h" #include "cc/layers/render_surface_impl.h" #include "cc/layers/scrollbar_layer_impl_base.h" +#include "cc/resources/ui_resource_request.h" #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_host_impl.h" #include "ui/gfx/size_conversions.h" @@ -40,7 +43,8 @@ LayerTreeImpl::LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl) contents_textures_purged_(false), viewport_size_invalid_(false), needs_update_draw_properties_(true), - needs_full_tree_sync_(true) { + needs_full_tree_sync_(true), + next_activation_forces_redraw_(false) { } LayerTreeImpl::~LayerTreeImpl() { @@ -111,8 +115,13 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { // The request queue should have been processed and does not require a push. DCHECK_EQ(ui_resource_request_queue_.size(), 0u); - target_tree->SetLatencyInfo(latency_info_); - latency_info_.Clear(); + if (next_activation_forces_redraw_) { + layer_tree_host_impl_->SetFullRootLayerDamage(); + next_activation_forces_redraw_ = false; + } + + target_tree->PassSwapPromises(&swap_promise_list_); + target_tree->SetPageScaleFactorAndLimits( page_scale_factor(), min_page_scale_factor(), max_page_scale_factor()); target_tree->SetPageScaleDelta( @@ -189,6 +198,11 @@ void LayerTreeImpl::SetPageScaleFactorAndLimits(float page_scale_factor, min_page_scale_factor_ = min_page_scale_factor; max_page_scale_factor_ = max_page_scale_factor; page_scale_factor_ = page_scale_factor; + + if (root_layer_scroll_offset_delegate_) { + root_layer_scroll_offset_delegate_->SetTotalPageScaleFactor( + total_page_scale_factor()); + } } void LayerTreeImpl::SetPageScaleDelta(float delta) { @@ -215,6 +229,11 @@ void LayerTreeImpl::SetPageScaleDelta(float delta) { UpdateMaxScrollOffset(); set_needs_update_draw_properties(); + + if (root_layer_scroll_offset_delegate_) { + root_layer_scroll_offset_delegate_->SetTotalPageScaleFactor( + total_page_scale_factor()); + } } gfx::SizeF LayerTreeImpl::ScrollableViewportSize() const { @@ -222,6 +241,15 @@ gfx::SizeF LayerTreeImpl::ScrollableViewportSize() const { 1.0f / total_page_scale_factor()); } +gfx::Rect LayerTreeImpl::RootScrollLayerDeviceViewportBounds() const { + if (!root_scroll_layer_ || root_scroll_layer_->children().empty()) + return gfx::Rect(); + LayerImpl* layer = root_scroll_layer_->children()[0]; + return MathUtil::MapClippedRect( + layer->screen_space_transform(), + gfx::Rect(layer->content_bounds())); +} + void LayerTreeImpl::UpdateMaxScrollOffset() { LayerImpl* root_scroll = RootScrollLayer(); if (!root_scroll || !root_scroll->children().size()) @@ -255,17 +283,17 @@ void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit() { root_layer(), base::Bind(&ApplySentScrollDeltasFromAbortedCommitTo)); } -static void ApplyScrollDeltasSinceBeginFrameTo(LayerImpl* layer) { - layer->ApplyScrollDeltasSinceBeginFrame(); +static void ApplyScrollDeltasSinceBeginMainFrameTo(LayerImpl* layer) { + layer->ApplyScrollDeltasSinceBeginMainFrame(); } -void LayerTreeImpl::ApplyScrollDeltasSinceBeginFrame() { +void LayerTreeImpl::ApplyScrollDeltasSinceBeginMainFrame() { DCHECK(IsPendingTree()); if (!root_layer()) return; LayerTreeHostCommon::CallFunctionForSubtree( - root_layer(), base::Bind(&ApplyScrollDeltasSinceBeginFrameTo)); + root_layer(), base::Bind(&ApplyScrollDeltasSinceBeginMainFrameTo)); } void LayerTreeImpl::SetViewportLayersFromIds( @@ -295,8 +323,6 @@ void LayerTreeImpl::ClearViewportLayers() { // of login that works for both scrollbar layer types. This is already planned // as part of the larger pinch-zoom re-factoring viewport. void LayerTreeImpl::UpdateSolidColorScrollbars() { - DCHECK(settings().solid_color_scrollbars); - LayerImpl* root_scroll = RootScrollLayer(); DCHECK(root_scroll); DCHECK(IsActiveTree()); @@ -327,9 +353,9 @@ void LayerTreeImpl::UpdateDrawProperties() { if (IsActiveTree() && RootScrollLayer() && RootContainerLayer()) UpdateRootScrollLayerSizeDelta(); - if (settings().solid_color_scrollbars && - IsActiveTree() && - RootScrollLayer()) { + if (IsActiveTree() && + RootContainerLayer() + && !RootContainerLayer()->masks_to_bounds()) { UpdateSolidColorScrollbars(); } @@ -352,6 +378,8 @@ void LayerTreeImpl::UpdateDrawProperties() { source_frame_number_); LayerImpl* page_scale_layer = page_scale_layer_ ? page_scale_layer_ : RootContainerLayer(); + bool can_render_to_separate_surface = + !output_surface()->ForcedDrawToSoftwareDevice(); LayerTreeHostCommon::CalcDrawPropsImplInputs inputs( root_layer(), DrawViewportSize(), @@ -361,11 +389,43 @@ void LayerTreeImpl::UpdateDrawProperties() { page_scale_layer, MaxTextureSize(), settings().can_use_lcd_text, + can_render_to_separate_surface, settings().layer_transforms_should_scale_layer_contents, &render_surface_layer_list_); LayerTreeHostCommon::CalculateDrawProperties(&inputs); } + { + TRACE_EVENT2("cc", + "LayerTreeImpl::UpdateTilePriorities", + "IsActive", + IsActiveTree(), + "SourceFrameNumber", + source_frame_number_); + // LayerIterator is used here instead of CallFunctionForSubtree to only + // UpdateTilePriorities on layers that will be visible (and thus have valid + // draw properties) and not because any ordering is required. + typedef LayerIterator<LayerImpl, + LayerImplList, + RenderSurfaceImpl, + LayerIteratorActions::FrontToBack> LayerIteratorType; + LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list_); + for (LayerIteratorType it = + LayerIteratorType::Begin(&render_surface_layer_list_); + it != end; + ++it) { + if (!it.represents_itself()) + continue; + LayerImpl* layer = *it; + + layer->UpdateTilePriorities(); + if (layer->mask_layer()) + layer->mask_layer()->UpdateTilePriorities(); + if (layer->replica_layer() && layer->replica_layer()->mask_layer()) + layer->replica_layer()->mask_layer()->UpdateTilePriorities(); + } + } + DCHECK(!needs_update_draw_properties_) << "CalcDrawProperties should not set_needs_update_draw_properties()"; } @@ -401,8 +461,6 @@ void LayerTreeImpl::PushPersistedState(LayerTreeImpl* pending_tree) { pending_tree->SetCurrentlyScrollingLayer( LayerTreeHostCommon::FindLayerInSubtree(pending_tree->root_layer(), currently_scrolling_layer_ ? currently_scrolling_layer_->id() : 0)); - pending_tree->SetLatencyInfo(latency_info_); - latency_info_.Clear(); } static void DidBecomeActiveRecursive(LayerImpl* layer) { @@ -553,6 +611,10 @@ void LayerTreeImpl::StartScrollbarAnimation() { layer_tree_host_impl_->StartScrollbarAnimation(); } +void LayerTreeImpl::DidAnimateScrollOffset() { + layer_tree_host_impl_->DidAnimateScrollOffset(); +} + void LayerTreeImpl::SetNeedsRedraw() { layer_tree_host_impl_->SetNeedsRedraw(); } @@ -584,7 +646,7 @@ scoped_ptr<base::Value> LayerTreeImpl::AsValue() const { typedef LayerIterator<LayerImpl, LayerImplList, RenderSurfaceImpl, - LayerIteratorActions::BackToFront> LayerIteratorType; + LayerIteratorActions::FrontToBack> LayerIteratorType; LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list_); for (LayerIteratorType it = LayerIteratorType::Begin( &render_surface_layer_list_); it != end; ++it) { @@ -600,11 +662,21 @@ scoped_ptr<base::Value> LayerTreeImpl::AsValue() const { void LayerTreeImpl::SetRootLayerScrollOffsetDelegate( LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate) { + if (root_layer_scroll_offset_delegate_ == root_layer_scroll_offset_delegate) + return; + root_layer_scroll_offset_delegate_ = root_layer_scroll_offset_delegate; + if (root_scroll_layer_) { root_scroll_layer_->SetScrollOffsetDelegate( root_layer_scroll_offset_delegate_); } + + if (root_layer_scroll_offset_delegate_) { + root_layer_scroll_offset_delegate_->SetScrollableSize(ScrollableSize()); + root_layer_scroll_offset_delegate_->SetTotalPageScaleFactor( + total_page_scale_factor()); + } } void LayerTreeImpl::UpdateRootScrollLayerSizeDelta() { @@ -626,16 +698,30 @@ void LayerTreeImpl::UpdateRootScrollLayerSizeDelta() { scrollable_viewport_size - original_viewport_size); } -void LayerTreeImpl::SetLatencyInfo(const ui::LatencyInfo& latency_info) { - latency_info_.MergeWith(latency_info); +void LayerTreeImpl::QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise) { + DCHECK(swap_promise); + if (swap_promise_list_.size() > kMaxQueuedSwapPromiseNumber) + BreakSwapPromises(SwapPromise::SWAP_PROMISE_LIST_OVERFLOW); + swap_promise_list_.push_back(swap_promise.Pass()); } -const ui::LatencyInfo& LayerTreeImpl::GetLatencyInfo() { - return latency_info_; +void LayerTreeImpl::PassSwapPromises( + ScopedPtrVector<SwapPromise>* new_swap_promise) { + swap_promise_list_.insert_and_take(swap_promise_list_.end(), + *new_swap_promise); + new_swap_promise->clear(); } -void LayerTreeImpl::ClearLatencyInfo() { - latency_info_.Clear(); +void LayerTreeImpl::FinishSwapPromises(CompositorFrameMetadata* metadata) { + for (size_t i = 0; i < swap_promise_list_.size(); i++) + swap_promise_list_[i]->DidSwap(metadata); + swap_promise_list_.clear(); +} + +void LayerTreeImpl::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) { + for (size_t i = 0; i < swap_promise_list_.size(); i++) + swap_promise_list_[i]->DidNotSwap(reason); + swap_promise_list_.clear(); } void LayerTreeImpl::DidModifyTilePriorities() { @@ -652,6 +738,10 @@ ResourceProvider::ResourceId LayerTreeImpl::ResourceIdForUIResource( return layer_tree_host_impl_->ResourceIdForUIResource(uid); } +bool LayerTreeImpl::IsUIResourceOpaque(UIResourceId uid) const { + return layer_tree_host_impl_->IsUIResourceOpaque(uid); +} + void LayerTreeImpl::ProcessUIResourceRequestQueue() { while (ui_resource_request_queue_.size() > 0) { UIResourceRequest req = ui_resource_request_queue_.front(); @@ -700,7 +790,7 @@ void LayerTreeImpl::RemoveLayerWithCopyOutputRequest(LayerImpl* layer) { layers_with_copy_output_request_.erase(it); } -const std::vector<LayerImpl*> LayerTreeImpl::LayersWithCopyOutputRequest() +const std::vector<LayerImpl*>& LayerTreeImpl::LayersWithCopyOutputRequest() const { // Only the active tree needs to know about layers with copy requests, as // they are aborted if not serviced during draw. diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h index 2ae33df2ba2..85a71f5cd72 100644 --- a/chromium/cc/trees/layer_tree_impl.h +++ b/chromium/cc/trees/layer_tree_impl.h @@ -11,10 +11,11 @@ #include "base/containers/hash_tables.h" #include "base/values.h" +#include "cc/base/scoped_ptr_vector.h" +#include "cc/base/swap_promise.h" #include "cc/layers/layer_impl.h" #include "cc/trees/layer_tree_host.h" #include "cc/resources/ui_resource_client.h" -#include "ui/events/latency_info.h" #if defined(COMPILER_GCC) namespace BASE_HASH_NAMESPACE { @@ -81,6 +82,7 @@ class CC_EXPORT LayerTreeImpl { void SetNeedsCommit(); gfx::Size DrawViewportSize() const; void StartScrollbarAnimation(); + void DidAnimateScrollOffset(); // Tree specific methods exposed to layer-impl tree. // --------------------------------------------------------------------------- @@ -124,7 +126,7 @@ class CC_EXPORT LayerTreeImpl { int outer_viewport_scroll_layer_id); void ClearViewportLayers(); void ApplySentScrollAndScaleDeltasFromAbortedCommit(); - void ApplyScrollDeltasSinceBeginFrame(); + void ApplyScrollDeltasSinceBeginMainFrame(); SkColor background_color() const { return background_color_; } void set_background_color(SkColor color) { background_color_ = color; } @@ -165,6 +167,8 @@ class CC_EXPORT LayerTreeImpl { void set_needs_full_tree_sync(bool needs) { needs_full_tree_sync_ = needs; } bool needs_full_tree_sync() const { return needs_full_tree_sync_; } + void ForceRedrawNextActivation() { next_activation_forces_redraw_ = true; } + void set_ui_resource_request_queue(const UIResourceRequestQueue& queue); const LayerImplList& RenderSurfaceLayerList() const; @@ -174,6 +178,8 @@ class CC_EXPORT LayerTreeImpl { gfx::Size ScrollableSize() const; gfx::SizeF ScrollableViewportSize() const; + gfx::Rect RootScrollLayerDeviceViewportBounds() const; + LayerImpl* LayerById(int id); // These should be called by LayerImpl's ctor/dtor. @@ -202,18 +208,25 @@ class CC_EXPORT LayerTreeImpl { void SetRootLayerScrollOffsetDelegate( LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate); - void SetLatencyInfo(const ui::LatencyInfo& latency_info); - const ui::LatencyInfo& GetLatencyInfo(); - void ClearLatencyInfo(); + // Call this function when you expect there to be a swap buffer. + // See swap_promise.h for how to use SwapPromise. + void QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise); + + // Take the |new_swap_promise| and append it to |swap_promise_list_|. + void PassSwapPromises(ScopedPtrVector<SwapPromise>* new_swap_promise); + void FinishSwapPromises(CompositorFrameMetadata* metadata); + void BreakSwapPromises(SwapPromise::DidNotSwapReason reason); void DidModifyTilePriorities(); ResourceProvider::ResourceId ResourceIdForUIResource(UIResourceId uid) const; void ProcessUIResourceRequestQueue(); + bool IsUIResourceOpaque(UIResourceId uid) const; + void AddLayerWithCopyOutputRequest(LayerImpl* layer); void RemoveLayerWithCopyOutputRequest(LayerImpl* layer); - const std::vector<LayerImpl*> LayersWithCopyOutputRequest() const; + const std::vector<LayerImpl*>& LayersWithCopyOutputRequest() const; protected: explicit LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl); @@ -250,8 +263,8 @@ class CC_EXPORT LayerTreeImpl { // Persisted state for non-impl-side-painting. int scrolling_layer_id_from_previous_tree_; - // List of visible layers for the most recently prepared frame. Used for - // rendering and input event hit testing. + // List of visible or hit-testable layers for the most recently prepared + // frame. Used for rendering and input event hit testing. LayerImplList render_surface_layer_list_; bool contents_textures_purged_; @@ -262,7 +275,9 @@ class CC_EXPORT LayerTreeImpl { // structural differences relative to the active tree. bool needs_full_tree_sync_; - ui::LatencyInfo latency_info_; + bool next_activation_forces_redraw_; + + ScopedPtrVector<SwapPromise> swap_promise_list_; UIResourceRequestQueue ui_resource_request_queue_; diff --git a/chromium/cc/trees/layer_tree_settings.cc b/chromium/cc/trees/layer_tree_settings.cc index 8e8e35d5faa..b39524cb61b 100644 --- a/chromium/cc/trees/layer_tree_settings.cc +++ b/chromium/cc/trees/layer_tree_settings.cc @@ -16,21 +16,20 @@ LayerTreeSettings::LayerTreeSettings() : impl_side_painting(false), allow_antialiasing(true), throttle_frame_production(true), - begin_frame_scheduling_enabled(false), - deadline_scheduling_enabled(false), + begin_impl_frame_scheduling_enabled(false), + deadline_scheduling_enabled(true), using_synchronous_renderer_compositor(false), per_tile_painting_enabled(false), partial_swap_enabled(false), - cache_render_pass_contents(true), accelerated_animation_enabled(true), background_color_instead_of_checkerboard(false), show_overdraw_in_tracing(false), can_use_lcd_text(true), should_clear_root_render_pass(true), + gpu_rasterization(false), scrollbar_animator(NoAnimator), scrollbar_linear_fade_delay_ms(300), scrollbar_linear_fade_length_ms(300), - solid_color_scrollbars(false), solid_color_scrollbar_color(SK_ColorWHITE), calculate_top_controls_position(false), use_memory_management(true), @@ -38,7 +37,7 @@ LayerTreeSettings::LayerTreeSettings() maximum_number_of_failed_draws_before_draw_is_forced_(3), layer_transforms_should_scale_layer_contents(false), minimum_contents_scale(0.0625f), - low_res_contents_scale_factor(0.125f), + low_res_contents_scale_factor(0.25f), top_controls_height(0.f), top_controls_show_threshold(0.5f), top_controls_hide_threshold(0.5f), @@ -54,14 +53,13 @@ LayerTreeSettings::LayerTreeSettings() max_tiles_for_interest_area(128), max_unused_resource_memory_percentage(100), highp_threshold_min(0), - force_direct_layer_drawing(false), strict_layer_property_change_checking(false), use_map_image(false), ignore_root_layer_flings(false), - use_rgba_4444_textures(false) { - // TODO(danakj): Renable surface caching when we can do it more realiably. - // crbug.com/170713 - cache_render_pass_contents = false; + use_rgba_4444_textures(false), + always_overscroll(false), + touch_hit_testing(true), + texture_id_allocation_chunk_size(64) { } LayerTreeSettings::~LayerTreeSettings() {} diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h index aa8cdd9860f..6ba5da464a2 100644 --- a/chromium/cc/trees/layer_tree_settings.h +++ b/chromium/cc/trees/layer_tree_settings.h @@ -21,17 +21,17 @@ class CC_EXPORT LayerTreeSettings { bool impl_side_painting; bool allow_antialiasing; bool throttle_frame_production; - bool begin_frame_scheduling_enabled; + bool begin_impl_frame_scheduling_enabled; bool deadline_scheduling_enabled; bool using_synchronous_renderer_compositor; bool per_tile_painting_enabled; bool partial_swap_enabled; - bool cache_render_pass_contents; bool accelerated_animation_enabled; bool background_color_instead_of_checkerboard; bool show_overdraw_in_tracing; bool can_use_lcd_text; bool should_clear_root_render_pass; + bool gpu_rasterization; enum ScrollbarAnimator { NoAnimator, @@ -41,7 +41,6 @@ class CC_EXPORT LayerTreeSettings { ScrollbarAnimator scrollbar_animator; int scrollbar_linear_fade_delay_ms; int scrollbar_linear_fade_length_ms; - bool solid_color_scrollbars; SkColor solid_color_scrollbar_color; bool calculate_top_controls_position; bool use_memory_management; @@ -64,11 +63,13 @@ class CC_EXPORT LayerTreeSettings { size_t max_tiles_for_interest_area; size_t max_unused_resource_memory_percentage; int highp_threshold_min; - bool force_direct_layer_drawing; // With Skia GPU backend. bool strict_layer_property_change_checking; bool use_map_image; bool ignore_root_layer_flings; bool use_rgba_4444_textures; + bool always_overscroll; + bool touch_hit_testing; + size_t texture_id_allocation_chunk_size; LayerTreeDebugState initial_debug_state; }; diff --git a/chromium/cc/trees/occlusion_tracker.cc b/chromium/cc/trees/occlusion_tracker.cc index 9fc26da5667..1c6c8a04e4e 100644 --- a/chromium/cc/trees/occlusion_tracker.cc +++ b/chromium/cc/trees/occlusion_tracker.cc @@ -22,7 +22,6 @@ OcclusionTrackerBase<LayerType, RenderSurfaceType>::OcclusionTrackerBase( gfx::Rect screen_space_clip_rect, bool record_metrics_for_frame) : screen_space_clip_rect_(screen_space_clip_rect), overdraw_metrics_(OverdrawMetrics::Create(record_metrics_for_frame)), - prevent_occlusion_(false), occluding_screen_space_rects_(NULL), non_occluding_screen_space_rects_(NULL) {} @@ -31,16 +30,13 @@ OcclusionTrackerBase<LayerType, RenderSurfaceType>::~OcclusionTrackerBase() {} template <typename LayerType, typename RenderSurfaceType> void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterLayer( - const LayerIteratorPosition<LayerType>& layer_iterator, - bool prevent_occlusion) { + const LayerIteratorPosition<LayerType>& layer_iterator) { LayerType* render_target = layer_iterator.target_render_surface_layer; if (layer_iterator.represents_itself) EnterRenderTarget(render_target); else if (layer_iterator.represents_target_render_surface) FinishedRenderTarget(render_target); - - prevent_occlusion_ = prevent_occlusion; } template <typename LayerType, typename RenderSurfaceType> @@ -54,8 +50,6 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveLayer( // but in a way that the surface's own occlusion won't occlude itself. else if (layer_iterator.represents_contributing_render_surface) LeaveToRenderTarget(render_target); - - prevent_occlusion_ = false; } template <typename RenderSurfaceType> @@ -156,14 +150,14 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterRenderTarget( return; const LayerType* old_target = NULL; - const RenderSurfaceType* old_ancestor_that_moves_pixels = NULL; + const RenderSurfaceType* old_occlusion_immune_ancestor = NULL; if (!stack_.empty()) { old_target = stack_.back().target; - old_ancestor_that_moves_pixels = - old_target->render_surface()->nearest_ancestor_that_moves_pixels(); + old_occlusion_immune_ancestor = + old_target->render_surface()->nearest_occlusion_immune_ancestor(); } - const RenderSurfaceType* new_ancestor_that_moves_pixels = - new_target->render_surface()->nearest_ancestor_that_moves_pixels(); + const RenderSurfaceType* new_occlusion_immune_ancestor = + new_target->render_surface()->nearest_occlusion_immune_ancestor(); stack_.push_back(StackObject(new_target)); @@ -171,14 +165,11 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterRenderTarget( // never copy in the occlusion from inside the target, since we are looking // at a new RenderSurface target. - // If we are entering a subtree that is going to move pixels around, then the - // occlusion we've computed so far won't apply to the pixels we're drawing - // here in the same way. We discard the occlusion thus far to be safe, and - // ensure we don't cull any pixels that are moved such that they become - // visible. - bool entering_subtree_that_moves_pixels = - new_ancestor_that_moves_pixels && - new_ancestor_that_moves_pixels != old_ancestor_that_moves_pixels; + // If entering an unoccluded subtree, do not carry forward the outside + // occlusion calculated so far. + bool entering_unoccluded_subtree = + new_occlusion_immune_ancestor && + new_occlusion_immune_ancestor != old_occlusion_immune_ancestor; bool have_transform_from_screen_to_new_target = false; gfx::Transform inverse_new_target_screen_space_transform( @@ -194,7 +185,7 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterRenderTarget( bool copy_outside_occlusion_forward = stack_.size() > 1 && - !entering_subtree_that_moves_pixels && + !entering_unoccluded_subtree && have_transform_from_screen_to_new_target && !entering_root_target; if (!copy_outside_occlusion_forward) @@ -233,14 +224,11 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::FinishedRenderTarget( // If the occlusion within the surface can not be applied to things outside of // the surface's subtree, then clear the occlusion here so it won't be used. - // TODO(senorblanco): Make this smarter for SkImageFilter case: once - // SkImageFilters can report affectsOpacity(), call that. - if (finished_target->mask_layer() || - !SurfaceOpacityKnown(surface) || + if (finished_target->mask_layer() || !SurfaceOpacityKnown(surface) || surface->draw_opacity() < 1 || + !finished_target->uses_default_blend_mode() || target_is_only_for_copy_request || - finished_target->filters().HasFilterThatAffectsOpacity() || - finished_target->filter()) { + finished_target->filters().HasFilterThatAffectsOpacity()) { stack_.back().occlusion_from_outside_target.Clear(); stack_.back().occlusion_from_inside_target.Clear(); } else if (!SurfaceTransformsToTargetKnown(surface)) { @@ -275,12 +263,6 @@ static void ReduceOcclusionBelowSurface(LayerType* contributing_layer, // to expand outside the clip. affected_area_in_target.Inset( -outset_left, -outset_top, -outset_right, -outset_bottom); - - gfx::Rect FilterOutsetsInTarget(-outset_left, - -outset_top, - outset_left + outset_right, - outset_top + outset_bottom); - Region affected_occlusion = IntersectRegions(*occlusion_from_inside_target, affected_area_in_target); Region::Iterator affected_occlusion_rects(affected_occlusion); @@ -350,10 +332,10 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveToRenderTarget( gfx::Rect unoccluded_replica_rect; if (old_target->background_filters().HasFilterThatMovesPixels()) { unoccluded_surface_rect = UnoccludedContributingSurfaceContentRect( - old_target, false, old_surface->content_rect(), NULL); + old_target, false, old_surface->content_rect()); if (old_target->has_replica()) { unoccluded_replica_rect = UnoccludedContributingSurfaceContentRect( - old_target, true, old_surface->content_rect(), NULL); + old_target, true, old_surface->content_rect()); } } @@ -417,9 +399,15 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>:: if (stack_.empty()) return; + if (!layer->DrawsContent()) + return; + if (!LayerOpacityKnown(layer) || layer->draw_opacity() < 1) return; + if (!layer->uses_default_blend_mode()) + return; + if (LayerIsInUnsorted3dRenderingContext(layer)) return; @@ -511,15 +499,7 @@ bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::Occluded( const LayerType* render_target, gfx::Rect content_rect, const gfx::Transform& draw_transform, - bool impl_draw_transform_is_unknown, - bool is_clipped, - gfx::Rect clip_rect_in_target, - bool* has_occlusion_from_outside_target_surface) const { - if (has_occlusion_from_outside_target_surface) - *has_occlusion_from_outside_target_surface = false; - if (prevent_occlusion_) - return false; - + bool impl_draw_transform_is_unknown) const { DCHECK(!stack_.empty()); if (stack_.empty()) return false; @@ -536,6 +516,11 @@ bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::Occluded( DCHECK(render_target->render_surface()); DCHECK_EQ(render_target, stack_.back().target); + if (stack_.back().occlusion_from_inside_target.IsEmpty() && + stack_.back().occlusion_from_outside_target.IsEmpty()) { + return false; + } + gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization); if (!draw_transform.GetInverse(&inverse_draw_transform)) return false; @@ -544,9 +529,6 @@ bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::Occluded( // partial pixels in the resulting Rect. Region unoccluded_region_in_target_surface = gfx::ToEnclosingRect( MathUtil::MapClippedRect(draw_transform, gfx::RectF(content_rect))); - // Layers can't clip across surfaces, so count this as internal occlusion. - if (is_clipped) - unoccluded_region_in_target_surface.Intersect(clip_rect_in_target); unoccluded_region_in_target_surface.Subtract( stack_.back().occlusion_from_inside_target); gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion = @@ -554,24 +536,9 @@ bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::Occluded( unoccluded_region_in_target_surface.Subtract( stack_.back().occlusion_from_outside_target); - // Treat other clipping as occlusion from outside the surface. - // TODO(danakj): Clip to visibleContentRect? - unoccluded_region_in_target_surface.Intersect( - render_target->render_surface()->content_rect()); - unoccluded_region_in_target_surface.Intersect( - ScreenSpaceClipRectInTargetSurface(render_target->render_surface(), - screen_space_clip_rect_)); - gfx::RectF unoccluded_rect_in_target_surface = unoccluded_region_in_target_surface.bounds(); - if (has_occlusion_from_outside_target_surface) { - // Check if the unoccluded rect shrank when applying outside occlusion. - *has_occlusion_from_outside_target_surface = !gfx::SubtractRects( - unoccluded_rect_in_target_surface_without_outside_occlusion, - unoccluded_rect_in_target_surface).IsEmpty(); - } - return unoccluded_rect_in_target_surface.IsEmpty(); } @@ -581,15 +548,7 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>:: const LayerType* render_target, gfx::Rect content_rect, const gfx::Transform& draw_transform, - bool impl_draw_transform_is_unknown, - bool is_clipped, - gfx::Rect clip_rect_in_target, - bool* has_occlusion_from_outside_target_surface) const { - if (has_occlusion_from_outside_target_surface) - *has_occlusion_from_outside_target_surface = false; - if (prevent_occlusion_) - return content_rect; - + bool impl_draw_transform_is_unknown) const { DCHECK(!stack_.empty()); if (stack_.empty()) return content_rect; @@ -606,6 +565,11 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>:: DCHECK(render_target->render_surface()); DCHECK_EQ(render_target, stack_.back().target); + if (stack_.back().occlusion_from_inside_target.IsEmpty() && + stack_.back().occlusion_from_outside_target.IsEmpty()) { + return content_rect; + } + gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization); if (!draw_transform.GetInverse(&inverse_draw_transform)) return content_rect; @@ -614,24 +578,11 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>:: // partial pixels in the resulting Rect. Region unoccluded_region_in_target_surface = gfx::ToEnclosingRect( MathUtil::MapClippedRect(draw_transform, gfx::RectF(content_rect))); - // Layers can't clip across surfaces, so count this as internal occlusion. - if (is_clipped) - unoccluded_region_in_target_surface.Intersect(clip_rect_in_target); unoccluded_region_in_target_surface.Subtract( stack_.back().occlusion_from_inside_target); - gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion = - unoccluded_region_in_target_surface.bounds(); unoccluded_region_in_target_surface.Subtract( stack_.back().occlusion_from_outside_target); - // Treat other clipping as occlusion from outside the surface. - // TODO(danakj): Clip to visibleContentRect? - unoccluded_region_in_target_surface.Intersect( - render_target->render_surface()->content_rect()); - unoccluded_region_in_target_surface.Intersect( - ScreenSpaceClipRectInTargetSurface(render_target->render_surface(), - screen_space_clip_rect_)); - gfx::RectF unoccluded_rect_in_target_surface = unoccluded_region_in_target_surface.bounds(); gfx::Rect unoccluded_rect = gfx::ToEnclosingRect( @@ -639,13 +590,6 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>:: unoccluded_rect_in_target_surface)); unoccluded_rect.Intersect(content_rect); - if (has_occlusion_from_outside_target_surface) { - // Check if the unoccluded rect shrank when applying outside occlusion. - *has_occlusion_from_outside_target_surface = !gfx::SubtractRects( - unoccluded_rect_in_target_surface_without_outside_occlusion, - unoccluded_rect_in_target_surface).IsEmpty(); - } - return unoccluded_rect; } @@ -654,8 +598,7 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>:: UnoccludedContributingSurfaceContentRect( const LayerType* layer, bool for_replica, - gfx::Rect content_rect, - bool* has_occlusion_from_outside_target_surface) const { + gfx::Rect content_rect) const { DCHECK(!stack_.empty()); // The layer is a contributing render_target so it should have a surface. DCHECK(layer->render_surface()); @@ -667,11 +610,6 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>:: // target in the occlusion tracker. DCHECK_EQ(layer, stack_.back().target); - if (has_occlusion_from_outside_target_surface) - *has_occlusion_from_outside_target_surface = false; - if (prevent_occlusion_) - return content_rect; - if (content_rect.IsEmpty()) return content_rect; @@ -705,11 +643,6 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>:: const StackObject& second_last = stack_[stack_.size() - 2]; unoccluded_region_in_target_surface.Subtract( second_last.occlusion_from_inside_target); - } - gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion = - unoccluded_region_in_target_surface.bounds(); - if (has_occlusion) { - const StackObject& second_last = stack_[stack_.size() - 2]; unoccluded_region_in_target_surface.Subtract( second_last.occlusion_from_outside_target); } @@ -729,13 +662,6 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>:: unoccluded_rect_in_target_surface)); unoccluded_rect.Intersect(content_rect); - if (has_occlusion_from_outside_target_surface) { - // Check if the unoccluded rect shrank when applying outside occlusion. - *has_occlusion_from_outside_target_surface = !gfx::SubtractRects( - unoccluded_rect_in_target_surface_without_outside_occlusion, - unoccluded_rect_in_target_surface).IsEmpty(); - } - return unoccluded_rect; } diff --git a/chromium/cc/trees/occlusion_tracker.h b/chromium/cc/trees/occlusion_tracker.h index 132b3fa3160..68418c7e435 100644 --- a/chromium/cc/trees/occlusion_tracker.h +++ b/chromium/cc/trees/occlusion_tracker.h @@ -37,10 +37,8 @@ class CC_EXPORT OcclusionTrackerBase { ~OcclusionTrackerBase(); // Called at the beginning of each step in the LayerIterator's front-to-back - // traversal. If |prevent_occlusion| is true, the layer will be considered - // unoccluded. - void EnterLayer(const LayerIteratorPosition<LayerType>& layer_iterator, - bool prevent_occlusion); + // traversal. + void EnterLayer(const LayerIteratorPosition<LayerType>& layer_iterator); // Called at the end of each step in the LayerIterator's front-to-back // traversal. void LeaveLayer(const LayerIteratorPosition<LayerType>& layer_iterator); @@ -48,29 +46,21 @@ class CC_EXPORT OcclusionTrackerBase { // Returns true if the given rect in content space for a layer is fully // occluded in either screen space or the layer's target surface. // |render_target| is the contributing layer's render target, and - // |draw_transform|, |transformsToTargetKnown| and |clippedRectInTarget| are - // relative to that. + // |draw_transform| and |impl_draw_transform_is_unknown| are relative to that. bool Occluded(const LayerType* render_target, gfx::Rect content_rect, const gfx::Transform& draw_transform, - bool impl_draw_transform_is_unknown, - bool is_clipped, - gfx::Rect clip_rect_in_target, - bool* has_occlusion_from_outside_target_surface) const; + bool impl_draw_transform_is_unknown) const; // Gives an unoccluded sub-rect of |content_rect| in the content space of a // layer. Used when considering occlusion for a layer that paints/draws // something. |render_target| is the contributing layer's render target, and - // |draw_transform|, |transformsToTargetKnown| and |clippedRectInTarget| are - // relative to that. + // |draw_transform| and |impl_draw_transform_is_unknown| are relative to that. gfx::Rect UnoccludedContentRect( const LayerType* render_target, gfx::Rect content_rect, const gfx::Transform& draw_transform, - bool impl_draw_transform_is_unknown, - bool is_clipped, - gfx::Rect clip_rect_in_target, - bool* has_occlusion_from_outside_target_surface) const; + bool impl_draw_transform_is_unknown) const; // Gives an unoccluded sub-rect of |content_rect| in the content space of the // render_target owned by the layer. Used when considering occlusion for a @@ -78,8 +68,7 @@ class CC_EXPORT OcclusionTrackerBase { gfx::Rect UnoccludedContributingSurfaceContentRect( const LayerType* layer, bool for_replica, - gfx::Rect content_rect, - bool* has_occlusion_from_outside_target_surface) const; + gfx::Rect content_rect) const; // Report operations for recording overdraw metrics. OverdrawMetrics* overdraw_metrics() const { @@ -155,7 +144,6 @@ class CC_EXPORT OcclusionTrackerBase { gfx::Rect screen_space_clip_rect_; scoped_ptr<class OverdrawMetrics> overdraw_metrics_; gfx::Size minimum_tracking_size_; - bool prevent_occlusion_; // This is used for visualizing the occlusion tracking process. std::vector<gfx::Rect>* occluding_screen_space_rects_; diff --git a/chromium/cc/trees/occlusion_tracker_unittest.cc b/chromium/cc/trees/occlusion_tracker_unittest.cc index 469d65a4cb2..89afe4f909b 100644 --- a/chromium/cc/trees/occlusion_tracker_unittest.cc +++ b/chromium/cc/trees/occlusion_tracker_unittest.cc @@ -30,9 +30,10 @@ namespace { class TestContentLayer : public Layer { public: - TestContentLayer() : Layer(), override_opaque_contents_rect_(false) {} + TestContentLayer() : Layer(), override_opaque_contents_rect_(false) { + SetIsDrawable(true); + } - virtual bool DrawsContent() const OVERRIDE { return true; } virtual Region VisibleContentOpaqueRegion() const OVERRIDE { if (override_opaque_contents_rect_) return gfx::IntersectRects(opaque_contents_rect_, visible_content_rect()); @@ -92,42 +93,25 @@ class TestOcclusionTrackerWithClip : TestOcclusionTrackerBase<LayerType, RenderSurfaceType>(viewport_rect, false) {} - bool OccludedLayer(const LayerType* layer, gfx::Rect content_rect) { - bool temp; - return OccludedLayer(layer, content_rect, &temp); - } - bool OccludedLayer(const LayerType* layer, - gfx::Rect content_rect, - bool* has_occlusion_from_outside_target_surface) const { + gfx::Rect content_rect) const { + DCHECK(layer->visible_content_rect().Contains(content_rect)); return this->Occluded(layer->render_target(), content_rect, layer->draw_transform(), - LayerImplDrawTransformIsUnknown(layer), - layer->is_clipped(), - layer->clip_rect(), - has_occlusion_from_outside_target_surface); + LayerImplDrawTransformIsUnknown(layer)); } + // Gives an unoccluded sub-rect of |content_rect| in the content space of the // layer. Simple wrapper around UnoccludedContentRect. gfx::Rect UnoccludedLayerContentRect(const LayerType* layer, gfx::Rect content_rect) const { - bool temp; - return UnoccludedLayerContentRect(layer, content_rect, &temp); - } - - gfx::Rect UnoccludedLayerContentRect( - const LayerType* layer, - gfx::Rect content_rect, - bool* has_occlusion_from_outside_target_surface) const { + DCHECK(layer->visible_content_rect().Contains(content_rect)); return this->UnoccludedContentRect( layer->render_target(), content_rect, layer->draw_transform(), - LayerImplDrawTransformIsUnknown(layer), - layer->is_clipped(), - layer->clip_rect(), - has_occlusion_from_outside_target_surface); + LayerImplDrawTransformIsUnknown(layer)); } }; @@ -359,12 +343,19 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test { Types::TestLayerIterator::Begin(render_surface_layer_list_.get()); } + void SetDrawsContent(LayerImpl* layer_impl, bool draws_content) { + layer_impl->SetDrawsContent(draws_content); + } + + void SetDrawsContent(Layer* layer, bool draws_content) { + layer->SetIsDrawable(draws_content); + } + void EnterLayer(typename Types::LayerType* layer, - typename Types::OcclusionTrackerType* occlusion, - bool prevent_occlusion) { + typename Types::OcclusionTrackerType* occlusion) { ASSERT_EQ(layer, *layer_iterator_); ASSERT_TRUE(layer_iterator_.represents_itself()); - occlusion->EnterLayer(layer_iterator_, prevent_occlusion); + occlusion->EnterLayer(layer_iterator_); } void LeaveLayer(typename Types::LayerType* layer, @@ -377,21 +368,20 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test { void VisitLayer(typename Types::LayerType* layer, typename Types::OcclusionTrackerType* occlusion) { - EnterLayer(layer, occlusion, false); + EnterLayer(layer, occlusion); LeaveLayer(layer, occlusion); } void EnterContributingSurface( typename Types::LayerType* layer, - typename Types::OcclusionTrackerType* occlusion, - bool prevent_occlusion) { + typename Types::OcclusionTrackerType* occlusion) { ASSERT_EQ(layer, *layer_iterator_); ASSERT_TRUE(layer_iterator_.represents_target_render_surface()); - occlusion->EnterLayer(layer_iterator_, false); + occlusion->EnterLayer(layer_iterator_); occlusion->LeaveLayer(layer_iterator_); ++layer_iterator_; ASSERT_TRUE(layer_iterator_.represents_contributing_render_surface()); - occlusion->EnterLayer(layer_iterator_, prevent_occlusion); + occlusion->EnterLayer(layer_iterator_); } void LeaveContributingSurface( @@ -406,7 +396,7 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test { void VisitContributingSurface( typename Types::LayerType* layer, typename Types::OcclusionTrackerType* occlusion) { - EnterContributingSurface(layer, occlusion, false); + EnterContributingSurface(layer, occlusion); LeaveContributingSurface(layer, occlusion); } @@ -567,7 +557,7 @@ class OcclusionTrackerTestIdentityTransforms gfx::Rect(0, 0, 1000, 1000), false); this->VisitLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -577,8 +567,8 @@ class OcclusionTrackerTestIdentityTransforms EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(30, 30, 70, 70))); EXPECT_FALSE(occlusion.OccludedLayer(parent, gfx::Rect(29, 30, 70, 70))); EXPECT_FALSE(occlusion.OccludedLayer(parent, gfx::Rect(30, 29, 70, 70))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(31, 30, 70, 70))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(30, 31, 70, 70))); + EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(31, 30, 69, 70))); + EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(30, 31, 70, 69))); EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( parent, gfx::Rect(30, 30, 70, 70)).IsEmpty()); @@ -593,19 +583,19 @@ class OcclusionTrackerTestIdentityTransforms parent, gfx::Rect(30, 29, 70, 70))); EXPECT_RECT_EQ(gfx::Rect(31, 29, 69, 1), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(31, 29, 70, 70))); + parent, gfx::Rect(31, 29, 69, 70))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(31, 30, 70, 70))); + parent, gfx::Rect(31, 30, 69, 70))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(31, 31, 70, 70))); + parent, gfx::Rect(31, 31, 69, 69))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(30, 31, 70, 70))); + parent, gfx::Rect(30, 31, 70, 69))); EXPECT_RECT_EQ(gfx::Rect(29, 31, 1, 69), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(29, 31, 70, 70))); + parent, gfx::Rect(29, 31, 70, 69))); } }; @@ -634,7 +624,7 @@ class OcclusionTrackerTestQuadsMismatchLayer gfx::Rect(0, 0, 1000, 1000)); this->VisitLayer(layer2, &occlusion); - this->EnterLayer(layer1, &occlusion, false); + this->EnterLayer(layer1, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -647,47 +637,26 @@ class OcclusionTrackerTestQuadsMismatchLayer gfx::Transform quad_transform; quad_transform.Translate(30.0, 30.0); - gfx::Rect clip_rect_in_target(0, 0, 100, 100); EXPECT_TRUE(occlusion.UnoccludedContentRect(parent, gfx::Rect(0, 0, 10, 10), quad_transform, - false, - true, - clip_rect_in_target, - NULL).IsEmpty()); + false).IsEmpty()); EXPECT_RECT_EQ(gfx::Rect(0, 0, 10, 10), occlusion.UnoccludedContentRect(parent, gfx::Rect(0, 0, 10, 10), quad_transform, - true, - true, - clip_rect_in_target, - NULL)); + true)); EXPECT_RECT_EQ(gfx::Rect(40, 40, 10, 10), occlusion.UnoccludedContentRect(parent, gfx::Rect(40, 40, 10, 10), quad_transform, - false, - true, - clip_rect_in_target, - NULL)); + false)); EXPECT_RECT_EQ(gfx::Rect(40, 30, 5, 10), occlusion.UnoccludedContentRect(parent, gfx::Rect(35, 30, 10, 10), quad_transform, - false, - true, - clip_rect_in_target, - NULL)); - EXPECT_RECT_EQ(gfx::Rect(40, 40, 5, 5), - occlusion.UnoccludedContentRect(parent, - gfx::Rect(40, 40, 10, 10), - quad_transform, - false, - true, - gfx::Rect(0, 0, 75, 75), - NULL)); + false)); } }; @@ -722,7 +691,7 @@ class OcclusionTrackerTestRotatedChild : public OcclusionTrackerTest<Types> { gfx::Rect(0, 0, 1000, 1000)); this->VisitLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -732,14 +701,14 @@ class OcclusionTrackerTestRotatedChild : public OcclusionTrackerTest<Types> { EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(30, 30, 70, 70))); EXPECT_FALSE(occlusion.OccludedLayer(parent, gfx::Rect(29, 30, 70, 70))); EXPECT_FALSE(occlusion.OccludedLayer(parent, gfx::Rect(30, 29, 70, 70))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(31, 30, 70, 70))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(30, 31, 70, 70))); + EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(31, 30, 69, 70))); + EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(30, 31, 70, 69))); EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( parent, gfx::Rect(30, 30, 70, 70)).IsEmpty()); EXPECT_RECT_EQ(gfx::Rect(29, 30, 1, 70), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(29, 30, 70, 70))); + parent, gfx::Rect(29, 30, 69, 70))); EXPECT_RECT_EQ(gfx::Rect(29, 29, 70, 70), occlusion.UnoccludedLayerContentRect( parent, gfx::Rect(29, 29, 70, 70))); @@ -748,19 +717,19 @@ class OcclusionTrackerTestRotatedChild : public OcclusionTrackerTest<Types> { parent, gfx::Rect(30, 29, 70, 70))); EXPECT_RECT_EQ(gfx::Rect(31, 29, 69, 1), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(31, 29, 70, 70))); + parent, gfx::Rect(31, 29, 69, 70))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(31, 30, 70, 70))); + parent, gfx::Rect(31, 30, 69, 70))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(31, 31, 70, 70))); + parent, gfx::Rect(31, 31, 69, 69))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(30, 31, 70, 70))); + parent, gfx::Rect(30, 31, 70, 69))); EXPECT_RECT_EQ(gfx::Rect(29, 31, 1, 69), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(29, 31, 70, 70))); + parent, gfx::Rect(29, 31, 70, 69))); } }; @@ -793,7 +762,7 @@ class OcclusionTrackerTestTranslatedChild : public OcclusionTrackerTest<Types> { gfx::Rect(0, 0, 1000, 1000)); this->VisitLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -803,8 +772,8 @@ class OcclusionTrackerTestTranslatedChild : public OcclusionTrackerTest<Types> { EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(50, 50, 50, 50))); EXPECT_FALSE(occlusion.OccludedLayer(parent, gfx::Rect(49, 50, 50, 50))); EXPECT_FALSE(occlusion.OccludedLayer(parent, gfx::Rect(50, 49, 50, 50))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(51, 50, 50, 50))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(50, 51, 50, 50))); + EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(51, 50, 49, 50))); + EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(50, 51, 50, 49))); EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( parent, gfx::Rect(50, 50, 50, 50)).IsEmpty()); @@ -819,16 +788,16 @@ class OcclusionTrackerTestTranslatedChild : public OcclusionTrackerTest<Types> { parent, gfx::Rect(50, 49, 50, 50))); EXPECT_RECT_EQ(gfx::Rect(51, 49, 49, 1), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(51, 49, 50, 50))); + parent, gfx::Rect(51, 49, 49, 50))); EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(51, 50, 50, 50)).IsEmpty()); + parent, gfx::Rect(51, 50, 49, 50)).IsEmpty()); EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(51, 51, 50, 50)).IsEmpty()); + parent, gfx::Rect(51, 51, 49, 49)).IsEmpty()); EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(50, 51, 50, 50)).IsEmpty()); + parent, gfx::Rect(50, 51, 50, 49)).IsEmpty()); EXPECT_RECT_EQ(gfx::Rect(49, 51, 1, 49), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(49, 51, 50, 50))); + parent, gfx::Rect(49, 51, 50, 49))); } }; @@ -865,7 +834,7 @@ class OcclusionTrackerTestChildInRotatedChild gfx::Rect(0, 0, 1000, 1000)); this->VisitLayer(layer, &occlusion); - this->EnterContributingSurface(child, &occlusion, false); + this->EnterContributingSurface(child, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -873,7 +842,7 @@ class OcclusionTrackerTestChildInRotatedChild occlusion.occlusion_from_inside_target().ToString()); this->LeaveContributingSurface(child, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -883,8 +852,8 @@ class OcclusionTrackerTestChildInRotatedChild EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(30, 40, 70, 60))); EXPECT_FALSE(occlusion.OccludedLayer(parent, gfx::Rect(29, 40, 70, 60))); EXPECT_FALSE(occlusion.OccludedLayer(parent, gfx::Rect(30, 39, 70, 60))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(31, 40, 70, 60))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(30, 41, 70, 60))); + EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(31, 40, 69, 60))); + EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(30, 41, 70, 59))); /* Justification for the above occlusion from |layer|: 100 @@ -972,7 +941,7 @@ class OcclusionTrackerTestScaledRenderSurface gfx::Rect(0, 0, 1000, 1000)); this->VisitLayer(occluder, &occlusion); - this->EnterLayer(layer2, &occlusion, false); + this->EnterLayer(layer2, &occlusion); EXPECT_EQ(gfx::Rect(100, 100, 100, 100).ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1050,7 +1019,7 @@ class OcclusionTrackerTestVisitTargetTwoTimes EXPECT_EQ(gfx::Rect(10, 430, 60, 70).ToString(), occlusion.occlusion_from_inside_target().ToString()); - this->EnterContributingSurface(child, &occlusion, false); + this->EnterContributingSurface(child, &occlusion); EXPECT_EQ(gfx::Rect(0, 440, 20, 60).ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1060,7 +1029,7 @@ class OcclusionTrackerTestVisitTargetTwoTimes // Occlusion in |child2| should get merged with the |child| surface we are // leaving now. this->LeaveContributingSurface(child, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1116,10 +1085,10 @@ class OcclusionTrackerTestVisitTargetTwoTimes parent, gfx::Rect(20, 39, 80, 60))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(31, 40, 70, 60))); + parent, gfx::Rect(31, 40, 69, 60))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(30, 41, 70, 60))); + parent, gfx::Rect(30, 41, 70, 59))); /* Justification for the above occlusion from |layer|: 100 @@ -1207,7 +1176,7 @@ class OcclusionTrackerTestSurfaceRotatedOffAxis layer_transform, layer->visible_content_rect()); this->VisitLayer(layer, &occlusion); - this->EnterContributingSurface(child, &occlusion, false); + this->EnterContributingSurface(child, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1215,7 +1184,7 @@ class OcclusionTrackerTestSurfaceRotatedOffAxis occlusion.occlusion_from_inside_target().ToString()); this->LeaveContributingSurface(child, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1276,7 +1245,7 @@ class OcclusionTrackerTestSurfaceWithTwoOpaqueChildren this->VisitLayer(layer2, &occlusion); this->VisitLayer(layer1, &occlusion); this->VisitLayer(child, &occlusion); - this->EnterContributingSurface(child, &occlusion, false); + this->EnterContributingSurface(child, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1285,31 +1254,23 @@ class OcclusionTrackerTestSurfaceWithTwoOpaqueChildren EXPECT_TRUE(occlusion.OccludedLayer(child, gfx::Rect(10, 430, 60, 70))); EXPECT_FALSE(occlusion.OccludedLayer(child, gfx::Rect(9, 430, 60, 70))); - // These rects are occluded except for the part outside the bounds of the - // target surface. - EXPECT_TRUE(occlusion.OccludedLayer(child, gfx::Rect(10, 429, 60, 70))); - EXPECT_TRUE(occlusion.OccludedLayer(child, gfx::Rect(11, 430, 60, 70))); - EXPECT_TRUE(occlusion.OccludedLayer(child, gfx::Rect(10, 431, 60, 70))); + EXPECT_TRUE(occlusion.OccludedLayer(child, gfx::Rect(11, 430, 59, 70))); + EXPECT_TRUE(occlusion.OccludedLayer(child, gfx::Rect(10, 431, 60, 69))); EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( child, gfx::Rect(10, 430, 60, 70)).IsEmpty()); EXPECT_RECT_EQ( gfx::Rect(9, 430, 1, 70), occlusion.UnoccludedLayerContentRect(child, gfx::Rect(9, 430, 60, 70))); - // These rects are occluded except for the part outside the bounds of the - // target surface. EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - child, gfx::Rect(10, 429, 60, 70))); + child, gfx::Rect(11, 430, 59, 70))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - child, gfx::Rect(11, 430, 60, 70))); - EXPECT_RECT_EQ(gfx::Rect(), - occlusion.UnoccludedLayerContentRect( - child, gfx::Rect(10, 431, 60, 70))); + child, gfx::Rect(10, 431, 60, 69))); this->LeaveContributingSurface(child, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1330,10 +1291,10 @@ class OcclusionTrackerTestSurfaceWithTwoOpaqueChildren parent, gfx::Rect(30, 39, 70, 60))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(31, 40, 70, 60))); + parent, gfx::Rect(31, 40, 69, 60))); EXPECT_RECT_EQ(gfx::Rect(), occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(30, 41, 70, 60))); + parent, gfx::Rect(30, 41, 70, 59))); /* Justification for the above occlusion from |layer1| and |layer2|: @@ -1402,27 +1363,21 @@ class OcclusionTrackerTestOverlappingSurfaceSiblings gfx::Rect(0, 0, 1000, 1000)); this->VisitLayer(layer2, &occlusion); - this->EnterContributingSurface(child2, &occlusion, false); + this->EnterContributingSurface(child2, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); EXPECT_EQ(gfx::Rect(-10, 420, 70, 80).ToString(), occlusion.occlusion_from_inside_target().ToString()); - EXPECT_TRUE(occlusion.OccludedLayer(child2, gfx::Rect(-10, 420, 70, 80))); - EXPECT_TRUE(occlusion.OccludedLayer(child2, gfx::Rect(-11, 420, 70, 80))); - EXPECT_TRUE(occlusion.OccludedLayer(child2, gfx::Rect(-10, 419, 70, 80))); - EXPECT_TRUE(occlusion.OccludedLayer(child2, gfx::Rect(-10, 420, 71, 80))); - EXPECT_TRUE(occlusion.OccludedLayer(child2, gfx::Rect(-10, 420, 70, 81))); - // There is nothing above child2's surface in the z-order. EXPECT_RECT_EQ(gfx::Rect(-10, 420, 70, 80), occlusion.UnoccludedContributingSurfaceContentRect( - child2, false, gfx::Rect(-10, 420, 70, 80), NULL)); + child2, false, gfx::Rect(-10, 420, 70, 80))); this->LeaveContributingSurface(child2, &occlusion); this->VisitLayer(layer1, &occlusion); - this->EnterContributingSurface(child1, &occlusion, false); + this->EnterContributingSurface(child1, &occlusion); EXPECT_EQ(gfx::Rect(0, 430, 70, 80).ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1432,10 +1387,10 @@ class OcclusionTrackerTestOverlappingSurfaceSiblings // child2's contents will occlude child1 below it. EXPECT_RECT_EQ(gfx::Rect(-10, 430, 10, 70), occlusion.UnoccludedContributingSurfaceContentRect( - child1, false, gfx::Rect(-10, 430, 80, 70), NULL)); + child1, false, gfx::Rect(-10, 430, 80, 70))); this->LeaveContributingSurface(child1, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1529,7 +1484,7 @@ class OcclusionTrackerTestOverlappingSurfaceSiblingsWithTwoTransforms gfx::Rect(0, 0, 1000, 1000)); this->VisitLayer(layer2, &occlusion); - this->EnterLayer(child2, &occlusion, false); + this->EnterLayer(child2, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1537,16 +1492,16 @@ class OcclusionTrackerTestOverlappingSurfaceSiblingsWithTwoTransforms occlusion.occlusion_from_inside_target().ToString()); this->LeaveLayer(child2, &occlusion); - this->EnterContributingSurface(child2, &occlusion, false); + this->EnterContributingSurface(child2, &occlusion); // There is nothing above child2's surface in the z-order. EXPECT_RECT_EQ(gfx::Rect(-10, 420, 70, 80), occlusion.UnoccludedContributingSurfaceContentRect( - child2, false, gfx::Rect(-10, 420, 70, 80), NULL)); + child2, false, gfx::Rect(-10, 420, 70, 80))); this->LeaveContributingSurface(child2, &occlusion); this->VisitLayer(layer1, &occlusion); - this->EnterContributingSurface(child1, &occlusion, false); + this->EnterContributingSurface(child1, &occlusion); EXPECT_EQ(gfx::Rect(420, -10, 70, 80).ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1556,16 +1511,16 @@ class OcclusionTrackerTestOverlappingSurfaceSiblingsWithTwoTransforms // child2's contents will occlude child1 below it. EXPECT_RECT_EQ(gfx::Rect(420, -20, 80, 90), occlusion.UnoccludedContributingSurfaceContentRect( - child1, false, gfx::Rect(420, -20, 80, 90), NULL)); + child1, false, gfx::Rect(420, -20, 80, 90))); EXPECT_RECT_EQ(gfx::Rect(490, -10, 10, 80), occlusion.UnoccludedContributingSurfaceContentRect( - child1, false, gfx::Rect(420, -10, 80, 90), NULL)); + child1, false, gfx::Rect(420, -10, 80, 90))); EXPECT_RECT_EQ(gfx::Rect(420, -20, 70, 10), occlusion.UnoccludedContributingSurfaceContentRect( - child1, false, gfx::Rect(420, -20, 70, 90), NULL)); + child1, false, gfx::Rect(420, -20, 70, 90))); this->LeaveContributingSurface(child1, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -1654,7 +1609,7 @@ class OcclusionTrackerTestFilters : public OcclusionTrackerTest<Types> { // Opacity layer won't contribute to occlusion. this->VisitLayer(opacity_layer, &occlusion); - this->EnterContributingSurface(opacity_layer, &occlusion, false); + this->EnterContributingSurface(opacity_layer, &occlusion); EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty()); EXPECT_TRUE(occlusion.occlusion_from_inside_target().IsEmpty()); @@ -1666,7 +1621,7 @@ class OcclusionTrackerTestFilters : public OcclusionTrackerTest<Types> { // Opaque layer will contribute to occlusion. this->VisitLayer(opaque_layer, &occlusion); - this->EnterContributingSurface(opaque_layer, &occlusion, false); + this->EnterContributingSurface(opaque_layer, &occlusion); EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty()); EXPECT_EQ(gfx::Rect(0, 430, 70, 70).ToString(), @@ -1680,19 +1635,19 @@ class OcclusionTrackerTestFilters : public OcclusionTrackerTest<Types> { // The blur layer needs to throw away any occlusion from outside its // subtree. - this->EnterLayer(blur_layer, &occlusion, false); + this->EnterLayer(blur_layer, &occlusion); EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty()); EXPECT_TRUE(occlusion.occlusion_from_inside_target().IsEmpty()); // And it won't contribute to occlusion. this->LeaveLayer(blur_layer, &occlusion); - this->EnterContributingSurface(blur_layer, &occlusion, false); + this->EnterContributingSurface(blur_layer, &occlusion); EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty()); EXPECT_TRUE(occlusion.occlusion_from_inside_target().IsEmpty()); // But the opaque layer's occlusion is preserved on the parent. this->LeaveContributingSurface(blur_layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty()); EXPECT_EQ(gfx::Rect(30, 30, 70, 70).ToString(), occlusion.occlusion_from_inside_target().ToString()); @@ -1730,7 +1685,7 @@ class OcclusionTrackerTestReplicaDoesOcclude occlusion.occlusion_from_inside_target().ToString()); this->VisitContributingSurface(surface, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); // The surface and replica should both be occluding the parent. EXPECT_EQ( @@ -1772,7 +1727,7 @@ class OcclusionTrackerTestReplicaWithClipping occlusion.occlusion_from_inside_target().ToString()); this->VisitContributingSurface(surface, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); // The surface and replica should both be occluding the parent. EXPECT_EQ( @@ -1813,7 +1768,7 @@ class OcclusionTrackerTestReplicaWithMask : public OcclusionTrackerTest<Types> { occlusion.occlusion_from_inside_target().ToString()); this->VisitContributingSurface(surface, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); // The replica should not be occluding the parent, since it has a mask // applied to it. @@ -1825,429 +1780,6 @@ class OcclusionTrackerTestReplicaWithMask : public OcclusionTrackerTest<Types> { ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestReplicaWithMask); template <class Types> -class OcclusionTrackerTestLayerClipRectOutsideChild - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestLayerClipRectOutsideChild(bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 300)); - typename Types::ContentLayerType* clip = - this->CreateDrawingLayer(parent, - this->identity_matrix, - gfx::PointF(200.f, 100.f), - gfx::Size(100, 100), - false); - clip->SetMasksToBounds(true); - typename Types::ContentLayerType* layer = - this->CreateDrawingLayer(clip, - this->identity_matrix, - gfx::PointF(-200.f, -100.f), - gfx::Size(200, 200), - false); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(0, 0, 1000, 1000)); - - this->EnterLayer(layer, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(100, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(100, 100, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(200, 100, 100, 100))); - - this->LeaveLayer(layer, &occlusion); - this->EnterLayer(clip, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(-100, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(0, -100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(100, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(0, 100, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(clip, gfx::Rect(0, 0, 100, 100))); - - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - occlusion.UnoccludedLayerContentRect( - clip, gfx::Rect(-100, -100, 300, 300))); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestLayerClipRectOutsideChild); - -template <class Types> -class OcclusionTrackerTestViewportRectOutsideChild - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestViewportRectOutsideChild(bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 300)); - typename Types::ContentLayerType* layer = - this->CreateDrawingSurface(parent, - this->identity_matrix, - gfx::PointF(), - gfx::Size(200, 200), - true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(200, 100, 100, 100)); - - this->EnterLayer(layer, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(100, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(100, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(200, 100, 100, 100))); - - this->LeaveLayer(layer, &occlusion); - this->VisitContributingSurface(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(100, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 100, 100, 100))); - EXPECT_FALSE( - occlusion.OccludedLayer(parent, gfx::Rect(200, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(200, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 200, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(100, 200, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(200, 200, 100, 100))); - - EXPECT_RECT_EQ(gfx::Rect(200, 100, 100, 100), - occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(0, 0, 300, 300))); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestViewportRectOutsideChild); - -template <class Types> -class OcclusionTrackerTestLayerClipRectOverChild - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestLayerClipRectOverChild(bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 300)); - typename Types::ContentLayerType* clip = - this->CreateDrawingLayer(parent, - this->identity_matrix, - gfx::PointF(100.f, 100.f), - gfx::Size(100, 100), - false); - clip->SetMasksToBounds(true); - typename Types::ContentLayerType* layer = - this->CreateDrawingSurface(clip, - this->identity_matrix, - gfx::PointF(-100.f, -100.f), - gfx::Size(200, 200), - true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(0, 0, 1000, 1000)); - - this->EnterLayer(layer, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(100, 0, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(100, 100, 100, 100))); - - this->LeaveLayer(layer, &occlusion); - this->VisitContributingSurface(layer, &occlusion); - - EXPECT_EQ(gfx::Rect(100, 100, 100, 100).ToString(), - occlusion.occlusion_from_inside_target().ToString()); - - this->EnterLayer(clip, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(0, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(100, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(100, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(200, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(200, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(0, 200, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(100, 200, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(clip, gfx::Rect(200, 200, 100, 100))); - - EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - clip, gfx::Rect(0, 0, 300, 300)).IsEmpty()); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestLayerClipRectOverChild); - -template <class Types> -class OcclusionTrackerTestViewportRectOverChild - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestViewportRectOverChild(bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 300)); - typename Types::ContentLayerType* layer = - this->CreateDrawingSurface(parent, - this->identity_matrix, - gfx::PointF(), - gfx::Size(200, 200), - true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(100, 100, 100, 100)); - - this->EnterLayer(layer, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(100, 0, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(100, 100, 100, 100))); - - this->LeaveLayer(layer, &occlusion); - this->VisitContributingSurface(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(100, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(100, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(200, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(200, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 200, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(100, 200, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(200, 200, 100, 100))); - - EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(0, 0, 300, 300)).IsEmpty()); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestViewportRectOverChild); - -template <class Types> -class OcclusionTrackerTestLayerClipRectPartlyOverChild - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestLayerClipRectPartlyOverChild(bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 300)); - typename Types::ContentLayerType* clip = - this->CreateDrawingLayer(parent, - this->identity_matrix, - gfx::PointF(50.f, 50.f), - gfx::Size(200, 200), - false); - clip->SetMasksToBounds(true); - typename Types::ContentLayerType* layer = - this->CreateDrawingSurface(clip, - this->identity_matrix, - gfx::PointF(-50.f, -50.f), - gfx::Size(200, 200), - true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(0, 0, 1000, 1000)); - - this->EnterLayer(layer, &occlusion, false); - - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(0, 100, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(100, 0, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(100, 100, 100, 100))); - - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 100, 50))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 50, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(100, 0, 100, 50))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 100, 50, 100))); - - this->LeaveLayer(layer, &occlusion); - this->VisitContributingSurface(layer, &occlusion); - this->EnterLayer(clip, &occlusion, false); - - EXPECT_EQ(gfx::Rect(50, 50, 150, 150).ToString(), - occlusion.occlusion_from_inside_target().ToString()); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestLayerClipRectPartlyOverChild); - -template <class Types> -class OcclusionTrackerTestViewportRectPartlyOverChild - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestViewportRectPartlyOverChild(bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 300)); - typename Types::ContentLayerType* layer = - this->CreateDrawingSurface(parent, - this->identity_matrix, - gfx::PointF(), - gfx::Size(200, 200), - true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(50, 50, 200, 200)); - - this->EnterLayer(layer, &occlusion, false); - - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(0, 100, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(100, 0, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(100, 100, 100, 100))); - - this->LeaveLayer(layer, &occlusion); - this->VisitContributingSurface(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(100, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(100, 100, 100, 100))); - EXPECT_FALSE( - occlusion.OccludedLayer(parent, gfx::Rect(200, 100, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(parent, gfx::Rect(200, 0, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(parent, gfx::Rect(0, 200, 100, 100))); - EXPECT_FALSE( - occlusion.OccludedLayer(parent, gfx::Rect(100, 200, 100, 100))); - EXPECT_FALSE( - occlusion.OccludedLayer(parent, gfx::Rect(200, 200, 100, 100))); - - EXPECT_RECT_EQ(gfx::Rect(50, 50, 200, 200), - occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(0, 0, 300, 300))); - EXPECT_RECT_EQ(gfx::Rect(200, 50, 50, 50), - occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(0, 0, 300, 100))); - EXPECT_RECT_EQ(gfx::Rect(200, 100, 50, 100), - occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(0, 100, 300, 100))); - EXPECT_RECT_EQ(gfx::Rect(200, 100, 50, 100), - occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(200, 100, 100, 100))); - EXPECT_RECT_EQ(gfx::Rect(100, 200, 100, 50), - occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(100, 200, 100, 100))); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestViewportRectPartlyOverChild); - -template <class Types> -class OcclusionTrackerTestViewportRectOverNothing - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestViewportRectOverNothing(bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 300)); - typename Types::ContentLayerType* layer = - this->CreateDrawingSurface(parent, - this->identity_matrix, - gfx::PointF(), - gfx::Size(200, 200), - true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(500, 500, 100, 100)); - - this->EnterLayer(layer, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(0, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(100, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(100, 100, 100, 100))); - - this->LeaveLayer(layer, &occlusion); - this->VisitContributingSurface(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); - - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(100, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(100, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(200, 100, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(200, 0, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(0, 200, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(100, 200, 100, 100))); - EXPECT_TRUE(occlusion.OccludedLayer(parent, gfx::Rect(200, 200, 100, 100))); - - EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(0, 0, 300, 300)).IsEmpty()); - EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(0, 0, 300, 100)).IsEmpty()); - EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(0, 100, 300, 100)).IsEmpty()); - EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(200, 100, 100, 100)).IsEmpty()); - EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - parent, gfx::Rect(100, 200, 100, 100)).IsEmpty()); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestViewportRectOverNothing); - -template <class Types> -class OcclusionTrackerTestLayerClipRectForLayerOffOrigin - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestLayerClipRectForLayerOffOrigin( - bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 300)); - typename Types::ContentLayerType* layer = - this->CreateDrawingSurface(parent, - this->identity_matrix, - gfx::PointF(), - gfx::Size(200, 200), - true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(0, 0, 1000, 1000)); - this->EnterLayer(layer, &occlusion, false); - - // This layer is translated when drawn into its target. So if the clip rect - // given from the target surface is not in that target space, then after - // translating these query rects into the target, they will fall outside the - // clip and be considered occluded. - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(0, 100, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(100, 0, 100, 100))); - EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(100, 100, 100, 100))); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestLayerClipRectForLayerOffOrigin); - -template <class Types> class OcclusionTrackerTestOpaqueContentsRegionEmpty : public OcclusionTrackerTest<Types> { protected: @@ -2267,19 +1799,16 @@ class OcclusionTrackerTestOpaqueContentsRegionEmpty TestOcclusionTrackerWithClip<typename Types::LayerType, typename Types::RenderSurfaceType> occlusion( gfx::Rect(0, 0, 1000, 1000)); - this->EnterLayer(layer, &occlusion, false); + this->EnterLayer(layer, &occlusion); EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(0, 0, 100, 100))); EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(100, 0, 100, 100))); EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(0, 100, 100, 100))); EXPECT_FALSE(occlusion.OccludedLayer(layer, gfx::Rect(100, 100, 100, 100))); - // Occluded since its outside the surface bounds. - EXPECT_TRUE(occlusion.OccludedLayer(layer, gfx::Rect(200, 100, 100, 100))); - this->LeaveLayer(layer, &occlusion); this->VisitContributingSurface(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty()); } @@ -2311,7 +1840,7 @@ class OcclusionTrackerTestOpaqueContentsRegionNonEmpty this->ResetLayerIterator(); this->VisitLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect(100, 100, 100, 100).ToString(), occlusion.occlusion_from_inside_target().ToString()); @@ -2331,7 +1860,7 @@ class OcclusionTrackerTestOpaqueContentsRegionNonEmpty this->ResetLayerIterator(); this->VisitLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect(120, 120, 180, 180).ToString(), occlusion.occlusion_from_inside_target().ToString()); @@ -2351,7 +1880,7 @@ class OcclusionTrackerTestOpaqueContentsRegionNonEmpty this->ResetLayerIterator(); this->VisitLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect(250, 250, 50, 50).ToString(), occlusion.occlusion_from_inside_target().ToString()); @@ -2392,7 +1921,7 @@ class OcclusionTrackerTest3dTransform : public OcclusionTrackerTest<Types> { TestOcclusionTrackerWithClip<typename Types::LayerType, typename Types::RenderSurfaceType> occlusion( gfx::Rect(0, 0, 1000, 1000)); - this->EnterLayer(layer, &occlusion, false); + this->EnterLayer(layer, &occlusion); // The layer is rotated in 3d but without preserving 3d, so it only gets // resized. @@ -2484,7 +2013,7 @@ class OcclusionTrackerTestPerspectiveTransform TestOcclusionTrackerWithClip<typename Types::LayerType, typename Types::RenderSurfaceType> occlusion( gfx::Rect(0, 0, 1000, 1000)); - this->EnterLayer(layer, &occlusion, false); + this->EnterLayer(layer, &occlusion); EXPECT_RECT_EQ( gfx::Rect(0, 0, 200, 200), @@ -2528,14 +2057,15 @@ class OcclusionTrackerTestPerspectiveTransformBehindCamera TestOcclusionTrackerWithClip<typename Types::LayerType, typename Types::RenderSurfaceType> occlusion( gfx::Rect(0, 0, 1000, 1000)); - this->EnterLayer(layer, &occlusion, false); + this->EnterLayer(layer, &occlusion); // The bottom 11 pixel rows of this layer remain visible inside the // container, after translation to the target surface. When translated back, // this will include many more pixels but must include at least the bottom // 11 rows. EXPECT_TRUE(occlusion.UnoccludedLayerContentRect( - layer, gfx::Rect(0, 0, 500, 500)).Contains(gfx::Rect(0, 489, 500, 11))); + layer, gfx::Rect(0, 26, 500, 474)). + Contains(gfx::Rect(0, 489, 500, 11))); } }; @@ -2572,7 +2102,7 @@ class OcclusionTrackerTestLayerBehindCameraDoesNotOcclude // The |layer| is entirely behind the camera and should not occlude. this->VisitLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_TRUE(occlusion.occlusion_from_inside_target().IsEmpty()); EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty()); } @@ -2614,7 +2144,7 @@ class OcclusionTrackerTestLargePixelsOccludeInsideClipRect // will actually go outside of the layer's clip rect. Ensure that those // pixels don't occlude things outside the clip rect. this->VisitLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), occlusion.occlusion_from_inside_target().ToString()); EXPECT_EQ(gfx::Rect().ToString(), @@ -2696,7 +2226,7 @@ class OcclusionTrackerTestAnimationOpacity1OnMainThread gfx::Rect(0, 0, 1000, 1000)); this->VisitLayer(topmost, &occlusion); - this->EnterLayer(parent2, &occlusion, false); + this->EnterLayer(parent2, &occlusion); // This occlusion will affect all surfaces. EXPECT_EQ(gfx::Rect(250, 0, 50, 300).ToString(), occlusion.occlusion_from_inside_target().ToString()); @@ -2708,7 +2238,7 @@ class OcclusionTrackerTestAnimationOpacity1OnMainThread this->LeaveLayer(parent2, &occlusion); this->VisitLayer(surface_child2, &occlusion); - this->EnterLayer(surface_child, &occlusion, false); + this->EnterLayer(surface_child, &occlusion); EXPECT_EQ(gfx::Rect(0, 0, 100, 300).ToString(), occlusion.occlusion_from_inside_target().ToString()); EXPECT_EQ(gfx::Rect(250, 0, 50, 300).ToString(), @@ -2717,7 +2247,7 @@ class OcclusionTrackerTestAnimationOpacity1OnMainThread occlusion.UnoccludedLayerContentRect( surface_child, gfx::Rect(0, 0, 200, 300))); this->LeaveLayer(surface_child, &occlusion); - this->EnterLayer(surface, &occlusion, false); + this->EnterLayer(surface, &occlusion); EXPECT_EQ(gfx::Rect(0, 0, 200, 300).ToString(), occlusion.occlusion_from_inside_target().ToString()); EXPECT_EQ(gfx::Rect(250, 0, 50, 300).ToString(), @@ -2727,7 +2257,7 @@ class OcclusionTrackerTestAnimationOpacity1OnMainThread surface, gfx::Rect(0, 0, 300, 300))); this->LeaveLayer(surface, &occlusion); - this->EnterContributingSurface(surface, &occlusion, false); + this->EnterContributingSurface(surface, &occlusion); // Occlusion within the surface is lost when leaving the animating surface. EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_inside_target().ToString()); @@ -2735,7 +2265,7 @@ class OcclusionTrackerTestAnimationOpacity1OnMainThread occlusion.occlusion_from_outside_target().ToString()); EXPECT_RECT_EQ(gfx::Rect(0, 0, 250, 300), occlusion.UnoccludedContributingSurfaceContentRect( - surface, false, gfx::Rect(0, 0, 300, 300), NULL)); + surface, false, gfx::Rect(0, 0, 300, 300))); this->LeaveContributingSurface(surface, &occlusion); // Occlusion from outside the animating surface still exists. @@ -2745,7 +2275,7 @@ class OcclusionTrackerTestAnimationOpacity1OnMainThread occlusion.occlusion_from_outside_target().ToString()); this->VisitLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); // Occlusion is not added for the animating |layer|. EXPECT_RECT_EQ(gfx::Rect(0, 0, 250, 300), @@ -2817,7 +2347,7 @@ class OcclusionTrackerTestAnimationOpacity0OnMainThread gfx::Rect(0, 0, 1000, 1000)); this->VisitLayer(topmost, &occlusion); - this->EnterLayer(parent2, &occlusion, false); + this->EnterLayer(parent2, &occlusion); // This occlusion will affect all surfaces. EXPECT_EQ(gfx::Rect(250, 0, 50, 300).ToString(), occlusion.occlusion_from_inside_target().ToString()); @@ -2829,7 +2359,7 @@ class OcclusionTrackerTestAnimationOpacity0OnMainThread this->LeaveLayer(parent2, &occlusion); this->VisitLayer(surface_child2, &occlusion); - this->EnterLayer(surface_child, &occlusion, false); + this->EnterLayer(surface_child, &occlusion); EXPECT_EQ(gfx::Rect(0, 0, 100, 300).ToString(), occlusion.occlusion_from_inside_target().ToString()); EXPECT_EQ(gfx::Rect(250, 0, 50, 300).ToString(), @@ -2838,7 +2368,7 @@ class OcclusionTrackerTestAnimationOpacity0OnMainThread occlusion.UnoccludedLayerContentRect( surface_child, gfx::Rect(0, 0, 200, 300))); this->LeaveLayer(surface_child, &occlusion); - this->EnterLayer(surface, &occlusion, false); + this->EnterLayer(surface, &occlusion); EXPECT_EQ(gfx::Rect(0, 0, 200, 300).ToString(), occlusion.occlusion_from_inside_target().ToString()); EXPECT_EQ(gfx::Rect(250, 0, 50, 300).ToString(), @@ -2848,7 +2378,7 @@ class OcclusionTrackerTestAnimationOpacity0OnMainThread surface, gfx::Rect(0, 0, 300, 300))); this->LeaveLayer(surface, &occlusion); - this->EnterContributingSurface(surface, &occlusion, false); + this->EnterContributingSurface(surface, &occlusion); // Occlusion within the surface is lost when leaving the animating surface. EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_inside_target().ToString()); @@ -2856,7 +2386,7 @@ class OcclusionTrackerTestAnimationOpacity0OnMainThread occlusion.occlusion_from_outside_target().ToString()); EXPECT_RECT_EQ(gfx::Rect(0, 0, 250, 300), occlusion.UnoccludedContributingSurfaceContentRect( - surface, false, gfx::Rect(0, 0, 300, 300), NULL)); + surface, false, gfx::Rect(0, 0, 300, 300))); this->LeaveContributingSurface(surface, &occlusion); // Occlusion from outside the animating surface still exists. @@ -2866,7 +2396,7 @@ class OcclusionTrackerTestAnimationOpacity0OnMainThread occlusion.occlusion_from_outside_target().ToString()); this->VisitLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); // Occlusion is not added for the animating |layer|. EXPECT_RECT_EQ(gfx::Rect(0, 0, 250, 300), @@ -2939,13 +2469,13 @@ class OcclusionTrackerTestAnimationTranslateOnMainThread gfx::Rect(0, 0, 1000, 1000)); this->VisitLayer(surface2, &occlusion); - this->EnterContributingSurface(surface2, &occlusion, false); + this->EnterContributingSurface(surface2, &occlusion); EXPECT_EQ(gfx::Rect(0, 0, 50, 300).ToString(), occlusion.occlusion_from_inside_target().ToString()); this->LeaveContributingSurface(surface2, &occlusion); - this->EnterLayer(surface_child2, &occlusion, false); + this->EnterLayer(surface_child2, &occlusion); // surface_child2 is moving in screen space but not relative to its target, // so occlusion should happen in its target space only. It also means that @@ -2961,7 +2491,7 @@ class OcclusionTrackerTestAnimationTranslateOnMainThread occlusion.OccludedLayer(surface_child, gfx::Rect(0, 0, 50, 300))); this->LeaveLayer(surface_child2, &occlusion); - this->EnterLayer(surface_child, &occlusion, false); + this->EnterLayer(surface_child, &occlusion); EXPECT_FALSE( occlusion.OccludedLayer(surface_child, gfx::Rect(0, 0, 100, 300))); EXPECT_EQ(gfx::Rect().ToString(), @@ -2981,7 +2511,7 @@ class OcclusionTrackerTestAnimationTranslateOnMainThread occlusion.OccludedLayer(surface_child, gfx::Rect(0, 0, 50, 300))); this->LeaveLayer(surface_child, &occlusion); - this->EnterLayer(surface, &occlusion, false); + this->EnterLayer(surface, &occlusion); // The surface_child is moving in screen space but not relative to its // target, so occlusion should happen from within the target only. EXPECT_EQ(gfx::Rect().ToString(), @@ -3003,14 +2533,14 @@ class OcclusionTrackerTestAnimationTranslateOnMainThread occlusion.UnoccludedLayerContentRect( surface, gfx::Rect(0, 0, 300, 300))); - this->EnterContributingSurface(surface, &occlusion, false); + this->EnterContributingSurface(surface, &occlusion); // The contributing |surface| is animating so it can't be occluded. EXPECT_RECT_EQ(gfx::Rect(0, 0, 300, 300), occlusion.UnoccludedContributingSurfaceContentRect( - surface, false, gfx::Rect(0, 0, 300, 300), NULL)); + surface, false, gfx::Rect(0, 0, 300, 300))); this->LeaveContributingSurface(surface, &occlusion); - this->EnterLayer(layer, &occlusion, false); + this->EnterLayer(layer, &occlusion); // The |surface| is moving in the screen and in its target, so all occlusion // within the surface is lost when leaving it. EXPECT_RECT_EQ(gfx::Rect(50, 0, 250, 300), @@ -3018,7 +2548,7 @@ class OcclusionTrackerTestAnimationTranslateOnMainThread parent, gfx::Rect(0, 0, 300, 300))); this->LeaveLayer(layer, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); // The |layer| is animating in the screen and in its target, so no occlusion // is added. EXPECT_RECT_EQ(gfx::Rect(50, 0, 250, 300), @@ -3162,17 +2692,18 @@ class OcclusionTrackerTestReplicaOccluded : public OcclusionTrackerTest<Types> { this->VisitLayer(surface, &occlusion); - EXPECT_EQ(gfx::Rect(0, 100, 100, 100).ToString(), + // Render target with replica ignores occlusion from outside. + EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), occlusion.occlusion_from_inside_target().ToString()); - this->EnterContributingSurface(surface, &occlusion, false); + this->EnterContributingSurface(surface, &occlusion); // Surface is not occluded so it shouldn't think it is. EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), occlusion.UnoccludedContributingSurfaceContentRect( - surface, false, gfx::Rect(0, 0, 100, 100), NULL)); + surface, false, gfx::Rect(0, 0, 100, 100))); } }; @@ -3219,20 +2750,21 @@ class OcclusionTrackerTestSurfaceWithReplicaUnoccluded this->VisitLayer(surface, &occlusion); - EXPECT_EQ(gfx::Rect(0, 0, 100, 110).ToString(), + // Render target with replica ignores occlusion from outside. + EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), occlusion.occlusion_from_inside_target().ToString()); - this->EnterContributingSurface(surface, &occlusion, false); + this->EnterContributingSurface(surface, &occlusion); // Surface is occluded, but only the top 10px of the replica. EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), occlusion.UnoccludedContributingSurfaceContentRect( - surface, false, gfx::Rect(0, 0, 100, 100), NULL)); + surface, false, gfx::Rect(0, 0, 100, 100))); EXPECT_RECT_EQ(gfx::Rect(0, 10, 100, 90), occlusion.UnoccludedContributingSurfaceContentRect( - surface, true, gfx::Rect(0, 0, 100, 100), NULL)); + surface, true, gfx::Rect(0, 0, 100, 100))); } }; @@ -3285,21 +2817,21 @@ class OcclusionTrackerTestSurfaceAndReplicaOccludedDifferently this->VisitLayer(surface, &occlusion); - EXPECT_EQ(UnionRegions(gfx::Rect(0, 0, 40, 100), gfx::Rect(0, 100, 50, 100)) - .ToString(), + // Render target with replica ignores occlusion from outside. + EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), occlusion.occlusion_from_inside_target().ToString()); - this->EnterContributingSurface(surface, &occlusion, false); + this->EnterContributingSurface(surface, &occlusion); // Surface and replica are occluded different amounts. EXPECT_RECT_EQ(gfx::Rect(40, 0, 60, 100), occlusion.UnoccludedContributingSurfaceContentRect( - surface, false, gfx::Rect(0, 0, 100, 100), NULL)); + surface, false, gfx::Rect(0, 0, 100, 100))); EXPECT_RECT_EQ(gfx::Rect(50, 0, 50, 100), occlusion.UnoccludedContributingSurfaceContentRect( - surface, true, gfx::Rect(0, 0, 100, 100), NULL)); + surface, true, gfx::Rect(0, 0, 100, 100))); } }; @@ -3362,29 +2894,29 @@ class OcclusionTrackerTestSurfaceChildOfSurface // |surface_child| exercises different code paths as its parent does not // have a clip rect. - this->EnterContributingSurface(surface_child, &occlusion, false); + this->EnterContributingSurface(surface_child, &occlusion); // The surface_child's parent does not have a clip rect as it owns a render // surface. Make sure the unoccluded rect does not get clipped away // inappropriately. EXPECT_RECT_EQ(gfx::Rect(0, 40, 100, 10), occlusion.UnoccludedContributingSurfaceContentRect( - surface_child, false, gfx::Rect(0, 0, 100, 50), NULL)); + surface_child, false, gfx::Rect(0, 0, 100, 50))); this->LeaveContributingSurface(surface_child, &occlusion); // When the surface_child's occlusion is transformed up to its parent, make // sure it is not clipped away inappropriately also. - this->EnterLayer(surface, &occlusion, false); + this->EnterLayer(surface, &occlusion); EXPECT_EQ(gfx::Rect(0, 0, 100, 50).ToString(), occlusion.occlusion_from_outside_target().ToString()); EXPECT_EQ(gfx::Rect(0, 10, 100, 50).ToString(), occlusion.occlusion_from_inside_target().ToString()); this->LeaveLayer(surface, &occlusion); - this->EnterContributingSurface(surface, &occlusion, false); + this->EnterContributingSurface(surface, &occlusion); // The surface's parent does have a clip rect as it is the root layer. EXPECT_RECT_EQ(gfx::Rect(0, 50, 100, 50), occlusion.UnoccludedContributingSurfaceContentRect( - surface, false, gfx::Rect(0, 0, 100, 100), NULL)); + surface, false, gfx::Rect(0, 0, 100, 100))); } }; @@ -3420,12 +2952,12 @@ class OcclusionTrackerTestTopmostSurfaceIsClippedToViewport // The root layer always has a clip rect. So the parent of |surface| has a // clip rect giving the surface itself a clip rect. - this->EnterContributingSurface(surface, &occlusion, false); + this->EnterContributingSurface(surface, &occlusion); // Make sure the parent's clip rect clips the unoccluded region of the // child surface. EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 200), occlusion.UnoccludedContributingSurfaceContentRect( - surface, false, gfx::Rect(0, 0, 100, 300), NULL)); + surface, false, gfx::Rect(0, 0, 100, 300))); } this->ResetLayerIterator(); { @@ -3438,12 +2970,12 @@ class OcclusionTrackerTestTopmostSurfaceIsClippedToViewport // The root layer always has a clip rect. So the parent of |surface| has a // clip rect giving the surface itself a clip rect. - this->EnterContributingSurface(surface, &occlusion, false); + this->EnterContributingSurface(surface, &occlusion); // Make sure the viewport rect clips the unoccluded region of the child // surface. EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), occlusion.UnoccludedContributingSurfaceContentRect( - surface, false, gfx::Rect(0, 0, 100, 300), NULL)); + surface, false, gfx::Rect(0, 0, 100, 300))); } } }; @@ -3508,21 +3040,21 @@ class OcclusionTrackerTestSurfaceChildOfClippingSurface // |surface_child| exercises different code paths as its parent does not // have a clip rect. - this->EnterContributingSurface(surface_child, &occlusion, false); + this->EnterContributingSurface(surface_child, &occlusion); // The surface_child's parent does not have a clip rect as it owns a render // surface. EXPECT_EQ( gfx::Rect(0, 50, 80, 50).ToString(), occlusion.UnoccludedContributingSurfaceContentRect( - surface_child, false, gfx::Rect(0, 0, 100, 100), NULL).ToString()); + surface_child, false, gfx::Rect(0, 0, 100, 100)).ToString()); this->LeaveContributingSurface(surface_child, &occlusion); this->VisitLayer(surface, &occlusion); - this->EnterContributingSurface(surface, &occlusion, false); + this->EnterContributingSurface(surface, &occlusion); // The surface's parent does have a clip rect as it is the root layer. EXPECT_EQ(gfx::Rect(0, 50, 80, 50).ToString(), occlusion.UnoccludedContributingSurfaceContentRect( - surface, false, gfx::Rect(0, 0, 100, 100), NULL).ToString()); + surface, false, gfx::Rect(0, 0, 100, 100)).ToString()); } }; @@ -3539,30 +3071,25 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter gfx::Transform scale_by_half; scale_by_half.Scale(0.5, 0.5); - // Make a surface and its replica, each 50x50, that are completely - // surrounded by opaque layers which are above them in the z-order. The - // surface is scaled to test that the pixel moving is done in the target - // space, where the background filter is applied, but the surface appears at - // 50, 50 and the replica at 200, 50. + // Make a 50x50 filtered surface that is completely surrounded by opaque + // layers which are above it in the z-order. The surface is scaled to test + // that the pixel moving is done in the target space, where the background + // filter is applied. typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 150)); + this->identity_matrix, gfx::PointF(), gfx::Size(200, 150)); typename Types::LayerType* filtered_surface = this->CreateDrawingLayer(parent, scale_by_half, gfx::PointF(50.f, 50.f), gfx::Size(100, 100), false); - this->CreateReplicaLayer(filtered_surface, - this->identity_matrix, - gfx::PointF(300.f, 0.f), - gfx::Size()); typename Types::LayerType* occluding_layer1 = this->CreateDrawingLayer( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(300, 50), true); + parent, this->identity_matrix, gfx::PointF(), gfx::Size(200, 50), true); typename Types::LayerType* occluding_layer2 = this->CreateDrawingLayer(parent, this->identity_matrix, gfx::PointF(0.f, 100.f), - gfx::Size(300, 50), + gfx::Size(200, 50), true); typename Types::LayerType* occluding_layer3 = this->CreateDrawingLayer(parent, @@ -3576,12 +3103,6 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter gfx::PointF(100.f, 50.f), gfx::Size(100, 50), true); - typename Types::LayerType* occluding_layer5 = - this->CreateDrawingLayer(parent, - this->identity_matrix, - gfx::PointF(250.f, 50.f), - gfx::Size(50, 50), - true); // Filters make the layer own a surface. FilterOperations filters; @@ -3602,18 +3123,16 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter // These layers occlude pixels directly beside the filtered_surface. Because // filtered surface blends pixels in a radius, it will need to see some of // the pixels (up to radius far) underneath the occluding layers. - this->VisitLayer(occluding_layer5, &occlusion); this->VisitLayer(occluding_layer4, &occlusion); this->VisitLayer(occluding_layer3, &occlusion); this->VisitLayer(occluding_layer2, &occlusion); this->VisitLayer(occluding_layer1, &occlusion); Region expected_occlusion; - expected_occlusion.Union(gfx::Rect(0, 0, 300, 50)); + expected_occlusion.Union(gfx::Rect(0, 0, 200, 50)); expected_occlusion.Union(gfx::Rect(0, 50, 50, 50)); expected_occlusion.Union(gfx::Rect(100, 50, 100, 50)); - expected_occlusion.Union(gfx::Rect(250, 50, 50, 50)); - expected_occlusion.Union(gfx::Rect(0, 100, 300, 50)); + expected_occlusion.Union(gfx::Rect(0, 100, 200, 50)); EXPECT_EQ(expected_occlusion.ToString(), occlusion.occlusion_from_inside_target().ToString()); @@ -3622,13 +3141,12 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter this->VisitLayer(filtered_surface, &occlusion); - // The filtered layer/replica does not occlude. + // The filtered layer does not occlude. Region expected_occlusion_outside_surface; - expected_occlusion_outside_surface.Union(gfx::Rect(-50, -50, 300, 50)); + expected_occlusion_outside_surface.Union(gfx::Rect(-50, -50, 200, 50)); expected_occlusion_outside_surface.Union(gfx::Rect(-50, 0, 50, 50)); expected_occlusion_outside_surface.Union(gfx::Rect(50, 0, 100, 50)); - expected_occlusion_outside_surface.Union(gfx::Rect(200, 0, 50, 50)); - expected_occlusion_outside_surface.Union(gfx::Rect(-50, 50, 300, 50)); + expected_occlusion_outside_surface.Union(gfx::Rect(-50, 50, 200, 50)); EXPECT_EQ(expected_occlusion_outside_surface.ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -3641,24 +3159,19 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter // are drawn. this->VisitContributingSurface(filtered_surface, &occlusion); - this->EnterLayer(parent, &occlusion, false); + this->EnterLayer(parent, &occlusion); Region expected_blurred_occlusion; - expected_blurred_occlusion.Union(gfx::Rect(0, 0, 300, 50 - outset_top)); + expected_blurred_occlusion.Union(gfx::Rect(0, 0, 200, 50 - outset_top)); expected_blurred_occlusion.Union(gfx::Rect( 0, 50 - outset_top, 50 - outset_left, 50 + outset_top + outset_bottom)); expected_blurred_occlusion.Union( gfx::Rect(100 + outset_right, 50 - outset_top, - 100 - outset_right - outset_left, - 50 + outset_top + outset_bottom)); - expected_blurred_occlusion.Union( - gfx::Rect(250 + outset_right, - 50 - outset_top, - 50 - outset_right, + 100 - outset_right, 50 + outset_top + outset_bottom)); expected_blurred_occlusion.Union( - gfx::Rect(0, 100 + outset_bottom, 300, 50 - outset_bottom)); + gfx::Rect(0, 100 + outset_bottom, 200, 50 - outset_bottom)); EXPECT_EQ(expected_blurred_occlusion.ToString(), occlusion.occlusion_from_inside_target().ToString()); @@ -3699,39 +3212,6 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter EXPECT_EQ( outset_rect.ToString(), occlusion.UnoccludedLayerContentRect(parent, test_rect).ToString()); - - // Nothing in the blur outsets for the filtered_surface's replica is - // occluded. - outset_rect = gfx::Rect(200 - outset_left, - 50 - outset_top, - 50 + outset_left + outset_right, - 50 + outset_top + outset_bottom); - test_rect = outset_rect; - EXPECT_EQ( - outset_rect.ToString(), - occlusion.UnoccludedLayerContentRect(parent, test_rect).ToString()); - - // Stuff outside the blur outsets is still occluded though. - test_rect = outset_rect; - test_rect.Inset(0, 0, -1, 0); - EXPECT_EQ( - outset_rect.ToString(), - occlusion.UnoccludedLayerContentRect(parent, test_rect).ToString()); - test_rect = outset_rect; - test_rect.Inset(0, 0, 0, -1); - EXPECT_EQ( - outset_rect.ToString(), - occlusion.UnoccludedLayerContentRect(parent, test_rect).ToString()); - test_rect = outset_rect; - test_rect.Inset(-1, 0, 0, 0); - EXPECT_EQ( - outset_rect.ToString(), - occlusion.UnoccludedLayerContentRect(parent, test_rect).ToString()); - test_rect = outset_rect; - test_rect.Inset(0, -1, 0, 0); - EXPECT_EQ( - outset_rect.ToString(), - occlusion.UnoccludedLayerContentRect(parent, test_rect).ToString()); } }; @@ -3815,238 +3295,6 @@ ALL_OCCLUSIONTRACKER_TEST( OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice); template <class Types> -class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilterWithClip - : public OcclusionTrackerTest<Types> { - protected: - explicit - OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilterWithClip( - bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - // Make a surface and its replica, Each 50x50, that are completely - // surrounded by opaque layers which are above them in the z-order. - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 150)); - // We stick the filtered surface inside a clipping surface so that we can - // make sure the clip is honored when exposing pixels for - // the background filter. - typename Types::LayerType* clipping_surface = - this->CreateDrawingSurface(parent, - this->identity_matrix, - gfx::PointF(), - gfx::Size(300, 70), - false); - clipping_surface->SetMasksToBounds(true); - typename Types::LayerType* filtered_surface = - this->CreateDrawingLayer(clipping_surface, - this->identity_matrix, - gfx::PointF(50.f, 50.f), - gfx::Size(50, 50), - false); - this->CreateReplicaLayer(filtered_surface, - this->identity_matrix, - gfx::PointF(150.f, 0.f), - gfx::Size()); - typename Types::LayerType* occluding_layer1 = this->CreateDrawingLayer( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(300, 50), true); - typename Types::LayerType* occluding_layer2 = - this->CreateDrawingLayer(parent, - this->identity_matrix, - gfx::PointF(0.f, 100.f), - gfx::Size(300, 50), - true); - typename Types::LayerType* occluding_layer3 = - this->CreateDrawingLayer(parent, - this->identity_matrix, - gfx::PointF(0.f, 50.f), - gfx::Size(50, 50), - true); - typename Types::LayerType* occluding_layer4 = - this->CreateDrawingLayer(parent, - this->identity_matrix, - gfx::PointF(100.f, 50.f), - gfx::Size(100, 50), - true); - typename Types::LayerType* occluding_layer5 = - this->CreateDrawingLayer(parent, - this->identity_matrix, - gfx::PointF(250.f, 50.f), - gfx::Size(50, 50), - true); - - // Filters make the layer own a surface. This filter is large enough that it - // goes outside the bottom of the clipping_surface. - FilterOperations filters; - filters.Append(FilterOperation::CreateBlurFilter(12.f)); - filtered_surface->SetBackgroundFilters(filters); - - // Save the distance of influence for the blur effect. - int outset_top, outset_right, outset_bottom, outset_left; - filters.GetOutsets( - &outset_top, &outset_right, &outset_bottom, &outset_left); - - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(0, 0, 1000, 1000)); - - // These layers occlude pixels directly beside the filtered_surface. Because - // filtered surface blends pixels in a radius, it will need to see some of - // the pixels (up to radius far) underneath the occluding layers. - this->VisitLayer(occluding_layer5, &occlusion); - this->VisitLayer(occluding_layer4, &occlusion); - this->VisitLayer(occluding_layer3, &occlusion); - this->VisitLayer(occluding_layer2, &occlusion); - this->VisitLayer(occluding_layer1, &occlusion); - - Region expected_occlusion; - expected_occlusion.Union(gfx::Rect(0, 0, 300, 50)); - expected_occlusion.Union(gfx::Rect(0, 50, 50, 50)); - expected_occlusion.Union(gfx::Rect(100, 50, 100, 50)); - expected_occlusion.Union(gfx::Rect(250, 50, 50, 50)); - expected_occlusion.Union(gfx::Rect(0, 100, 300, 50)); - - EXPECT_EQ(expected_occlusion.ToString(), - occlusion.occlusion_from_inside_target().ToString()); - EXPECT_EQ(gfx::Rect().ToString(), - occlusion.occlusion_from_outside_target().ToString()); - - // Everything outside the surface/replica is occluded but the - // surface/replica itself is not. - this->VisitLayer(filtered_surface, &occlusion); - - // The filtered layer/replica does not occlude. - Region expected_occlusion_outside_surface; - expected_occlusion_outside_surface.Union(gfx::Rect(-50, -50, 300, 50)); - expected_occlusion_outside_surface.Union(gfx::Rect(-50, 0, 50, 50)); - expected_occlusion_outside_surface.Union(gfx::Rect(50, 0, 100, 50)); - expected_occlusion_outside_surface.Union(gfx::Rect(200, 0, 50, 50)); - expected_occlusion_outside_surface.Union(gfx::Rect(-50, 50, 300, 50)); - - EXPECT_EQ(expected_occlusion_outside_surface.ToString(), - occlusion.occlusion_from_outside_target().ToString()); - EXPECT_EQ(gfx::Rect().ToString(), - occlusion.occlusion_from_inside_target().ToString()); - - // The surface has a background blur, so it needs pixels that are currently - // considered occluded in order to be drawn. So the pixels it needs should - // be removed some the occluded area so that when we get to the parent they - // are drawn. - this->VisitContributingSurface(filtered_surface, &occlusion); - - this->VisitLayer(clipping_surface, &occlusion); - this->EnterContributingSurface(clipping_surface, &occlusion, false); - - Region expected_blurred_occlusion; - expected_blurred_occlusion.Union(gfx::Rect(0, 0, 300, 50 - outset_top)); - expected_blurred_occlusion.Union(gfx::Rect( - 0, 50 - outset_top, 50 - outset_left, 20 + outset_top + outset_bottom)); - expected_blurred_occlusion.Union( - gfx::Rect(100 + outset_right, - 50 - outset_top, - 100 - outset_right - outset_left, - 20 + outset_top + outset_bottom)); - expected_blurred_occlusion.Union( - gfx::Rect(250 + outset_right, - 50 - outset_top, - 50 - outset_right, - 20 + outset_top + outset_bottom)); - expected_blurred_occlusion.Union(gfx::Rect(0, 100 + 5, 300, 50 - 5)); - - EXPECT_EQ(expected_blurred_occlusion.ToString(), - occlusion.occlusion_from_outside_target().ToString()); - EXPECT_EQ(gfx::Rect().ToString(), - occlusion.occlusion_from_inside_target().ToString()); - - gfx::Rect outset_rect; - gfx::Rect clipped_outset_rect; - gfx::Rect test_rect; - - // Nothing in the (clipped) blur outsets for the filtered_surface is - // occluded. - outset_rect = gfx::Rect(50 - outset_left, - 50 - outset_top, - 50 + outset_left + outset_right, - 50 + outset_top + outset_bottom); - clipped_outset_rect = outset_rect; - clipped_outset_rect.Intersect(gfx::Rect(0 - outset_left, - 0 - outset_top, - 300 + outset_left + outset_right, - 70 + outset_top + outset_bottom)); - clipped_outset_rect.Intersect(gfx::Rect(0, 0, 300, 70)); - test_rect = outset_rect; - EXPECT_RECT_EQ( - clipped_outset_rect, - occlusion.UnoccludedLayerContentRect(clipping_surface, test_rect)); - - // Stuff outside the (clipped) blur outsets is still occluded though. - test_rect = outset_rect; - test_rect.Inset(0, 0, -1, 0); - EXPECT_RECT_EQ( - clipped_outset_rect, - occlusion.UnoccludedLayerContentRect(clipping_surface, test_rect)); - test_rect = outset_rect; - test_rect.Inset(0, 0, 0, -1); - EXPECT_RECT_EQ( - clipped_outset_rect, - occlusion.UnoccludedLayerContentRect(clipping_surface, test_rect)); - test_rect = outset_rect; - test_rect.Inset(-1, 0, 0, 0); - EXPECT_RECT_EQ( - clipped_outset_rect, - occlusion.UnoccludedLayerContentRect(clipping_surface, test_rect)); - test_rect = outset_rect; - test_rect.Inset(0, -1, 0, 0); - EXPECT_RECT_EQ( - clipped_outset_rect, - occlusion.UnoccludedLayerContentRect(clipping_surface, test_rect)); - - // Nothing in the (clipped) blur outsets for the filtered_surface's replica - // is occluded. - outset_rect = gfx::Rect(200 - outset_left, - 50 - outset_top, - 50 + outset_left + outset_right, - 50 + outset_top + outset_bottom); - clipped_outset_rect = outset_rect; - clipped_outset_rect.Intersect(gfx::Rect(0 - outset_left, - 0 - outset_top, - 300 + outset_left + outset_right, - 70 + outset_top + outset_bottom)); - clipped_outset_rect.Intersect(gfx::Rect(0, 0, 300, 70)); - test_rect = outset_rect; - EXPECT_RECT_EQ( - clipped_outset_rect, - occlusion.UnoccludedLayerContentRect(clipping_surface, test_rect)); - - // Stuff outside the (clipped) blur outsets is still occluded though. - test_rect = outset_rect; - test_rect.Inset(0, 0, -1, 0); - EXPECT_RECT_EQ( - clipped_outset_rect, - occlusion.UnoccludedLayerContentRect(clipping_surface, test_rect)); - test_rect = outset_rect; - test_rect.Inset(0, 0, 0, -1); - EXPECT_RECT_EQ( - clipped_outset_rect, - occlusion.UnoccludedLayerContentRect(clipping_surface, test_rect)); - test_rect = outset_rect; - test_rect.Inset(-1, 0, 0, 0); - EXPECT_RECT_EQ( - clipped_outset_rect, - occlusion.UnoccludedLayerContentRect(clipping_surface, test_rect)); - test_rect = outset_rect; - test_rect.Inset(0, -1, 0, 0); - EXPECT_RECT_EQ( - clipped_outset_rect, - occlusion.UnoccludedLayerContentRect(clipping_surface, test_rect)); - } -}; - -ALL_OCCLUSIONTRACKER_TEST( - OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilterWithClip); - -template <class Types> class OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter : public OcclusionTrackerTest<Types> { protected: @@ -4135,35 +3383,24 @@ class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded gfx::Transform scale_by_half; scale_by_half.Scale(0.5, 0.5); - // Make a surface and its replica, each 50x50, that are completely occluded - // by opaque layers which are above them in the z-order. The surface is + // Make a 50x50 filtered surface that is completely occluded by an opaque + // layer which is above it in the z-order. The surface is // scaled to test that the pixel moving is done in the target space, where - // the background filter is applied, but the surface appears at 50, 50 and - // the replica at 200, 50. + // the background filter is applied, but the surface appears at 50, 50. typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(300, 150)); + this->identity_matrix, gfx::PointF(), gfx::Size(200, 150)); typename Types::LayerType* filtered_surface = this->CreateDrawingLayer(parent, scale_by_half, gfx::PointF(50.f, 50.f), gfx::Size(100, 100), false); - this->CreateReplicaLayer(filtered_surface, - this->identity_matrix, - gfx::PointF(300.f, 0.f), - gfx::Size()); - typename Types::LayerType* above_surface_layer = + typename Types::LayerType* occluding_layer = this->CreateDrawingLayer(parent, this->identity_matrix, gfx::PointF(50.f, 50.f), gfx::Size(50, 50), true); - typename Types::LayerType* above_replica_layer = - this->CreateDrawingLayer(parent, - this->identity_matrix, - gfx::PointF(200.f, 50.f), - gfx::Size(50, 50), - true); // Filters make the layer own a surface. FilterOperations filters; @@ -4176,20 +3413,16 @@ class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded typename Types::RenderSurfaceType> occlusion( gfx::Rect(0, 0, 1000, 1000)); - this->VisitLayer(above_replica_layer, &occlusion); - this->VisitLayer(above_surface_layer, &occlusion); + this->VisitLayer(occluding_layer, &occlusion); this->VisitLayer(filtered_surface, &occlusion); { // The layers above the filtered surface occlude from outside. gfx::Rect occlusion_above_surface = gfx::Rect(0, 0, 50, 50); - gfx::Rect occlusion_above_replica = gfx::Rect(150, 0, 50, 50); - Region expected_opaque_region = - UnionRegions(occlusion_above_surface, occlusion_above_replica); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_inside_target().ToString()); - EXPECT_EQ(expected_opaque_region.ToString(), + EXPECT_EQ(occlusion_above_surface.ToString(), occlusion.occlusion_from_outside_target().ToString()); } @@ -4200,11 +3433,8 @@ class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded // The filter is completely occluded, so it should not blur anything and // reduce any occlusion. gfx::Rect occlusion_above_surface = gfx::Rect(50, 50, 50, 50); - gfx::Rect occlusion_above_replica = gfx::Rect(200, 50, 50, 50); - Region expected_opaque_region = - UnionRegions(occlusion_above_surface, occlusion_above_replica); - EXPECT_EQ(expected_opaque_region.ToString(), + EXPECT_EQ(occlusion_above_surface.ToString(), occlusion.occlusion_from_inside_target().ToString()); EXPECT_EQ(gfx::Rect().ToString(), occlusion.occlusion_from_outside_target().ToString()); @@ -4381,379 +3611,6 @@ class OcclusionTrackerTestMinimumTrackingSize ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestMinimumTrackingSize); template <class Types> -class OcclusionTrackerTestViewportClipIsExternalOcclusion - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestViewportClipIsExternalOcclusion( - bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(400, 400)); - typename Types::LayerType* small = - this->CreateDrawingSurface(parent, - this->identity_matrix, - gfx::PointF(), - gfx::Size(200, 200), - false); - typename Types::LayerType* large = - this->CreateDrawingLayer(small, - this->identity_matrix, - gfx::PointF(), - gfx::Size(400, 400), - false); - small->SetMasksToBounds(true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(0, 0, 100, 100)); - - this->EnterLayer(large, &occlusion, false); - - bool has_occlusion_from_outside_target_surface = false; - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - occlusion.UnoccludedLayerContentRect( - large, - gfx::Rect(0, 0, 400, 400), - &has_occlusion_from_outside_target_surface)); - EXPECT_TRUE(has_occlusion_from_outside_target_surface); - - has_occlusion_from_outside_target_surface = false; - EXPECT_FALSE( - occlusion.OccludedLayer(large, - gfx::Rect(0, 0, 400, 400), - &has_occlusion_from_outside_target_surface)); - EXPECT_TRUE(has_occlusion_from_outside_target_surface); - - this->LeaveLayer(large, &occlusion); - this->VisitLayer(small, &occlusion); - - has_occlusion_from_outside_target_surface = false; - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - occlusion.UnoccludedLayerContentRect( - small, - gfx::Rect(0, 0, 200, 200), - &has_occlusion_from_outside_target_surface)); - EXPECT_TRUE(has_occlusion_from_outside_target_surface); - - has_occlusion_from_outside_target_surface = false; - EXPECT_FALSE( - occlusion.OccludedLayer(small, - gfx::Rect(0, 0, 200, 200), - &has_occlusion_from_outside_target_surface)); - EXPECT_TRUE(has_occlusion_from_outside_target_surface); - - this->EnterContributingSurface(small, &occlusion, false); - - has_occlusion_from_outside_target_surface = false; - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - occlusion.UnoccludedContributingSurfaceContentRect( - small, - false, - gfx::Rect(0, 0, 200, 200), - &has_occlusion_from_outside_target_surface)); - EXPECT_TRUE(has_occlusion_from_outside_target_surface); - } -}; - -ALL_OCCLUSIONTRACKER_TEST( - OcclusionTrackerTestViewportClipIsExternalOcclusion) - -template <class Types> -class OcclusionTrackerTestLayerClipIsExternalOcclusion - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestLayerClipIsExternalOcclusion(bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(400, 400)); - typename Types::LayerType* smallest = this->CreateDrawingLayer( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(50, 50), false); - typename Types::LayerType* smaller = - this->CreateDrawingSurface(smallest, - this->identity_matrix, - gfx::PointF(), - gfx::Size(100, 100), - false); - typename Types::LayerType* small = - this->CreateDrawingSurface(smaller, - this->identity_matrix, - gfx::PointF(), - gfx::Size(200, 200), - false); - typename Types::LayerType* large = - this->CreateDrawingLayer(small, - this->identity_matrix, - gfx::PointF(), - gfx::Size(400, 400), - false); - smallest->SetMasksToBounds(true); - smaller->SetMasksToBounds(true); - small->SetMasksToBounds(true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(0, 0, 1000, 1000)); - - this->EnterLayer(large, &occlusion, false); - - // Clipping from the smaller layer is from outside the target surface. - bool has_occlusion_from_outside_target_surface = false; - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - occlusion.UnoccludedLayerContentRect( - large, - gfx::Rect(0, 0, 400, 400), - &has_occlusion_from_outside_target_surface)); - EXPECT_TRUE(has_occlusion_from_outside_target_surface); - - has_occlusion_from_outside_target_surface = false; - EXPECT_FALSE( - occlusion.OccludedLayer(large, - gfx::Rect(0, 0, 400, 400), - &has_occlusion_from_outside_target_surface)); - EXPECT_TRUE(has_occlusion_from_outside_target_surface); - - this->LeaveLayer(large, &occlusion); - this->VisitLayer(small, &occlusion); - - // Clipping from the smaller layer is from outside the target surface. - has_occlusion_from_outside_target_surface = false; - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - occlusion.UnoccludedLayerContentRect( - small, - gfx::Rect(0, 0, 200, 200), - &has_occlusion_from_outside_target_surface)); - EXPECT_TRUE(has_occlusion_from_outside_target_surface); - - has_occlusion_from_outside_target_surface = false; - EXPECT_FALSE( - occlusion.OccludedLayer(small, - gfx::Rect(0, 0, 200, 200), - &has_occlusion_from_outside_target_surface)); - EXPECT_TRUE(has_occlusion_from_outside_target_surface); - - this->EnterContributingSurface(small, &occlusion, false); - - // The |small| surface is clipped from outside its target by |smallest|. - has_occlusion_from_outside_target_surface = false; - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), - occlusion.UnoccludedContributingSurfaceContentRect( - small, - false, - gfx::Rect(0, 0, 200, 200), - &has_occlusion_from_outside_target_surface)); - EXPECT_TRUE(has_occlusion_from_outside_target_surface); - - this->LeaveContributingSurface(small, &occlusion); - this->VisitLayer(smaller, &occlusion); - this->EnterContributingSurface(smaller, &occlusion, false); - - // The |smaller| surface is clipped from inside its target by |smallest|. - has_occlusion_from_outside_target_surface = false; - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), - occlusion.UnoccludedContributingSurfaceContentRect( - smaller, - false, - gfx::Rect(0, 0, 100, 100), - &has_occlusion_from_outside_target_surface)); - EXPECT_FALSE(has_occlusion_from_outside_target_surface); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestLayerClipIsExternalOcclusion) - -template <class Types> -class OcclusionTrackerTestPreventOcclusionOnLayer - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestPreventOcclusionOnLayer(bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(400, 400)); - typename Types::LayerType* unprevented = this->CreateDrawingLayer( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(50, 50), false); - typename Types::LayerType* prevented = this->CreateDrawingLayer( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(50, 50), false); - typename Types::LayerType* occluding = this->CreateDrawingLayer( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(50, 50), true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(0, 0, 1000, 1000)); - bool external_occlusion = false; - - this->VisitLayer(occluding, &occlusion); - this->EnterLayer(prevented, &occlusion, true); - - // This layer is not occluded because it is prevented. - EXPECT_FALSE(occlusion.OccludedLayer(prevented, - gfx::Rect(50, 50), - &external_occlusion)); - EXPECT_FALSE(external_occlusion); - - EXPECT_EQ(gfx::Rect(50, 50).ToString(), - occlusion.UnoccludedLayerContentRect( - prevented, - gfx::Rect(50, 50), - &external_occlusion).ToString()); - EXPECT_FALSE(external_occlusion); - - this->LeaveLayer(prevented, &occlusion); - this->EnterLayer(unprevented, &occlusion, false); - - // This layer is fully occluded. - EXPECT_TRUE(occlusion.OccludedLayer(unprevented, - gfx::Rect(50, 50), - &external_occlusion)); - EXPECT_FALSE(external_occlusion); - - EXPECT_EQ(gfx::Rect().ToString(), - occlusion.UnoccludedLayerContentRect( - unprevented, - gfx::Rect(50, 50), - &external_occlusion).ToString()); - EXPECT_FALSE(external_occlusion); - - this->LeaveLayer(unprevented, &occlusion); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestPreventOcclusionOnLayer) - -template <class Types> -class OcclusionTrackerTestPreventOcclusionOnContributingSurface - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestPreventOcclusionOnContributingSurface( - bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(400, 400)); - typename Types::LayerType* unprevented = this->CreateDrawingSurface( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(50, 50), false); - typename Types::LayerType* prevented = this->CreateDrawingSurface( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(50, 50), false); - typename Types::LayerType* occluding = this->CreateDrawingLayer( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(50, 50), true); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(0, 0, 1000, 1000)); - bool external_occlusion = false; - - this->VisitLayer(occluding, &occlusion); - this->EnterLayer(prevented, &occlusion, true); - - // This layer is not occluded because it is prevented. - EXPECT_EQ(gfx::Rect(50, 50).ToString(), - occlusion.UnoccludedLayerContentRect( - prevented, - gfx::Rect(50, 50), - &external_occlusion).ToString()); - EXPECT_FALSE(external_occlusion); - - this->LeaveLayer(prevented, &occlusion); - this->EnterContributingSurface(prevented, &occlusion, true); - - // This contributing surface is not occluded because it is prevented. - EXPECT_EQ(gfx::Rect(50, 50).ToString(), - occlusion.UnoccludedContributingSurfaceContentRect( - prevented, - false, // is_replica - gfx::Rect(50, 50), - &external_occlusion).ToString()); - EXPECT_FALSE(external_occlusion); - - this->LeaveContributingSurface(prevented, &occlusion); - this->EnterLayer(unprevented, &occlusion, false); - - // This layer is fully occluded from outside its surface. - EXPECT_EQ(gfx::Rect().ToString(), - occlusion.UnoccludedLayerContentRect( - unprevented, - gfx::Rect(50, 50), - &external_occlusion).ToString()); - EXPECT_TRUE(external_occlusion); - - this->LeaveLayer(unprevented, &occlusion); - this->EnterContributingSurface(unprevented, &occlusion, false); - - // This contributing surface is fully occluded. - EXPECT_EQ(gfx::Rect().ToString(), - occlusion.UnoccludedContributingSurfaceContentRect( - unprevented, - false, // is_replica - gfx::Rect(50, 50), - &external_occlusion).ToString()); - EXPECT_FALSE(external_occlusion); - - this->LeaveContributingSurface(unprevented, &occlusion); - } -}; - -ALL_OCCLUSIONTRACKER_TEST( - OcclusionTrackerTestPreventOcclusionOnContributingSurface) - -template <class Types> -class OcclusionTrackerTestPreventOcclusionByClipping - : public OcclusionTrackerTest<Types> { - protected: - explicit OcclusionTrackerTestPreventOcclusionByClipping(bool opaque_layers) - : OcclusionTrackerTest<Types>(opaque_layers) {} - void RunMyTest() { - typename Types::ContentLayerType* parent = this->CreateRoot( - this->identity_matrix, gfx::PointF(), gfx::Size(400, 400)); - typename Types::LayerType* unprevented = this->CreateDrawingLayer( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(50, 50), false); - typename Types::LayerType* prevented = this->CreateDrawingLayer( - parent, this->identity_matrix, gfx::PointF(), gfx::Size(50, 50), false); - this->CalcDrawEtc(parent); - - TestOcclusionTrackerWithClip<typename Types::LayerType, - typename Types::RenderSurfaceType> occlusion( - gfx::Rect(0, 0, 10, 10)); - bool external_occlusion = false; - - this->EnterLayer(prevented, &occlusion, true); - - // This layer is not occluded because it is prevented. - EXPECT_FALSE(occlusion.OccludedLayer(prevented, - gfx::Rect(50, 50), - &external_occlusion)); - EXPECT_FALSE(external_occlusion); - - EXPECT_EQ(gfx::Rect(50, 50).ToString(), - occlusion.UnoccludedLayerContentRect( - prevented, - gfx::Rect(50, 50), - &external_occlusion).ToString()); - EXPECT_FALSE(external_occlusion); - - this->LeaveLayer(prevented, &occlusion); - this->EnterLayer(unprevented, &occlusion, false); - - // This layer is clipped by the screen space clip rect. - EXPECT_EQ(gfx::Rect(10, 10).ToString(), - occlusion.UnoccludedLayerContentRect( - unprevented, - gfx::Rect(50, 50), - &external_occlusion).ToString()); - EXPECT_TRUE(external_occlusion); - - this->LeaveLayer(unprevented, &occlusion); - } -}; - -ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestPreventOcclusionByClipping) - -template <class Types> class OcclusionTrackerTestScaledLayerIsClipped : public OcclusionTrackerTest<Types> { protected: @@ -4929,5 +3786,37 @@ class OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude) +template <class Types> +class OcclusionTrackerTestEmptyEventLayerDoesNotOcclude + : public OcclusionTrackerTest<Types> { + protected: + explicit OcclusionTrackerTestEmptyEventLayerDoesNotOcclude( + bool opaque_layers) + : OcclusionTrackerTest<Types>(opaque_layers) {} + void RunMyTest() { + typename Types::ContentLayerType* root = this->CreateRoot( + this->identity_matrix, gfx::Point(), gfx::Size(400, 400)); + typename Types::ContentLayerType* empty_layer = this->CreateDrawingLayer( + root, this->identity_matrix, gfx::Point(), gfx::Size(200, 200), true); + this->SetDrawsContent(empty_layer, false); + empty_layer->SetTouchEventHandlerRegion(gfx::Rect(10, 10, 10, 10)); + + this->CalcDrawEtc(root); + + TestOcclusionTrackerWithClip<typename Types::LayerType, + typename Types::RenderSurfaceType> occlusion( + gfx::Rect(0, 0, 1000, 1000), false); + + this->VisitLayer(empty_layer, &occlusion); + + EXPECT_EQ(gfx::Rect().ToString(), + occlusion.occlusion_from_outside_target().ToString()); + EXPECT_EQ(gfx::Rect().ToString(), + occlusion.occlusion_from_inside_target().ToString()); + } +}; + +ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestEmptyEventLayerDoesNotOcclude) + } // namespace } // namespace cc diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h index 84844c89497..69975a6dd7f 100644 --- a/chromium/cc/trees/proxy.h +++ b/chromium/cc/trees/proxy.h @@ -81,6 +81,7 @@ class CC_EXPORT Proxy { virtual void MainThreadHasStoppedFlinging() = 0; virtual bool CommitRequested() const = 0; + virtual bool BeginMainFrameRequested() const = 0; // Must be called before using the proxy. virtual void Start(scoped_ptr<OutputSurface> first_output_surface) = 0; diff --git a/chromium/cc/trees/quad_culler.cc b/chromium/cc/trees/quad_culler.cc index 760c79dad8d..2fc8aaa6caa 100644 --- a/chromium/cc/trees/quad_culler.cc +++ b/chromium/cc/trees/quad_culler.cc @@ -84,29 +84,19 @@ bool QuadCuller::Append(scoped_ptr<DrawQuad> draw_quad, DCHECK(shared_quad_state_list_->back() == current_shared_quad_state_); gfx::Rect culled_rect; - bool has_occlusion_from_outside_target_surface; bool impl_draw_transform_is_unknown = false; if (for_surface_) { culled_rect = occlusion_tracker_.UnoccludedContributingSurfaceContentRect( - layer_, - false, - draw_quad->rect, - &has_occlusion_from_outside_target_surface); + layer_, false, draw_quad->visible_rect); } else { culled_rect = occlusion_tracker_.UnoccludedContentRect( layer_->render_target(), - draw_quad->rect, + draw_quad->visible_rect, draw_quad->quadTransform(), - impl_draw_transform_is_unknown, - draw_quad->isClipped(), - draw_quad->clipRect(), - &has_occlusion_from_outside_target_surface); + impl_draw_transform_is_unknown); } - append_quads_data->had_occlusion_from_outside_target_surface |= - has_occlusion_from_outside_target_surface; - return AppendQuadInternal(draw_quad.Pass(), culled_rect, quad_list_, diff --git a/chromium/cc/trees/quad_culler_unittest.cc b/chromium/cc/trees/quad_culler_unittest.cc index 120e0072087..c07a0a79e04 100644 --- a/chromium/cc/trees/quad_culler_unittest.cc +++ b/chromium/cc/trees/quad_culler_unittest.cc @@ -11,10 +11,13 @@ #include "cc/layers/append_quads_data.h" #include "cc/layers/render_surface_impl.h" #include "cc/layers/tiled_layer_impl.h" +#include "cc/quads/render_pass_draw_quad.h" +#include "cc/quads/solid_color_draw_quad.h" #include "cc/quads/tile_draw_quad.h" #include "cc/resources/layer_tiling_data.h" #include "cc/test/fake_impl_proxy.h" #include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/occlusion_tracker_test_common.h" #include "cc/trees/occlusion_tracker.h" #include "cc/trees/single_thread_proxy.h" #include "testing/gmock/include/gmock/gmock.h" @@ -24,22 +27,15 @@ namespace cc { namespace { -class TestOcclusionTrackerImpl : public OcclusionTrackerImpl { +class TestOcclusionTrackerImpl + : public TestOcclusionTrackerBase<LayerImpl, RenderSurfaceImpl> { public: TestOcclusionTrackerImpl(gfx::Rect scissor_rect_in_screen, bool record_metrics_for_frame = true) - : OcclusionTrackerImpl(scissor_rect_in_screen, record_metrics_for_frame), - scissor_rect_in_screen_(scissor_rect_in_screen) {} - - protected: - virtual gfx::Rect LayerScissorRectInTargetSurface( - const LayerImpl* layer) const { - return scissor_rect_in_screen_; - } + : TestOcclusionTrackerBase(scissor_rect_in_screen, + record_metrics_for_frame) {} private: - gfx::Rect scissor_rect_in_screen_; - DISALLOW_COPY_AND_ASSIGN(TestOcclusionTrackerImpl); }; @@ -54,14 +50,13 @@ class QuadCullerTest : public testing::Test { : host_impl_(&proxy_), layer_id_(1) {} - scoped_ptr<TiledLayerImpl> MakeLayer( - TiledLayerImpl* parent, - const gfx::Transform& draw_transform, - gfx::Rect layer_rect, - float opacity, - bool opaque, - gfx::Rect layer_opaque_rect, - LayerImplList& surface_layer_list) { + scoped_ptr<TiledLayerImpl> MakeLayer(TiledLayerImpl* parent, + const gfx::Transform& draw_transform, + gfx::Rect layer_rect, + float opacity, + bool opaque, + gfx::Rect layer_opaque_rect, + LayerImplList& surface_layer_list) { scoped_ptr<TiledLayerImpl> layer = TiledLayerImpl::Create(host_impl_.active_tree(), layer_id_++); scoped_ptr<LayerTilingData> tiler = LayerTilingData::Create( @@ -69,6 +64,7 @@ class QuadCullerTest : public testing::Test { tiler->SetBounds(layer_rect.size()); layer->SetTilingData(*tiler); layer->set_skips_draw(false); + layer->SetDrawsContent(true); layer->draw_properties().target_space_transform = draw_transform; layer->draw_properties().screen_space_transform = draw_transform; layer->draw_properties().visible_content_rect = layer_rect; @@ -112,7 +108,7 @@ class QuadCullerTest : public testing::Test { TiledLayerImpl* layer, LayerIteratorType* it, OcclusionTrackerImpl* occlusion_tracker) { - occlusion_tracker->EnterLayer(*it, false); + occlusion_tracker->EnterLayer(*it); QuadCuller quad_culler( quad_list, shared_state_list, layer, *occlusion_tracker, false, false); AppendQuadsData data; @@ -126,6 +122,7 @@ class QuadCullerTest : public testing::Test { FakeLayerTreeHostImpl host_impl_; int layer_id_; + private: DISALLOW_COPY_AND_ASSIGN(QuadCullerTest); }; @@ -139,21 +136,20 @@ class QuadCullerTest : public testing::Test { gfx::Size child_size = gfx::Size(200, 200); \ gfx::Rect child_rect = gfx::Rect(child_size); -TEST_F(QuadCullerTest, VerifyNoCulling) { +TEST_F(QuadCullerTest, NoCulling) { DECLARE_AND_INITIALIZE_TEST_QUADS(); - scoped_ptr<TiledLayerImpl> root_layer = - MakeLayer(NULL, - gfx::Transform(), - root_rect, - 1, - true, - gfx::Rect(), - render_surface_layer_list); + scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, + gfx::Transform(), + root_rect, + 1.f, + true, + gfx::Rect(), + render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), gfx::Transform(), child_rect, - 1, + 1.f, false, gfx::Rect(), render_surface_layer_list); @@ -170,7 +166,7 @@ TEST_F(QuadCullerTest, VerifyNoCulling) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 13u); + EXPECT_EQ(13u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1); EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), @@ -180,21 +176,20 @@ TEST_F(QuadCullerTest, VerifyNoCulling) { occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1); } -TEST_F(QuadCullerTest, VerifyCullChildLinesUpTopLeft) { +TEST_F(QuadCullerTest, CullChildLinesUpTopLeft) { DECLARE_AND_INITIALIZE_TEST_QUADS(); - scoped_ptr<TiledLayerImpl> root_layer = - MakeLayer(NULL, - gfx::Transform(), - root_rect, - 1, - true, - gfx::Rect(), - render_surface_layer_list); + scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, + gfx::Transform(), + root_rect, + 1.f, + true, + gfx::Rect(), + render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), gfx::Transform(), child_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); @@ -211,7 +206,7 @@ TEST_F(QuadCullerTest, VerifyCullChildLinesUpTopLeft) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 9u); + EXPECT_EQ(9u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1); EXPECT_NEAR( @@ -221,17 +216,16 @@ TEST_F(QuadCullerTest, VerifyCullChildLinesUpTopLeft) { 1); } -TEST_F(QuadCullerTest, VerifyCullWhenChildOpacityNotOne) { +TEST_F(QuadCullerTest, CullWhenChildOpacityNotOne) { DECLARE_AND_INITIALIZE_TEST_QUADS(); - scoped_ptr<TiledLayerImpl> root_layer = - MakeLayer(NULL, - gfx::Transform(), - root_rect, - 1, - true, - gfx::Rect(), - render_surface_layer_list); + scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, + gfx::Transform(), + root_rect, + 1.f, + true, + gfx::Rect(), + render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), child_transform, child_rect, @@ -252,7 +246,7 @@ TEST_F(QuadCullerTest, VerifyCullWhenChildOpacityNotOne) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 13u); + EXPECT_EQ(13u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1); EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), @@ -262,21 +256,20 @@ TEST_F(QuadCullerTest, VerifyCullWhenChildOpacityNotOne) { occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1); } -TEST_F(QuadCullerTest, VerifyCullWhenChildOpaqueFlagFalse) { +TEST_F(QuadCullerTest, CullWhenChildOpaqueFlagFalse) { DECLARE_AND_INITIALIZE_TEST_QUADS(); - scoped_ptr<TiledLayerImpl> root_layer = - MakeLayer(NULL, - gfx::Transform(), - root_rect, - 1, - true, - gfx::Rect(), - render_surface_layer_list); + scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, + gfx::Transform(), + root_rect, + 1.f, + true, + gfx::Rect(), + render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), child_transform, child_rect, - 1, + 1.f, false, gfx::Rect(), render_surface_layer_list); @@ -293,7 +286,7 @@ TEST_F(QuadCullerTest, VerifyCullWhenChildOpaqueFlagFalse) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 13u); + EXPECT_EQ(13u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1); EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), @@ -303,21 +296,21 @@ TEST_F(QuadCullerTest, VerifyCullWhenChildOpaqueFlagFalse) { occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1); } -TEST_F(QuadCullerTest, VerifyCullCenterTileOnly) { +TEST_F(QuadCullerTest, CullCenterTileOnly) { DECLARE_AND_INITIALIZE_TEST_QUADS(); child_transform.Translate(50, 50); scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, gfx::Transform(), root_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), child_transform, child_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); @@ -337,19 +330,19 @@ TEST_F(QuadCullerTest, VerifyCullCenterTileOnly) { ASSERT_EQ(quad_list.size(), 12u); gfx::Rect quad_visible_rect1 = quad_list[5]->visible_rect; - EXPECT_EQ(quad_visible_rect1.height(), 50); + EXPECT_EQ(50, quad_visible_rect1.height()); gfx::Rect quad_visible_rect3 = quad_list[7]->visible_rect; - EXPECT_EQ(quad_visible_rect3.width(), 50); + EXPECT_EQ(50, quad_visible_rect3.width()); // Next index is 8, not 9, since centre quad culled. gfx::Rect quad_visible_rect4 = quad_list[8]->visible_rect; - EXPECT_EQ(quad_visible_rect4.width(), 50); - EXPECT_EQ(quad_visible_rect4.x(), 250); + EXPECT_EQ(50, quad_visible_rect4.width()); + EXPECT_EQ(250, quad_visible_rect4.x()); gfx::Rect quad_visible_rect6 = quad_list[10]->visible_rect; - EXPECT_EQ(quad_visible_rect6.height(), 50); - EXPECT_EQ(quad_visible_rect6.y(), 250); + EXPECT_EQ(50, quad_visible_rect6.height()); + EXPECT_EQ(250, quad_visible_rect6.y()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 100000, 1); @@ -360,7 +353,7 @@ TEST_F(QuadCullerTest, VerifyCullCenterTileOnly) { 1); } -TEST_F(QuadCullerTest, VerifyCullCenterTileNonIntegralSize1) { +TEST_F(QuadCullerTest, CullCenterTileNonIntegralSize1) { DECLARE_AND_INITIALIZE_TEST_QUADS(); child_transform.Translate(100, 100); @@ -368,22 +361,22 @@ TEST_F(QuadCullerTest, VerifyCullCenterTileNonIntegralSize1) { // Make the root layer's quad have extent (99.1, 99.1) -> (200.9, 200.9) to // make sure it doesn't get culled due to transform rounding. gfx::Transform root_transform; - root_transform.Translate(99.1, 99.1); - root_transform.Scale(1.018, 1.018); + root_transform.Translate(99.1f, 99.1f); + root_transform.Scale(1.018f, 1.018f); root_rect = child_rect = gfx::Rect(0, 0, 100, 100); scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, root_transform, root_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), child_transform, child_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); @@ -400,7 +393,7 @@ TEST_F(QuadCullerTest, VerifyCullCenterTileNonIntegralSize1) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 2u); + EXPECT_EQ(2u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 20363, 1); @@ -410,14 +403,14 @@ TEST_F(QuadCullerTest, VerifyCullCenterTileNonIntegralSize1) { occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1); } -TEST_F(QuadCullerTest, VerifyCullCenterTileNonIntegralSize2) { +TEST_F(QuadCullerTest, CullCenterTileNonIntegralSize2) { DECLARE_AND_INITIALIZE_TEST_QUADS(); // Make the child's quad slightly smaller than, and centred over, the root // layer tile. Verify the child does not cause the quad below to be culled // due to rounding. - child_transform.Translate(100.1, 100.1); - child_transform.Scale(0.982, 0.982); + child_transform.Translate(100.1f, 100.1f); + child_transform.Scale(0.982f, 0.982f); gfx::Transform root_transform; root_transform.Translate(100, 100); @@ -427,14 +420,14 @@ TEST_F(QuadCullerTest, VerifyCullCenterTileNonIntegralSize2) { scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, root_transform, root_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), child_transform, child_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); @@ -451,7 +444,7 @@ TEST_F(QuadCullerTest, VerifyCullCenterTileNonIntegralSize2) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 2u); + EXPECT_EQ(2u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 19643, 1); @@ -461,21 +454,21 @@ TEST_F(QuadCullerTest, VerifyCullCenterTileNonIntegralSize2) { occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1); } -TEST_F(QuadCullerTest, VerifyCullChildLinesUpBottomRight) { +TEST_F(QuadCullerTest, CullChildLinesUpBottomRight) { DECLARE_AND_INITIALIZE_TEST_QUADS(); child_transform.Translate(100, 100); scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, gfx::Transform(), root_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), child_transform, child_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); @@ -492,7 +485,7 @@ TEST_F(QuadCullerTest, VerifyCullChildLinesUpBottomRight) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 9u); + EXPECT_EQ(9u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1); EXPECT_NEAR( @@ -502,14 +495,14 @@ TEST_F(QuadCullerTest, VerifyCullChildLinesUpBottomRight) { 1); } -TEST_F(QuadCullerTest, VerifyCullSubRegion) { +TEST_F(QuadCullerTest, CullSubRegion) { DECLARE_AND_INITIALIZE_TEST_QUADS(); child_transform.Translate(50, 50); scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, gfx::Transform(), root_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); @@ -520,7 +513,7 @@ TEST_F(QuadCullerTest, VerifyCullSubRegion) { scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), child_transform, child_rect, - 1, + 1.f, false, child_opaque_rect, render_surface_layer_list); @@ -537,7 +530,7 @@ TEST_F(QuadCullerTest, VerifyCullSubRegion) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 12u); + EXPECT_EQ(12u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1); EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), @@ -548,14 +541,14 @@ TEST_F(QuadCullerTest, VerifyCullSubRegion) { 1); } -TEST_F(QuadCullerTest, VerifyCullSubRegion2) { +TEST_F(QuadCullerTest, CullSubRegion2) { DECLARE_AND_INITIALIZE_TEST_QUADS(); child_transform.Translate(50, 10); scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, gfx::Transform(), root_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); @@ -566,7 +559,7 @@ TEST_F(QuadCullerTest, VerifyCullSubRegion2) { scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), child_transform, child_rect, - 1, + 1.f, false, child_opaque_rect, render_surface_layer_list); @@ -583,7 +576,7 @@ TEST_F(QuadCullerTest, VerifyCullSubRegion2) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 12u); + EXPECT_EQ(12u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1); EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), @@ -594,14 +587,14 @@ TEST_F(QuadCullerTest, VerifyCullSubRegion2) { 1); } -TEST_F(QuadCullerTest, VerifyCullSubRegionCheckOvercull) { +TEST_F(QuadCullerTest, CullSubRegionCheckOvercull) { DECLARE_AND_INITIALIZE_TEST_QUADS(); child_transform.Translate(50, 49); scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, gfx::Transform(), root_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); @@ -612,7 +605,7 @@ TEST_F(QuadCullerTest, VerifyCullSubRegionCheckOvercull) { scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), child_transform, child_rect, - 1, + 1.f, false, child_opaque_rect, render_surface_layer_list); @@ -629,7 +622,7 @@ TEST_F(QuadCullerTest, VerifyCullSubRegionCheckOvercull) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 13u); + EXPECT_EQ(13u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1); EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), @@ -640,7 +633,7 @@ TEST_F(QuadCullerTest, VerifyCullSubRegionCheckOvercull) { 1); } -TEST_F(QuadCullerTest, VerifyNonAxisAlignedQuadsDontOcclude) { +TEST_F(QuadCullerTest, NonAxisAlignedQuadsDontOcclude) { DECLARE_AND_INITIALIZE_TEST_QUADS(); // Use a small rotation so as to not disturb the geometry significantly. @@ -649,14 +642,14 @@ TEST_F(QuadCullerTest, VerifyNonAxisAlignedQuadsDontOcclude) { scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, gfx::Transform(), root_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), child_transform, child_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); @@ -673,7 +666,7 @@ TEST_F(QuadCullerTest, VerifyNonAxisAlignedQuadsDontOcclude) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 13u); + EXPECT_EQ(13u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 130000, 1); EXPECT_NEAR( @@ -688,7 +681,7 @@ TEST_F(QuadCullerTest, VerifyNonAxisAlignedQuadsDontOcclude) { // child would normally occlude, three will move (slightly) out from under the // child layer, and one moves further under the child. Only this last tile // should be culled. -TEST_F(QuadCullerTest, VerifyNonAxisAlignedQuadsSafelyCulled) { +TEST_F(QuadCullerTest, NonAxisAlignedQuadsSafelyCulled) { DECLARE_AND_INITIALIZE_TEST_QUADS(); // Use a small rotation so as to not disturb the geometry significantly. @@ -698,14 +691,14 @@ TEST_F(QuadCullerTest, VerifyNonAxisAlignedQuadsSafelyCulled) { scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, parent_transform, root_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), gfx::Transform(), child_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); @@ -722,7 +715,7 @@ TEST_F(QuadCullerTest, VerifyNonAxisAlignedQuadsSafelyCulled) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 12u); + EXPECT_EQ(12u, quad_list.size()); EXPECT_NEAR( occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 100600, 1); EXPECT_NEAR( @@ -732,24 +725,25 @@ TEST_F(QuadCullerTest, VerifyNonAxisAlignedQuadsSafelyCulled) { 1); } -TEST_F(QuadCullerTest, VerifyCullOutsideScissorOverTile) { +TEST_F(QuadCullerTest, WithoutMetrics) { DECLARE_AND_INITIALIZE_TEST_QUADS(); - scoped_ptr<TiledLayerImpl> root_layer = - MakeLayer(NULL, - gfx::Transform(), - root_rect, - 1, - true, - gfx::Rect(), - render_surface_layer_list); + scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL, + gfx::Transform(), + root_rect, + 1.f, + true, + gfx::Rect(), + render_surface_layer_list); scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), gfx::Transform(), child_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); - TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(200, 100, 100, 100)); + bool record_metrics = false; + TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000), + record_metrics); LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list); AppendQuads(&quad_list, @@ -762,174 +756,163 @@ TEST_F(QuadCullerTest, VerifyCullOutsideScissorOverTile) { root_layer.get(), &it, &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 1u); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 10000, 1); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1); - EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), - 120000, - 1); + EXPECT_EQ(9u, quad_list.size()); + EXPECT_EQ(0.f, + occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque()); + EXPECT_EQ(0.f, + occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent()); + EXPECT_EQ(0.f, + occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing()); } -TEST_F(QuadCullerTest, VerifyCullOutsideScissorOverCulledTile) { +TEST_F(QuadCullerTest, PartialCullingNotDestroyed) { DECLARE_AND_INITIALIZE_TEST_QUADS(); - scoped_ptr<TiledLayerImpl> root_layer = - MakeLayer(NULL, - gfx::Transform(), - root_rect, - 1, - true, - gfx::Rect(), - render_surface_layer_list); - scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), - gfx::Transform(), - child_rect, - 1, - true, - gfx::Rect(), - render_surface_layer_list); - TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(100, 100, 100, 100)); - LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list); - - AppendQuads(&quad_list, - &shared_state_list, - child_layer.get(), - &it, - &occlusion_tracker); - AppendQuads(&quad_list, - &shared_state_list, - root_layer.get(), - &it, - &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 1u); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 10000, 1); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1); - EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), - 120000, - 1); -} -TEST_F(QuadCullerTest, VerifyCullOutsideScissorOverPartialTiles) { - DECLARE_AND_INITIALIZE_TEST_QUADS(); - scoped_ptr<TiledLayerImpl> root_layer = - MakeLayer(NULL, - gfx::Transform(), - root_rect, - 1, - true, - gfx::Rect(), - render_surface_layer_list); - scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), + scoped_ptr<TiledLayerImpl> dummy_layer = MakeLayer(NULL, gfx::Transform(), - child_rect, - 1, - true, gfx::Rect(), - render_surface_layer_list); - TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(50, 50, 200, 200)); - LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list); - - AppendQuads(&quad_list, - &shared_state_list, - child_layer.get(), - &it, - &occlusion_tracker); - AppendQuads(&quad_list, - &shared_state_list, - root_layer.get(), - &it, - &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 9u); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 40000, 1); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1); - EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), - 90000, - 1); -} - -TEST_F(QuadCullerTest, VerifyCullOutsideScissorOverNoTiles) { - DECLARE_AND_INITIALIZE_TEST_QUADS(); - scoped_ptr<TiledLayerImpl> root_layer = - MakeLayer(NULL, - gfx::Transform(), - root_rect, - 1, - true, - gfx::Rect(), - render_surface_layer_list); - scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), - gfx::Transform(), - child_rect, - 1, + 1.f, true, gfx::Rect(), render_surface_layer_list); - TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(500, 500, 100, 100)); + + TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(1000, 1000)); LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list); - AppendQuads(&quad_list, - &shared_state_list, - child_layer.get(), - &it, - &occlusion_tracker); - AppendQuads(&quad_list, - &shared_state_list, - root_layer.get(), - &it, - &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 0u); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 0, 1); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1); - EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), - 130000, - 1); + QuadCuller culler(&quad_list, + &shared_state_list, + dummy_layer.get(), + occlusion_tracker, + false, + false); + + SharedQuadState* sqs = culler.UseSharedQuadState(SharedQuadState::Create()); + + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(sqs, gfx::Rect(100, 100), SK_ColorRED, false); + + scoped_ptr<RenderPassDrawQuad> pass_quad = RenderPassDrawQuad::Create(); + pass_quad->SetNew(sqs, + gfx::Rect(100, 100), + RenderPass::Id(10, 10), + false, + 0, + gfx::Rect(), + gfx::RectF(), + FilterOperations(), + FilterOperations()); + + scoped_ptr<RenderPassDrawQuad> replica_quad = RenderPassDrawQuad::Create(); + replica_quad->SetNew(sqs, + gfx::Rect(100, 100), + RenderPass::Id(10, 10), + true, + 0, + gfx::Rect(), + gfx::RectF(), + FilterOperations(), + FilterOperations()); + + // Set a visible rect on the quads. + color_quad->visible_rect = gfx::Rect(20, 30, 10, 11); + pass_quad->visible_rect = gfx::Rect(50, 60, 13, 14); + replica_quad->visible_rect = gfx::Rect(30, 40, 15, 16); + + // Nothing is occluding. + occlusion_tracker.EnterLayer(it); + + EXPECT_EQ(0u, quad_list.size()); + + AppendQuadsData data; + culler.Append(color_quad.PassAs<DrawQuad>(), &data); + culler.Append(pass_quad.PassAs<DrawQuad>(), &data); + culler.Append(replica_quad.PassAs<DrawQuad>(), &data); + + ASSERT_EQ(3u, quad_list.size()); + + // The partial culling is preserved. + EXPECT_EQ(gfx::Rect(20, 30, 10, 11).ToString(), + quad_list[0]->visible_rect.ToString()); + EXPECT_EQ(gfx::Rect(50, 60, 13, 14).ToString(), + quad_list[1]->visible_rect.ToString()); + EXPECT_EQ(gfx::Rect(30, 40, 15, 16).ToString(), + quad_list[2]->visible_rect.ToString()); } -TEST_F(QuadCullerTest, VerifyWithoutMetrics) { +TEST_F(QuadCullerTest, PartialCullingWithOcclusionNotDestroyed) { DECLARE_AND_INITIALIZE_TEST_QUADS(); - scoped_ptr<TiledLayerImpl> root_layer = - MakeLayer(NULL, - gfx::Transform(), - root_rect, - 1, - true, - gfx::Rect(), - render_surface_layer_list); - scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(), + + scoped_ptr<TiledLayerImpl> dummy_layer = MakeLayer(NULL, gfx::Transform(), - child_rect, - 1, + gfx::Rect(), + 1.f, true, gfx::Rect(), render_surface_layer_list); - TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(50, 50, 200, 200), - false); + + TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(1000, 1000)); LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list); - AppendQuads(&quad_list, - &shared_state_list, - child_layer.get(), - &it, - &occlusion_tracker); - AppendQuads(&quad_list, - &shared_state_list, - root_layer.get(), - &it, - &occlusion_tracker); - EXPECT_EQ(quad_list.size(), 9u); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 0, 1); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1); - EXPECT_NEAR( - occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1); + QuadCuller culler(&quad_list, + &shared_state_list, + dummy_layer.get(), + occlusion_tracker, + false, + false); + + SharedQuadState* sqs = culler.UseSharedQuadState(SharedQuadState::Create()); + + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(sqs, gfx::Rect(100, 100), SK_ColorRED, false); + + scoped_ptr<RenderPassDrawQuad> pass_quad = RenderPassDrawQuad::Create(); + pass_quad->SetNew(sqs, + gfx::Rect(100, 100), + RenderPass::Id(10, 10), + false, + 0, + gfx::Rect(), + gfx::RectF(), + FilterOperations(), + FilterOperations()); + + scoped_ptr<RenderPassDrawQuad> replica_quad = RenderPassDrawQuad::Create(); + replica_quad->SetNew(sqs, + gfx::Rect(100, 100), + RenderPass::Id(10, 10), + true, + 0, + gfx::Rect(), + gfx::RectF(), + FilterOperations(), + FilterOperations()); + + // Set a visible rect on the quads. + color_quad->visible_rect = gfx::Rect(10, 10, 10, 11); + pass_quad->visible_rect = gfx::Rect(10, 20, 13, 14); + replica_quad->visible_rect = gfx::Rect(10, 30, 15, 16); + + // Occlude the left part of the visible rects. + occlusion_tracker.EnterLayer(it); + occlusion_tracker.set_occlusion_from_outside_target(gfx::Rect(0, 0, 15, 100)); + + EXPECT_EQ(0u, quad_list.size()); + + AppendQuadsData data; + culler.Append(color_quad.PassAs<DrawQuad>(), &data); + culler.Append(pass_quad.PassAs<DrawQuad>(), &data); + culler.Append(replica_quad.PassAs<DrawQuad>(), &data); + + ASSERT_EQ(3u, quad_list.size()); + + // The partial culling is preserved, while the left side of the quads is newly + // occluded. + EXPECT_EQ(gfx::Rect(15, 10, 5, 11).ToString(), + quad_list[0]->visible_rect.ToString()); + EXPECT_EQ(gfx::Rect(15, 20, 8, 14).ToString(), + quad_list[1]->visible_rect.ToString()); + EXPECT_EQ(gfx::Rect(15, 30, 10, 16).ToString(), + quad_list[2]->visible_rect.ToString()); } } // namespace diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc index 85db94c6902..f1f8a4f5824 100644 --- a/chromium/cc/trees/single_thread_proxy.cc +++ b/chromium/cc/trees/single_thread_proxy.cc @@ -6,6 +6,7 @@ #include "base/auto_reset.h" #include "base/debug/trace_event.h" +#include "cc/debug/benchmark_instrumentation.h" #include "cc/output/context_provider.h" #include "cc/output/output_surface.h" #include "cc/quads/draw_quad.h" @@ -13,18 +14,24 @@ #include "cc/resources/resource_update_controller.h" #include "cc/trees/blocking_task_runner.h" #include "cc/trees/layer_tree_host.h" +#include "cc/trees/layer_tree_host_single_thread_client.h" #include "cc/trees/layer_tree_impl.h" +#include "ui/gfx/frame_time.h" namespace cc { -scoped_ptr<Proxy> SingleThreadProxy::Create(LayerTreeHost* layer_tree_host) { +scoped_ptr<Proxy> SingleThreadProxy::Create( + LayerTreeHost* layer_tree_host, + LayerTreeHostSingleThreadClient* client) { return make_scoped_ptr( - new SingleThreadProxy(layer_tree_host)).PassAs<Proxy>(); + new SingleThreadProxy(layer_tree_host, client)).PassAs<Proxy>(); } -SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host) +SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host, + LayerTreeHostSingleThreadClient* client) : Proxy(NULL), layer_tree_host_(layer_tree_host), + client_(client), created_offscreen_context_provider_(false), next_frame_is_newly_committed_frame_(false), inside_draw_(false) { @@ -58,7 +65,7 @@ bool SingleThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) { gfx::Rect device_viewport_damage_rect = rect; LayerTreeHostImpl::FrameData frame; - if (!CommitAndComposite(base::TimeTicks::Now(), + if (!CommitAndComposite(gfx::FrameTime::Now(), device_viewport_damage_rect, true, // for_readback &frame)) @@ -114,11 +121,12 @@ void SingleThreadProxy::CreateAndInitializeOutputSurface() { return; } - scoped_refptr<cc::ContextProvider> offscreen_context_provider; + scoped_refptr<ContextProvider> offscreen_context_provider; if (created_offscreen_context_provider_) { offscreen_context_provider = - layer_tree_host_->client()->OffscreenContextProviderForMainThread(); - if (!offscreen_context_provider.get()) { + layer_tree_host_->client()->OffscreenContextProvider(); + if (!offscreen_context_provider.get() || + !offscreen_context_provider->BindToCurrentThread()) { OnOutputSurfaceInitializeAttempted(false); return; } @@ -169,13 +177,13 @@ const RendererCapabilities& SingleThreadProxy::GetRendererCapabilities() const { } void SingleThreadProxy::SetNeedsAnimate() { - // Thread-only feature. - NOTREACHED(); + DCHECK(Proxy::IsMainThread()); + client_->ScheduleAnimation(); } void SingleThreadProxy::SetNeedsUpdateLayers() { DCHECK(Proxy::IsMainThread()); - layer_tree_host_->ScheduleComposite(); + client_->ScheduleComposite(); } void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { @@ -190,15 +198,11 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { // to receive its callbacks before that. BlockingTaskRunner::CapturePostTasks blocked; - RenderingStatsInstrumentation* stats_instrumentation = - layer_tree_host_->rendering_stats_instrumentation(); - base::TimeTicks start_time = stats_instrumentation->StartRecording(); - layer_tree_host_impl_->BeginCommit(); - if (layer_tree_host_->contents_texture_manager()) { - layer_tree_host_->contents_texture_manager()-> - PushTexturePrioritiesToBackings(); + if (PrioritizedResourceManager* contents_texture_manager = + layer_tree_host_->contents_texture_manager()) { + contents_texture_manager->PushTexturePrioritiesToBackings(); } layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get()); @@ -226,9 +230,10 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { DCHECK_EQ(1.f, scroll_info->page_scale_delta); #endif - base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); - stats_instrumentation->AddCommit(duration); - stats_instrumentation->IssueTraceEventForMainThreadStats(); + RenderingStatsInstrumentation* stats_instrumentation = + layer_tree_host_->rendering_stats_instrumentation(); + BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent( + stats_instrumentation->main_thread_rendering_stats()); stats_instrumentation->AccumulateAndClearMainThreadStats(); } layer_tree_host_->CommitComplete(); @@ -237,11 +242,12 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { void SingleThreadProxy::SetNeedsCommit() { DCHECK(Proxy::IsMainThread()); - layer_tree_host_->ScheduleComposite(); + client_->ScheduleComposite(); } void SingleThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) { SetNeedsRedrawRectOnImplThread(damage_rect); + client_->ScheduleComposite(); } void SingleThreadProxy::SetNextCommitWaitsForActivation() { @@ -255,6 +261,8 @@ void SingleThreadProxy::SetDeferCommits(bool defer_commits) { bool SingleThreadProxy::CommitRequested() const { return false; } +bool SingleThreadProxy::BeginMainFrameRequested() const { return false; } + size_t SingleThreadProxy::MaxPartialTextureUpdates() const { return std::numeric_limits<size_t>::max(); } @@ -284,7 +292,7 @@ void SingleThreadProxy::NotifyReadyToActivate() { } void SingleThreadProxy::SetNeedsRedrawOnImplThread() { - layer_tree_host_->ScheduleComposite(); + client_->ScheduleComposite(); } void SingleThreadProxy::SetNeedsManageTilesOnImplThread() { @@ -306,7 +314,7 @@ void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() { } void SingleThreadProxy::SetNeedsCommitOnImplThread() { - layer_tree_host_->ScheduleComposite(); + client_->ScheduleComposite(); } void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread( @@ -321,27 +329,28 @@ bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread( size_t limit_bytes, int priority_cutoff) { DCHECK(IsImplThread()); - if (!layer_tree_host_->contents_texture_manager()) - return false; + PrioritizedResourceManager* contents_texture_manager = + layer_tree_host_->contents_texture_manager(); - return layer_tree_host_->contents_texture_manager()->ReduceMemoryOnImplThread( - limit_bytes, priority_cutoff, layer_tree_host_impl_->resource_provider()); -} + ResourceProvider* resource_provider = + layer_tree_host_impl_->resource_provider(); -void SingleThreadProxy::ReduceWastedContentsTextureMemoryOnImplThread() { - // Impl-side painting only. - NOTREACHED(); + if (!contents_texture_manager || !resource_provider) + return false; + + return contents_texture_manager->ReduceMemoryOnImplThread( + limit_bytes, priority_cutoff, resource_provider); } void SingleThreadProxy::SendManagedMemoryStats() { DCHECK(Proxy::IsImplThread()); if (!layer_tree_host_impl_) return; - if (!layer_tree_host_->contents_texture_manager()) - return; - PrioritizedResourceManager* contents_texture_manager = layer_tree_host_->contents_texture_manager(); + if (!contents_texture_manager) + return; + layer_tree_host_impl_->SendManagedMemoryStats( contents_texture_manager->MemoryVisibleBytes(), contents_texture_manager->MemoryVisibleAndNearbyBytes(), @@ -353,6 +362,15 @@ bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; } void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() { // Cause a commit so we can notice the lost context. SetNeedsCommitOnImplThread(); + client_->DidAbortSwapBuffers(); +} + +void SingleThreadProxy::DidSwapBuffersOnImplThread() { + client_->DidPostSwapBuffers(); +} + +void SingleThreadProxy::OnSwapBuffersCompleteOnImplThread() { + client_->DidCompleteSwapBuffers(); } // Called by the legacy scheduling path (e.g. where render_widget does the @@ -420,21 +438,12 @@ bool SingleThreadProxy::CommitAndComposite( layer_tree_host_->AnimateLayers(frame_begin_time); - scoped_refptr<cc::ContextProvider> offscreen_context_provider; - if (renderer_capabilities_for_main_thread_.using_offscreen_context3d && - layer_tree_host_->needs_offscreen_context()) { - offscreen_context_provider = - layer_tree_host_->client()->OffscreenContextProviderForMainThread(); - if (offscreen_context_provider.get()) - created_offscreen_context_provider_ = true; - } - - if (layer_tree_host_->contents_texture_manager()) { - layer_tree_host_->contents_texture_manager() - ->UnlinkAndClearEvictedBackings(); - layer_tree_host_->contents_texture_manager()->SetMaxMemoryLimitBytes( + if (PrioritizedResourceManager* contents_texture_manager = + layer_tree_host_->contents_texture_manager()) { + contents_texture_manager->UnlinkAndClearEvictedBackings(); + contents_texture_manager->SetMaxMemoryLimitBytes( layer_tree_host_impl_->memory_allocation_limit_bytes()); - layer_tree_host_->contents_texture_manager()->SetExternalPriorityCutoff( + contents_texture_manager->SetExternalPriorityCutoff( layer_tree_host_impl_->memory_allocation_priority_cutoff()); } @@ -443,13 +452,27 @@ bool SingleThreadProxy::CommitAndComposite( layer_tree_host_->UpdateLayers(queue.get()); layer_tree_host_->WillCommit(); + + scoped_refptr<ContextProvider> offscreen_context_provider; + if (renderer_capabilities_for_main_thread_.using_offscreen_context3d && + layer_tree_host_->needs_offscreen_context()) { + offscreen_context_provider = + layer_tree_host_->client()->OffscreenContextProvider(); + if (offscreen_context_provider.get() && + !offscreen_context_provider->BindToCurrentThread()) + offscreen_context_provider = NULL; + + if (offscreen_context_provider.get()) + created_offscreen_context_provider_ = true; + } + DoCommit(queue.Pass()); bool result = DoComposite(offscreen_context_provider, frame_begin_time, device_viewport_damage_rect, for_readback, frame); - layer_tree_host_->DidBeginFrame(); + layer_tree_host_->DidBeginMainFrame(); return result; } @@ -466,7 +489,7 @@ void SingleThreadProxy::UpdateBackgroundAnimateTicking() { } bool SingleThreadProxy::DoComposite( - scoped_refptr<cc::ContextProvider> offscreen_context_provider, + scoped_refptr<ContextProvider> offscreen_context_provider, base::TimeTicks frame_begin_time, gfx::Rect device_viewport_damage_rect, bool for_readback, @@ -497,9 +520,11 @@ bool SingleThreadProxy::DoComposite( layer_tree_host_impl_->CurrentFrameTime()); UpdateBackgroundAnimateTicking(); - layer_tree_host_impl_->PrepareToDraw(frame, device_viewport_damage_rect); - layer_tree_host_impl_->DrawLayers(frame, frame_begin_time); - layer_tree_host_impl_->DidDrawAllLayers(*frame); + if (!layer_tree_host_impl_->IsContextLost()) { + layer_tree_host_impl_->PrepareToDraw(frame, device_viewport_damage_rect); + layer_tree_host_impl_->DrawLayers(frame, frame_begin_time); + layer_tree_host_impl_->DidDrawAllLayers(*frame); + } lost_output_surface = layer_tree_host_impl_->IsContextLost(); bool start_ready_animations = true; @@ -509,7 +534,7 @@ bool SingleThreadProxy::DoComposite( } if (lost_output_surface) { - cc::ContextProvider* offscreen_contexts = + ContextProvider* offscreen_contexts = layer_tree_host_impl_->offscreen_context_provider(); if (offscreen_contexts) offscreen_contexts->VerifyContexts(); diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h index 474fb1f1101..463141c1748 100644 --- a/chromium/cc/trees/single_thread_proxy.h +++ b/chromium/cc/trees/single_thread_proxy.h @@ -17,10 +17,13 @@ namespace cc { class ContextProvider; class LayerTreeHost; +class LayerTreeHostSingleThreadClient; class SingleThreadProxy : public Proxy, LayerTreeHostImplClient { public: - static scoped_ptr<Proxy> Create(LayerTreeHost* layer_tree_host); + static scoped_ptr<Proxy> Create( + LayerTreeHost* layer_tree_host, + LayerTreeHostSingleThreadClient* client); virtual ~SingleThreadProxy(); // Proxy implementation @@ -39,6 +42,7 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient { virtual void NotifyInputThrottledUntilCommit() OVERRIDE {} virtual void SetDeferCommits(bool defer_commits) OVERRIDE; virtual bool CommitRequested() const OVERRIDE; + virtual bool BeginMainFrameRequested() const OVERRIDE; virtual void MainThreadHasStoppedFlinging() OVERRIDE {} virtual void Start(scoped_ptr<OutputSurface> first_output_surface) OVERRIDE; virtual void Stop() OVERRIDE; @@ -50,8 +54,9 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient { // LayerTreeHostImplClient implementation virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE; - virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {} - virtual void BeginFrameOnImplThread(const BeginFrameArgs& args) + virtual void DidSwapBuffersOnImplThread() OVERRIDE; + virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE; + virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE {} virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE; virtual void NotifyReadyToActivate() OVERRIDE; @@ -66,19 +71,20 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient { virtual bool ReduceContentsTextureMemoryOnImplThread( size_t limit_bytes, int priority_cutoff) OVERRIDE; - virtual void ReduceWastedContentsTextureMemoryOnImplThread() OVERRIDE; virtual void SendManagedMemoryStats() OVERRIDE; virtual bool IsInsideDraw() OVERRIDE; virtual void RenewTreePriority() OVERRIDE {} virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay) OVERRIDE {} virtual void DidActivatePendingTree() OVERRIDE {} + virtual void DidManageTiles() OVERRIDE {} // Called by the legacy path where RenderWidget does the scheduling. void CompositeImmediately(base::TimeTicks frame_begin_time); private: - explicit SingleThreadProxy(LayerTreeHost* layer_tree_host); + SingleThreadProxy(LayerTreeHost* layer_tree_host, + LayerTreeHostSingleThreadClient* client); void OnOutputSurfaceInitializeAttempted(bool success); bool CommitAndComposite(base::TimeTicks frame_begin_time, @@ -86,12 +92,11 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient { bool for_readback, LayerTreeHostImpl::FrameData* frame); void DoCommit(scoped_ptr<ResourceUpdateQueue> queue); - bool DoComposite( - scoped_refptr<cc::ContextProvider> offscreen_context_provider, - base::TimeTicks frame_begin_time, - gfx::Rect device_viewport_damage_rect, - bool for_readback, - LayerTreeHostImpl::FrameData* frame); + bool DoComposite(scoped_refptr<ContextProvider> offscreen_context_provider, + base::TimeTicks frame_begin_time, + gfx::Rect device_viewport_damage_rect, + bool for_readback, + LayerTreeHostImpl::FrameData* frame); void DidSwapFrame(); bool ShouldComposite() const; @@ -99,6 +104,7 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient { // Accessed on main thread only. LayerTreeHost* layer_tree_host_; + LayerTreeHostSingleThreadClient* client_; bool created_offscreen_context_provider_; // Holds the first output surface passed from Start. Should not be used for diff --git a/chromium/cc/trees/thread_proxy.cc b/chromium/cc/trees/thread_proxy.cc index b5dff0e2bcb..2823182d590 100644 --- a/chromium/cc/trees/thread_proxy.cc +++ b/chromium/cc/trees/thread_proxy.cc @@ -10,6 +10,8 @@ #include "base/bind.h" #include "base/debug/trace_event.h" #include "base/metrics/histogram.h" +#include "cc/base/swap_promise.h" +#include "cc/debug/benchmark_instrumentation.h" #include "cc/input/input_handler.h" #include "cc/output/context_provider.h" #include "cc/output/output_surface.h" @@ -21,13 +23,11 @@ #include "cc/trees/blocking_task_runner.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_impl.h" +#include "ui/gfx/frame_time.h" namespace { // Measured in seconds. -const double kContextRecreationTickRate = 0.03; - -// Measured in seconds. const double kSmoothnessTakesPriorityExpirationDelay = 0.25; const size_t kDurationHistorySize = 60; @@ -35,6 +35,19 @@ const double kCommitAndActivationDurationEstimationPercentile = 50.0; const double kDrawDurationEstimationPercentile = 100.0; const int kDrawDurationEstimatePaddingInMicroseconds = 0; +class SwapPromiseChecker { + public: + explicit SwapPromiseChecker(cc::LayerTreeHost* layer_tree_host) + : layer_tree_host_(layer_tree_host) {} + + ~SwapPromiseChecker() { + layer_tree_host_->BreakSwapPromises(cc::SwapPromise::COMMIT_FAILS); + } + + private: + cc::LayerTreeHost* layer_tree_host_; +}; + } // namespace namespace cc { @@ -71,16 +84,15 @@ ThreadProxy::ThreadProxy( commit_requested_(false), commit_request_sent_to_impl_thread_(false), created_offscreen_context_provider_(false), - layer_tree_host_(layer_tree_host), + layer_tree_host_unsafe_(layer_tree_host), + contents_texture_manager_unsafe_(NULL), started_(false), textures_acquired_(true), in_composite_and_readback_(false), manage_tiles_pending_(false), commit_waits_for_activation_(false), inside_commit_(false), - weak_factory_on_impl_thread_(this), - weak_factory_(this), - begin_frame_sent_to_main_thread_completion_event_on_impl_thread_(NULL), + begin_main_frame_sent_completion_event_on_impl_thread_(NULL), readback_request_on_impl_thread_(NULL), commit_completion_event_on_impl_thread_(NULL), completion_event_for_commit_held_on_tree_activation_(NULL), @@ -88,8 +100,8 @@ ThreadProxy::ThreadProxy( next_frame_is_newly_committed_frame_on_impl_thread_(false), throttle_frame_production_( layer_tree_host->settings().throttle_frame_production), - begin_frame_scheduling_enabled_( - layer_tree_host->settings().begin_frame_scheduling_enabled), + begin_impl_frame_scheduling_enabled_( + layer_tree_host->settings().begin_impl_frame_scheduling_enabled), using_synchronous_renderer_compositor_( layer_tree_host->settings().using_synchronous_renderer_compositor), inside_draw_(false), @@ -98,11 +110,14 @@ ThreadProxy::ThreadProxy( input_throttled_until_commit_(false), renew_tree_priority_on_impl_thread_pending_(false), draw_duration_history_(kDurationHistorySize), - begin_frame_to_commit_duration_history_(kDurationHistorySize), - commit_to_activate_duration_history_(kDurationHistorySize) { + begin_main_frame_to_commit_duration_history_(kDurationHistorySize), + commit_to_activate_duration_history_(kDurationHistorySize), + weak_factory_on_impl_thread_(this), + weak_factory_(this), + layer_tree_host_id_(layer_tree_host->id()) { TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy"); DCHECK(IsMainThread()); - DCHECK(layer_tree_host_); + DCHECK(this->layer_tree_host()); } ThreadProxy::~ThreadProxy() { @@ -114,14 +129,14 @@ ThreadProxy::~ThreadProxy() { bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) { TRACE_EVENT0("cc", "ThreadProxy::CompositeAndReadback"); DCHECK(IsMainThread()); - DCHECK(layer_tree_host_); + DCHECK(layer_tree_host()); if (defer_commits_) { TRACE_EVENT0("cc", "CompositeAndReadback_DeferCommit"); return false; } - if (!layer_tree_host_->InitializeOutputSurfaceIfNeeded()) { + if (!layer_tree_host()->InitializeOutputSurfaceIfNeeded()) { TRACE_EVENT0("cc", "CompositeAndReadback_EarlyOut_LR_Uninitialized"); return false; } @@ -132,22 +147,22 @@ bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) { request.pixels = pixels; { DebugScopedSetMainThreadBlocked main_thread_blocked(this); - CompletionEvent begin_frame_sent_to_main_thread_completion; + CompletionEvent begin_main_frame_sent_completion; Proxy::ImplThreadTaskRunner() ->PostTask(FROM_HERE, base::Bind(&ThreadProxy::ForceCommitForReadbackOnImplThread, impl_thread_weak_ptr_, - &begin_frame_sent_to_main_thread_completion, + &begin_main_frame_sent_completion, &request)); - begin_frame_sent_to_main_thread_completion.Wait(); + begin_main_frame_sent_completion.Wait(); } in_composite_and_readback_ = true; // This is the forced commit. - // Note: The Impl thread also queues a separate BeginFrameOnMainThread on the + // Note: The Impl thread also queues a separate BeginMainFrame on the // main thread, which will be called after this CompositeAndReadback // completes, to replace the forced commit. - BeginFrameOnMainThread(scoped_ptr<BeginFrameAndCommitState>()); + BeginMainFrame(scoped_ptr<BeginMainFrameAndCommitState>()); in_composite_and_readback_ = false; // Composite and readback requires a second commit to undo any changes @@ -159,15 +174,15 @@ bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) { } void ThreadProxy::ForceCommitForReadbackOnImplThread( - CompletionEvent* begin_frame_sent_completion, + CompletionEvent* begin_main_frame_sent_completion, ReadbackRequest* request) { TRACE_EVENT0("cc", "ThreadProxy::ForceCommitForReadbackOnImplThread"); DCHECK(IsImplThread()); - DCHECK(!begin_frame_sent_to_main_thread_completion_event_on_impl_thread_); + DCHECK(!begin_main_frame_sent_completion_event_on_impl_thread_); DCHECK(!readback_request_on_impl_thread_); if (!layer_tree_host_impl_) { - begin_frame_sent_completion->Signal(); + begin_main_frame_sent_completion->Signal(); request->success = false; request->completion.Signal(); return; @@ -177,12 +192,12 @@ void ThreadProxy::ForceCommitForReadbackOnImplThread( scheduler_on_impl_thread_->SetNeedsForcedCommitForReadback(); if (scheduler_on_impl_thread_->CommitPending()) { - begin_frame_sent_completion->Signal(); + begin_main_frame_sent_completion->Signal(); return; } - begin_frame_sent_to_main_thread_completion_event_on_impl_thread_ = - begin_frame_sent_completion; + begin_main_frame_sent_completion_event_on_impl_thread_ = + begin_main_frame_sent_completion; } void ThreadProxy::FinishAllRendering() { @@ -253,7 +268,7 @@ void ThreadProxy::DoCreateAndInitializeOutputSurface() { scoped_ptr<OutputSurface> output_surface = first_output_surface_.Pass(); if (!output_surface) - output_surface = layer_tree_host_->CreateOutputSurface(); + output_surface = layer_tree_host()->CreateOutputSurface(); RendererCapabilities capabilities; bool success = !!output_surface; @@ -264,8 +279,8 @@ void ThreadProxy::DoCreateAndInitializeOutputSurface() { scoped_refptr<ContextProvider> offscreen_context_provider; if (created_offscreen_context_provider_) { - offscreen_context_provider = layer_tree_host_->client()-> - OffscreenContextProviderForCompositorThread(); + offscreen_context_provider = + layer_tree_host()->client()->OffscreenContextProvider(); success = !!offscreen_context_provider.get(); if (!success) { OnOutputSurfaceInitializeAttempted(false, capabilities); @@ -300,14 +315,14 @@ void ThreadProxy::OnOutputSurfaceInitializeAttempted( bool success, const RendererCapabilities& capabilities) { DCHECK(IsMainThread()); - DCHECK(layer_tree_host_); + DCHECK(layer_tree_host()); if (success) { renderer_capabilities_main_thread_copy_ = capabilities; } LayerTreeHost::CreateResult result = - layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success); + layer_tree_host()->OnCreateAndInitializeOutputSurfaceAttempted(success); if (result == LayerTreeHost::CreateFailedButTryAgain) { if (!output_surface_creation_callback_.callback().is_null()) { Proxy::MainThreadTaskRunner()->PostTask( @@ -331,7 +346,7 @@ void ThreadProxy::SendCommitRequestToImplThreadIfNeeded() { const RendererCapabilities& ThreadProxy::GetRendererCapabilities() const { DCHECK(IsMainThread()); - DCHECK(!layer_tree_host_->output_surface_lost()); + DCHECK(!layer_tree_host()->output_surface_lost()); return renderer_capabilities_main_thread_copy_; } @@ -348,6 +363,11 @@ void ThreadProxy::SetNeedsAnimate() { void ThreadProxy::SetNeedsUpdateLayers() { DCHECK(IsMainThread()); + + if (commit_request_sent_to_impl_thread_) + return; + TRACE_EVENT0("cc", "ThreadProxy::SetNeedsUpdateLayers"); + SendCommitRequestToImplThreadIfNeeded(); } @@ -375,7 +395,7 @@ void ThreadProxy::CheckOutputSurfaceStatusOnImplThread() { TRACE_EVENT0("cc", "ThreadProxy::CheckOutputSurfaceStatusOnImplThread"); if (!layer_tree_host_impl_->IsContextLost()) return; - if (cc::ContextProvider* offscreen_contexts = + if (ContextProvider* offscreen_contexts = layer_tree_host_impl_->offscreen_context_provider()) offscreen_contexts->VerifyContexts(); scheduler_on_impl_thread_->DidLoseOutputSurface(); @@ -389,27 +409,23 @@ void ThreadProxy::OnSwapBuffersCompleteOnImplThread() { base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_)); } -void ThreadProxy::SetNeedsBeginFrameOnImplThread(bool enable) { +void ThreadProxy::SetNeedsBeginImplFrame(bool enable) { DCHECK(IsImplThread()); - TRACE_EVENT1("cc", "ThreadProxy::SetNeedsBeginFrameOnImplThread", + TRACE_EVENT1("cc", "ThreadProxy::SetNeedsBeginImplFrame", "enable", enable); - layer_tree_host_impl_->SetNeedsBeginFrame(enable); + layer_tree_host_impl_->SetNeedsBeginImplFrame(enable); UpdateBackgroundAnimateTicking(); } -void ThreadProxy::BeginFrameOnImplThread(const BeginFrameArgs& args) { +void ThreadProxy::BeginImplFrame(const BeginFrameArgs& args) { DCHECK(IsImplThread()); - TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnImplThread"); + TRACE_EVENT0("cc", "ThreadProxy::BeginImplFrame"); // Sample the frame time now. This time will be used for updating animations // when we draw. layer_tree_host_impl_->CurrentFrameTimeTicks(); - scheduler_on_impl_thread_->BeginFrame(args); -} - -void ThreadProxy::DidBeginFrameDeadlineOnImplThread() { - layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame(); + scheduler_on_impl_thread_->BeginImplFrame(args); } void ThreadProxy::OnCanDrawStateChanged(bool can_draw) { @@ -449,10 +465,12 @@ bool ThreadProxy::ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes, int priority_cutoff) { DCHECK(IsImplThread()); - if (!layer_tree_host_->contents_texture_manager()) + if (!contents_texture_manager_on_impl_thread()) + return false; + if (!layer_tree_host_impl_->resource_provider()) return false; - bool reduce_result = layer_tree_host_->contents_texture_manager()-> + bool reduce_result = contents_texture_manager_on_impl_thread()-> ReduceMemoryOnImplThread(limit_bytes, priority_cutoff, layer_tree_host_impl_->resource_provider()); @@ -468,34 +486,24 @@ bool ThreadProxy::ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes, return true; } -void ThreadProxy::ReduceWastedContentsTextureMemoryOnImplThread() { - DCHECK(IsImplThread()); - - if (!layer_tree_host_->contents_texture_manager()) - return; - - layer_tree_host_->contents_texture_manager()->ReduceWastedMemoryOnImplThread( - layer_tree_host_impl_->resource_provider()); -} - void ThreadProxy::SendManagedMemoryStats() { DCHECK(IsImplThread()); if (!layer_tree_host_impl_) return; - if (!layer_tree_host_->contents_texture_manager()) + if (!contents_texture_manager_on_impl_thread()) return; // If we are using impl-side painting, then SendManagedMemoryStats is called // directly after the tile manager's manage function, and doesn't need to // interact with main thread's layer tree. - if (layer_tree_host_->settings().impl_side_painting) + if (layer_tree_host_impl_->settings().impl_side_painting) return; layer_tree_host_impl_->SendManagedMemoryStats( - layer_tree_host_->contents_texture_manager()->MemoryVisibleBytes(), - layer_tree_host_->contents_texture_manager()-> + contents_texture_manager_on_impl_thread()->MemoryVisibleBytes(), + contents_texture_manager_on_impl_thread()-> MemoryVisibleAndNearbyBytes(), - layer_tree_host_->contents_texture_manager()->MemoryUseBytes()); + contents_texture_manager_on_impl_thread()->MemoryUseBytes()); } bool ThreadProxy::IsInsideDraw() { return inside_draw_; } @@ -529,7 +537,7 @@ void ThreadProxy::SetDeferCommits(bool defer_commits) { if (!defer_commits_ && pending_deferred_commit_) Proxy::MainThreadTaskRunner()->PostTask( FROM_HERE, - base::Bind(&ThreadProxy::BeginFrameOnMainThread, + base::Bind(&ThreadProxy::BeginMainFrame, main_thread_weak_ptr_, base::Passed(&pending_deferred_commit_))); } @@ -539,6 +547,11 @@ bool ThreadProxy::CommitRequested() const { return commit_requested_; } +bool ThreadProxy::BeginMainFrameRequested() const { + DCHECK(IsMainThread()); + return commit_request_sent_to_impl_thread_; +} + void ThreadProxy::SetNeedsRedrawOnImplThread() { DCHECK(IsImplThread()); TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedrawOnImplThread"); @@ -547,7 +560,6 @@ void ThreadProxy::SetNeedsRedrawOnImplThread() { void ThreadProxy::SetNeedsManageTilesOnImplThread() { DCHECK(IsImplThread()); - TRACE_EVENT0("cc", "ThreadProxy::SetNeedsManageTilesOnImplThread"); scheduler_on_impl_thread_->SetNeedsManageTiles(); } @@ -607,6 +619,28 @@ void ThreadProxy::SetInputThrottledUntilCommitOnImplThread( RenewTreePriority(); } +LayerTreeHost* ThreadProxy::layer_tree_host() { + DCHECK(IsMainThread() || IsMainThreadBlocked()); + return layer_tree_host_unsafe_; +} + +const LayerTreeHost* ThreadProxy::layer_tree_host() const { + DCHECK(IsMainThread() || IsMainThreadBlocked()); + return layer_tree_host_unsafe_; +} + +PrioritizedResourceManager* +ThreadProxy::contents_texture_manager_on_main_thread() { + DCHECK(IsMainThread() || IsMainThreadBlocked()); + return layer_tree_host()->contents_texture_manager(); +} + +PrioritizedResourceManager* +ThreadProxy::contents_texture_manager_on_impl_thread() { + DCHECK(IsImplThread()); + return contents_texture_manager_unsafe_; +} + void ThreadProxy::Start(scoped_ptr<OutputSurface> first_output_surface) { DCHECK(IsMainThread()); DCHECK(Proxy::HasImplThread()); @@ -663,7 +697,8 @@ void ThreadProxy::Stop() { weak_factory_.InvalidateWeakPtrs(); DCHECK(!layer_tree_host_impl_.get()); // verify that the impl deleted. - layer_tree_host_ = NULL; + contents_texture_manager_unsafe_ = NULL; + layer_tree_host_unsafe_ = NULL; started_ = false; } @@ -692,54 +727,59 @@ void ThreadProxy::FinishAllRenderingOnImplThread(CompletionEvent* completion) { completion->Signal(); } -void ThreadProxy::ScheduledActionSendBeginFrameToMainThread() { - TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionSendBeginFrameToMainThread"); - scoped_ptr<BeginFrameAndCommitState> begin_frame_state( - new BeginFrameAndCommitState); - begin_frame_state->monotonic_frame_begin_time = +void ThreadProxy::ScheduledActionSendBeginMainFrame() { + TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionSendBeginMainFrame"); + scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state( + new BeginMainFrameAndCommitState); + begin_main_frame_state->monotonic_frame_begin_time = layer_tree_host_impl_->CurrentPhysicalTimeTicks(); - begin_frame_state->scroll_info = + begin_main_frame_state->scroll_info = layer_tree_host_impl_->ProcessScrollDeltas(); if (!layer_tree_host_impl_->settings().impl_side_painting) { DCHECK_GT(layer_tree_host_impl_->memory_allocation_limit_bytes(), 0u); } - begin_frame_state->memory_allocation_limit_bytes = + begin_main_frame_state->memory_allocation_limit_bytes = layer_tree_host_impl_->memory_allocation_limit_bytes(); - begin_frame_state->memory_allocation_priority_cutoff = + begin_main_frame_state->memory_allocation_priority_cutoff = layer_tree_host_impl_->memory_allocation_priority_cutoff(); - begin_frame_state->evicted_ui_resources = + begin_main_frame_state->evicted_ui_resources = layer_tree_host_impl_->EvictedUIResourcesExist(); Proxy::MainThreadTaskRunner()->PostTask( FROM_HERE, - base::Bind(&ThreadProxy::BeginFrameOnMainThread, + base::Bind(&ThreadProxy::BeginMainFrame, main_thread_weak_ptr_, - base::Passed(&begin_frame_state))); + base::Passed(&begin_main_frame_state))); - if (begin_frame_sent_to_main_thread_completion_event_on_impl_thread_) { - begin_frame_sent_to_main_thread_completion_event_on_impl_thread_->Signal(); - begin_frame_sent_to_main_thread_completion_event_on_impl_thread_ = NULL; + if (begin_main_frame_sent_completion_event_on_impl_thread_) { + begin_main_frame_sent_completion_event_on_impl_thread_->Signal(); + begin_main_frame_sent_completion_event_on_impl_thread_ = NULL; } - begin_frame_sent_to_main_thread_time_ = base::TimeTicks::HighResNow(); + begin_main_frame_sent_time_ = base::TimeTicks::HighResNow(); } -void ThreadProxy::BeginFrameOnMainThread( - scoped_ptr<BeginFrameAndCommitState> begin_frame_state) { - TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnMainThread"); +void ThreadProxy::BeginMainFrame( + scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) { + TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame"); DCHECK(IsMainThread()); - if (!layer_tree_host_) + if (!layer_tree_host()) return; if (defer_commits_) { - pending_deferred_commit_ = begin_frame_state.Pass(); - layer_tree_host_->DidDeferCommit(); + pending_deferred_commit_ = begin_main_frame_state.Pass(); + layer_tree_host()->DidDeferCommit(); TRACE_EVENT0("cc", "EarlyOut_DeferCommits"); return; } + // If the commit finishes, LayerTreeHost will transfer its swap promises to + // LayerTreeImpl. The destructor of SwapPromiseChecker checks LayerTressHost's + // swap promises. + SwapPromiseChecker swap_promise_checker(layer_tree_host()); + // Do not notify the impl thread of commit requests that occur during - // the apply/animate/layout part of the BeginFrameAndCommit process since + // the apply/animate/layout part of the BeginMainFrameAndCommit process since // those commit requests will get painted immediately. Once we have done // the paint, commit_requested_ will be set to false to allow new commit // requests to be scheduled. @@ -751,7 +791,7 @@ void ThreadProxy::BeginFrameOnMainThread( // callbacks will trigger another frame. animate_requested_ = false; - if (!in_composite_and_readback_ && !layer_tree_host_->visible()) { + if (!in_composite_and_readback_ && !layer_tree_host()->visible()) { commit_requested_ = false; commit_request_sent_to_impl_thread_ = false; @@ -759,46 +799,49 @@ void ThreadProxy::BeginFrameOnMainThread( bool did_handle = false; Proxy::ImplThreadTaskRunner()->PostTask( FROM_HERE, - base::Bind(&ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread, + base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread, impl_thread_weak_ptr_, did_handle)); return; } - if (begin_frame_state) - layer_tree_host_->ApplyScrollAndScale(*begin_frame_state->scroll_info); + if (begin_main_frame_state) { + layer_tree_host()->ApplyScrollAndScale( + *begin_main_frame_state->scroll_info); + } - layer_tree_host_->WillBeginFrame(); + layer_tree_host()->WillBeginMainFrame(); - if (begin_frame_state) { - layer_tree_host_->UpdateClientAnimations( - begin_frame_state->monotonic_frame_begin_time); - layer_tree_host_->AnimateLayers( - begin_frame_state->monotonic_frame_begin_time); + if (begin_main_frame_state) { + layer_tree_host()->UpdateClientAnimations( + begin_main_frame_state->monotonic_frame_begin_time); + layer_tree_host()->AnimateLayers( + begin_main_frame_state->monotonic_frame_begin_time); } // Unlink any backings that the impl thread has evicted, so that we know to // re-paint them in UpdateLayers. - if (layer_tree_host_->contents_texture_manager()) { - layer_tree_host_->contents_texture_manager()-> + if (contents_texture_manager_on_main_thread()) { + contents_texture_manager_on_main_thread()-> UnlinkAndClearEvictedBackings(); - if (begin_frame_state) { - layer_tree_host_->contents_texture_manager()->SetMaxMemoryLimitBytes( - begin_frame_state->memory_allocation_limit_bytes); - layer_tree_host_->contents_texture_manager()->SetExternalPriorityCutoff( - begin_frame_state->memory_allocation_priority_cutoff); + if (begin_main_frame_state) { + contents_texture_manager_on_main_thread()->SetMaxMemoryLimitBytes( + begin_main_frame_state->memory_allocation_limit_bytes); + contents_texture_manager_on_main_thread()->SetExternalPriorityCutoff( + begin_main_frame_state->memory_allocation_priority_cutoff); } } // Recreate all UI resources if there were evicted UI resources when the impl // thread initiated the commit. - bool evicted_ui_resources = - begin_frame_state ? begin_frame_state->evicted_ui_resources : false; + bool evicted_ui_resources = begin_main_frame_state + ? begin_main_frame_state->evicted_ui_resources + : false; if (evicted_ui_resources) - layer_tree_host_->RecreateUIResources(); + layer_tree_host()->RecreateUIResources(); - layer_tree_host_->Layout(); + layer_tree_host()->Layout(); // Clear the commit flag after updating animations and layout here --- objects // that only layout when painted will trigger another SetNeedsCommit inside @@ -814,28 +857,28 @@ void ThreadProxy::BeginFrameOnMainThread( scoped_ptr<ResourceUpdateQueue> queue = make_scoped_ptr(new ResourceUpdateQueue); - bool updated = layer_tree_host_->UpdateLayers(queue.get()); + bool updated = layer_tree_host()->UpdateLayers(queue.get()); // Once single buffered layers are committed, they cannot be modified until // they are drawn by the impl thread. textures_acquired_ = false; - layer_tree_host_->WillCommit(); + layer_tree_host()->WillCommit(); if (!updated && can_cancel_this_commit) { TRACE_EVENT0("cc", "EarlyOut_NoUpdates"); bool did_handle = true; Proxy::ImplThreadTaskRunner()->PostTask( FROM_HERE, - base::Bind(&ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread, + base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread, impl_thread_weak_ptr_, did_handle)); // Although the commit is internally aborted, this is because it has been // detected to be a no-op. From the perspective of an embedder, this commit // went through, and input should no longer be throttled, etc. - layer_tree_host_->CommitComplete(); - layer_tree_host_->DidBeginFrame(); + layer_tree_host()->CommitComplete(); + layer_tree_host()->DidBeginMainFrame(); return; } @@ -849,11 +892,11 @@ void ThreadProxy::BeginFrameOnMainThread( SetNeedsAnimate(); } - scoped_refptr<cc::ContextProvider> offscreen_context_provider; + scoped_refptr<ContextProvider> offscreen_context_provider; if (renderer_capabilities_main_thread_copy_.using_offscreen_context3d && - layer_tree_host_->needs_offscreen_context()) { - offscreen_context_provider = layer_tree_host_->client()-> - OffscreenContextProviderForCompositorThread(); + layer_tree_host()->needs_offscreen_context()) { + offscreen_context_provider = + layer_tree_host()->client()->OffscreenContextProvider(); if (offscreen_context_provider.get()) created_offscreen_context_provider_ = true; } @@ -863,7 +906,7 @@ void ThreadProxy::BeginFrameOnMainThread( // point of view, but asynchronously performed on the impl thread, // coordinated by the Scheduler. { - TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnMainThread::commit"); + TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame::commit"); DebugScopedSetMainThreadBlocked main_thread_blocked(this); @@ -872,10 +915,6 @@ void ThreadProxy::BeginFrameOnMainThread( // to receive its callbacks before that. BlockingTaskRunner::CapturePostTasks blocked; - RenderingStatsInstrumentation* stats_instrumentation = - layer_tree_host_->rendering_stats_instrumentation(); - base::TimeTicks start_time = stats_instrumentation->StartRecording(); - CompletionEvent completion; Proxy::ImplThreadTaskRunner()->PostTask( FROM_HERE, @@ -886,20 +925,21 @@ void ThreadProxy::BeginFrameOnMainThread( offscreen_context_provider)); completion.Wait(); - base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); - stats_instrumentation->AddCommit(duration); - stats_instrumentation->IssueTraceEventForMainThreadStats(); + RenderingStatsInstrumentation* stats_instrumentation = + layer_tree_host()->rendering_stats_instrumentation(); + BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent( + stats_instrumentation->main_thread_rendering_stats()); stats_instrumentation->AccumulateAndClearMainThreadStats(); } - layer_tree_host_->CommitComplete(); - layer_tree_host_->DidBeginFrame(); + layer_tree_host()->CommitComplete(); + layer_tree_host()->DidBeginMainFrame(); } void ThreadProxy::StartCommitOnImplThread( CompletionEvent* completion, ResourceUpdateQueue* raw_queue, - scoped_refptr<cc::ContextProvider> offscreen_context_provider) { + scoped_refptr<ContextProvider> offscreen_context_provider) { scoped_ptr<ResourceUpdateQueue> queue(raw_queue); TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread"); @@ -919,8 +959,18 @@ void ThreadProxy::StartCommitOnImplThread( layer_tree_host_impl_->SetOffscreenContextProvider( offscreen_context_provider); - if (layer_tree_host_->contents_texture_manager()) { - if (layer_tree_host_->contents_texture_manager()-> + if (contents_texture_manager_unsafe_) { + DCHECK_EQ(contents_texture_manager_unsafe_, + contents_texture_manager_on_main_thread()); + } else { + // Cache this pointer that was created on the main thread side to avoid a + // data race between creating it and using it on the compositor thread. + contents_texture_manager_unsafe_ = + contents_texture_manager_on_main_thread(); + } + + if (contents_texture_manager_on_main_thread()) { + if (contents_texture_manager_on_main_thread()-> LinkedEvictedBackingsExist()) { // Clear any uploads we were making to textures linked to evicted // resources @@ -930,7 +980,7 @@ void ThreadProxy::StartCommitOnImplThread( SetNeedsCommitOnImplThread(); } - layer_tree_host_->contents_texture_manager()-> + contents_texture_manager_on_main_thread()-> PushTexturePrioritiesToBackings(); } @@ -945,23 +995,17 @@ void ThreadProxy::StartCommitOnImplThread( scheduler_on_impl_thread_->AnticipatedDrawTime()); } -void ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread(bool did_handle) { - TRACE_EVENT0("cc", "ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread"); +void ThreadProxy::BeginMainFrameAbortedOnImplThread(bool did_handle) { + TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread"); DCHECK(IsImplThread()); DCHECK(scheduler_on_impl_thread_); DCHECK(scheduler_on_impl_thread_->CommitPending()); DCHECK(!layer_tree_host_impl_->pending_tree()); - // If the begin frame data was handled, then scroll and scale set was applied - // by the main thread, so the active tree needs to be updated as if these sent - // values were applied and committed. - if (did_handle) { - layer_tree_host_impl_->active_tree() - ->ApplySentScrollAndScaleDeltasFromAbortedCommit(); - layer_tree_host_impl_->active_tree()->ResetContentsTexturesPurged(); + if (did_handle) SetInputThrottledUntilCommitOnImplThread(false); - } - scheduler_on_impl_thread_->BeginFrameAbortedByMainThread(did_handle); + layer_tree_host_impl_->BeginMainFrameAborted(did_handle); + scheduler_on_impl_thread_->BeginMainFrameAborted(did_handle); } void ThreadProxy::ScheduledActionCommit() { @@ -976,8 +1020,8 @@ void ThreadProxy::ScheduledActionCommit() { inside_commit_ = true; layer_tree_host_impl_->BeginCommit(); - layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get()); - layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get()); + layer_tree_host()->BeginCommitOnImplThread(layer_tree_host_impl_.get()); + layer_tree_host()->FinishCommitOnImplThread(layer_tree_host_impl_.get()); layer_tree_host_impl_->CommitComplete(); inside_commit_ = false; @@ -987,7 +1031,7 @@ void ThreadProxy::ScheduledActionCommit() { next_frame_is_newly_committed_frame_on_impl_thread_ = true; - if (layer_tree_host_->settings().impl_side_painting && + if (layer_tree_host()->settings().impl_side_painting && commit_waits_for_activation_) { // For some layer types in impl-side painting, the commit is held until // the pending tree is activated. It's also possible that the @@ -1004,8 +1048,8 @@ void ThreadProxy::ScheduledActionCommit() { commit_waits_for_activation_ = false; commit_complete_time_ = base::TimeTicks::HighResNow(); - begin_frame_to_commit_duration_history_.InsertSample( - commit_complete_time_ - begin_frame_sent_to_main_thread_time_); + begin_main_frame_to_commit_duration_history_.InsertSample( + commit_complete_time_ - begin_main_frame_sent_time_); // SetVisible kicks off the next scheduler action, so this must be last. scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); @@ -1096,7 +1140,7 @@ DrawSwapReadbackResult ThreadProxy::DrawSwapReadbackInternal( if (draw_frame) { layer_tree_host_impl_->DrawLayers( &frame, - scheduler_on_impl_thread_->LastBeginFrameOnImplThreadTime()); + scheduler_on_impl_thread_->LastBeginImplFrameTime()); result.did_draw = true; } layer_tree_host_impl_->DidDrawAllLayers(frame); @@ -1254,8 +1298,8 @@ base::TimeDelta ThreadProxy::DrawDurationEstimate() { return historical_estimate + padding; } -base::TimeDelta ThreadProxy::BeginFrameToCommitDurationEstimate() { - return begin_frame_to_commit_duration_history_.Percentile( +base::TimeDelta ThreadProxy::BeginMainFrameToCommitDurationEstimate() { + return begin_main_frame_to_commit_duration_history_.Percentile( kCommitAndActivationDurationEstimationPercentile); } @@ -1264,14 +1308,18 @@ base::TimeDelta ThreadProxy::CommitToActivateDurationEstimate() { kCommitAndActivationDurationEstimationPercentile); } -void ThreadProxy::PostBeginFrameDeadline(const base::Closure& closure, - base::TimeTicks deadline) { - base::TimeDelta delta = deadline - base::TimeTicks::Now(); +void ThreadProxy::PostBeginImplFrameDeadline(const base::Closure& closure, + base::TimeTicks deadline) { + base::TimeDelta delta = deadline - gfx::FrameTime::Now(); if (delta <= base::TimeDelta()) delta = base::TimeDelta(); Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, closure, delta); } +void ThreadProxy::DidBeginImplFrameDeadline() { + layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame(); +} + void ThreadProxy::ReadyToFinalizeTextureUpdates() { DCHECK(IsImplThread()); scheduler_on_impl_thread_->FinishCommit(); @@ -1279,25 +1327,25 @@ void ThreadProxy::ReadyToFinalizeTextureUpdates() { void ThreadProxy::DidCommitAndDrawFrame() { DCHECK(IsMainThread()); - if (!layer_tree_host_) + if (!layer_tree_host()) return; - layer_tree_host_->DidCommitAndDrawFrame(); + layer_tree_host()->DidCommitAndDrawFrame(); } void ThreadProxy::DidCompleteSwapBuffers() { DCHECK(IsMainThread()); - if (!layer_tree_host_) + if (!layer_tree_host()) return; - layer_tree_host_->DidCompleteSwapBuffers(); + layer_tree_host()->DidCompleteSwapBuffers(); } void ThreadProxy::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events, base::Time wall_clock_time) { TRACE_EVENT0("cc", "ThreadProxy::SetAnimationEvents"); DCHECK(IsMainThread()); - if (!layer_tree_host_) + if (!layer_tree_host()) return; - layer_tree_host_->SetAnimationEvents(events.Pass(), wall_clock_time); + layer_tree_host()->SetAnimationEvents(events.Pass(), wall_clock_time); } void ThreadProxy::CreateAndInitializeOutputSurface() { @@ -1320,7 +1368,7 @@ void ThreadProxy::CreateAndInitializeOutputSurface() { if (has_initialized_output_surface_on_impl_thread) return; - layer_tree_host_->DidLoseOutputSurface(); + layer_tree_host()->DidLoseOutputSurface(); output_surface_creation_callback_.Reset(base::Bind( &ThreadProxy::DoCreateAndInitializeOutputSurface, base::Unretained(this))); @@ -1339,8 +1387,8 @@ void ThreadProxy::HasInitializedOutputSurfaceOnImplThread( void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread"); DCHECK(IsImplThread()); - layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this); - const LayerTreeSettings& settings = layer_tree_host_->settings(); + layer_tree_host_impl_ = layer_tree_host()->CreateLayerTreeHostImpl(this); + const LayerTreeSettings& settings = layer_tree_host()->settings(); SchedulerSettings scheduler_settings; scheduler_settings.deadline_scheduling_enabled = settings.deadline_scheduling_enabled; @@ -1353,7 +1401,8 @@ void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { settings.using_synchronous_renderer_compositor; scheduler_settings.throttle_frame_production = settings.throttle_frame_production; - scheduler_on_impl_thread_ = Scheduler::Create(this, scheduler_settings); + scheduler_on_impl_thread_ = Scheduler::Create(this, scheduler_settings, + layer_tree_host_id_); scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); impl_thread_weak_ptr_ = weak_factory_on_impl_thread_.GetWeakPtr(); @@ -1372,7 +1421,7 @@ void ThreadProxy::InitializeOutputSurfaceOnImplThread( DCHECK(success); DCHECK(capabilities); - layer_tree_host_->DeleteContentsTexturesOnImplThread( + layer_tree_host()->DeleteContentsTexturesOnImplThread( layer_tree_host_impl_->resource_provider()); *success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass()); @@ -1403,10 +1452,10 @@ void ThreadProxy::FinishGLOnImplThread(CompletionEvent* completion) { void ThreadProxy::LayerTreeHostClosedOnImplThread(CompletionEvent* completion) { TRACE_EVENT0("cc", "ThreadProxy::LayerTreeHostClosedOnImplThread"); DCHECK(IsImplThread()); - layer_tree_host_->DeleteContentsTexturesOnImplThread( + layer_tree_host()->DeleteContentsTexturesOnImplThread( layer_tree_host_impl_->resource_provider()); current_resource_update_controller_on_impl_thread_.reset(); - layer_tree_host_impl_->SetNeedsBeginFrame(false); + layer_tree_host_impl_->SetNeedsBeginImplFrame(false); scheduler_on_impl_thread_.reset(); layer_tree_host_impl_.reset(); weak_factory_on_impl_thread_.InvalidateWeakPtrs(); @@ -1417,12 +1466,12 @@ size_t ThreadProxy::MaxPartialTextureUpdates() const { return ResourceUpdateController::MaxPartialTextureUpdates(); } -ThreadProxy::BeginFrameAndCommitState::BeginFrameAndCommitState() +ThreadProxy::BeginMainFrameAndCommitState::BeginMainFrameAndCommitState() : memory_allocation_limit_bytes(0), memory_allocation_priority_cutoff(0), evicted_ui_resources(false) {} -ThreadProxy::BeginFrameAndCommitState::~BeginFrameAndCommitState() {} +ThreadProxy::BeginMainFrameAndCommitState::~BeginMainFrameAndCommitState() {} scoped_ptr<base::Value> ThreadProxy::AsValue() const { scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); @@ -1502,7 +1551,7 @@ void ThreadProxy::RenewTreePriority() { DCHECK(IsImplThread()); bool smoothness_takes_priority = layer_tree_host_impl_->pinch_gesture_active() || - layer_tree_host_impl_->CurrentlyScrollingLayer() || + layer_tree_host_impl_->IsCurrentlyScrolling() || layer_tree_host_impl_->page_scale_animation_active(); base::TimeTicks now = layer_tree_host_impl_->CurrentPhysicalTimeTicks(); @@ -1597,4 +1646,9 @@ void ThreadProxy::DidActivatePendingTree() { base::TimeTicks::HighResNow() - commit_complete_time_); } +void ThreadProxy::DidManageTiles() { + DCHECK(IsImplThread()); + scheduler_on_impl_thread_->DidManageTiles(); +} + } // namespace cc diff --git a/chromium/cc/trees/thread_proxy.h b/chromium/cc/trees/thread_proxy.h index 78a59613d39..cf041edbcfd 100644 --- a/chromium/cc/trees/thread_proxy.h +++ b/chromium/cc/trees/thread_proxy.h @@ -56,6 +56,7 @@ class ThreadProxy : public Proxy, virtual void NotifyInputThrottledUntilCommit() OVERRIDE; virtual void SetDeferCommits(bool defer_commits) OVERRIDE; virtual bool CommitRequested() const OVERRIDE; + virtual bool BeginMainFrameRequested() const OVERRIDE; virtual void MainThreadHasStoppedFlinging() OVERRIDE; virtual void Start(scoped_ptr<OutputSurface> first_output_surface) OVERRIDE; virtual void Stop() OVERRIDE; @@ -68,11 +69,13 @@ class ThreadProxy : public Proxy, // LayerTreeHostImplClient implementation virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE; + virtual void DidSwapBuffersOnImplThread() OVERRIDE {} virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE; - virtual void BeginFrameOnImplThread(const BeginFrameArgs& args) OVERRIDE; - virtual void DidBeginFrameDeadlineOnImplThread() OVERRIDE; + virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE; virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE; virtual void NotifyReadyToActivate() OVERRIDE; + // Please call these 2 functions through + // LayerTreeHostImpl's SetNeedsRedraw() and SetNeedsRedrawRect(). virtual void SetNeedsRedrawOnImplThread() OVERRIDE; virtual void SetNeedsRedrawRectOnImplThread(gfx::Rect dirty_rect) OVERRIDE; virtual void SetNeedsManageTilesOnImplThread() OVERRIDE; @@ -84,17 +87,17 @@ class ThreadProxy : public Proxy, virtual bool ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes, int priority_cutoff) OVERRIDE; - virtual void ReduceWastedContentsTextureMemoryOnImplThread() OVERRIDE; virtual void SendManagedMemoryStats() OVERRIDE; virtual bool IsInsideDraw() OVERRIDE; virtual void RenewTreePriority() OVERRIDE; virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay) OVERRIDE; virtual void DidActivatePendingTree() OVERRIDE; + virtual void DidManageTiles() OVERRIDE; // SchedulerClient implementation - virtual void SetNeedsBeginFrameOnImplThread(bool enable) OVERRIDE; - virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE; + virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE; + virtual void ScheduledActionSendBeginMainFrame() OVERRIDE; virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE; virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE; @@ -107,10 +110,11 @@ class ThreadProxy : public Proxy, virtual void ScheduledActionManageTiles() OVERRIDE; virtual void DidAnticipatedDrawTimeChange(base::TimeTicks time) OVERRIDE; virtual base::TimeDelta DrawDurationEstimate() OVERRIDE; - virtual base::TimeDelta BeginFrameToCommitDurationEstimate() OVERRIDE; + virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE; virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE; - virtual void PostBeginFrameDeadline(const base::Closure& closure, - base::TimeTicks deadline) OVERRIDE; + virtual void PostBeginImplFrameDeadline(const base::Closure& closure, + base::TimeTicks deadline) OVERRIDE; + virtual void DidBeginImplFrameDeadline() OVERRIDE; // ResourceUpdateControllerClient implementation virtual void ReadyToFinalizeTextureUpdates() OVERRIDE; @@ -119,9 +123,9 @@ class ThreadProxy : public Proxy, ThreadProxy(LayerTreeHost* layer_tree_host, scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner); - struct BeginFrameAndCommitState { - BeginFrameAndCommitState(); - ~BeginFrameAndCommitState(); + struct BeginMainFrameAndCommitState { + BeginMainFrameAndCommitState(); + ~BeginMainFrameAndCommitState(); base::TimeTicks monotonic_frame_begin_time; scoped_ptr<ScrollAndScaleSet> scroll_info; @@ -131,8 +135,8 @@ class ThreadProxy : public Proxy, }; // Called on main thread. - void BeginFrameOnMainThread( - scoped_ptr<BeginFrameAndCommitState> begin_frame_state); + void BeginMainFrame( + scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state); void DidCommitAndDrawFrame(); void DidCompleteSwapBuffers(); void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue, @@ -150,13 +154,13 @@ class ThreadProxy : public Proxy, struct SchedulerStateRequest; void ForceCommitForReadbackOnImplThread( - CompletionEvent* begin_frame_sent_completion, + CompletionEvent* begin_main_frame_sent_completion, ReadbackRequest* request); void StartCommitOnImplThread( CompletionEvent* completion, ResourceUpdateQueue* queue, - scoped_refptr<cc::ContextProvider> offscreen_context_provider); - void BeginFrameAbortedByMainThreadOnImplThread(bool did_handle); + scoped_refptr<ContextProvider> offscreen_context_provider); + void BeginMainFrameAbortedOnImplThread(bool did_handle); void RequestReadbackOnImplThread(ReadbackRequest* request); void FinishAllRenderingOnImplThread(CompletionEvent* completion); void InitializeImplOnImplThread(CompletionEvent* completion); @@ -191,6 +195,10 @@ class ThreadProxy : public Proxy, void StartScrollbarAnimationOnImplThread(); void MainThreadHasStoppedFlingingOnImplThread(); void SetInputThrottledUntilCommitOnImplThread(bool is_throttled); + LayerTreeHost* layer_tree_host(); + const LayerTreeHost* layer_tree_host() const; + PrioritizedResourceManager* contents_texture_manager_on_main_thread(); + PrioritizedResourceManager* contents_texture_manager_on_impl_thread(); // Accessed on main thread only. @@ -198,12 +206,17 @@ class ThreadProxy : public Proxy, bool animate_requested_; // Set only when SetNeedsCommit is called. bool commit_requested_; - // Set by SetNeedsCommit and SetNeedsAnimate. + // Set by SetNeedsAnimate, SetNeedsUpdateLayers, and SetNeedsCommit. bool commit_request_sent_to_impl_thread_; - // Set by BeginFrameOnMainThread + // Set by BeginMainFrame bool created_offscreen_context_provider_; base::CancelableClosure output_surface_creation_callback_; - LayerTreeHost* layer_tree_host_; + // Don't use this variable directly, go through layer_tree_host() to ensure it + // is only used on the main thread or if the main thread is blocked. + LayerTreeHost* layer_tree_host_unsafe_; + // Use one of the contents_texture_manager_on functions above instead of using + // this variable directly. + PrioritizedResourceManager* contents_texture_manager_unsafe_; RendererCapabilities renderer_capabilities_main_thread_copy_; bool started_; bool textures_acquired_; @@ -219,19 +232,14 @@ class ThreadProxy : public Proxy, bool commit_waits_for_activation_; bool inside_commit_; - base::WeakPtrFactory<ThreadProxy> weak_factory_on_impl_thread_; - - base::WeakPtr<ThreadProxy> main_thread_weak_ptr_; - base::WeakPtrFactory<ThreadProxy> weak_factory_; - scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl_; scoped_ptr<Scheduler> scheduler_on_impl_thread_; // Set when the main thread is waiting on a - // ScheduledActionSendBeginFrameToMainThread to be issued. + // ScheduledActionSendBeginMainFrame to be issued. CompletionEvent* - begin_frame_sent_to_main_thread_completion_event_on_impl_thread_; + begin_main_frame_sent_completion_event_on_impl_thread_; // Set when the main thread is waiting on a readback. ReadbackRequest* readback_request_on_impl_thread_; @@ -253,7 +261,7 @@ class ThreadProxy : public Proxy, bool next_frame_is_newly_committed_frame_on_impl_thread_; bool throttle_frame_production_; - bool begin_frame_scheduling_enabled_; + bool begin_impl_frame_scheduling_enabled_; bool using_synchronous_renderer_compositor_; bool inside_draw_; @@ -262,21 +270,27 @@ class ThreadProxy : public Proxy, bool defer_commits_; bool input_throttled_until_commit_; - scoped_ptr<BeginFrameAndCommitState> pending_deferred_commit_; + scoped_ptr<BeginMainFrameAndCommitState> pending_deferred_commit_; base::TimeTicks smoothness_takes_priority_expiration_time_; bool renew_tree_priority_on_impl_thread_pending_; RollingTimeDeltaHistory draw_duration_history_; - RollingTimeDeltaHistory begin_frame_to_commit_duration_history_; + RollingTimeDeltaHistory begin_main_frame_to_commit_duration_history_; RollingTimeDeltaHistory commit_to_activate_duration_history_; // Used for computing samples added to - // begin_frame_to_commit_draw_duration_history_ and + // begin_main_frame_to_commit_duration_history_ and // activation_duration_history_. - base::TimeTicks begin_frame_sent_to_main_thread_time_; + base::TimeTicks begin_main_frame_sent_time_; base::TimeTicks commit_complete_time_; + base::WeakPtr<ThreadProxy> main_thread_weak_ptr_; + base::WeakPtrFactory<ThreadProxy> weak_factory_on_impl_thread_; + base::WeakPtrFactory<ThreadProxy> weak_factory_; + + const int layer_tree_host_id_; + DISALLOW_COPY_AND_ASSIGN(ThreadProxy); }; diff --git a/chromium/cc/trees/tree_synchronizer_unittest.cc b/chromium/cc/trees/tree_synchronizer_unittest.cc index 4e0c89fca5c..827c3662f79 100644 --- a/chromium/cc/trees/tree_synchronizer_unittest.cc +++ b/chromium/cc/trees/tree_synchronizer_unittest.cc @@ -552,11 +552,8 @@ TEST_F(TreeSynchronizerTest, SynchronizeAnimations) { FakeProxy proxy; DebugScopedSetImplThread impl(&proxy); FakeRenderingStatsInstrumentation stats_instrumentation; - scoped_ptr<LayerTreeHostImpl> host_impl = - LayerTreeHostImpl::Create(settings, - NULL, - &proxy, - &stats_instrumentation); + scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create( + settings, NULL, &proxy, &stats_instrumentation, NULL, 0); scoped_refptr<Layer> layer_tree_root = Layer::Create(); host_->SetRootLayer(layer_tree_root); @@ -587,11 +584,8 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollParent) { FakeProxy proxy; DebugScopedSetImplThread impl(&proxy); FakeRenderingStatsInstrumentation stats_instrumentation; - scoped_ptr<LayerTreeHostImpl> host_impl = - LayerTreeHostImpl::Create(settings, - NULL, - &proxy, - &stats_instrumentation); + scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create( + settings, NULL, &proxy, &stats_instrumentation, NULL, 0); scoped_refptr<Layer> layer_tree_root = Layer::Create(); scoped_refptr<Layer> scroll_parent = Layer::Create(); @@ -665,11 +659,8 @@ TEST_F(TreeSynchronizerTest, SynchronizeClipParent) { FakeProxy proxy; DebugScopedSetImplThread impl(&proxy); FakeRenderingStatsInstrumentation stats_instrumentation; - scoped_ptr<LayerTreeHostImpl> host_impl = - LayerTreeHostImpl::Create(settings, - NULL, - &proxy, - &stats_instrumentation); + scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create( + settings, NULL, &proxy, &stats_instrumentation, NULL, 0); scoped_refptr<Layer> layer_tree_root = Layer::Create(); scoped_refptr<Layer> clip_parent = Layer::Create(); |