1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/gpu/render_widget_compositor.h"
10 #include "base/command_line.h"
11 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/synchronization/lock.h"
14 #include "base/time/time.h"
15 #include "cc/base/switches.h"
16 #include "cc/debug/layer_tree_debug_state.h"
17 #include "cc/layers/layer.h"
18 #include "cc/trees/layer_tree_host.h"
19 #include "content/common/gpu/client/context_provider_command_buffer.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/renderer/gpu/input_handler_manager.h"
22 #include "content/renderer/render_thread_impl.h"
23 #include "third_party/WebKit/public/platform/WebSize.h"
24 #include "third_party/WebKit/public/web/WebWidget.h"
25 #include "ui/gl/gl_switches.h"
26 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
32 using WebKit::WebFloatPoint
;
33 using WebKit::WebSize
;
34 using WebKit::WebRect
;
39 bool GetSwitchValueAsInt(
40 const CommandLine
& command_line
,
41 const std::string
& switch_string
,
45 std::string string_value
= command_line
.GetSwitchValueASCII(switch_string
);
47 if (base::StringToInt(string_value
, &int_value
) &&
48 int_value
>= min_value
&& int_value
<= max_value
) {
52 LOG(WARNING
) << "Failed to parse switch " << switch_string
<< ": " <<
58 bool GetSwitchValueAsFloat(
59 const CommandLine
& command_line
,
60 const std::string
& switch_string
,
64 std::string string_value
= command_line
.GetSwitchValueASCII(switch_string
);
66 if (base::StringToDouble(string_value
, &double_value
) &&
67 double_value
>= min_value
&& double_value
<= max_value
) {
68 *result
= static_cast<float>(double_value
);
71 LOG(WARNING
) << "Failed to parse switch " << switch_string
<< ": " <<
81 scoped_ptr
<RenderWidgetCompositor
> RenderWidgetCompositor::Create(
84 scoped_ptr
<RenderWidgetCompositor
> compositor(
85 new RenderWidgetCompositor(widget
, threaded
));
87 CommandLine
* cmd
= CommandLine::ForCurrentProcess();
89 cc::LayerTreeSettings settings
;
91 // For web contents, layer transforms should scale up the contents of layers
92 // to keep content always crisp when possible.
93 settings
.layer_transforms_should_scale_layer_contents
= true;
95 settings
.throttle_frame_production
=
96 !cmd
->HasSwitch(switches::kDisableGpuVsync
);
97 settings
.begin_frame_scheduling_enabled
=
98 cmd
->HasSwitch(switches::kEnableBeginFrameScheduling
);
99 settings
.using_synchronous_renderer_compositor
=
100 widget
->UsingSynchronousRendererCompositor();
101 settings
.per_tile_painting_enabled
=
102 cmd
->HasSwitch(cc::switches::kEnablePerTilePainting
);
103 settings
.accelerated_animation_enabled
=
104 !cmd
->HasSwitch(cc::switches::kDisableThreadedAnimation
);
105 settings
.force_direct_layer_drawing
=
106 cmd
->HasSwitch(cc::switches::kForceDirectLayerDrawing
);
108 int default_tile_width
= settings
.default_tile_size
.width();
109 if (cmd
->HasSwitch(switches::kDefaultTileWidth
)) {
110 GetSwitchValueAsInt(*cmd
, switches::kDefaultTileWidth
, 1,
111 std::numeric_limits
<int>::max(), &default_tile_width
);
113 int default_tile_height
= settings
.default_tile_size
.height();
114 if (cmd
->HasSwitch(switches::kDefaultTileHeight
)) {
115 GetSwitchValueAsInt(*cmd
, switches::kDefaultTileHeight
, 1,
116 std::numeric_limits
<int>::max(), &default_tile_height
);
118 settings
.default_tile_size
= gfx::Size(default_tile_width
,
119 default_tile_height
);
121 int max_untiled_layer_width
= settings
.max_untiled_layer_size
.width();
122 if (cmd
->HasSwitch(switches::kMaxUntiledLayerWidth
)) {
123 GetSwitchValueAsInt(*cmd
, switches::kMaxUntiledLayerWidth
, 1,
124 std::numeric_limits
<int>::max(),
125 &max_untiled_layer_width
);
127 int max_untiled_layer_height
= settings
.max_untiled_layer_size
.height();
128 if (cmd
->HasSwitch(switches::kMaxUntiledLayerHeight
)) {
129 GetSwitchValueAsInt(*cmd
, switches::kMaxUntiledLayerHeight
, 1,
130 std::numeric_limits
<int>::max(),
131 &max_untiled_layer_height
);
134 settings
.max_untiled_layer_size
= gfx::Size(max_untiled_layer_width
,
135 max_untiled_layer_height
);
137 settings
.impl_side_painting
= cc::switches::IsImplSidePaintingEnabled();
139 settings
.calculate_top_controls_position
=
140 cmd
->HasSwitch(cc::switches::kEnableTopControlsPositionCalculation
);
141 if (cmd
->HasSwitch(cc::switches::kTopControlsHeight
)) {
142 std::string controls_height_str
=
143 cmd
->GetSwitchValueASCII(cc::switches::kTopControlsHeight
);
144 double controls_height
;
145 if (base::StringToDouble(controls_height_str
, &controls_height
) &&
147 settings
.top_controls_height
= controls_height
;
150 if (settings
.calculate_top_controls_position
&&
151 settings
.top_controls_height
<= 0) {
153 << "Top controls repositioning enabled without valid height set.";
154 settings
.calculate_top_controls_position
= false;
157 if (cmd
->HasSwitch(cc::switches::kTopControlsShowThreshold
)) {
158 std::string top_threshold_str
=
159 cmd
->GetSwitchValueASCII(cc::switches::kTopControlsShowThreshold
);
160 double show_threshold
;
161 if (base::StringToDouble(top_threshold_str
, &show_threshold
) &&
162 show_threshold
>= 0.f
&& show_threshold
<= 1.f
)
163 settings
.top_controls_show_threshold
= show_threshold
;
166 if (cmd
->HasSwitch(cc::switches::kTopControlsHideThreshold
)) {
167 std::string top_threshold_str
=
168 cmd
->GetSwitchValueASCII(cc::switches::kTopControlsHideThreshold
);
169 double hide_threshold
;
170 if (base::StringToDouble(top_threshold_str
, &hide_threshold
) &&
171 hide_threshold
>= 0.f
&& hide_threshold
<= 1.f
)
172 settings
.top_controls_hide_threshold
= hide_threshold
;
175 settings
.partial_swap_enabled
= widget
->AllowPartialSwap() &&
176 cmd
->HasSwitch(cc::switches::kEnablePartialSwap
);
177 settings
.background_color_instead_of_checkerboard
=
178 cmd
->HasSwitch(cc::switches::kBackgroundColorInsteadOfCheckerboard
);
179 settings
.show_overdraw_in_tracing
=
180 cmd
->HasSwitch(cc::switches::kTraceOverdraw
);
181 settings
.can_use_lcd_text
= cc::switches::IsLCDTextEnabled();
182 settings
.use_pinch_virtual_viewport
=
183 cmd
->HasSwitch(cc::switches::kEnablePinchVirtualViewport
);
184 settings
.allow_antialiasing
&=
185 !cmd
->HasSwitch(cc::switches::kDisableCompositedAntialiasing
);
187 // These flags should be mirrored by UI versions in ui/compositor/.
188 settings
.initial_debug_state
.show_debug_borders
=
189 cmd
->HasSwitch(cc::switches::kShowCompositedLayerBorders
);
190 settings
.initial_debug_state
.show_fps_counter
=
191 cmd
->HasSwitch(cc::switches::kShowFPSCounter
);
192 settings
.initial_debug_state
.show_paint_rects
=
193 cmd
->HasSwitch(switches::kShowPaintRects
);
194 settings
.initial_debug_state
.show_property_changed_rects
=
195 cmd
->HasSwitch(cc::switches::kShowPropertyChangedRects
);
196 settings
.initial_debug_state
.show_surface_damage_rects
=
197 cmd
->HasSwitch(cc::switches::kShowSurfaceDamageRects
);
198 settings
.initial_debug_state
.show_screen_space_rects
=
199 cmd
->HasSwitch(cc::switches::kShowScreenSpaceRects
);
200 settings
.initial_debug_state
.show_replica_screen_space_rects
=
201 cmd
->HasSwitch(cc::switches::kShowReplicaScreenSpaceRects
);
202 settings
.initial_debug_state
.show_occluding_rects
=
203 cmd
->HasSwitch(cc::switches::kShowOccludingRects
);
204 settings
.initial_debug_state
.show_non_occluding_rects
=
205 cmd
->HasSwitch(cc::switches::kShowNonOccludingRects
);
207 settings
.initial_debug_state
.SetRecordRenderingStats(
208 cmd
->HasSwitch(switches::kEnableGpuBenchmarking
));
210 if (cmd
->HasSwitch(cc::switches::kSlowDownRasterScaleFactor
)) {
211 const int kMinSlowDownScaleFactor
= 0;
212 const int kMaxSlowDownScaleFactor
= INT_MAX
;
215 cc::switches::kSlowDownRasterScaleFactor
,
216 kMinSlowDownScaleFactor
,
217 kMaxSlowDownScaleFactor
,
218 &settings
.initial_debug_state
.slow_down_raster_scale_factor
);
221 if (cmd
->HasSwitch(cc::switches::kNumRasterThreads
)) {
222 const int kMinRasterThreads
= 1;
223 const int kMaxRasterThreads
= 64;
224 int num_raster_threads
;
225 if (GetSwitchValueAsInt(*cmd
, cc::switches::kNumRasterThreads
,
226 kMinRasterThreads
, kMaxRasterThreads
,
227 &num_raster_threads
))
228 settings
.num_raster_threads
= num_raster_threads
;
231 if (cmd
->HasSwitch(cc::switches::kLowResolutionContentsScaleFactor
)) {
232 const int kMinScaleFactor
= settings
.minimum_contents_scale
;
233 const int kMaxScaleFactor
= 1;
234 GetSwitchValueAsFloat(*cmd
,
235 cc::switches::kLowResolutionContentsScaleFactor
,
236 kMinScaleFactor
, kMaxScaleFactor
,
237 &settings
.low_res_contents_scale_factor
);
240 if (cmd
->HasSwitch(cc::switches::kMaxTilesForInterestArea
)) {
241 int max_tiles_for_interest_area
;
242 if (GetSwitchValueAsInt(*cmd
,
243 cc::switches::kMaxTilesForInterestArea
,
244 1, std::numeric_limits
<int>::max(),
245 &max_tiles_for_interest_area
))
246 settings
.max_tiles_for_interest_area
= max_tiles_for_interest_area
;
249 if (cmd
->HasSwitch(cc::switches::kMaxUnusedResourceMemoryUsagePercentage
)) {
250 int max_unused_resource_memory_percentage
;
251 if (GetSwitchValueAsInt(
253 cc::switches::kMaxUnusedResourceMemoryUsagePercentage
,
255 &max_unused_resource_memory_percentage
)) {
256 settings
.max_unused_resource_memory_percentage
=
257 max_unused_resource_memory_percentage
;
261 settings
.strict_layer_property_change_checking
=
262 cmd
->HasSwitch(cc::switches::kStrictLayerPropertyChangeChecking
);
264 settings
.use_map_image
= cc::switches::IsMapImageEnabled();
266 #if defined(OS_ANDROID)
267 // TODO(danakj): Move these to the android code.
268 settings
.max_partial_texture_updates
= 0;
269 settings
.scrollbar_animator
= cc::LayerTreeSettings::LinearFade
;
270 settings
.solid_color_scrollbars
= true;
271 settings
.solid_color_scrollbar_color
=
272 cmd
->HasSwitch(switches::kHideScrollbars
)
273 ? SK_ColorTRANSPARENT
274 : SkColorSetARGB(128, 128, 128, 128);
275 settings
.solid_color_scrollbar_thickness_dip
= 3;
276 settings
.highp_threshold_min
= 2048;
277 // Android WebView handles root layer flings itself.
278 settings
.ignore_root_layer_flings
=
279 widget
->UsingSynchronousRendererCompositor();
280 #elif !defined(OS_MACOSX)
281 if (cmd
->HasSwitch(switches::kEnableOverlayScrollbars
)) {
282 settings
.scrollbar_animator
= cc::LayerTreeSettings::Thinning
;
283 settings
.solid_color_scrollbars
= true;
285 if (cmd
->HasSwitch(cc::switches::kEnablePinchVirtualViewport
) ||
286 cmd
->HasSwitch(switches::kEnableOverlayScrollbars
)) {
287 settings
.solid_color_scrollbar_color
= SkColorSetARGB(128, 128, 128, 128);
288 settings
.solid_color_scrollbar_thickness_dip
= 7;
292 if (!compositor
->initialize(settings
))
293 return scoped_ptr
<RenderWidgetCompositor
>();
295 return compositor
.Pass();
298 RenderWidgetCompositor::RenderWidgetCompositor(RenderWidget
* widget
,
300 : threaded_(threaded
),
301 suppress_schedule_composite_(false),
305 RenderWidgetCompositor::~RenderWidgetCompositor() {}
307 const base::WeakPtr
<cc::InputHandler
>&
308 RenderWidgetCompositor::GetInputHandler() {
309 return layer_tree_host_
->GetInputHandler();
312 void RenderWidgetCompositor::SetSuppressScheduleComposite(bool suppress
) {
313 if (suppress_schedule_composite_
== suppress
)
317 TRACE_EVENT_ASYNC_BEGIN0("gpu",
318 "RenderWidgetCompositor::SetSuppressScheduleComposite", this);
320 TRACE_EVENT_ASYNC_END0("gpu",
321 "RenderWidgetCompositor::SetSuppressScheduleComposite", this);
322 suppress_schedule_composite_
= suppress
;
325 void RenderWidgetCompositor::Animate(base::TimeTicks time
) {
326 layer_tree_host_
->UpdateClientAnimations(time
);
329 void RenderWidgetCompositor::Composite(base::TimeTicks frame_begin_time
) {
330 layer_tree_host_
->Composite(frame_begin_time
);
333 void RenderWidgetCompositor::SetNeedsDisplayOnAllLayers() {
334 layer_tree_host_
->SetNeedsDisplayOnAllLayers();
337 void RenderWidgetCompositor::SetRasterizeOnlyVisibleContent() {
338 cc::LayerTreeDebugState current
= layer_tree_host_
->debug_state();
339 current
.rasterize_only_visible_content
= true;
340 layer_tree_host_
->SetDebugState(current
);
343 void RenderWidgetCompositor::GetRenderingStats(cc::RenderingStats
* stats
) {
344 layer_tree_host_
->CollectRenderingStats(stats
);
347 void RenderWidgetCompositor::UpdateTopControlsState(
348 cc::TopControlsState constraints
,
349 cc::TopControlsState current
,
351 layer_tree_host_
->UpdateTopControlsState(constraints
,
356 void RenderWidgetCompositor::SetOverdrawBottomHeight(
357 float overdraw_bottom_height
) {
358 layer_tree_host_
->SetOverdrawBottomHeight(overdraw_bottom_height
);
361 void RenderWidgetCompositor::SetNeedsRedrawRect(gfx::Rect damage_rect
) {
362 layer_tree_host_
->SetNeedsRedrawRect(damage_rect
);
365 void RenderWidgetCompositor::SetLatencyInfo(
366 const ui::LatencyInfo
& latency_info
) {
367 layer_tree_host_
->SetLatencyInfo(latency_info
);
370 int RenderWidgetCompositor::GetLayerTreeId() const {
371 return layer_tree_host_
->id();
374 void RenderWidgetCompositor::NotifyInputThrottledUntilCommit() {
375 layer_tree_host_
->NotifyInputThrottledUntilCommit();
378 const cc::Layer
* RenderWidgetCompositor::GetRootLayer() const {
379 return layer_tree_host_
->root_layer();
382 bool RenderWidgetCompositor::initialize(cc::LayerTreeSettings settings
) {
383 scoped_refptr
<base::MessageLoopProxy
> compositor_message_loop_proxy
=
384 RenderThreadImpl::current()->compositor_message_loop_proxy();
385 layer_tree_host_
= cc::LayerTreeHost::Create(this,
387 compositor_message_loop_proxy
);
388 return layer_tree_host_
;
391 void RenderWidgetCompositor::setSurfaceReady() {
392 layer_tree_host_
->SetLayerTreeHostClientReady();
395 void RenderWidgetCompositor::setRootLayer(const WebKit::WebLayer
& layer
) {
396 layer_tree_host_
->SetRootLayer(
397 static_cast<const webkit::WebLayerImpl
*>(&layer
)->layer());
400 void RenderWidgetCompositor::clearRootLayer() {
401 layer_tree_host_
->SetRootLayer(scoped_refptr
<cc::Layer
>());
404 void RenderWidgetCompositor::setViewportSize(
406 const WebSize
& device_viewport_size
) {
407 layer_tree_host_
->SetViewportSize(device_viewport_size
);
410 WebSize
RenderWidgetCompositor::layoutViewportSize() const {
411 return layer_tree_host_
->device_viewport_size();
414 WebSize
RenderWidgetCompositor::deviceViewportSize() const {
415 return layer_tree_host_
->device_viewport_size();
418 WebFloatPoint
RenderWidgetCompositor::adjustEventPointForPinchZoom(
419 const WebFloatPoint
& point
) const {
423 void RenderWidgetCompositor::setDeviceScaleFactor(float device_scale
) {
424 layer_tree_host_
->SetDeviceScaleFactor(device_scale
);
427 float RenderWidgetCompositor::deviceScaleFactor() const {
428 return layer_tree_host_
->device_scale_factor();
431 void RenderWidgetCompositor::setBackgroundColor(WebKit::WebColor color
) {
432 layer_tree_host_
->set_background_color(color
);
435 void RenderWidgetCompositor::setHasTransparentBackground(bool transparent
) {
436 layer_tree_host_
->set_has_transparent_background(transparent
);
439 void RenderWidgetCompositor::setOverhangBitmap(const SkBitmap
& bitmap
) {
440 layer_tree_host_
->SetOverhangBitmap(bitmap
);
443 void RenderWidgetCompositor::setVisible(bool visible
) {
444 layer_tree_host_
->SetVisible(visible
);
447 void RenderWidgetCompositor::setPageScaleFactorAndLimits(
448 float page_scale_factor
, float minimum
, float maximum
) {
449 layer_tree_host_
->SetPageScaleFactorAndLimits(
450 page_scale_factor
, minimum
, maximum
);
453 void RenderWidgetCompositor::startPageScaleAnimation(
454 const WebKit::WebPoint
& destination
,
456 float new_page_scale
,
457 double duration_sec
) {
458 base::TimeDelta duration
= base::TimeDelta::FromMicroseconds(
459 duration_sec
* base::Time::kMicrosecondsPerSecond
);
460 layer_tree_host_
->StartPageScaleAnimation(
461 gfx::Vector2d(destination
.x
, destination
.y
),
467 void RenderWidgetCompositor::setNeedsAnimate() {
468 layer_tree_host_
->SetNeedsAnimate();
471 void RenderWidgetCompositor::setNeedsRedraw() {
473 layer_tree_host_
->SetNeedsAnimate();
475 widget_
->scheduleAnimation();
478 bool RenderWidgetCompositor::commitRequested() const {
479 return layer_tree_host_
->CommitRequested();
482 void RenderWidgetCompositor::didStopFlinging() {
483 layer_tree_host_
->DidStopFlinging();
486 void RenderWidgetCompositor::registerForAnimations(WebKit::WebLayer
* layer
) {
487 cc::Layer
* cc_layer
= static_cast<webkit::WebLayerImpl
*>(layer
)->layer();
488 cc_layer
->layer_animation_controller()->SetAnimationRegistrar(
489 layer_tree_host_
->animation_registrar());
492 bool RenderWidgetCompositor::compositeAndReadback(
493 void *pixels
, const WebRect
& rect_in_device_viewport
) {
494 return layer_tree_host_
->CompositeAndReadback(pixels
,
495 rect_in_device_viewport
);
498 void RenderWidgetCompositor::finishAllRendering() {
499 layer_tree_host_
->FinishAllRendering();
502 void RenderWidgetCompositor::setDeferCommits(bool defer_commits
) {
503 layer_tree_host_
->SetDeferCommits(defer_commits
);
506 void RenderWidgetCompositor::setShowFPSCounter(bool show
) {
507 cc::LayerTreeDebugState debug_state
= layer_tree_host_
->debug_state();
508 debug_state
.show_fps_counter
= show
;
509 layer_tree_host_
->SetDebugState(debug_state
);
512 void RenderWidgetCompositor::setShowPaintRects(bool show
) {
513 cc::LayerTreeDebugState debug_state
= layer_tree_host_
->debug_state();
514 debug_state
.show_paint_rects
= show
;
515 layer_tree_host_
->SetDebugState(debug_state
);
518 void RenderWidgetCompositor::setShowDebugBorders(bool show
) {
519 cc::LayerTreeDebugState debug_state
= layer_tree_host_
->debug_state();
520 debug_state
.show_debug_borders
= show
;
521 layer_tree_host_
->SetDebugState(debug_state
);
524 void RenderWidgetCompositor::setContinuousPaintingEnabled(bool enabled
) {
525 cc::LayerTreeDebugState debug_state
= layer_tree_host_
->debug_state();
526 debug_state
.continuous_painting
= enabled
;
527 layer_tree_host_
->SetDebugState(debug_state
);
530 void RenderWidgetCompositor::setShowScrollBottleneckRects(bool show
) {
531 cc::LayerTreeDebugState debug_state
= layer_tree_host_
->debug_state();
532 debug_state
.show_touch_event_handler_rects
= show
;
533 debug_state
.show_wheel_event_handler_rects
= show
;
534 debug_state
.show_non_fast_scrollable_rects
= show
;
535 layer_tree_host_
->SetDebugState(debug_state
);
538 void RenderWidgetCompositor::WillBeginFrame() {
539 widget_
->InstrumentWillBeginFrame();
540 widget_
->willBeginCompositorFrame();
543 void RenderWidgetCompositor::DidBeginFrame() {
544 widget_
->InstrumentDidBeginFrame();
547 void RenderWidgetCompositor::Animate(double frame_begin_time
) {
548 widget_
->webwidget()->animate(frame_begin_time
);
551 void RenderWidgetCompositor::Layout() {
552 widget_
->webwidget()->layout();
555 void RenderWidgetCompositor::ApplyScrollAndScale(gfx::Vector2d scroll_delta
,
557 widget_
->webwidget()->applyScrollAndScale(scroll_delta
, page_scale
);
560 scoped_ptr
<cc::OutputSurface
> RenderWidgetCompositor::CreateOutputSurface(
562 return widget_
->CreateOutputSurface(fallback
);
565 void RenderWidgetCompositor::DidInitializeOutputSurface(bool success
) {
567 widget_
->webwidget()->didExitCompositingMode();
570 void RenderWidgetCompositor::WillCommit() {
571 widget_
->InstrumentWillComposite();
574 void RenderWidgetCompositor::DidCommit() {
575 widget_
->DidCommitCompositorFrame();
576 widget_
->didBecomeReadyForAdditionalInput();
579 void RenderWidgetCompositor::DidCommitAndDrawFrame() {
580 widget_
->didCommitAndDrawCompositorFrame();
583 void RenderWidgetCompositor::DidCompleteSwapBuffers() {
584 widget_
->didCompleteSwapBuffers();
587 void RenderWidgetCompositor::ScheduleComposite() {
588 if (!suppress_schedule_composite_
)
589 widget_
->scheduleComposite();
592 scoped_refptr
<cc::ContextProvider
>
593 RenderWidgetCompositor::OffscreenContextProviderForMainThread() {
594 return RenderThreadImpl::current()->OffscreenContextProviderForMainThread();
597 scoped_refptr
<cc::ContextProvider
>
598 RenderWidgetCompositor::OffscreenContextProviderForCompositorThread() {
599 return RenderThreadImpl::current()->
600 OffscreenContextProviderForCompositorThread();
603 } // namespace content