diff options
Diffstat (limited to 'chromium/cc/trees/layer_tree_host_impl.cc')
-rw-r--r-- | chromium/cc/trees/layer_tree_host_impl.cc | 1481 |
1 files changed, 855 insertions, 626 deletions
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc index e4d1b735765..e35187e34df 100644 --- a/chromium/cc/trees/layer_tree_host_impl.cc +++ b/chromium/cc/trees/layer_tree_host_impl.cc @@ -22,7 +22,6 @@ #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" #include "cc/debug/rendering_stats_instrumentation.h" #include "cc/debug/traced_value.h" @@ -33,6 +32,7 @@ #include "cc/layers/layer_impl.h" #include "cc/layers/layer_iterator.h" #include "cc/layers/painted_scrollbar_layer_impl.h" +#include "cc/layers/quad_sink.h" #include "cc/layers/render_surface_impl.h" #include "cc/layers/scrollbar_layer_impl_base.h" #include "cc/output/compositor_frame_metadata.h" @@ -44,18 +44,23 @@ #include "cc/quads/shared_quad_state.h" #include "cc/quads/solid_color_draw_quad.h" #include "cc/quads/texture_draw_quad.h" +#include "cc/resources/direct_raster_worker_pool.h" +#include "cc/resources/image_copy_raster_worker_pool.h" +#include "cc/resources/image_raster_worker_pool.h" #include "cc/resources/memory_history.h" #include "cc/resources/picture_layer_tiling.h" +#include "cc/resources/pixel_buffer_raster_worker_pool.h" #include "cc/resources/prioritized_resource_manager.h" +#include "cc/resources/raster_worker_pool.h" +#include "cc/resources/resource_pool.h" #include "cc/resources/texture_mailbox_deleter.h" #include "cc/resources/ui_resource_bitmap.h" #include "cc/scheduler/delay_based_time_source.h" -#include "cc/scheduler/texture_uploader.h" #include "cc/trees/damage_tracker.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_impl.h" -#include "cc/trees/quad_culler.h" +#include "cc/trees/occlusion_tracker.h" #include "cc/trees/single_thread_proxy.h" #include "cc/trees/tree_synchronizer.h" #include "gpu/GLES2/gl2extchromium.h" @@ -98,26 +103,14 @@ size_t GetMaxTransferBufferUsageBytes(cc::ContextProvider* context_provider) { 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) { +unsigned 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) + if (context_provider->ContextCapabilities().gpu.egl_image_external) return GL_TEXTURE_EXTERNAL_OES; - if (context_provider->ContextCapabilities().texture_rectangle) + if (context_provider->ContextCapabilities().gpu.texture_rectangle) return GL_TEXTURE_RECTANGLE_ARB; -#endif return GL_TEXTURE_2D; } @@ -161,18 +154,17 @@ class LayerTreeHostImplTimeSourceAdapter : public TimeSourceClient { new DebugScopedSetImplThread(layer_tree_host_impl_->proxy())); } - // TODO(enne): This should probably happen post-animate. + layer_tree_host_impl_->Animate( + layer_tree_host_impl_->CurrentFrameTimeTicks()); + layer_tree_host_impl_->UpdateBackgroundAnimateTicking(true); + bool start_ready_animations = true; + layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); + if (layer_tree_host_impl_->pending_tree()) { layer_tree_host_impl_->pending_tree()->UpdateDrawProperties(); layer_tree_host_impl_->ManageTiles(); } - layer_tree_host_impl_->Animate( - layer_tree_host_impl_->CurrentFrameTimeTicks(), - layer_tree_host_impl_->CurrentFrameTime()); - layer_tree_host_impl_->UpdateBackgroundAnimateTicking(true); - bool start_ready_animations = true; - layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame(); } @@ -223,11 +215,13 @@ LayerTreeHostImpl::LayerTreeHostImpl( int id) : client_(client), proxy_(proxy), + use_gpu_rasterization_(false), + on_demand_task_graph_runner_(NULL), input_handler_client_(NULL), did_lock_scrolling_layer_(false), should_bubble_scrolls_(false), - last_scroll_did_bubble_(false), wheel_scrolling_(false), + scroll_affects_scroll_handler_(false), scroll_layer_id_when_mouse_over_scrollbar_(0), tile_priorities_dirty_(false), root_layer_scroll_offset_delegate_(NULL), @@ -243,26 +237,26 @@ LayerTreeHostImpl::LayerTreeHostImpl( paint_time_counter_(PaintTimeCounter::Create()), memory_history_(MemoryHistory::Create()), debug_rect_history_(DebugRectHistory::Create()), - texture_mailbox_deleter_(new TextureMailboxDeleter), + texture_mailbox_deleter_(new TextureMailboxDeleter( + proxy_->HasImplThread() ? proxy_->ImplThreadTaskRunner() + : proxy_->MainThreadTaskRunner())), max_memory_needed_bytes_(0), - last_sent_memory_visible_bytes_(0), - last_sent_memory_visible_and_nearby_bytes_(0), - last_sent_memory_use_bytes_(0), zero_budget_(false), device_scale_factor_(1.f), overhang_ui_resource_id_(0), overdraw_bottom_height_(0.f), device_viewport_valid_for_tile_management_(true), - external_stencil_test_enabled_(false), + begin_impl_frame_interval_(BeginFrameArgs::DefaultInterval()), animation_registrar_(AnimationRegistrar::Create()), rendering_stats_instrumentation_(rendering_stats_instrumentation), micro_benchmark_controller_(this), need_to_update_visible_tiles_before_draw_(false), -#ifndef NDEBUG +#if DCHECK_IS_ON did_lose_called_(false), #endif shared_bitmap_manager_(manager), - id_(id) { + id_(id), + transfer_buffer_memory_limit_(0u) { DCHECK(proxy_->IsImplThread()); DidVisibilityChange(this, visible_); @@ -281,14 +275,14 @@ LayerTreeHostImpl::LayerTreeHostImpl( // LTHI always has an active tree. active_tree_ = LayerTreeImpl::create(this); TRACE_EVENT_OBJECT_CREATED_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", this); + TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", id_); } LayerTreeHostImpl::~LayerTreeHostImpl() { DCHECK(proxy_->IsImplThread()); TRACE_EVENT0("cc", "LayerTreeHostImpl::~LayerTreeHostImpl()"); TRACE_EVENT_OBJECT_DELETED_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", this); + TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", id_); if (input_handler_client_) { input_handler_client_->WillShutdown(); @@ -298,9 +292,15 @@ LayerTreeHostImpl::~LayerTreeHostImpl() { // The layer trees must be destroyed before the layer tree host. We've // made a contract with our animation controllers that the registrar // will outlive them, and we must make good. + if (recycle_tree_) + recycle_tree_->Shutdown(); + if (pending_tree_) + pending_tree_->Shutdown(); + active_tree_->Shutdown(); recycle_tree_.reset(); pending_tree_.reset(); active_tree_.reset(); + DestroyTileManager(); } void LayerTreeHostImpl::BeginMainFrameAborted(bool did_handle) { @@ -313,7 +313,12 @@ void LayerTreeHostImpl::BeginMainFrameAborted(bool did_handle) { } } -void LayerTreeHostImpl::BeginCommit() {} +void LayerTreeHostImpl::BeginCommit() { + TRACE_EVENT0("cc", "LayerTreeHostImpl::BeginCommit"); + + if (settings_.impl_side_painting) + CreatePendingTree(); +} void LayerTreeHostImpl::CommitComplete() { TRACE_EVENT0("cc", "LayerTreeHostImpl::CommitComplete"); @@ -331,13 +336,18 @@ void LayerTreeHostImpl::CommitComplete() { else ManageTiles(); } else { + // If we're not in impl-side painting, the tree is immediately considered + // active. + active_tree_->ProcessUIResourceRequestQueue(); + active_tree_->DidBecomeActive(); + + ActivateAnimations(); + active_tree_->set_needs_update_draw_properties(); if (time_source_client_adapter_ && time_source_client_adapter_->Active()) DCHECK(active_tree_->root_layer()); } - client_->SendManagedMemoryStats(); - micro_benchmark_controller_.DidCompleteCommit(); } @@ -393,12 +403,11 @@ bool LayerTreeHostImpl::CanDraw() const { return true; } -void LayerTreeHostImpl::Animate(base::TimeTicks monotonic_time, - base::Time wall_clock_time) { +void LayerTreeHostImpl::Animate(base::TimeTicks monotonic_time) { if (input_handler_client_) input_handler_client_->Animate(monotonic_time); AnimatePageScale(monotonic_time); - AnimateLayers(monotonic_time, wall_clock_time); + AnimateLayers(monotonic_time); AnimateScrollbars(monotonic_time); AnimateTopControls(monotonic_time); } @@ -408,34 +417,22 @@ void LayerTreeHostImpl::ManageTiles() { return; if (!tile_priorities_dirty_) return; - if (!device_viewport_valid_for_tile_management_) - return; tile_priorities_dirty_ = false; tile_manager_->ManageTiles(global_tile_state_); - size_t memory_required_bytes; - size_t memory_nice_to_have_bytes; - size_t memory_allocated_bytes; - size_t memory_used_bytes; - tile_manager_->GetMemoryStats(&memory_required_bytes, - &memory_nice_to_have_bytes, - &memory_allocated_bytes, - &memory_used_bytes); - SendManagedMemoryStats(memory_required_bytes, - memory_nice_to_have_bytes, - memory_used_bytes); -} - -void LayerTreeHostImpl::StartPageScaleAnimation(gfx::Vector2d target_offset, - bool anchor_point, - float page_scale, - base::TimeDelta duration) { - if (!RootScrollLayer()) + client_->DidManageTiles(); +} + +void LayerTreeHostImpl::StartPageScaleAnimation( + const gfx::Vector2d& target_offset, + bool anchor_point, + float page_scale, + base::TimeDelta duration) { + if (!InnerViewportScrollLayer()) return; - gfx::Vector2dF scroll_total = - RootScrollLayer()->scroll_offset() + RootScrollLayer()->ScrollDelta(); + gfx::Vector2dF scroll_total = active_tree_->TotalScrollOffset(); gfx::SizeF scaled_scrollable_size = active_tree_->ScrollableSize(); gfx::SizeF viewport_size = UnscaledScrollableViewportSize(); @@ -462,28 +459,41 @@ void LayerTreeHostImpl::StartPageScaleAnimation(gfx::Vector2d target_offset, duration.InSecondsF()); } - SetNeedsRedraw(); + SetNeedsAnimate(); client_->SetNeedsCommitOnImplThread(); client_->RenewTreePriority(); } -void LayerTreeHostImpl::ScheduleAnimation() { - SetNeedsRedraw(); +bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt( + const gfx::Point& viewport_point, + InputHandler::ScrollInputType type) { + if (!CurrentlyScrollingLayer()) + return false; + + gfx::PointF device_viewport_point = + gfx::ScalePoint(viewport_point, device_scale_factor_); + + LayerImpl* layer_impl = + active_tree_->FindLayerThatIsHitByPoint(device_viewport_point); + + bool scroll_on_main_thread = false; + LayerImpl* scrolling_layer_impl = FindScrollLayerForDeviceViewportPoint( + device_viewport_point, type, layer_impl, &scroll_on_main_thread, NULL); + return CurrentlyScrollingLayer() == scrolling_layer_impl; } -bool LayerTreeHostImpl::HaveTouchEventHandlersAt(gfx::Point viewport_point) { +bool LayerTreeHostImpl::HaveTouchEventHandlersAt( + const 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_); LayerImpl* layer_impl = - LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion( - device_viewport_point, - active_tree_->RenderSurfaceLayerList()); + active_tree_->FindLayerThatIsHitByPointInTouchHandlerRegion( + device_viewport_point); + return layer_impl != NULL; } @@ -550,22 +560,20 @@ static DrawMode GetDrawMode(OutputSurface* output_surface) { return DRAW_MODE_HARDWARE; } else { DCHECK_EQ(!output_surface->software_device(), - output_surface->capabilities().delegated_rendering); + output_surface->capabilities().delegated_rendering && + !output_surface->capabilities().deferred_gl_initialization) + << output_surface->capabilities().delegated_rendering << " " + << output_surface->capabilities().deferred_gl_initialization; return DRAW_MODE_SOFTWARE; } } -static void AppendQuadsForLayer(RenderPass* target_render_pass, - LayerImpl* layer, - const OcclusionTrackerImpl& occlusion_tracker, - AppendQuadsData* append_quads_data) { - bool for_surface = false; - QuadCuller quad_culler(&target_render_pass->quad_list, - &target_render_pass->shared_quad_state_list, - layer, - occlusion_tracker, - layer->ShowDebugBorders(), - for_surface); +static void AppendQuadsForLayer( + RenderPass* target_render_pass, + LayerImpl* layer, + const OcclusionTracker<LayerImpl>& occlusion_tracker, + AppendQuadsData* append_quads_data) { + QuadSink quad_culler(target_render_pass, &occlusion_tracker); layer->AppendQuads(&quad_culler, append_quads_data); } @@ -573,15 +581,9 @@ static void AppendQuadsForRenderSurfaceLayer( RenderPass* target_render_pass, LayerImpl* layer, const RenderPass* contributing_render_pass, - const OcclusionTrackerImpl& occlusion_tracker, + const OcclusionTracker<LayerImpl>& occlusion_tracker, AppendQuadsData* append_quads_data) { - bool for_surface = true; - QuadCuller quad_culler(&target_render_pass->quad_list, - &target_render_pass->shared_quad_state_list, - layer, - occlusion_tracker, - layer->ShowDebugBorders(), - for_surface); + QuadSink quad_culler(target_render_pass, &occlusion_tracker); bool is_replica = false; layer->render_surface()->AppendQuads(&quad_culler, @@ -601,12 +603,12 @@ static void AppendQuadsForRenderSurfaceLayer( static void AppendQuadsToFillScreen( ResourceProvider::ResourceId overhang_resource_id, - gfx::SizeF overhang_resource_scaled_size, - gfx::Rect root_scroll_layer_rect, + const gfx::SizeF& overhang_resource_scaled_size, + const gfx::Rect& root_scroll_layer_rect, RenderPass* target_render_pass, LayerImpl* root_layer, SkColor screen_background_color, - const OcclusionTrackerImpl& occlusion_tracker) { + const OcclusionTracker<LayerImpl>& occlusion_tracker) { if (!root_layer || !SkColorGetA(screen_background_color)) return; @@ -624,13 +626,7 @@ static void AppendQuadsToFillScreen( 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, - root_layer, - occlusion_tracker, - root_layer->ShowDebugBorders(), - for_surface); + QuadSink quad_culler(target_render_pass, &occlusion_tracker); // Manually create the quad state for the gutter quads, as the root layer // doesn't have any bounds and so can't generate this itself. @@ -639,68 +635,67 @@ static void AppendQuadsToFillScreen( gfx::Rect root_target_rect = root_layer->render_surface()->content_rect(); float opacity = 1.f; - SharedQuadState* shared_quad_state = - quad_culler.UseSharedQuadState(SharedQuadState::Create()); - shared_quad_state->SetAll(root_layer->draw_transform(), + int sorting_context_id = 0; + SharedQuadState* shared_quad_state = quad_culler.CreateSharedQuadState(); + shared_quad_state->SetAll(gfx::Transform(), root_target_rect.size(), root_target_rect, root_target_rect, false, opacity, - SkXfermode::kSrcOver_Mode); + SkXfermode::kSrcOver_Mode, + sorting_context_id); - AppendQuadsData append_quads_data; - - gfx::Transform transform_to_layer_space(gfx::Transform::kSkipInitialization); - bool did_invert = root_layer->screen_space_transform().GetInverse( - &transform_to_layer_space); - DCHECK(did_invert); 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()); + gfx::Rect screen_space_rect = fill_rects.rect(); + gfx::Rect visible_screen_space_rect = screen_space_rect; // 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); + quad->SetNew(shared_quad_state, + screen_space_rect, + visible_screen_space_rect, + screen_background_color, + false); + quad_culler.Append(quad.PassAs<DrawQuad>()); } 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()); + gfx::Rect screen_space_rect = fill_rects.rect(); + gfx::Rect opaque_screen_space_rect = screen_space_rect; + gfx::Rect visible_screen_space_rect = screen_space_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, + screen_space_rect, + opaque_screen_space_rect, + visible_screen_space_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()), + gfx::PointF( + screen_space_rect.x() / overhang_resource_scaled_size.width(), + screen_space_rect.y() / overhang_resource_scaled_size.height()), + gfx::PointF( + screen_space_rect.right() / overhang_resource_scaled_size.width(), + screen_space_rect.bottom() / + overhang_resource_scaled_size.height()), screen_background_color, vertex_opacity, false); - quad_culler.Append(tex_quad.PassAs<DrawQuad>(), &append_quads_data); + quad_culler.Append(tex_quad.PassAs<DrawQuad>()); } } -bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { +DrawResult LayerTreeHostImpl::CalculateRenderPasses( + FrameData* frame) { DCHECK(frame->render_passes.empty()); - - if (!CanDraw() || !active_tree_->root_layer()) - return false; + DCHECK(CanDraw()); + DCHECK(active_tree_->root_layer()); TrackDamageForAllSurfaces(active_tree_->root_layer(), *frame->render_surface_layer_list); @@ -714,17 +709,18 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { root_surface->content_rect()); bool root_surface_has_contributing_layers = !root_surface->layer_list().empty(); + bool hud_wants_to_draw_ = active_tree_->hud_layer() && + active_tree_->hud_layer()->IsAnimatingHUDContents(); if (root_surface_has_contributing_layers && - root_surface_has_no_visible_damage) { + root_surface_has_no_visible_damage && + active_tree_->LayersWithCopyOutputRequest().empty() && + !hud_wants_to_draw_) { TRACE_EVENT0("cc", "LayerTreeHostImpl::CalculateRenderPasses::EmptyDamageRect"); frame->has_no_damage = true; - // A copy request should cause damage, so we should not have any copy - // requests in this case. - DCHECK_EQ(0u, active_tree_->LayersWithCopyOutputRequest().size()); DCHECK(!output_surface_->capabilities() .draw_and_swap_full_viewport_every_frame); - return true; + return DRAW_SUCCESS; } TRACE_EVENT1("cc", @@ -748,13 +744,19 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { render_surface_layer->render_surface()->AppendRenderPasses(frame); } - bool record_metrics_for_frame = - settings_.show_overdraw_in_tracing && - base::debug::TraceLog::GetInstance() && - base::debug::TraceLog::GetInstance()->IsEnabled(); - OcclusionTrackerImpl occlusion_tracker( - active_tree_->root_layer()->render_surface()->content_rect(), - record_metrics_for_frame); + // When we are displaying the HUD, change the root damage rect to cover the + // entire root surface. This will disable partial-swap/scissor optimizations + // that would prevent the HUD from updating, since the HUD does not cause + // damage itself, to prevent it from messing with damage visualizations. Since + // damage visualizations are done off the LayerImpls and RenderSurfaceImpls, + // changing the RenderPass does not affect them. + if (active_tree_->hud_layer()) { + RenderPass* root_pass = frame->render_passes.back(); + root_pass->damage_rect = root_pass->output_rect; + } + + OcclusionTracker<LayerImpl> occlusion_tracker( + active_tree_->root_layer()->render_surface()->content_rect()); occlusion_tracker.set_minimum_tracking_size( settings_.minimum_occlusion_tracking_size); @@ -767,18 +769,15 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { &frame->non_occluding_screen_space_rects); } - // Add quads to the Render passes in FrontToBack order to allow for testing + // Add quads to the Render passes in front-to-back order to allow for testing // occlusion and performing culling during the tree walk. - typedef LayerIterator<LayerImpl, - LayerImplList, - RenderSurfaceImpl, - LayerIteratorActions::FrontToBack> LayerIteratorType; + typedef LayerIterator<LayerImpl> LayerIteratorType; // Typically when we are missing a texture and use a checkerboard quad, we // still draw the frame. However when the layer being checkerboarded is moving // due to an impl-animation, we drop the frame to avoid flashing due to the // texture suddenly appearing in the future. - bool draw_frame = true; + DrawResult draw_result = DRAW_SUCCESS; // When we have a copy request for a layer, we need to draw no matter // what, as the layer may disappear after this frame. bool have_copy_request = false; @@ -819,14 +818,11 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { contributing_render_pass, occlusion_tracker, &append_quads_data); - } else if (it.represents_itself() && it->DrawsContent() && + } else if (it.represents_itself() && !it->visible_content_rect().IsEmpty()) { - bool impl_draw_transform_is_unknown = false; - bool occluded = occlusion_tracker.Occluded( - it->render_target(), - it->visible_content_rect(), - it->draw_transform(), - impl_draw_transform_is_unknown); + bool occluded = occlusion_tracker.Occluded(it->render_target(), + it->visible_content_rect(), + it->draw_transform()); if (!occluded && it->WillDraw(draw_mode, resource_provider_.get())) { DCHECK_EQ(active_tree_, it->layer_tree_impl()); @@ -860,25 +856,33 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { ++layers_drawn; } + rendering_stats_instrumentation_->AddVisibleContentArea( + append_quads_data.visible_content_area); + rendering_stats_instrumentation_->AddApproximatedVisibleContentArea( + append_quads_data.approximated_visible_content_area); + if (append_quads_data.num_missing_tiles) { bool layer_has_animating_transform = it->screen_space_transform_is_animating() || it->draw_transform_is_animating(); if (layer_has_animating_transform) - draw_frame = false; + draw_result = DRAW_ABORTED_CHECKERBOARD_ANIMATIONS; } - if (append_quads_data.had_incomplete_tile) + if (append_quads_data.had_incomplete_tile) { frame->contains_incomplete_tile = true; + if (active_tree()->RequiresHighResToDraw()) + draw_result = DRAW_ABORTED_MISSING_HIGH_RES_CONTENT; + } occlusion_tracker.LeaveLayer(it); } if (have_copy_request || output_surface_->capabilities().draw_and_swap_full_viewport_every_frame) - draw_frame = true; + draw_result = DRAW_SUCCESS; -#ifndef NDEBUG +#if DCHECK_IS_ON 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) DCHECK(frame->render_passes[i]->quad_list[j]->shared_quad_state); @@ -900,11 +904,6 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { occlusion_tracker); } - if (draw_frame) - occlusion_tracker.overdraw_metrics()->RecordMetrics(this); - else - DCHECK(!have_copy_request); - RemoveRenderPasses(CullRenderPassesWithNoQuads(), frame); renderer_->DecideRenderPassAllocationsForFrame(frame->render_passes); @@ -925,7 +924,7 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { if (output_surface_->ForcedDrawToSoftwareDevice()) DCHECK_EQ(1u, frame->render_passes.size()); - return draw_frame; + return draw_result; } void LayerTreeHostImpl::MainThreadHasStoppedFlinging() { @@ -939,8 +938,7 @@ void LayerTreeHostImpl::UpdateBackgroundAnimateTicking( if (should_background_tick) DCHECK(active_tree_->root_layer()); - bool enabled = should_background_tick && - !animation_registrar_->active_animation_controllers().empty(); + bool enabled = should_background_tick && needs_animate_layers(); // Lazily create the time_source adapter so that we can vary the interval for // testing. @@ -961,7 +959,7 @@ void LayerTreeHostImpl::DidAnimateScrollOffset() { client_->RenewTreePriority(); } -void LayerTreeHostImpl::SetViewportDamage(gfx::Rect damage_rect) { +void LayerTreeHostImpl::SetViewportDamage(const gfx::Rect& damage_rect) { viewport_damage_rect_.Union(damage_rect); } @@ -1077,8 +1075,7 @@ void LayerTreeHostImpl::RemoveRenderPasses(RenderPassCuller culler, } } -bool LayerTreeHostImpl::PrepareToDraw(FrameData* frame, - gfx::Rect device_viewport_damage_rect) { +DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) { TRACE_EVENT1("cc", "LayerTreeHostImpl::PrepareToDraw", "SourceFrameNumber", @@ -1090,7 +1087,8 @@ bool LayerTreeHostImpl::PrepareToDraw(FrameData* frame, } need_to_update_visible_tiles_before_draw_ = true; - active_tree_->UpdateDrawProperties(); + bool ok = active_tree_->UpdateDrawProperties(); + DCHECK(ok) << "UpdateDrawProperties failed during draw"; frame->render_surface_layer_list = &active_tree_->RenderSurfaceLayerList(); frame->render_passes.clear(); @@ -1100,22 +1098,23 @@ bool LayerTreeHostImpl::PrepareToDraw(FrameData* frame, frame->has_no_damage = false; if (active_tree_->root_layer()) { - device_viewport_damage_rect.Union(viewport_damage_rect_); + gfx::Rect device_viewport_damage_rect = viewport_damage_rect_; viewport_damage_rect_ = gfx::Rect(); active_tree_->root_layer()->render_surface()->damage_tracker()-> AddDamageNextUpdate(device_viewport_damage_rect); } - if (!CalculateRenderPasses(frame)) { + DrawResult draw_result = CalculateRenderPasses(frame); + if (draw_result != DRAW_SUCCESS) { DCHECK(!output_surface_->capabilities() .draw_and_swap_full_viewport_every_frame); - return false; + return draw_result; } - // If we return true, then we expect DrawLayers() to be called before this - // function is called again. - return true; + // If we return DRAW_SUCCESS, then we expect DrawLayers() to be called before + // this function is called again. + return draw_result; } void LayerTreeHostImpl::EvictTexturesForTesting() { @@ -1127,9 +1126,24 @@ void LayerTreeHostImpl::BlockNotifyReadyToActivateForTesting(bool block) { } void LayerTreeHostImpl::DidInitializeVisibleTileForTesting() { + // Add arbitrary damage, to trigger prepare-to-draws. + // Here, setting damage as viewport size, used only for testing. + SetFullRootLayerDamage(); DidInitializeVisibleTile(); } +void LayerTreeHostImpl::ResetTreesForTesting() { + if (active_tree_) + active_tree_->DetachLayerTree(); + active_tree_ = LayerTreeImpl::create(this); + if (pending_tree_) + pending_tree_->DetachLayerTree(); + pending_tree_.reset(); + if (recycle_tree_) + recycle_tree_->DetachLayerTree(); + recycle_tree_.reset(); +} + void LayerTreeHostImpl::EnforceManagedMemoryPolicy( const ManagedMemoryPolicy& policy) { @@ -1146,7 +1160,6 @@ void LayerTreeHostImpl::EnforceManagedMemoryPolicy( client_->OnCanDrawStateChanged(CanDraw()); client_->RenewTreePriority(); } - client_->SendManagedMemoryStats(); UpdateTileManagerMemoryPolicy(policy); } @@ -1156,14 +1169,16 @@ void LayerTreeHostImpl::UpdateTileManagerMemoryPolicy( if (!tile_manager_) return; - // TODO(reveman): We should avoid keeping around unused resources if - // possible. crbug.com/224475 - 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); + global_tile_state_.hard_memory_limit_in_bytes = 0; + global_tile_state_.soft_memory_limit_in_bytes = 0; + if (visible_ && policy.bytes_limit_when_visible > 0) { + global_tile_state_.hard_memory_limit_in_bytes = + policy.bytes_limit_when_visible; + global_tile_state_.soft_memory_limit_in_bytes = + (static_cast<int64>(global_tile_state_.hard_memory_limit_in_bytes) * + settings_.max_memory_for_prepaint_percentage) / + 100; + } global_tile_state_.memory_limit_policy = ManagedMemoryPolicy::PriorityCutoffToTileMemoryLimitPolicy( visible_ ? @@ -1171,6 +1186,34 @@ void LayerTreeHostImpl::UpdateTileManagerMemoryPolicy( gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING); global_tile_state_.num_resources_limit = policy.num_resources_limit; + // TODO(reveman): We should avoid keeping around unused resources if + // possible. crbug.com/224475 + // Unused limit is calculated from soft-limit, as hard-limit may + // be very high and shouldn't typically be exceeded. + size_t unused_memory_limit_in_bytes = static_cast<size_t>( + (static_cast<int64>(global_tile_state_.soft_memory_limit_in_bytes) * + settings_.max_unused_resource_memory_percentage) / + 100); + + DCHECK(resource_pool_); + resource_pool_->CheckBusyResources(); + // Soft limit is used for resource pool such that memory returns to soft + // limit after going over. + resource_pool_->SetResourceUsageLimits( + global_tile_state_.soft_memory_limit_in_bytes, + unused_memory_limit_in_bytes, + global_tile_state_.num_resources_limit); + + // Staging pool resources are used as transfer buffers so we use + // |transfer_buffer_memory_limit_| as the memory limit for this resource pool. + if (staging_resource_pool_) { + staging_resource_pool_->CheckBusyResources(); + staging_resource_pool_->SetResourceUsageLimits( + visible_ ? transfer_buffer_memory_limit_ : 0, + transfer_buffer_memory_limit_, + std::numeric_limits<size_t>::max()); + } + DidModifyTilePriorities(); } @@ -1182,17 +1225,36 @@ void LayerTreeHostImpl::DidModifyTilePriorities() { } void LayerTreeHostImpl::DidInitializeVisibleTile() { - // TODO(reveman): Determine tiles that changed and only damage - // what's necessary. - SetFullRootLayerDamage(); if (client_ && !client_->IsInsideDraw()) client_->DidInitializeVisibleTileOnImplThread(); } +const std::vector<PictureLayerImpl*>& LayerTreeHostImpl::GetPictureLayers() { + return picture_layers_; +} + void LayerTreeHostImpl::NotifyReadyToActivate() { client_->NotifyReadyToActivate(); } +void LayerTreeHostImpl::NotifyTileStateChanged(const Tile* tile) { + TRACE_EVENT0("cc", "LayerTreeHostImpl::NotifyTileStateChanged"); + + if (active_tree_) { + LayerImpl* layer_impl = + active_tree_->FindActiveTreeLayerById(tile->layer_id()); + if (layer_impl) + layer_impl->NotifyTileStateChanged(tile); + } + + if (pending_tree_) { + LayerImpl* layer_impl = + pending_tree_->FindPendingTreeLayerById(tile->layer_id()); + if (layer_impl) + layer_impl->NotifyTileStateChanged(tile); + } +} + void LayerTreeHostImpl::SetMemoryPolicy(const ManagedMemoryPolicy& policy) { SetManagedMemoryPolicy(policy, zero_budget_); } @@ -1247,32 +1309,36 @@ void LayerTreeHostImpl::SetManagedMemoryPolicy( void LayerTreeHostImpl::SetExternalDrawConstraints( const gfx::Transform& transform, - gfx::Rect viewport, - gfx::Rect clip, + const gfx::Rect& viewport, + const gfx::Rect& clip, bool valid_for_tile_management) { + if (external_transform_ != transform || external_viewport_ != viewport) { + active_tree_->set_needs_update_draw_properties(); + } + external_transform_ = transform; external_viewport_ = viewport; external_clip_ = clip; device_viewport_valid_for_tile_management_ = valid_for_tile_management; } -void LayerTreeHostImpl::SetNeedsRedrawRect(gfx::Rect damage_rect) { +void LayerTreeHostImpl::SetNeedsRedrawRect(const gfx::Rect& damage_rect) { if (damage_rect.IsEmpty()) return; NotifySwapPromiseMonitorsOfSetNeedsRedraw(); client_->SetNeedsRedrawRectOnImplThread(damage_rect); } -void LayerTreeHostImpl::BeginImplFrame(const BeginFrameArgs& args) { - client_->BeginImplFrame(args); +void LayerTreeHostImpl::BeginFrame(const BeginFrameArgs& args) { + client_->BeginFrame(args); } void LayerTreeHostImpl::DidSwapBuffers() { client_->DidSwapBuffersOnImplThread(); } -void LayerTreeHostImpl::OnSwapBuffersComplete() { - client_->OnSwapBuffersCompleteOnImplThread(); +void LayerTreeHostImpl::DidSwapBuffersComplete() { + client_->DidSwapBuffersCompleteOnImplThread(); } void LayerTreeHostImpl::ReclaimResources(const CompositorFrameAck* ack) { @@ -1280,6 +1346,20 @@ void LayerTreeHostImpl::ReclaimResources(const CompositorFrameAck* ack) { // processing it. if (renderer_) renderer_->ReceiveSwapBuffersAck(*ack); + + // In OOM, we now might be able to release more resources that were held + // because they were exported. + if (tile_manager_) { + DCHECK(resource_pool_); + + resource_pool_->CheckBusyResources(); + resource_pool_->ReduceResourceUsage(); + } + // If we're not visible, we likely released resources, so we want to + // aggressively flush here to make sure those DeleteTextures make it to the + // GPU process to free up the memory. + if (resource_provider_ && !visible_) + resource_provider_->ShallowFlushIfSupported(); } void LayerTreeHostImpl::OnCanDrawStateChangedForTree() { @@ -1302,10 +1382,10 @@ CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const { metadata.overdraw_bottom_height = overdraw_bottom_height_; } - if (!RootScrollLayer()) + if (!InnerViewportScrollLayer()) return metadata; - metadata.root_scroll_offset = RootScrollLayer()->TotalScrollOffset(); + metadata.root_scroll_offset = active_tree_->TotalScrollOffset(); return metadata; } @@ -1320,7 +1400,7 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame, DCHECK(CanDraw()); if (frame->has_no_damage) { - TRACE_EVENT0("cc", "EarlyOut_NoDamage"); + TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoDamage", TRACE_EVENT_SCOPE_THREAD); DCHECK(!output_surface_->capabilities() .draw_and_swap_full_viewport_every_frame); return; @@ -1330,7 +1410,6 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame, fps_counter_->SaveTimeStamp(frame_begin_time, !output_surface_->context_provider()); - bool on_main_thread = false; rendering_stats_instrumentation_->IncrementFrameCount( 1, on_main_thread); @@ -1343,6 +1422,7 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame, if (debug_state_.ShowHudRects()) { debug_rect_history_->SaveDebugRectsForCurrentFrame( active_tree_->root_layer(), + active_tree_->hud_layer(), *frame->render_surface_layer_list, frame->occluding_screen_space_rects, frame->non_occluding_screen_space_rects, @@ -1370,8 +1450,11 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame, TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( TRACE_DISABLED_BY_DEFAULT("cc.debug") "," - TRACE_DISABLED_BY_DEFAULT("cc.debug.quads"), "cc::LayerTreeHostImpl", - this, TracedValue::FromValue(AsValueWithFrame(frame).release())); + TRACE_DISABLED_BY_DEFAULT("cc.debug.quads") "," + TRACE_DISABLED_BY_DEFAULT("devtools.timeline.layers"), + "cc::LayerTreeHostImpl", + id_, + TracedValue::FromValue(AsValueWithFrame(frame).release())); // 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 @@ -1383,31 +1466,21 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame, } 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_, 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 - // properly. - bool allow_partial_swap = !debug_state_.ShowHudRects(); - renderer_->DrawFrame(&frame->render_passes, - offscreen_context_provider_.get(), device_scale_factor_, DeviceViewport(), DeviceClip(), - allow_partial_swap, false); } // The render passes should be consumed by the renderer. @@ -1424,6 +1497,7 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame, } active_tree_->root_layer()->ResetAllChangeTrackingForSubtree(); + devtools_instrumentation::DidDrawFrame(id_); BenchmarkInstrumentation::IssueImplThreadRenderingStatsEvent( rendering_stats_instrumentation_->impl_thread_rendering_stats()); rendering_stats_instrumentation_->AccumulateAndClearImplThreadStats(); @@ -1448,43 +1522,105 @@ bool LayerTreeHostImpl::IsContextLost() { return renderer_ && renderer_->IsContextLost(); } -const RendererCapabilities& LayerTreeHostImpl::GetRendererCapabilities() const { +void LayerTreeHostImpl::SetUseGpuRasterization(bool use_gpu) { + if (use_gpu == use_gpu_rasterization_) + return; + + use_gpu_rasterization_ = use_gpu; + ReleaseTreeResources(); + + // Replace existing tile manager with another one that uses appropriate + // rasterizer. + if (tile_manager_) { + DestroyTileManager(); + CreateAndSetTileManager(); + } + + // We have released tilings for both active and pending tree. + // We would not have any content to draw until the pending tree is activated. + // Prevent the active tree from drawing until activation. + active_tree_->SetRequiresHighResToDraw(); +} + +const RendererCapabilitiesImpl& +LayerTreeHostImpl::GetRendererCapabilities() const { return renderer_->Capabilities(); } bool LayerTreeHostImpl::SwapBuffers(const LayerTreeHostImpl::FrameData& frame) { + active_tree()->ResetRequiresHighResToDraw(); if (frame.has_no_damage) { active_tree()->BreakSwapPromises(SwapPromise::SWAP_FAILS); return false; } CompositorFrameMetadata metadata = MakeCompositorFrameMetadata(); active_tree()->FinishSwapPromises(&metadata); + for (size_t i = 0; i < metadata.latency_info.size(); i++) { + TRACE_EVENT_FLOW_STEP0( + "input", + "LatencyInfo.Flow", + TRACE_ID_DONT_MANGLE(metadata.latency_info[i].trace_id), + "SwapBuffers"); + } renderer_->SwapBuffers(metadata); return true; } -void LayerTreeHostImpl::SetNeedsBeginImplFrame(bool enable) { +void LayerTreeHostImpl::SetNeedsBeginFrame(bool enable) { if (output_surface_) - output_surface_->SetNeedsBeginImplFrame(enable); + output_surface_->SetNeedsBeginFrame(enable); + else + DCHECK(!enable); +} + +void LayerTreeHostImpl::WillBeginImplFrame(const BeginFrameArgs& args) { + // Sample the frame time now. This time will be used for updating animations + // when we draw. + UpdateCurrentFrameTime(); + // Cache the begin impl frame interval + begin_impl_frame_interval_ = args.interval; +} + +gfx::SizeF LayerTreeHostImpl::ComputeInnerViewportContainerSize() const { + gfx::SizeF dip_size = + gfx::ScaleSize(device_viewport_size_, 1.f / device_scale_factor()); + + float top_offset = + top_controls_manager_ ? top_controls_manager_->content_top_offset() : 0.f; + + return gfx::SizeF(dip_size.width(), + dip_size.height() - top_offset - overdraw_bottom_height_); +} + +void LayerTreeHostImpl::UpdateInnerViewportContainerSize() { + LayerImpl* container_layer = active_tree_->InnerViewportContainerLayer(); + if (!container_layer) + return; + + // We pass the value returned from UnscaledScrollableViewportSize() here as + // it accounts for scrollbar dimensions when + // container_layer->masks_to_bounds() is set. + container_layer->SetTemporaryImplBounds(UnscaledScrollableViewportSize()); } gfx::SizeF LayerTreeHostImpl::UnscaledScrollableViewportSize() const { // 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(); + LayerImpl* container_layer = active_tree_->InnerViewportContainerLayer(); if (container_layer && container_layer->masks_to_bounds()) { DCHECK(!top_controls_manager_); DCHECK_EQ(0, overdraw_bottom_height_); return container_layer->bounds(); } - gfx::SizeF dip_size = - gfx::ScaleSize(device_viewport_size_, 1.f / device_scale_factor()); + return ComputeInnerViewportContainerSize(); +} - float top_offset = - top_controls_manager_ ? top_controls_manager_->content_top_offset() : 0.f; - return gfx::SizeF(dip_size.width(), - dip_size.height() - top_offset - overdraw_bottom_height_); +float LayerTreeHostImpl::VerticalAdjust() const { + if (!active_tree_->InnerViewportContainerLayer()) + return 0; + + return active_tree_->InnerViewportContainerLayer()->BoundsDelta().y(); } void LayerTreeHostImpl::DidLoseOutputSurface() { @@ -1495,27 +1631,25 @@ void LayerTreeHostImpl::DidLoseOutputSurface() { // important) in production. We should adjust the test to not need this. if (renderer_) client_->DidLoseOutputSurfaceOnImplThread(); -#ifndef NDEBUG +#if DCHECK_IS_ON did_lose_called_ = true; #endif } -void LayerTreeHostImpl::Readback(void* pixels, - gfx::Rect rect_in_device_viewport) { - DCHECK(renderer_); - renderer_->GetFramebufferPixels(pixels, rect_in_device_viewport); -} - bool LayerTreeHostImpl::HaveRootScrollLayer() const { - return !!RootScrollLayer(); + return !!InnerViewportScrollLayer(); } LayerImpl* LayerTreeHostImpl::RootLayer() const { return active_tree_->root_layer(); } -LayerImpl* LayerTreeHostImpl::RootScrollLayer() const { - return active_tree_->RootScrollLayer(); +LayerImpl* LayerTreeHostImpl::InnerViewportScrollLayer() const { + return active_tree_->InnerViewportScrollLayer(); +} + +LayerImpl* LayerTreeHostImpl::OuterViewportScrollLayer() const { + return active_tree_->OuterViewportScrollLayer(); } LayerImpl* LayerTreeHostImpl::CurrentlyScrollingLayer() const { @@ -1524,7 +1658,10 @@ LayerImpl* LayerTreeHostImpl::CurrentlyScrollingLayer() const { bool LayerTreeHostImpl::IsCurrentlyScrolling() const { return CurrentlyScrollingLayer() || - (RootScrollLayer() && RootScrollLayer()->IsExternalFlingActive()); + (InnerViewportScrollLayer() && + InnerViewportScrollLayer()->IsExternalFlingActive()) || + (OuterViewportScrollLayer() && + OuterViewportScrollLayer()->IsExternalFlingActive()); } // Content layers can be either directly scrollable or contained in an outer @@ -1551,6 +1688,13 @@ void LayerTreeHostImpl::CreatePendingTree() { recycle_tree_.swap(pending_tree_); else pending_tree_ = LayerTreeImpl::create(this); + + // Update the delta from the active tree, which may have + // adjusted its delta prior to the pending tree being created. + DCHECK_EQ(1.f, pending_tree_->sent_page_scale_delta()); + pending_tree_->SetPageScaleDelta(active_tree_->page_scale_delta() / + active_tree_->sent_page_scale_delta()); + client_->OnCanDrawStateChanged(CanDraw()); TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree:waiting", pending_tree_.get()); } @@ -1594,6 +1738,7 @@ void LayerTreeHostImpl::ActivatePendingTree() { active_tree_->DidBecomeActive(); active_tree_->SetRootLayerScrollOffsetDelegate( root_layer_scroll_offset_delegate_); + ActivateAnimations(); client_->OnCanDrawStateChanged(CanDraw()); SetNeedsRedraw(); @@ -1607,14 +1752,13 @@ void LayerTreeHostImpl::ActivatePendingTree() { stats.impl_stats.rasterize_time); } + UpdateInnerViewportContainerSize(); client_->DidActivatePendingTree(); if (!tree_activation_callback_.is_null()) tree_activation_callback_.Run(); 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) { @@ -1626,7 +1770,11 @@ void LayerTreeHostImpl::SetVisible(bool visible) { DidVisibilityChange(this, visible_); EnforceManagedMemoryPolicy(ActualManagedMemoryPolicy()); - if (!visible_) + // If we just became visible, we have to ensure that we draw high res tiles, + // to prevent checkerboard/low res flashes. + if (visible_) + active_tree()->SetRequiresHighResToDraw(); + else EvictAllUIResources(); // Evict tiles immediately if invisible since this tab may never get another @@ -1640,6 +1788,11 @@ void LayerTreeHostImpl::SetVisible(bool visible) { renderer_->SetVisible(visible); } +void LayerTreeHostImpl::SetNeedsAnimate() { + NotifySwapPromiseMonitorsOfSetNeedsRedraw(); + client_->SetNeedsAnimateOnImplThread(); +} + void LayerTreeHostImpl::SetNeedsRedraw() { NotifySwapPromiseMonitorsOfSetNeedsRedraw(); client_->SetNeedsRedrawOnImplThread(); @@ -1650,6 +1803,9 @@ ManagedMemoryPolicy LayerTreeHostImpl::ActualManagedMemoryPolicy() const { if (debug_state_.rasterize_only_visible_content) { actual.priority_cutoff_when_visible = gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY; + } else if (use_gpu_rasterization()) { + actual.priority_cutoff_when_visible = + gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE; } if (zero_budget_) { @@ -1669,67 +1825,143 @@ int LayerTreeHostImpl::memory_allocation_priority_cutoff() const { } void LayerTreeHostImpl::ReleaseTreeResources() { - if (active_tree_->root_layer()) - SendReleaseResourcesRecursive(active_tree_->root_layer()); - if (pending_tree_ && pending_tree_->root_layer()) - SendReleaseResourcesRecursive(pending_tree_->root_layer()); - if (recycle_tree_ && recycle_tree_->root_layer()) - SendReleaseResourcesRecursive(recycle_tree_->root_layer()); + active_tree_->ReleaseResources(); + if (pending_tree_) + pending_tree_->ReleaseResources(); + if (recycle_tree_) + recycle_tree_->ReleaseResources(); EvictAllUIResources(); } -void LayerTreeHostImpl::CreateAndSetRenderer( - OutputSurface* output_surface, - ResourceProvider* resource_provider, - bool skip_gl_renderer) { +void LayerTreeHostImpl::CreateAndSetRenderer() { DCHECK(!renderer_); - if (output_surface->capabilities().delegated_rendering) { + DCHECK(output_surface_); + DCHECK(resource_provider_); + + if (output_surface_->capabilities().delegated_rendering) { renderer_ = DelegatingRenderer::Create( - this, &settings_, output_surface, resource_provider); - } else if (output_surface->context_provider() && !skip_gl_renderer) { + this, &settings_, output_surface_.get(), resource_provider_.get()); + } else if (output_surface_->context_provider()) { renderer_ = GLRenderer::Create(this, &settings_, - output_surface, - resource_provider, + output_surface_.get(), + resource_provider_.get(), texture_mailbox_deleter_.get(), settings_.highp_threshold_min); - } else if (output_surface->software_device()) { + } else if (output_surface_->software_device()) { renderer_ = SoftwareRenderer::Create( - this, &settings_, output_surface, resource_provider); + this, &settings_, output_surface_.get(), resource_provider_.get()); } + DCHECK(renderer_); - if (renderer_) { - renderer_->SetVisible(visible_); - SetFullRootLayerDamage(); + renderer_->SetVisible(visible_); + SetFullRootLayerDamage(); - // See note in LayerTreeImpl::UpdateDrawProperties. Renderer needs to be - // initialized to get max texture size. Also, after releasing resources, - // trees need another update to generate new ones. - active_tree_->set_needs_update_draw_properties(); - if (pending_tree_) - pending_tree_->set_needs_update_draw_properties(); - } + // See note in LayerTreeImpl::UpdateDrawProperties. Renderer needs to be + // initialized to get max texture size. Also, after releasing resources, + // trees need another update to generate new ones. + active_tree_->set_needs_update_draw_properties(); + if (pending_tree_) + pending_tree_->set_needs_update_draw_properties(); + client_->UpdateRendererCapabilitiesOnImplThread(); } -void LayerTreeHostImpl::CreateAndSetTileManager( - ResourceProvider* resource_provider, - ContextProvider* context_provider, - bool using_map_image) { +void LayerTreeHostImpl::CreateAndSetTileManager() { + DCHECK(!tile_manager_); DCHECK(settings_.impl_side_painting); - DCHECK(resource_provider); + DCHECK(output_surface_); + DCHECK(resource_provider_); + DCHECK(proxy_->ImplThreadTaskRunner()); + + ContextProvider* context_provider = output_surface_->context_provider(); + transfer_buffer_memory_limit_ = + GetMaxTransferBufferUsageBytes(context_provider); + + if (use_gpu_rasterization_ && context_provider) { + resource_pool_ = + ResourcePool::Create(resource_provider_.get(), + GL_TEXTURE_2D, + resource_provider_->best_texture_format()); + + raster_worker_pool_ = + DirectRasterWorkerPool::Create(proxy_->ImplThreadTaskRunner(), + resource_provider_.get(), + context_provider); + on_demand_task_graph_runner_ = &synchronous_task_graph_runner_; + } else if (UseZeroCopyTextureUpload()) { + resource_pool_ = + ResourcePool::Create(resource_provider_.get(), + GetMapImageTextureTarget(context_provider), + resource_provider_->best_texture_format()); + + raster_worker_pool_ = + ImageRasterWorkerPool::Create(proxy_->ImplThreadTaskRunner(), + RasterWorkerPool::GetTaskGraphRunner(), + resource_provider_.get()); + on_demand_task_graph_runner_ = RasterWorkerPool::GetTaskGraphRunner(); + } else if (UseOneCopyTextureUpload()) { + // We need to create a staging resource pool when using copy rasterizer. + staging_resource_pool_ = + ResourcePool::Create(resource_provider_.get(), + GetMapImageTextureTarget(context_provider), + resource_provider_->best_texture_format()); + resource_pool_ = + ResourcePool::Create(resource_provider_.get(), + GL_TEXTURE_2D, + resource_provider_->best_texture_format()); + + raster_worker_pool_ = ImageCopyRasterWorkerPool::Create( + proxy_->ImplThreadTaskRunner(), + RasterWorkerPool::GetTaskGraphRunner(), + resource_provider_.get(), + staging_resource_pool_.get()); + on_demand_task_graph_runner_ = RasterWorkerPool::GetTaskGraphRunner(); + } else { + resource_pool_ = ResourcePool::Create( + resource_provider_.get(), + GL_TEXTURE_2D, + resource_provider_->memory_efficient_texture_format()); + + raster_worker_pool_ = PixelBufferRasterWorkerPool::Create( + proxy_->ImplThreadTaskRunner(), + RasterWorkerPool::GetTaskGraphRunner(), + resource_provider_.get(), + transfer_buffer_memory_limit_); + on_demand_task_graph_runner_ = RasterWorkerPool::GetTaskGraphRunner(); + } + tile_manager_ = TileManager::Create(this, - resource_provider, - settings_.num_raster_threads, - rendering_stats_instrumentation_, - using_map_image, - GetMaxTransferBufferUsageBytes(context_provider), - GetMaxRasterTasksUsageBytes(context_provider), - GetMapImageTextureTarget(context_provider)); + proxy_->ImplThreadTaskRunner(), + resource_pool_.get(), + raster_worker_pool_->AsRasterizer(), + rendering_stats_instrumentation_); UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy()); need_to_update_visible_tiles_before_draw_ = false; + on_demand_task_namespace_ = on_demand_task_graph_runner_->GetNamespaceToken(); +} + +void LayerTreeHostImpl::DestroyTileManager() { + tile_manager_.reset(); + resource_pool_.reset(); + staging_resource_pool_.reset(); + raster_worker_pool_.reset(); +} + +bool LayerTreeHostImpl::UseZeroCopyTextureUpload() const { + // Note: we use zero-copy by default when the renderer is using + // shared memory resources. + return (settings_.use_zero_copy || + GetRendererCapabilities().using_shared_memory_resources) && + GetRendererCapabilities().using_map_image; +} + +bool LayerTreeHostImpl::UseOneCopyTextureUpload() const { + // Sync query support is required by one-copy rasterizer. + return settings_.use_one_copy && GetRendererCapabilities().using_map_image && + resource_provider_->use_sync_query(); } void LayerTreeHostImpl::EnforceZeroBudget(bool zero_budget) { @@ -1738,7 +1970,8 @@ void LayerTreeHostImpl::EnforceZeroBudget(bool zero_budget) { bool LayerTreeHostImpl::InitializeRenderer( scoped_ptr<OutputSurface> output_surface) { -#ifndef NDEBUG + TRACE_EVENT0("cc", "LayerTreeHostImpl::InitializeRenderer"); +#if DCHECK_IS_ON DCHECK(!renderer_ || did_lose_called_); #endif @@ -1749,120 +1982,77 @@ bool LayerTreeHostImpl::InitializeRenderer( // Note: order is important here. renderer_.reset(); - tile_manager_.reset(); + DestroyTileManager(); resource_provider_.reset(); output_surface_.reset(); if (!output_surface->BindToClient(this)) return false; - scoped_ptr<ResourceProvider> resource_provider = - ResourceProvider::Create(output_surface.get(), + output_surface_ = output_surface.Pass(); + 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; + settings_.texture_id_allocation_chunk_size, + settings_.use_distance_field_text); - if (output_surface->capabilities().deferred_gl_initialization) + if (output_surface_->capabilities().deferred_gl_initialization) EnforceZeroBudget(true); - bool skip_gl_renderer = false; - CreateAndSetRenderer( - output_surface.get(), resource_provider.get(), skip_gl_renderer); + CreateAndSetRenderer(); - if (!renderer_) - return false; + transfer_buffer_memory_limit_ = + GetMaxTransferBufferUsageBytes(output_surface_->context_provider()); - if (settings_.impl_side_painting) { - CreateAndSetTileManager(resource_provider.get(), - output_surface->context_provider().get(), - GetRendererCapabilities().using_map_image); - } + if (settings_.impl_side_painting) + CreateAndSetTileManager(); - // 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); + // Initialize vsync parameters to sane values. + const base::TimeDelta display_refresh_interval = + base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond / + settings_.refresh_rate); + CommitVSyncParameters(base::TimeTicks(), display_refresh_interval); - output_surface->InitializeBeginImplFrameEmulation( - proxy_->ImplThreadTaskRunner(), - settings_.throttle_frame_production, - display_refresh_interval); - } + // TODO(brianderson): Don't use a hard-coded parent draw time. + base::TimeDelta parent_draw_time = + (!settings_.begin_frame_scheduling_enabled && + output_surface_->capabilities().adjust_deadline_for_parent) + ? BeginFrameArgs::DefaultEstimatedParentDrawTime() + : base::TimeDelta(); + client_->SetEstimatedParentDrawTime(parent_draw_time); - int max_frames_pending = - output_surface->capabilities().max_frames_pending; + int max_frames_pending = output_surface_->capabilities().max_frames_pending; if (max_frames_pending <= 0) max_frames_pending = OutputSurface::DEFAULT_MAX_FRAMES_PENDING; - output_surface->SetMaxFramesPending(max_frames_pending); - - resource_provider_ = resource_provider.Pass(); - output_surface_ = output_surface.Pass(); - + client_->SetMaxSwapsPendingOnImplThread(max_frames_pending); client_->OnCanDrawStateChanged(CanDraw()); return true; } -bool LayerTreeHostImpl::DeferredInitialize( - scoped_refptr<ContextProvider> offscreen_context_provider) { +void LayerTreeHostImpl::CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) { + client_->CommitVSyncParameters(timebase, interval); +} + +void LayerTreeHostImpl::DeferredInitialize() { DCHECK(output_surface_->capabilities().deferred_gl_initialization); DCHECK(settings_.impl_side_painting); DCHECK(output_surface_->context_provider()); ReleaseTreeResources(); renderer_.reset(); + DestroyTileManager(); - bool resource_provider_success = resource_provider_->InitializeGL(); - - bool success = resource_provider_success; - if (success) { - bool skip_gl_renderer = false; - CreateAndSetRenderer( - output_surface_.get(), resource_provider_.get(), skip_gl_renderer); - if (!renderer_) - success = false; - } - - if (success) { - if (offscreen_context_provider.get() && - !offscreen_context_provider->BindToCurrentThread()) - success = false; - } - - if (success) { - EnforceZeroBudget(false); - client_->SetNeedsCommitOnImplThread(); - } else { - if (offscreen_context_provider.get()) { - if (offscreen_context_provider->BindToCurrentThread()) - offscreen_context_provider->VerifyContexts(); - offscreen_context_provider = NULL; - } - - client_->DidLoseOutputSurfaceOnImplThread(); + resource_provider_->InitializeGL(); - if (resource_provider_success) { - // If this fails the context provider will be dropped from the output - // surface and destroyed. But the GLRenderer expects the output surface - // to stick around - and hold onto the context3d - as long as it is alive. - // TODO(danakj): Remove the need for this code path: crbug.com/276411 - renderer_.reset(); - - // The resource provider can't stay in GL mode or it tries to clean up GL - // stuff, but the context provider is going away on the output surface - // which contradicts being in GL mode. - // TODO(danakj): Remove the need for this code path: crbug.com/276411 - resource_provider_->InitializeSoftware(); - } - } + CreateAndSetRenderer(); + EnforceZeroBudget(false); + CreateAndSetTileManager(); - SetOffscreenContextProvider(offscreen_context_provider); - return success; + client_->SetNeedsCommitOnImplThread(); } void LayerTreeHostImpl::ReleaseGL() { @@ -1872,26 +2062,19 @@ void LayerTreeHostImpl::ReleaseGL() { ReleaseTreeResources(); renderer_.reset(); - tile_manager_.reset(); - resource_provider_->InitializeSoftware(); + DestroyTileManager(); - bool skip_gl_renderer = true; - CreateAndSetRenderer( - output_surface_.get(), resource_provider_.get(), skip_gl_renderer); - DCHECK(renderer_); + resource_provider_->InitializeSoftware(); + output_surface_->ReleaseContextProvider(); + CreateAndSetRenderer(); EnforceZeroBudget(true); - CreateAndSetTileManager(resource_provider_.get(), - NULL, - GetRendererCapabilities().using_map_image); - DCHECK(tile_manager_); - - SetOffscreenContextProvider(NULL); + CreateAndSetTileManager(); client_->SetNeedsCommitOnImplThread(); } -void LayerTreeHostImpl::SetViewportSize(gfx::Size device_viewport_size) { +void LayerTreeHostImpl::SetViewportSize(const gfx::Size& device_viewport_size) { if (device_viewport_size == device_viewport_size_) return; @@ -1900,10 +2083,10 @@ void LayerTreeHostImpl::SetViewportSize(gfx::Size device_viewport_size) { device_viewport_size_ = device_viewport_size; - UpdateMaxScrollOffset(); - + UpdateInnerViewportContainerSize(); client_->OnCanDrawStateChanged(CanDraw()); SetFullRootLayerDamage(); + active_tree_->set_needs_update_draw_properties(); } void LayerTreeHostImpl::SetOverdrawBottomHeight(float overdraw_bottom_height) { @@ -1911,13 +2094,13 @@ void LayerTreeHostImpl::SetOverdrawBottomHeight(float overdraw_bottom_height) { return; overdraw_bottom_height_ = overdraw_bottom_height; - UpdateMaxScrollOffset(); + UpdateInnerViewportContainerSize(); SetFullRootLayerDamage(); } void LayerTreeHostImpl::SetOverhangUIResource( UIResourceId overhang_ui_resource_id, - gfx::Size overhang_ui_resource_size) { + const gfx::Size& overhang_ui_resource_size) { overhang_ui_resource_id_ = overhang_ui_resource_id; overhang_ui_resource_size_ = overhang_ui_resource_size; } @@ -1927,7 +2110,7 @@ void LayerTreeHostImpl::SetDeviceScaleFactor(float device_scale_factor) { return; device_scale_factor_ = device_scale_factor; - UpdateMaxScrollOffset(); + UpdateInnerViewportContainerSize(); SetFullRootLayerDamage(); } @@ -1953,21 +2136,14 @@ const gfx::Transform& LayerTreeHostImpl::DrawTransform() const { return external_transform_; } -void LayerTreeHostImpl::UpdateMaxScrollOffset() { - active_tree_->UpdateMaxScrollOffset(); -} - void LayerTreeHostImpl::DidChangeTopControlsPosition() { + UpdateInnerViewportContainerSize(); SetNeedsRedraw(); + SetNeedsAnimate(); active_tree_->set_needs_update_draw_properties(); SetFullRootLayerDamage(); } -bool LayerTreeHostImpl::EnsureRenderSurfaceLayerList() { - active_tree_->UpdateDrawProperties(); - return !active_tree_->RenderSurfaceLayerList().empty(); -} - void LayerTreeHostImpl::BindToClient(InputHandlerClient* client) { DCHECK(input_handler_client_ == NULL); input_handler_client_ = client; @@ -1980,12 +2156,15 @@ static LayerImpl* NextScrollLayer(LayerImpl* layer) { } LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint( - gfx::PointF device_viewport_point, InputHandler::ScrollInputType type, - LayerImpl* layer_impl, bool* scroll_on_main_thread) const { + const gfx::PointF& device_viewport_point, + InputHandler::ScrollInputType type, + LayerImpl* layer_impl, + bool* scroll_on_main_thread, + bool* optional_has_ancestor_scroll_handler) const { DCHECK(scroll_on_main_thread); // Walk up the hierarchy and look for a scrollable layer. - LayerImpl* potentially_scrolling_layer_impl = 0; + LayerImpl* potentially_scrolling_layer_impl = NULL; for (; layer_impl; layer_impl = NextScrollLayer(layer_impl)) { // The content layer can also block attempts to scroll outside the main // thread. @@ -2006,24 +2185,39 @@ LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint( return NULL; } + if (optional_has_ancestor_scroll_handler && + scroll_layer_impl->have_scroll_event_handlers()) + *optional_has_ancestor_scroll_handler = true; + if (status == ScrollStarted && !potentially_scrolling_layer_impl) potentially_scrolling_layer_impl = scroll_layer_impl; } - // When hiding top controls is enabled and the controls are hidden or - // overlaying the content, force scrolls to be enabled on the root layer to - // allow bringing the top controls back into view. - if (!potentially_scrolling_layer_impl && top_controls_manager_ && - top_controls_manager_->content_top_offset() != - settings_.top_controls_height) { - potentially_scrolling_layer_impl = RootScrollLayer(); - } + // Falling back to the root scroll layer ensures generation of root overscroll + // notifications while preventing scroll updates from being unintentionally + // forwarded to the main thread. + if (!potentially_scrolling_layer_impl) + potentially_scrolling_layer_impl = OuterViewportScrollLayer() + ? OuterViewportScrollLayer() + : InnerViewportScrollLayer(); return potentially_scrolling_layer_impl; } +// Similar to LayerImpl::HasAncestor, but walks up the scroll parents. +static bool HasScrollAncestor(LayerImpl* child, LayerImpl* scroll_ancestor) { + DCHECK(scroll_ancestor); + for (LayerImpl* ancestor = child; ancestor; + ancestor = NextScrollLayer(ancestor)) { + if (ancestor->scrollable()) + return ancestor == scroll_ancestor; + } + return false; +} + InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( - gfx::Point viewport_point, InputHandler::ScrollInputType type) { + const gfx::Point& viewport_point, + InputHandler::ScrollInputType type) { TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBegin"); if (top_controls_manager_) @@ -2032,33 +2226,35 @@ InputHandler::ScrollStatus LayerTreeHostImpl::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()); + LayerImpl* layer_impl = + active_tree_->FindLayerThatIsHitByPoint(device_viewport_point); + + if (layer_impl) { + LayerImpl* scroll_layer_impl = + active_tree_->FindFirstScrollingLayerThatIsHitByPoint( + device_viewport_point); + if (scroll_layer_impl && !HasScrollAncestor(layer_impl, scroll_layer_impl)) + return ScrollUnknown; + } + bool scroll_on_main_thread = false; - LayerImpl* potentially_scrolling_layer_impl = - FindScrollLayerForDeviceViewportPoint(device_viewport_point, type, - layer_impl, &scroll_on_main_thread); + LayerImpl* scrolling_layer_impl = + FindScrollLayerForDeviceViewportPoint(device_viewport_point, + type, + layer_impl, + &scroll_on_main_thread, + &scroll_affects_scroll_handler_); 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); + if (scrolling_layer_impl) { + active_tree_->SetCurrentlyScrollingLayer(scrolling_layer_impl); should_bubble_scrolls_ = (type != NonBubblingGesture); - last_scroll_did_bubble_ = false; wheel_scrolling_ = (type == Wheel); client_->RenewTreePriority(); UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", false); @@ -2070,8 +2266,8 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( gfx::Vector2dF LayerTreeHostImpl::ScrollLayerWithViewportSpaceDelta( LayerImpl* layer_impl, float scale_from_viewport_to_screen_space, - gfx::PointF viewport_point, - gfx::Vector2dF viewport_delta) { + const gfx::PointF& viewport_point, + const gfx::Vector2dF& viewport_delta) { // Layers with non-invertible screen space transforms should not have passed // the scroll hit test in the first place. DCHECK(layer_impl->screen_space_transform().IsInvertible()); @@ -2144,14 +2340,14 @@ gfx::Vector2dF LayerTreeHostImpl::ScrollLayerWithViewportSpaceDelta( } static gfx::Vector2dF ScrollLayerWithLocalDelta(LayerImpl* layer_impl, - gfx::Vector2dF local_delta) { + const gfx::Vector2dF& local_delta) { gfx::Vector2dF previous_delta(layer_impl->ScrollDelta()); layer_impl->ScrollBy(local_delta); return layer_impl->ScrollDelta() - previous_delta; } -bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, - gfx::Vector2dF scroll_delta) { +bool LayerTreeHostImpl::ScrollBy(const gfx::Point& viewport_point, + const gfx::Vector2dF& scroll_delta) { TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBy"); if (!CurrentlyScrollingLayer()) return false; @@ -2160,9 +2356,15 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, gfx::Vector2dF unused_root_delta; bool did_scroll_x = false; bool did_scroll_y = false; - bool consume_by_top_controls = top_controls_manager_ && - (CurrentlyScrollingLayer() == RootScrollLayer() || scroll_delta.y() < 0); - last_scroll_did_bubble_ = false; + bool did_scroll_top_controls = false; + // TODO(wjmaclean) Should we guard against CurrentlyScrollingLayer() == 0 + // here? + bool consume_by_top_controls = + top_controls_manager_ && + (((CurrentlyScrollingLayer() == InnerViewportScrollLayer() || + CurrentlyScrollingLayer() == OuterViewportScrollLayer()) && + InnerViewportScrollLayer()->MaxScrollOffset().y() > 0) || + scroll_delta.y() < 0); for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); layer_impl; @@ -2170,12 +2372,20 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, if (!layer_impl->scrollable()) continue; - if (layer_impl == RootScrollLayer()) { + if (layer_impl == InnerViewportScrollLayer()) { // Only allow bubble scrolling when the scroll is in the direction to make // the top controls visible. - if (consume_by_top_controls && layer_impl == RootScrollLayer()) { - pending_delta = top_controls_manager_->ScrollBy(pending_delta); - UpdateMaxScrollOffset(); + gfx::Vector2dF applied_delta; + gfx::Vector2dF excess_delta; + if (consume_by_top_controls) { + excess_delta = top_controls_manager_->ScrollBy(pending_delta); + applied_delta = pending_delta - excess_delta; + pending_delta = excess_delta; + // Force updating of vertical adjust values if needed. + if (applied_delta.y() != 0) { + did_scroll_top_controls = true; + layer_impl->ScrollbarParametersDidChange(); + } } // Track root layer deltas for reporting overscroll. unused_root_delta = pending_delta; @@ -2196,27 +2406,36 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, applied_delta = ScrollLayerWithLocalDelta(layer_impl, pending_delta); } + const float kEpsilon = 0.1f; + if (layer_impl == InnerViewportScrollLayer()) { + unused_root_delta.Subtract(applied_delta); + if (std::abs(unused_root_delta.x()) < kEpsilon) + unused_root_delta.set_x(0.0f); + if (std::abs(unused_root_delta.y()) < kEpsilon) + unused_root_delta.set_y(0.0f); + // Disable overscroll on axes which is impossible to scroll. + if (settings_.report_overscroll_only_for_scrollable_axes) { + if (std::abs(active_tree_->TotalMaxScrollOffset().x()) <= kEpsilon) + unused_root_delta.set_x(0.0f); + if (std::abs(active_tree_->TotalMaxScrollOffset().y()) <= kEpsilon) + unused_root_delta.set_y(0.0f); + } + } + // If the layer wasn't able to move, try the next one in the hierarchy. - float move_threshold = 0.1f; - bool did_move_layer_x = std::abs(applied_delta.x()) > move_threshold; - bool did_move_layer_y = std::abs(applied_delta.y()) > move_threshold; + bool did_move_layer_x = std::abs(applied_delta.x()) > kEpsilon; + bool did_move_layer_y = std::abs(applied_delta.y()) > kEpsilon; did_scroll_x |= did_move_layer_x; did_scroll_y |= did_move_layer_y; if (!did_move_layer_x && !did_move_layer_y) { - if (!did_lock_scrolling_layer_) + // Scrolls should always bubble between the outer and inner viewports + if (should_bubble_scrolls_ || !did_lock_scrolling_layer_ || + layer_impl == OuterViewportScrollLayer()) continue; - - if (should_bubble_scrolls_) { - last_scroll_did_bubble_ = true; - continue; - } - - break; + else + break; } - if (layer_impl == RootScrollLayer()) - unused_root_delta.Subtract(applied_delta); - did_lock_scrolling_layer_ = true; if (!should_bubble_scrolls_) { active_tree_->SetCurrentlyScrollingLayer(layer_impl); @@ -2242,8 +2461,8 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, break; } - bool did_scroll = did_scroll_x || did_scroll_y; - if (did_scroll) { + bool did_scroll_content = did_scroll_x || did_scroll_y; + if (did_scroll_content) { client_->SetNeedsCommitOnImplThread(); SetNeedsRedraw(); client_->RenewTreePriority(); @@ -2256,22 +2475,19 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, accumulated_root_overscroll_.set_y(0); accumulated_root_overscroll_ += unused_root_delta; - bool did_overscroll = !gfx::ToRoundedVector2d(unused_root_delta).IsZero(); + bool did_overscroll = !unused_root_delta.IsZero(); if (did_overscroll && input_handler_client_) { - DidOverscrollParams params; - params.accumulated_overscroll = accumulated_root_overscroll_; - params.latest_overscroll_delta = unused_root_delta; - params.current_fling_velocity = current_fling_velocity_; - input_handler_client_->DidOverscroll(params); + input_handler_client_->DidOverscroll(accumulated_root_overscroll_, + unused_root_delta); } - return did_scroll; + return did_scroll_content || did_scroll_top_controls; } // This implements scrolling by page as described here: // http://msdn.microsoft.com/en-us/library/windows/desktop/ms645601(v=vs.85).aspx#_win32_The_Mouse_Wheel // for events with WHEEL_PAGESCROLL set. -bool LayerTreeHostImpl::ScrollVerticallyByPage(gfx::Point viewport_point, +bool LayerTreeHostImpl::ScrollVerticallyByPage(const gfx::Point& viewport_point, ScrollDirection direction) { DCHECK(wheel_scrolling_); @@ -2281,10 +2497,10 @@ bool LayerTreeHostImpl::ScrollVerticallyByPage(gfx::Point viewport_point, if (!layer_impl->scrollable()) continue; - if (!layer_impl->vertical_scrollbar_layer()) + if (!layer_impl->HasScrollbar(VERTICAL)) continue; - float height = layer_impl->vertical_scrollbar_layer()->bounds().height(); + float height = layer_impl->clip_height(); // These magical values match WebKit and are designed to scroll nearly the // entire visible content height but leave a bit of overlap. @@ -2319,20 +2535,20 @@ void LayerTreeHostImpl::SetRootLayerScrollOffsetDelegate( void LayerTreeHostImpl::OnRootLayerDelegatedScrollOffsetChanged() { DCHECK(root_layer_scroll_offset_delegate_ != NULL); client_->SetNeedsCommitOnImplThread(); + active_tree_->set_needs_update_draw_properties(); } void LayerTreeHostImpl::ClearCurrentlyScrollingLayer() { active_tree_->ClearCurrentlyScrollingLayer(); did_lock_scrolling_layer_ = false; + scroll_affects_scroll_handler_ = false; accumulated_root_overscroll_ = gfx::Vector2dF(); - current_fling_velocity_ = gfx::Vector2dF(); } void LayerTreeHostImpl::ScrollEnd() { if (top_controls_manager_) top_controls_manager_->ScrollEnd(); ClearCurrentlyScrollingLayer(); - StartScrollbarAnimation(); } InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() { @@ -2340,24 +2556,24 @@ InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() { return ScrollIgnored; if (settings_.ignore_root_layer_flings && - active_tree_->CurrentlyScrollingLayer() == - active_tree_->RootScrollLayer()) { + (active_tree_->CurrentlyScrollingLayer() == InnerViewportScrollLayer() || + active_tree_->CurrentlyScrollingLayer() == OuterViewportScrollLayer())) { ClearCurrentlyScrollingLayer(); return ScrollIgnored; } - if (!wheel_scrolling_) - should_bubble_scrolls_ = last_scroll_did_bubble_; + if (!wheel_scrolling_) { + // Allow the fling to lock to the first layer that moves after the initial + // fling |ScrollBy()| event. + did_lock_scrolling_layer_ = false; + should_bubble_scrolls_ = false; + } return ScrollStarted; } -void LayerTreeHostImpl::NotifyCurrentFlingVelocity(gfx::Vector2dF velocity) { - current_fling_velocity_ = velocity; -} - float LayerTreeHostImpl::DeviceSpaceDistanceToLayer( - gfx::PointF device_viewport_point, + const gfx::PointF& device_viewport_point, LayerImpl* layer_impl) { if (!layer_impl) return std::numeric_limits<float>::max(); @@ -2373,16 +2589,11 @@ float LayerTreeHostImpl::DeviceSpaceDistanceToLayer( device_viewport_point); } -void LayerTreeHostImpl::MouseMoveAt(gfx::Point viewport_point) { - if (!EnsureRenderSurfaceLayerList()) - return; - +void LayerTreeHostImpl::MouseMoveAt(const gfx::Point& viewport_point) { gfx::PointF device_viewport_point = gfx::ScalePoint(viewport_point, device_scale_factor_); - - LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint( - device_viewport_point, - active_tree_->RenderSurfaceLayerList()); + LayerImpl* layer_impl = + active_tree_->FindLayerThatIsHitByPoint(device_viewport_point); if (HandleMouseOverScrollbar(layer_impl, device_viewport_point)) return; @@ -2390,20 +2601,24 @@ void LayerTreeHostImpl::MouseMoveAt(gfx::Point viewport_point) { LayerImpl* scroll_layer_impl = active_tree_->LayerById( scroll_layer_id_when_mouse_over_scrollbar_); + // The check for a null scroll_layer_impl below was added to see if it will + // eliminate the crashes described in http://crbug.com/326635. + // TODO(wjmaclean) Add a unit test if this fixes the crashes. ScrollbarAnimationController* animation_controller = - scroll_layer_impl->scrollbar_animation_controller(); - if (animation_controller) { - animation_controller->DidMouseMoveOffScrollbar( - CurrentPhysicalTimeTicks()); - StartScrollbarAnimation(); - } + scroll_layer_impl ? scroll_layer_impl->scrollbar_animation_controller() + : NULL; + if (animation_controller) + animation_controller->DidMouseMoveOffScrollbar(); 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); + LayerImpl* scroll_layer_impl = + FindScrollLayerForDeviceViewportPoint(device_viewport_point, + InputHandler::Gesture, + layer_impl, + &scroll_on_main_thread, + NULL); if (scroll_on_main_thread || !scroll_layer_impl) return; @@ -2412,30 +2627,28 @@ void LayerTreeHostImpl::MouseMoveAt(gfx::Point viewport_point) { 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())); + // TODO(wjmaclean) Is it ok to choose distance from more than two scrollbars? + float distance_to_scrollbar = std::numeric_limits<float>::max(); + for (LayerImpl::ScrollbarSet::iterator it = + scroll_layer_impl->scrollbars()->begin(); + it != scroll_layer_impl->scrollbars()->end(); + ++it) + distance_to_scrollbar = + std::min(distance_to_scrollbar, + DeviceSpaceDistanceToLayer(device_viewport_point, *it)); - bool should_animate = animation_controller->DidMouseMoveNear( - CurrentPhysicalTimeTicks(), distance_to_scrollbar / device_scale_factor_); - if (should_animate) - StartScrollbarAnimation(); + animation_controller->DidMouseMoveNear(distance_to_scrollbar / + device_scale_factor_); } bool LayerTreeHostImpl::HandleMouseOverScrollbar(LayerImpl* layer_impl, - gfx::PointF device_viewport_point) { + const 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(); + layer_impl->scrollbar_animation_controller()->DidMouseMoveNear(0); } else { scroll_layer_id_when_mouse_over_scrollbar_ = 0; } @@ -2451,17 +2664,28 @@ void LayerTreeHostImpl::PinchGestureBegin() { previous_pinch_anchor_ = gfx::Point(); client_->RenewTreePriority(); pinch_gesture_end_should_clear_scrolling_layer_ = !CurrentlyScrollingLayer(); - active_tree_->SetCurrentlyScrollingLayer(RootScrollLayer()); + if (active_tree_->OuterViewportScrollLayer()) { + active_tree_->SetCurrentlyScrollingLayer( + active_tree_->OuterViewportScrollLayer()); + } else { + active_tree_->SetCurrentlyScrollingLayer( + active_tree_->InnerViewportScrollLayer()); + } if (top_controls_manager_) top_controls_manager_->PinchBegin(); } void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta, - gfx::Point anchor) { + const gfx::Point& anchor) { + if (!InnerViewportScrollLayer()) + return; + TRACE_EVENT0("cc", "LayerTreeHostImpl::PinchGestureUpdate"); - if (!RootScrollLayer()) - return; + // For a moment the scroll offset ends up being outside of the max range. This + // confuses the delegate so we switch it off till after we're done processing + // the pinch update. + active_tree_->SetRootLayerScrollOffsetDelegate(NULL); // Keep the center-of-pinch anchor specified by (x, y) in a stable // position over the course of the magnify. @@ -2477,8 +2701,27 @@ void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta, previous_pinch_anchor_ = anchor; move.Scale(1 / active_tree_->page_scale_factor()); + // If clamping the inner viewport scroll offset causes a change, it should + // be accounted for from the intended move. + move -= InnerViewportScrollLayer()->ClampScrollToMaxScrollOffset(); - RootScrollLayer()->ScrollBy(move); + // We manually manage the bubbling behaviour here as it is different to that + // implemented in LayerTreeHostImpl::ScrollBy(). Specifically: + // 1) we want to explicit limit the bubbling to the outer/inner viewports, + // 2) we don't want the directional limitations on the unused parts that + // ScrollBy() implements, and + // 3) pinching should not engage the top controls manager. + gfx::Vector2dF unused = OuterViewportScrollLayer() + ? OuterViewportScrollLayer()->ScrollBy(move) + : move; + + if (!unused.IsZero()) { + InnerViewportScrollLayer()->ScrollBy(unused); + InnerViewportScrollLayer()->ClampScrollToMaxScrollOffset(); + } + + active_tree_->SetRootLayerScrollOffsetDelegate( + root_layer_scroll_offset_delegate_); client_->SetNeedsCommitOnImplThread(); SetNeedsRedraw(); @@ -2529,13 +2772,51 @@ void LayerTreeHostImpl::SetFullRootLayerDamage() { SetViewportDamage(gfx::Rect(DrawViewportSize())); } -void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks time) { - if (!page_scale_animation_ || !RootScrollLayer()) +void LayerTreeHostImpl::RunOnDemandRasterTask(Task* on_demand_raster_task) { + DCHECK(on_demand_task_graph_runner_); + + // Construct a task graph that contains this single raster task. + TaskGraph graph; + graph.nodes.push_back( + TaskGraph::Node(on_demand_raster_task, + RasterWorkerPool::kOnDemandRasterTaskPriority, + 0u)); + + // Schedule task and wait for task graph runner to finish running it. + on_demand_task_graph_runner_->ScheduleTasks(on_demand_task_namespace_, + &graph); + + if (on_demand_task_graph_runner_ == &synchronous_task_graph_runner_) + on_demand_task_graph_runner_->RunUntilIdle(); + + on_demand_task_graph_runner_->WaitForTasksToFinishRunning( + on_demand_task_namespace_); + + // Collect task now that it has finished running. + Task::Vector completed_tasks; + on_demand_task_graph_runner_->CollectCompletedTasks(on_demand_task_namespace_, + &completed_tasks); + DCHECK_EQ(1u, completed_tasks.size()); + DCHECK_EQ(completed_tasks[0], on_demand_raster_task); +} + +void LayerTreeHostImpl::ScrollViewportBy(gfx::Vector2dF scroll_delta) { + DCHECK(InnerViewportScrollLayer()); + LayerImpl* scroll_layer = OuterViewportScrollLayer() + ? OuterViewportScrollLayer() + : InnerViewportScrollLayer(); + + gfx::Vector2dF unused_delta = scroll_layer->ScrollBy(scroll_delta); + + if (!unused_delta.IsZero() && (scroll_layer == OuterViewportScrollLayer())) + InnerViewportScrollLayer()->ScrollBy(unused_delta); +} + +void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks monotonic_time) { + if (!page_scale_animation_) return; - double monotonic_time = (time - base::TimeTicks()).InSecondsF(); - gfx::Vector2dF scroll_total = RootScrollLayer()->scroll_offset() + - RootScrollLayer()->ScrollDelta(); + gfx::Vector2dF scroll_total = active_tree_->TotalScrollOffset(); if (!page_scale_animation_->IsAnimationStarted()) page_scale_animation_->StartAnimation(monotonic_time); @@ -2546,52 +2827,52 @@ void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks time) { gfx::Vector2dF next_scroll = page_scale_animation_->ScrollOffsetAtTime(monotonic_time); - RootScrollLayer()->ScrollBy(next_scroll - scroll_total); + ScrollViewportBy(next_scroll - scroll_total); SetNeedsRedraw(); if (page_scale_animation_->IsAnimationCompleteAtTime(monotonic_time)) { page_scale_animation_.reset(); client_->SetNeedsCommitOnImplThread(); client_->RenewTreePriority(); + } else { + SetNeedsAnimate(); } } void LayerTreeHostImpl::AnimateTopControls(base::TimeTicks time) { - if (!top_controls_manager_ || !RootScrollLayer()) + if (!top_controls_manager_ || !top_controls_manager_->animation()) return; gfx::Vector2dF scroll = top_controls_manager_->Animate(time); - UpdateMaxScrollOffset(); - if (RootScrollLayer()->TotalScrollOffset().y() == 0.f) + if (active_tree_->TotalScrollOffset().y() == 0.f) return; - RootScrollLayer()->ScrollBy(gfx::ScaleVector2d( - scroll, 1.f / active_tree_->total_page_scale_factor())); + if (!scroll.IsZero()) { + ScrollViewportBy(gfx::ScaleVector2d( + scroll, 1.f / active_tree_->total_page_scale_factor())); + SetNeedsRedraw(); + } + SetNeedsAnimate(); } -void LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time, - base::Time wall_clock_time) { +void LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time) { if (!settings_.accelerated_animation_enabled || - animation_registrar_->active_animation_controllers().empty() || + !needs_animate_layers() || !active_tree_->root_layer()) return; TRACE_EVENT0("cc", "LayerTreeHostImpl::AnimateLayers"); - - last_animation_time_ = wall_clock_time; - double monotonic_seconds = (monotonic_time - base::TimeTicks()).InSecondsF(); - AnimationRegistrar::AnimationControllerMap copy = animation_registrar_->active_animation_controllers(); for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin(); iter != copy.end(); ++iter) - (*iter).second->Animate(monotonic_seconds); + (*iter).second->Animate(monotonic_time); - SetNeedsRedraw(); + SetNeedsAnimate(); } void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) { if (!settings_.accelerated_animation_enabled || - animation_registrar_->active_animation_controllers().empty() || + !needs_animate_layers() || !active_tree_->root_layer()) return; @@ -2606,40 +2887,28 @@ void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) { (*iter).second->UpdateState(start_ready_animations, events.get()); if (!events->empty()) { - client_->PostAnimationEventsToMainThreadOnImplThread(events.Pass(), - last_animation_time_); + client_->PostAnimationEventsToMainThreadOnImplThread(events.Pass()); } -} -base::TimeDelta LayerTreeHostImpl::LowFrequencyAnimationInterval() const { - return base::TimeDelta::FromSeconds(1); + SetNeedsAnimate(); } -void LayerTreeHostImpl::SendReleaseResourcesRecursive(LayerImpl* current) { - DCHECK(current); - // TODO(boliu): Rename DidLoseOutputSurface to ReleaseResources. - current->DidLoseOutputSurface(); - if (current->mask_layer()) - SendReleaseResourcesRecursive(current->mask_layer()); - if (current->replica_layer()) - SendReleaseResourcesRecursive(current->replica_layer()); - for (size_t i = 0; i < current->children().size(); ++i) - SendReleaseResourcesRecursive(current->children()[i]); -} - -void LayerTreeHostImpl::SetOffscreenContextProvider( - const scoped_refptr<ContextProvider>& offscreen_context_provider) { - if (!offscreen_context_provider.get()) { - offscreen_context_provider_ = NULL; +void LayerTreeHostImpl::ActivateAnimations() { + if (!settings_.accelerated_animation_enabled || !needs_animate_layers() || + !active_tree_->root_layer()) return; - } - if (!offscreen_context_provider->BindToCurrentThread()) { - offscreen_context_provider_ = NULL; - return; - } + TRACE_EVENT0("cc", "LayerTreeHostImpl::ActivateAnimations"); + AnimationRegistrar::AnimationControllerMap copy = + animation_registrar_->active_animation_controllers(); + for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin(); + iter != copy.end(); + ++iter) + (*iter).second->ActivateAnimations(); +} - offscreen_context_provider_ = offscreen_context_provider; +base::TimeDelta LayerTreeHostImpl::LowFrequencyAnimationInterval() const { + return base::TimeDelta::FromSeconds(1); } std::string LayerTreeHostImpl::LayerTreeAsJson() const { @@ -2656,35 +2925,6 @@ int LayerTreeHostImpl::SourceAnimationFrameNumber() const { return fps_counter_->current_frame_number(); } -void LayerTreeHostImpl::SendManagedMemoryStats( - size_t memory_visible_bytes, - size_t memory_visible_and_nearby_bytes, - size_t memory_use_bytes) { - if (!renderer_) - return; - - // Round the numbers being sent up to the next 8MB, to throttle the rate - // at which we spam the GPU process. - static const size_t rounding_step = 8 * 1024 * 1024; - memory_visible_bytes = RoundUp(memory_visible_bytes, rounding_step); - memory_visible_and_nearby_bytes = RoundUp(memory_visible_and_nearby_bytes, - rounding_step); - memory_use_bytes = RoundUp(memory_use_bytes, rounding_step); - if (last_sent_memory_visible_bytes_ == memory_visible_bytes && - last_sent_memory_visible_and_nearby_bytes_ == - memory_visible_and_nearby_bytes && - last_sent_memory_use_bytes_ == memory_use_bytes) { - return; - } - last_sent_memory_visible_bytes_ = memory_visible_bytes; - last_sent_memory_visible_and_nearby_bytes_ = memory_visible_and_nearby_bytes; - last_sent_memory_use_bytes_ = memory_use_bytes; - - renderer_->SendManagedMemoryStats(last_sent_memory_visible_bytes_, - last_sent_memory_visible_and_nearby_bytes_, - last_sent_memory_use_bytes_); -} - void LayerTreeHostImpl::AnimateScrollbars(base::TimeTicks time) { AnimateScrollbarsRecursive(active_tree_->root_layer(), time); } @@ -2696,39 +2936,25 @@ void LayerTreeHostImpl::AnimateScrollbarsRecursive(LayerImpl* layer, ScrollbarAnimationController* scrollbar_controller = layer->scrollbar_animation_controller(); - if (scrollbar_controller && scrollbar_controller->Animate(time)) { - TRACE_EVENT_INSTANT0( - "cc", "LayerTreeHostImpl::SetNeedsRedraw due to AnimateScrollbars", - TRACE_EVENT_SCOPE_THREAD); - SetNeedsRedraw(); - } + if (scrollbar_controller) + scrollbar_controller->Animate(time); for (size_t i = 0; i < layer->children().size(); ++i) AnimateScrollbarsRecursive(layer->children()[i], time); } -void LayerTreeHostImpl::StartScrollbarAnimation() { - TRACE_EVENT0("cc", "LayerTreeHostImpl::StartScrollbarAnimation"); - StartScrollbarAnimationRecursive(RootLayer(), CurrentPhysicalTimeTicks()); +void LayerTreeHostImpl::PostDelayedScrollbarFade( + const base::Closure& start_fade, + base::TimeDelta delay) { + client_->PostDelayedScrollbarFadeOnImplThread(start_fade, delay); } -void LayerTreeHostImpl::StartScrollbarAnimationRecursive(LayerImpl* layer, - base::TimeTicks time) { - if (!layer) - return; - - ScrollbarAnimationController* scrollbar_controller = - layer->scrollbar_animation_controller(); - if (scrollbar_controller && scrollbar_controller->IsAnimating()) { - base::TimeDelta delay = scrollbar_controller->DelayBeforeStart(time); - if (delay > base::TimeDelta()) - client_->RequestScrollbarAnimationOnImplThread(delay); - else if (scrollbar_controller->Animate(time)) - SetNeedsRedraw(); - } - - for (size_t i = 0; i < layer->children().size(); ++i) - StartScrollbarAnimationRecursive(layer->children()[i], time); +void LayerTreeHostImpl::SetNeedsScrollbarAnimationFrame() { + TRACE_EVENT_INSTANT0( + "cc", + "LayerTreeHostImpl::SetNeedsRedraw due to scrollbar fade", + TRACE_EVENT_SCOPE_THREAD); + SetNeedsAnimate(); } void LayerTreeHostImpl::SetTreePriority(TreePriority priority) { @@ -2741,31 +2967,21 @@ void LayerTreeHostImpl::SetTreePriority(TreePriority priority) { DidModifyTilePriorities(); } -void LayerTreeHostImpl::ResetCurrentFrameTimeForNextFrame() { - current_frame_timeticks_ = base::TimeTicks(); - current_frame_time_ = base::Time(); +void LayerTreeHostImpl::UpdateCurrentFrameTime() { + DCHECK(current_frame_timeticks_.is_null()); + current_frame_timeticks_ = gfx::FrameTime::Now(); } -void LayerTreeHostImpl::UpdateCurrentFrameTime(base::TimeTicks* ticks, - base::Time* now) const { - if (ticks->is_null()) { - DCHECK(now->is_null()); - *ticks = CurrentPhysicalTimeTicks(); - *now = base::Time::Now(); - } +void LayerTreeHostImpl::ResetCurrentFrameTimeForNextFrame() { + current_frame_timeticks_ = base::TimeTicks(); } base::TimeTicks LayerTreeHostImpl::CurrentFrameTimeTicks() { - UpdateCurrentFrameTime(¤t_frame_timeticks_, ¤t_frame_time_); - return current_frame_timeticks_; -} - -base::Time LayerTreeHostImpl::CurrentFrameTime() { - UpdateCurrentFrameTime(¤t_frame_timeticks_, ¤t_frame_time_); - return current_frame_time_; -} - -base::TimeTicks LayerTreeHostImpl::CurrentPhysicalTimeTicks() const { + // Try to use the current frame time to keep animations non-jittery. But if + // we're not in a frame (because this is during an input event or a delayed + // task), fall back to physical time. This should still be monotonic. + if (!current_frame_timeticks_.is_null()) + return current_frame_timeticks_; return gfx::FrameTime::Now(); } @@ -2924,4 +3140,17 @@ void LayerTreeHostImpl::NotifySwapPromiseMonitorsOfSetNeedsRedraw() { (*it)->OnSetNeedsRedrawOnImpl(); } +void LayerTreeHostImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) { + DCHECK(std::find(picture_layers_.begin(), picture_layers_.end(), layer) == + picture_layers_.end()); + picture_layers_.push_back(layer); +} + +void LayerTreeHostImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) { + std::vector<PictureLayerImpl*>::iterator it = + std::find(picture_layers_.begin(), picture_layers_.end(), layer); + DCHECK(it != picture_layers_.end()); + picture_layers_.erase(it); +} + } // namespace cc |