Update from https://crrev.com/306655
Includes updates to ui/ and mojo/services for cc and gpu changes and
a minor update to a unit test in sky/ for skia interface changes.
Review URL: https://codereview.chromium.org/761903003
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 6d5fec4..7e66bd9 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -323,10 +323,24 @@
"resources/bitmap_raster_worker_pool.h",
"resources/bitmap_skpicture_content_layer_updater.cc",
"resources/bitmap_skpicture_content_layer_updater.h",
+ "resources/clip_display_item.cc",
+ "resources/clip_display_item.h",
"resources/content_layer_updater.cc",
"resources/content_layer_updater.h",
+ "resources/display_item.cc",
+ "resources/display_item.h",
+ "resources/display_item_list.cc",
+ "resources/display_item_list.h",
+ "resources/display_list_raster_source.cc",
+ "resources/display_list_raster_source.h",
+ "resources/display_list_recording_source.cc",
+ "resources/display_list_recording_source.h",
+ "resources/drawing_display_item.cc",
+ "resources/drawing_display_item.h",
"resources/eviction_tile_priority_queue.cc",
"resources/eviction_tile_priority_queue.h",
+ "resources/filter_display_item.cc",
+ "resources/filter_display_item.h",
"resources/gpu_raster_worker_pool.cc",
"resources/gpu_raster_worker_pool.h",
"resources/image_layer_updater.cc",
@@ -366,6 +380,8 @@
"resources/raster_buffer.cc",
"resources/raster_buffer.h",
"resources/raster_source.h",
+ "resources/raster_source_helper.cc",
+ "resources/raster_source_helper.h",
"resources/raster_tile_priority_queue.cc",
"resources/raster_tile_priority_queue.h",
"resources/raster_worker_pool.cc",
@@ -417,8 +433,14 @@
"resources/tile_manager.h",
"resources/tile_priority.cc",
"resources/tile_priority.h",
+ "resources/tiling_set_eviction_queue.cc",
+ "resources/tiling_set_eviction_queue.h",
"resources/transferable_resource.cc",
"resources/transferable_resource.h",
+ "resources/transform_display_item.cc",
+ "resources/transform_display_item.h",
+ "resources/transparency_display_item.cc",
+ "resources/transparency_display_item.h",
"resources/ui_resource_bitmap.cc",
"resources/ui_resource_bitmap.h",
"resources/ui_resource_client.h",
@@ -482,6 +504,7 @@
deps = [
"//base",
"//base/third_party/dynamic_annotations",
+ "//cc/surfaces:surface_id",
"//gpu",
"//gpu/command_buffer/client:gles2_interface",
"//gpu/command_buffer/client:gpu_memory_buffer_manager",
@@ -635,6 +658,7 @@
]
deps = [
"//base",
+ "//base/test:test_support",
"//base/third_party/dynamic_annotations",
"//gpu/command_buffer/client:gles2_c_lib",
"//gpu/command_buffer/client:gles2_implementation",
@@ -720,6 +744,7 @@
"quads/draw_quad_unittest.cc",
"quads/list_container_unittest.cc",
"quads/render_pass_unittest.cc",
+ "resources/display_item_list_unittest.cc",
"resources/layer_quad_unittest.cc",
"resources/picture_layer_tiling_set_unittest.cc",
"resources/picture_layer_tiling_unittest.cc",
@@ -786,6 +811,7 @@
":test_support",
"//base/test:test_support",
"//cc/surfaces",
+ "//cc/surfaces:surface_id",
"//gpu",
"//gpu:test_support",
"//gpu/command_buffer/client:gles2_interface",
@@ -795,6 +821,8 @@
"//ui/events:events_base",
"//ui/gfx",
"//ui/gfx/geometry",
+ "//ui/gfx:test_support",
+ "//ui/gl",
]
}
@@ -818,6 +846,7 @@
":cc",
":test_support",
"//base",
+ "//base/test:test_support",
"//gpu",
"//gpu:test_support",
"//gpu/command_buffer/common:gles2_utils",
@@ -827,5 +856,6 @@
"//testing/perf",
"//ui/gfx",
"//ui/gfx/geometry",
+ "//ui/gl",
]
}
diff --git a/cc/base/rolling_time_delta_history.cc b/cc/base/rolling_time_delta_history.cc
index 0f95cc5..db04f58 100644
--- a/cc/base/rolling_time_delta_history.cc
+++ b/cc/base/rolling_time_delta_history.cc
@@ -26,10 +26,6 @@
chronological_sample_deque_.push_back(it);
}
-size_t RollingTimeDeltaHistory::SampleCount() {
- return sample_set_.size();
-}
-
void RollingTimeDeltaHistory::Clear() {
chronological_sample_deque_.clear();
sample_set_.clear();
diff --git a/cc/base/rolling_time_delta_history.h b/cc/base/rolling_time_delta_history.h
index 603c813..e51fb86 100644
--- a/cc/base/rolling_time_delta_history.h
+++ b/cc/base/rolling_time_delta_history.h
@@ -23,8 +23,6 @@
void InsertSample(base::TimeDelta time);
- size_t SampleCount();
-
void Clear();
// Returns the smallest sample that is greater than or equal to the specified
diff --git a/cc/blink/BUILD.gn b/cc/blink/BUILD.gn
index fac991b..138be59 100644
--- a/cc/blink/BUILD.gn
+++ b/cc/blink/BUILD.gn
@@ -33,6 +33,8 @@
"web_compositor_support_impl.h",
"web_content_layer_impl.cc",
"web_content_layer_impl.h",
+ "web_display_item_list_impl.cc",
+ "web_display_item_list_impl.h",
"web_external_bitmap_impl.cc",
"web_external_bitmap_impl.h",
"web_external_texture_layer_impl.cc",
diff --git a/cc/blink/cc_blink.gyp b/cc/blink/cc_blink.gyp
index d9f19ea..892082c 100644
--- a/cc/blink/cc_blink.gyp
+++ b/cc/blink/cc_blink.gyp
@@ -36,6 +36,8 @@
'web_compositor_support_impl.h',
'web_content_layer_impl.cc',
'web_content_layer_impl.h',
+ 'web_display_item_list_impl.cc',
+ 'web_display_item_list_impl.h',
'web_external_bitmap_impl.cc',
'web_external_bitmap_impl.h',
'web_external_texture_layer_impl.cc',
diff --git a/cc/blink/web_compositor_support_impl.cc b/cc/blink/web_compositor_support_impl.cc
index ae098fc..042908c 100644
--- a/cc/blink/web_compositor_support_impl.cc
+++ b/cc/blink/web_compositor_support_impl.cc
@@ -9,6 +9,7 @@
#include "cc/animation/transform_operations.h"
#include "cc/blink/web_animation_impl.h"
#include "cc/blink/web_content_layer_impl.h"
+#include "cc/blink/web_display_item_list_impl.h"
#include "cc/blink/web_external_texture_layer_impl.h"
#include "cc/blink/web_filter_animation_curve_impl.h"
#include "cc/blink/web_filter_operations_impl.h"
@@ -27,6 +28,9 @@
using blink::WebCompositorAnimationCurve;
using blink::WebContentLayer;
using blink::WebContentLayerClient;
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+using blink::WebDisplayItemList;
+#endif
using blink::WebExternalTextureLayer;
using blink::WebExternalTextureLayerClient;
using blink::WebFilterAnimationCurve;
@@ -91,6 +95,12 @@
is_left_side_vertical_scrollbar);
}
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+WebDisplayItemList* WebCompositorSupportImpl::createDisplayItemList() {
+ return new WebDisplayItemListImpl();
+}
+#endif
+
WebCompositorAnimation* WebCompositorSupportImpl::createAnimation(
const blink::WebCompositorAnimationCurve& curve,
blink::WebCompositorAnimation::TargetProperty target,
diff --git a/cc/blink/web_compositor_support_impl.h b/cc/blink/web_compositor_support_impl.h
index 0f6371a..1c5198c 100644
--- a/cc/blink/web_compositor_support_impl.h
+++ b/cc/blink/web_compositor_support_impl.h
@@ -10,6 +10,7 @@
#include "cc/blink/cc_blink_export.h"
#include "third_party/WebKit/public/platform/WebCompositorAnimationCurve.h"
#include "third_party/WebKit/public/platform/WebCompositorSupport.h"
+#include "third_party/WebKit/public/platform/WebContentLayerClient.h"
#include "third_party/WebKit/public/platform/WebLayer.h"
#include "third_party/WebKit/public/platform/WebTransformOperations.h"
@@ -41,6 +42,9 @@
int thumb_thickness,
int track_start,
bool is_left_side_vertical_scrollbar);
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+ virtual blink::WebDisplayItemList* createDisplayItemList();
+#endif
virtual blink::WebCompositorAnimation* createAnimation(
const blink::WebCompositorAnimationCurve& curve,
blink::WebCompositorAnimation::TargetProperty target,
diff --git a/cc/blink/web_content_layer_impl.cc b/cc/blink/web_content_layer_impl.cc
index d0a4cca..9757ff3 100644
--- a/cc/blink/web_content_layer_impl.cc
+++ b/cc/blink/web_content_layer_impl.cc
@@ -4,6 +4,7 @@
#include "cc/blink/web_content_layer_impl.h"
+#include "cc/blink/web_display_item_list_impl.h"
#include "cc/layers/content_layer.h"
#include "cc/layers/picture_layer.h"
#include "third_party/WebKit/public/platform/WebContentLayerClient.h"
@@ -63,6 +64,25 @@
: blink::WebContentLayerClient::GraphicsContextDisabled);
}
+scoped_refptr<cc::DisplayItemList>
+WebContentLayerImpl::PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ ContentLayerClient::GraphicsContextStatus graphics_context_status) {
+ if (!client_)
+ return cc::DisplayItemList::Create();
+
+ WebDisplayItemListImpl list;
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+ bool can_use_lcd_text = true;
+ client_->paintContents(
+ &list, clip, can_use_lcd_text,
+ graphics_context_status == ContentLayerClient::GRAPHICS_CONTEXT_ENABLED
+ ? blink::WebContentLayerClient::GraphicsContextEnabled
+ : blink::WebContentLayerClient::GraphicsContextDisabled);
+#endif
+ return list.ToDisplayItemList();
+}
+
bool WebContentLayerImpl::FillsBoundsCompletely() const {
return false;
}
diff --git a/cc/blink/web_content_layer_impl.h b/cc/blink/web_content_layer_impl.h
index 2966bd4..148f4fc 100644
--- a/cc/blink/web_content_layer_impl.h
+++ b/cc/blink/web_content_layer_impl.h
@@ -40,6 +40,9 @@
const gfx::Rect& clip,
ContentLayerClient::GraphicsContextStatus
graphics_context_status) override;
+ scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus graphics_context_status) override;
bool FillsBoundsCompletely() const override;
scoped_ptr<WebLayerImpl> layer_;
@@ -47,9 +50,6 @@
bool draws_content_;
private:
- bool can_use_lcd_text_;
- bool ignore_lcd_text_change_;
-
DISALLOW_COPY_AND_ASSIGN(WebContentLayerImpl);
};
diff --git a/cc/blink/web_display_item_list_impl.cc b/cc/blink/web_display_item_list_impl.cc
new file mode 100644
index 0000000..4ba3431
--- /dev/null
+++ b/cc/blink/web_display_item_list_impl.cc
@@ -0,0 +1,90 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/blink/web_display_item_list_impl.h"
+
+#include <vector>
+
+#include "cc/blink/web_blend_mode.h"
+#include "cc/resources/clip_display_item.h"
+#include "cc/resources/drawing_display_item.h"
+#include "cc/resources/filter_display_item.h"
+#include "cc/resources/transform_display_item.h"
+#include "cc/resources/transparency_display_item.h"
+#include "skia/ext/refptr.h"
+#include "third_party/WebKit/public/platform/WebFloatRect.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/utils/SkMatrix44.h"
+#include "ui/gfx/transform.h"
+
+namespace cc_blink {
+
+WebDisplayItemListImpl::WebDisplayItemListImpl()
+ : display_item_list_(cc::DisplayItemList::Create()) {
+}
+
+scoped_refptr<cc::DisplayItemList> WebDisplayItemListImpl::ToDisplayItemList() {
+ return display_item_list_;
+}
+
+void WebDisplayItemListImpl::appendDrawingItem(
+ SkPicture* picture,
+ const blink::WebFloatPoint& location) {
+ display_item_list_->AppendItem(
+ cc::DrawingDisplayItem::Create(skia::SharePtr(picture), location));
+}
+
+void WebDisplayItemListImpl::appendClipItem(
+ const blink::WebRect& clip_rect,
+ const blink::WebVector<SkRRect>& rounded_clip_rects) {
+ std::vector<SkRRect> rounded_rects;
+ for (size_t i = 0; i < rounded_clip_rects.size(); ++i) {
+ rounded_rects.push_back(rounded_clip_rects[i]);
+ }
+ display_item_list_->AppendItem(
+ cc::ClipDisplayItem::Create(clip_rect, rounded_rects));
+}
+
+void WebDisplayItemListImpl::appendEndClipItem() {
+ display_item_list_->AppendItem(cc::EndClipDisplayItem::Create());
+}
+
+void WebDisplayItemListImpl::appendTransformItem(const SkMatrix44& matrix) {
+ gfx::Transform transform;
+ transform.matrix() = matrix;
+ display_item_list_->AppendItem(cc::TransformDisplayItem::Create(transform));
+}
+
+void WebDisplayItemListImpl::appendTransparencyItem(
+ float opacity,
+ blink::WebBlendMode blend_mode) {
+ display_item_list_->AppendItem(cc::TransparencyDisplayItem::Create(
+ opacity, BlendModeToSkia(blend_mode)));
+}
+
+void WebDisplayItemListImpl::appendEndTransformItem() {
+ display_item_list_->AppendItem(cc::EndTransformDisplayItem::Create());
+}
+
+void WebDisplayItemListImpl::appendEndTransparencyItem() {
+ display_item_list_->AppendItem(cc::EndTransparencyDisplayItem::Create());
+}
+
+void WebDisplayItemListImpl::appendFilterItem(
+ SkImageFilter* filter,
+ const blink::WebFloatRect& bounds) {
+ display_item_list_->AppendItem(
+ cc::FilterDisplayItem::Create(skia::SharePtr(filter), bounds));
+}
+
+void WebDisplayItemListImpl::appendEndFilterItem() {
+ display_item_list_->AppendItem(cc::EndFilterDisplayItem::Create());
+}
+
+WebDisplayItemListImpl::~WebDisplayItemListImpl() {
+}
+
+} // namespace cc_blink
diff --git a/cc/blink/web_display_item_list_impl.h b/cc/blink/web_display_item_list_impl.h
new file mode 100644
index 0000000..4725498
--- /dev/null
+++ b/cc/blink/web_display_item_list_impl.h
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_BLINK_WEB_DISPLAY_ITEM_LIST_IMPL_H_
+#define CC_BLINK_WEB_DISPLAY_ITEM_LIST_IMPL_H_
+
+#include "base/memory/ref_counted.h"
+#include "cc/blink/cc_blink_export.h"
+#include "cc/resources/display_item_list.h"
+#include "third_party/WebKit/public/platform/WebBlendMode.h"
+#include "third_party/WebKit/public/platform/WebContentLayerClient.h"
+#include "third_party/WebKit/public/platform/WebFloatPoint.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+#include "third_party/WebKit/public/platform/WebDisplayItemList.h"
+#endif
+
+class SkImageFilter;
+class SkMatrix44;
+class SkPicture;
+class SkRRect;
+
+namespace cc_blink {
+
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+class WebDisplayItemListImpl : public blink::WebDisplayItemList {
+#else
+class WebDisplayItemListImpl {
+#endif
+
+ public:
+ CC_BLINK_EXPORT WebDisplayItemListImpl();
+ virtual ~WebDisplayItemListImpl();
+
+ scoped_refptr<cc::DisplayItemList> ToDisplayItemList();
+
+ // blink::WebDisplayItemList implementation.
+ virtual void appendDrawingItem(SkPicture* picture,
+ const blink::WebFloatPoint& location);
+ virtual void appendClipItem(
+ const blink::WebRect& clip_rect,
+ const blink::WebVector<SkRRect>& rounded_clip_rects);
+ virtual void appendEndClipItem();
+ virtual void appendTransformItem(const SkMatrix44& matrix);
+ virtual void appendEndTransformItem();
+ virtual void appendTransparencyItem(float opacity,
+ blink::WebBlendMode blend_mode);
+ virtual void appendEndTransparencyItem();
+ virtual void appendFilterItem(SkImageFilter* filter,
+ const blink::WebFloatRect& bounds);
+ virtual void appendEndFilterItem();
+
+ private:
+ scoped_refptr<cc::DisplayItemList> display_item_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebDisplayItemListImpl);
+};
+
+} // namespace cc_blink
+
+#endif // CC_BLINK_WEB_DISPLAY_ITEM_LIST_IMPL_H_
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 046d43c..3374251 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -358,10 +358,24 @@
'resources/bitmap_raster_worker_pool.h',
'resources/bitmap_skpicture_content_layer_updater.cc',
'resources/bitmap_skpicture_content_layer_updater.h',
+ 'resources/clip_display_item.cc',
+ 'resources/clip_display_item.h',
'resources/content_layer_updater.cc',
'resources/content_layer_updater.h',
+ 'resources/display_item.cc',
+ 'resources/display_item.h',
+ 'resources/display_item_list.cc',
+ 'resources/display_item_list.h',
+ 'resources/display_list_raster_source.cc',
+ 'resources/display_list_raster_source.h',
+ 'resources/display_list_recording_source.cc',
+ 'resources/display_list_recording_source.h',
+ 'resources/drawing_display_item.cc',
+ 'resources/drawing_display_item.h',
'resources/eviction_tile_priority_queue.cc',
'resources/eviction_tile_priority_queue.h',
+ 'resources/filter_display_item.cc',
+ 'resources/filter_display_item.h',
'resources/gpu_raster_worker_pool.cc',
'resources/gpu_raster_worker_pool.h',
'resources/image_layer_updater.cc',
@@ -401,6 +415,8 @@
'resources/raster_buffer.cc',
'resources/raster_buffer.h',
'resources/raster_source.h',
+ 'resources/raster_source_helper.cc',
+ 'resources/raster_source_helper.h',
'resources/raster_tile_priority_queue.cc',
'resources/raster_tile_priority_queue.h',
'resources/raster_worker_pool.cc',
@@ -453,8 +469,14 @@
'resources/tile_manager.h',
'resources/tile_priority.cc',
'resources/tile_priority.h',
+ 'resources/tiling_set_eviction_queue.cc',
+ 'resources/tiling_set_eviction_queue.h',
'resources/transferable_resource.cc',
'resources/transferable_resource.h',
+ 'resources/transform_display_item.cc',
+ 'resources/transform_display_item.h',
+ 'resources/transparency_display_item.cc',
+ 'resources/transparency_display_item.h',
'resources/ui_resource_bitmap.cc',
'resources/ui_resource_bitmap.h',
'resources/ui_resource_client.h',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index d4a031f..d0b1000 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -74,6 +74,7 @@
'quads/draw_quad_unittest.cc',
'quads/list_container_unittest.cc',
'quads/render_pass_unittest.cc',
+ 'resources/display_item_list_unittest.cc',
'resources/layer_quad_unittest.cc',
'resources/picture_layer_tiling_set_unittest.cc',
'resources/picture_layer_tiling_unittest.cc',
diff --git a/cc/debug/rasterize_and_record_benchmark.cc b/cc/debug/rasterize_and_record_benchmark.cc
index a2052ab..41d6210 100644
--- a/cc/debug/rasterize_and_record_benchmark.cc
+++ b/cc/debug/rasterize_and_record_benchmark.cc
@@ -18,6 +18,7 @@
#include "cc/resources/picture_pile.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
#include "ui/gfx/geometry/rect.h"
namespace cc {
@@ -64,6 +65,7 @@
DCHECK(!results_.get());
results_ = make_scoped_ptr(new base::DictionaryValue);
results_->SetInteger("pixels_recorded", record_results_.pixels_recorded);
+ results_->SetInteger("picture_memory_usage", record_results_.bytes_used);
for (int i = 0; i < Picture::RECORDING_MODE_COUNT; i++) {
std::string name = base::StringPrintf("record_time%s_ms", kModeSuffixes[i]);
@@ -119,6 +121,7 @@
Picture::RecordingMode mode =
static_cast<Picture::RecordingMode>(mode_index);
base::TimeDelta min_time = base::TimeDelta::Max();
+ size_t memory_used = 0;
// Parameters for LapTimer.
const int kTimeLimitMillis = 1;
@@ -131,18 +134,21 @@
LapTimer timer(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval);
+ scoped_refptr<Picture> picture;
do {
- scoped_refptr<Picture> picture = Picture::Create(
- visible_content_rect, painter, tile_grid_info, false, mode);
+ picture = Picture::Create(visible_content_rect, painter, tile_grid_info,
+ false, mode);
timer.NextLap();
} while (!timer.HasTimeLimitExpired());
base::TimeDelta duration =
base::TimeDelta::FromMillisecondsD(timer.MsPerLap());
if (duration < min_time)
min_time = duration;
+ memory_used = picture->ApproximateMemoryUsage();
}
if (mode == Picture::RECORD_NORMALLY) {
+ record_results_.bytes_used += memory_used;
record_results_.pixels_recorded +=
visible_content_rect.width() * visible_content_rect.height();
}
@@ -151,7 +157,8 @@
}
RasterizeAndRecordBenchmark::RecordResults::RecordResults()
- : pixels_recorded(0) {}
+ : pixels_recorded(0), bytes_used(0) {
+}
RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {}
diff --git a/cc/debug/rasterize_and_record_benchmark.h b/cc/debug/rasterize_and_record_benchmark.h
index 68d5d05..8a23292 100644
--- a/cc/debug/rasterize_and_record_benchmark.h
+++ b/cc/debug/rasterize_and_record_benchmark.h
@@ -46,6 +46,7 @@
~RecordResults();
int pixels_recorded;
+ size_t bytes_used;
base::TimeDelta total_best_time[Picture::RECORDING_MODE_COUNT];
};
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc
index e276a41..c1fc809 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -173,6 +173,8 @@
scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
result->SetDouble("rasterize_time_ms",
rasterize_results_.total_best_time.InMillisecondsF());
+ result->SetDouble("total_pictures_in_pile_size",
+ rasterize_results_.total_memory_usage);
result->SetInteger("pixels_rasterized", rasterize_results_.pixels_rasterized);
result->SetInteger("pixels_rasterized_with_non_solid_color",
rasterize_results_.pixels_rasterized_with_non_solid_color);
@@ -263,16 +265,22 @@
rasterize_results_.pixels_rasterized += tile_size;
rasterize_results_.total_best_time += min_time;
}
+
+ const RasterSource* layer_raster_source = layer->GetRasterSource();
+ rasterize_results_.total_memory_usage +=
+ layer_raster_source->GetPictureMemoryUsage();
}
RasterizeAndRecordBenchmarkImpl::RasterizeResults::RasterizeResults()
: pixels_rasterized(0),
pixels_rasterized_with_non_solid_color(0),
pixels_rasterized_as_opaque(0),
+ total_memory_usage(0),
total_layers(0),
total_picture_layers(0),
total_picture_layers_with_no_content(0),
- total_picture_layers_off_screen(0) {}
+ total_picture_layers_off_screen(0) {
+}
RasterizeAndRecordBenchmarkImpl::RasterizeResults::~RasterizeResults() {}
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.h b/cc/debug/rasterize_and_record_benchmark_impl.h
index c0f26fd..7ca471a 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.h
+++ b/cc/debug/rasterize_and_record_benchmark_impl.h
@@ -41,6 +41,7 @@
int pixels_rasterized_with_non_solid_color;
int pixels_rasterized_as_opaque;
base::TimeDelta total_best_time;
+ int total_memory_usage;
int total_layers;
int total_picture_layers;
int total_picture_layers_with_no_content;
diff --git a/cc/layers/content_layer_client.h b/cc/layers/content_layer_client.h
index ea22e97..c8d3a7e 100644
--- a/cc/layers/content_layer_client.h
+++ b/cc/layers/content_layer_client.h
@@ -6,6 +6,7 @@
#define CC_LAYERS_CONTENT_LAYER_CLIENT_H_
#include "cc/base/cc_export.h"
+#include "cc/resources/display_item_list.h"
class SkCanvas;
@@ -27,6 +28,10 @@
const gfx::Rect& clip,
GraphicsContextStatus gc_status) = 0;
+ virtual scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) = 0;
+
// If true the layer may skip clearing the background before rasterizing,
// because it will cover any uncleared data with content.
virtual bool FillsBoundsCompletely() const = 0;
diff --git a/cc/layers/picture_image_layer.cc b/cc/layers/picture_image_layer.cc
index dba506e..5d76618 100644
--- a/cc/layers/picture_image_layer.cc
+++ b/cc/layers/picture_image_layer.cc
@@ -60,6 +60,13 @@
canvas->drawBitmap(bitmap_, 0, 0);
}
+scoped_refptr<DisplayItemList> PictureImageLayer::PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) {
+ NOTIMPLEMENTED();
+ return DisplayItemList::Create();
+}
+
bool PictureImageLayer::FillsBoundsCompletely() const {
return false;
}
diff --git a/cc/layers/picture_image_layer.h b/cc/layers/picture_image_layer.h
index 3f8d68d..57c7de2 100644
--- a/cc/layers/picture_image_layer.h
+++ b/cc/layers/picture_image_layer.h
@@ -27,6 +27,9 @@
SkCanvas* canvas,
const gfx::Rect& clip,
ContentLayerClient::GraphicsContextStatus gc_status) override;
+ scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) override;
bool FillsBoundsCompletely() const override;
protected:
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index d734538..55241d0 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -7,6 +7,7 @@
#include "base/auto_reset.h"
#include "cc/layers/content_layer_client.h"
#include "cc/layers/picture_layer_impl.h"
+#include "cc/resources/display_list_recording_source.h"
#include "cc/resources/picture_pile.h"
#include "cc/trees/layer_tree_impl.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
@@ -20,7 +21,6 @@
PictureLayer::PictureLayer(ContentLayerClient* client)
: client_(client),
- recording_source_(new PicturePile),
instrumentation_object_tracker_(id()),
update_source_frame_number_(-1),
can_use_lcd_text_for_update_(true),
@@ -79,6 +79,13 @@
void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
Layer::SetLayerTreeHost(host);
if (host) {
+ if (!recording_source_) {
+ if (host->settings().use_display_lists) {
+ recording_source_.reset(new DisplayListRecordingSource);
+ } else {
+ recording_source_.reset(new PicturePile);
+ }
+ }
recording_source_->SetMinContentsScale(
host->settings().minimum_contents_scale);
recording_source_->SetTileGridSize(host->settings().default_tile_grid_size);
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 0eb9621..1827bea 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -98,6 +98,14 @@
layer_tree_impl()->UnregisterPictureLayerImpl(this);
}
+scoped_ptr<TilingSetEvictionQueue> PictureLayerImpl::CreateEvictionQueue(
+ TreePriority tree_priority) {
+ if (!tilings_)
+ return make_scoped_ptr(new TilingSetEvictionQueue());
+ return make_scoped_ptr(
+ new TilingSetEvictionQueue(tilings_.get(), tree_priority));
+}
+
const char* PictureLayerImpl::LayerTypeAsString() const {
return "cc::PictureLayerImpl";
}
@@ -1475,158 +1483,4 @@
}
}
-PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator()
- : layer_(nullptr),
- tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES),
- current_category_(PictureLayerTiling::EVENTUALLY),
- current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
- current_tiling_(0u) {
-}
-
-PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator(
- PictureLayerImpl* layer,
- TreePriority tree_priority)
- : layer_(layer),
- tree_priority_(tree_priority),
- current_category_(PictureLayerTiling::EVENTUALLY),
- current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
- current_tiling_(0u) {
- // Early out if the layer has no tilings.
- if (!layer_->tilings_ || !layer_->tilings_->num_tilings())
- return;
-
- current_tiling_ = CurrentTilingRange().start - 1u;
- do {
- if (!AdvanceToNextTiling())
- break;
-
- current_iterator_ = PictureLayerTiling::TilingEvictionTileIterator(
- layer_->tilings_->tiling_at(CurrentTilingIndex()),
- tree_priority,
- current_category_);
- } while (!current_iterator_);
-}
-
-PictureLayerImpl::LayerEvictionTileIterator::~LayerEvictionTileIterator() {
-}
-
-Tile* PictureLayerImpl::LayerEvictionTileIterator::operator*() {
- DCHECK(*this);
- return *current_iterator_;
-}
-
-const Tile* PictureLayerImpl::LayerEvictionTileIterator::operator*() const {
- DCHECK(*this);
- return *current_iterator_;
-}
-
-PictureLayerImpl::LayerEvictionTileIterator&
-PictureLayerImpl::LayerEvictionTileIterator::
-operator++() {
- DCHECK(*this);
- ++current_iterator_;
- while (!current_iterator_) {
- if (!AdvanceToNextTiling())
- break;
-
- current_iterator_ = PictureLayerTiling::TilingEvictionTileIterator(
- layer_->tilings_->tiling_at(CurrentTilingIndex()),
- tree_priority_,
- current_category_);
- }
- return *this;
-}
-
-PictureLayerImpl::LayerEvictionTileIterator::operator bool() const {
- return !!current_iterator_;
-}
-
-bool PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextCategory() {
- switch (current_category_) {
- case PictureLayerTiling::EVENTUALLY:
- current_category_ =
- PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION;
- return true;
- case PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
- current_category_ = PictureLayerTiling::SOON;
- return true;
- case PictureLayerTiling::SOON:
- current_category_ = PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION;
- return true;
- case PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION:
- current_category_ = PictureLayerTiling::NOW;
- return true;
- case PictureLayerTiling::NOW:
- current_category_ = PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION;
- return true;
- case PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION:
- return false;
- }
- NOTREACHED();
- return false;
-}
-
-bool
-PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextTilingRangeType() {
- switch (current_tiling_range_type_) {
- case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
- current_tiling_range_type_ = PictureLayerTilingSet::LOWER_THAN_LOW_RES;
- return true;
- case PictureLayerTilingSet::LOWER_THAN_LOW_RES:
- current_tiling_range_type_ =
- PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES;
- return true;
- case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
- current_tiling_range_type_ = PictureLayerTilingSet::LOW_RES;
- return true;
- case PictureLayerTilingSet::LOW_RES:
- current_tiling_range_type_ = PictureLayerTilingSet::HIGH_RES;
- return true;
- case PictureLayerTilingSet::HIGH_RES:
- if (!AdvanceToNextCategory())
- return false;
-
- current_tiling_range_type_ = PictureLayerTilingSet::HIGHER_THAN_HIGH_RES;
- return true;
- }
- NOTREACHED();
- return false;
-}
-
-bool PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextTiling() {
- DCHECK_NE(current_tiling_, CurrentTilingRange().end);
- ++current_tiling_;
- while (current_tiling_ == CurrentTilingRange().end) {
- if (!AdvanceToNextTilingRangeType())
- return false;
-
- current_tiling_ = CurrentTilingRange().start;
- }
- return true;
-}
-
-PictureLayerTilingSet::TilingRange
-PictureLayerImpl::LayerEvictionTileIterator::CurrentTilingRange() const {
- return layer_->tilings_->GetTilingRange(current_tiling_range_type_);
-}
-
-size_t PictureLayerImpl::LayerEvictionTileIterator::CurrentTilingIndex() const {
- DCHECK_NE(current_tiling_, CurrentTilingRange().end);
- switch (current_tiling_range_type_) {
- case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
- case PictureLayerTilingSet::LOW_RES:
- case PictureLayerTilingSet::HIGH_RES:
- return current_tiling_;
- // Tilings in the following ranges are accessed in reverse order.
- case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
- case PictureLayerTilingSet::LOWER_THAN_LOW_RES: {
- PictureLayerTilingSet::TilingRange tiling_range = CurrentTilingRange();
- size_t current_tiling_range_offset = current_tiling_ - tiling_range.start;
- return tiling_range.end - 1 - current_tiling_range_offset;
- }
- }
- NOTREACHED();
- return 0;
-}
-
} // namespace cc
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 9a77546..52d8433 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -15,6 +15,7 @@
#include "cc/resources/picture_layer_tiling.h"
#include "cc/resources/picture_layer_tiling_set.h"
#include "cc/resources/picture_pile_impl.h"
+#include "cc/resources/tiling_set_eviction_queue.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkPicture.h"
@@ -67,40 +68,14 @@
PictureLayerTiling::TilingRasterTileIterator iterators_[NUM_ITERATORS];
};
- class CC_EXPORT LayerEvictionTileIterator {
- public:
- LayerEvictionTileIterator();
- LayerEvictionTileIterator(PictureLayerImpl* layer,
- TreePriority tree_priority);
- ~LayerEvictionTileIterator();
-
- Tile* operator*();
- const Tile* operator*() const;
- LayerEvictionTileIterator& operator++();
- operator bool() const;
-
- private:
- bool AdvanceToNextCategory();
- bool AdvanceToNextTilingRangeType();
- bool AdvanceToNextTiling();
-
- PictureLayerTilingSet::TilingRange CurrentTilingRange() const;
- size_t CurrentTilingIndex() const;
-
- PictureLayerImpl* layer_;
- TreePriority tree_priority_;
-
- PictureLayerTiling::EvictionCategory current_category_;
- PictureLayerTilingSet::TilingRangeType current_tiling_range_type_;
- size_t current_tiling_;
- PictureLayerTiling::TilingEvictionTileIterator current_iterator_;
- };
-
static scoped_ptr<PictureLayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
return make_scoped_ptr(new PictureLayerImpl(tree_impl, id));
}
~PictureLayerImpl() override;
+ scoped_ptr<TilingSetEvictionQueue> CreateEvictionQueue(
+ TreePriority tree_priority);
+
// LayerImpl overrides.
const char* LayerTypeAsString() const override;
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
@@ -154,6 +129,9 @@
bool AllTilesRequiredForActivationAreReadyToDraw() const;
bool AllTilesRequiredForDrawAreReadyToDraw() const;
+ // Used for benchmarking
+ const RasterSource* GetRasterSource() const { return raster_source_.get(); }
+
protected:
friend class LayerRasterTileIterator;
using TileRequirementCheck = bool (PictureLayerTiling::*)(const Tile*) const;
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc
index 1f98a68..bfb5703 100644
--- a/cc/layers/picture_layer_impl_perftest.cc
+++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -115,7 +115,7 @@
true);
}
- void RunEvictionIteratorConstructAndIterateTest(
+ void RunEvictionQueueConstructAndIterateTest(
const std::string& test_name,
int num_tiles,
const gfx::Size& viewport_size) {
@@ -129,12 +129,12 @@
timer_.Reset();
do {
int count = num_tiles;
- PictureLayerImpl::LayerEvictionTileIterator it(
- pending_layer_, priorities[priority_count]);
+ scoped_ptr<TilingSetEvictionQueue> queue =
+ pending_layer_->CreateEvictionQueue(priorities[priority_count]);
while (count--) {
- ASSERT_TRUE(it) << "count: " << count;
- ASSERT_TRUE(*it != nullptr) << "count: " << count;
- ++it;
+ ASSERT_TRUE(!queue->IsEmpty()) << "count: " << count;
+ ASSERT_TRUE(queue->Top() != nullptr) << "count: " << count;
+ queue->Pop();
}
priority_count = (priority_count + 1) % arraysize(priorities);
timer_.NextLap();
@@ -148,8 +148,8 @@
true);
}
- void RunEvictionIteratorConstructTest(const std::string& test_name,
- const gfx::Rect& viewport) {
+ void RunEvictionQueueConstructTest(const std::string& test_name,
+ const gfx::Rect& viewport) {
host_impl_.SetViewportSize(viewport.size());
pending_layer_->SetScrollOffset(
gfx::ScrollOffset(viewport.x(), viewport.y()));
@@ -161,8 +161,8 @@
int priority_count = 0;
timer_.Reset();
do {
- PictureLayerImpl::LayerEvictionTileIterator it(
- pending_layer_, priorities[priority_count]);
+ scoped_ptr<TilingSetEvictionQueue> queue =
+ pending_layer_->CreateEvictionQueue(priorities[priority_count]);
priority_count = (priority_count + 1) % arraysize(priorities);
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
@@ -225,6 +225,7 @@
gfx::Rect(9999, 0, 100, 100));
}
+// TODO(e_hakkinen): Rename these tests once the perf numbers are in.
TEST_F(PictureLayerImplPerfTest, LayerEvictionTileIteratorConstructAndIterate) {
SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
@@ -240,16 +241,17 @@
ASSERT_TRUE(host_impl_.tile_manager() != nullptr);
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
- RunEvictionIteratorConstructAndIterateTest(
+ RunEvictionQueueConstructAndIterateTest(
"32_100x100", 32, gfx::Size(100, 100));
- RunEvictionIteratorConstructAndIterateTest(
+ RunEvictionQueueConstructAndIterateTest(
"32_500x500", 32, gfx::Size(500, 500));
- RunEvictionIteratorConstructAndIterateTest(
+ RunEvictionQueueConstructAndIterateTest(
"64_100x100", 64, gfx::Size(100, 100));
- RunEvictionIteratorConstructAndIterateTest(
+ RunEvictionQueueConstructAndIterateTest(
"64_500x500", 64, gfx::Size(500, 500));
}
+// TODO(e_hakkinen): Rename these tests once the perf numbers are in.
TEST_F(PictureLayerImplPerfTest, LayerEvictionTileIteratorConstruct) {
SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
@@ -265,11 +267,9 @@
ASSERT_TRUE(host_impl_.tile_manager() != nullptr);
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
- RunEvictionIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
- RunEvictionIteratorConstructTest("5000_0_100x100",
- gfx::Rect(5000, 0, 100, 100));
- RunEvictionIteratorConstructTest("9999_0_100x100",
- gfx::Rect(9999, 0, 100, 100));
+ RunEvictionQueueConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
+ RunEvictionQueueConstructTest("5000_0_100x100", gfx::Rect(5000, 0, 100, 100));
+ RunEvictionQueueConstructTest("9999_0_100x100", gfx::Rect(9999, 0, 100, 100));
}
} // namespace
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 246e625..ce66675 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -330,7 +330,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -347,7 +347,7 @@
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
// Update tiles with viewport for tile priority as (0, 0, 100, 100) and the
// identify transform for tile priority.
@@ -385,7 +385,7 @@
// should be (200, 200, 100, 100) applied with the said transform.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
viewport_rect_for_tile_priority = gfx::Rect(200, 200, 100, 100);
transform_for_tile_priority.Translate(100, 100);
@@ -426,7 +426,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -468,7 +468,7 @@
// Should update viewport and transform, but not update visible rect.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
resourceless_software_draw = true;
viewport = gfx::ScaleToEnclosingRect(viewport, 2);
transform.Translate(1.f, 1.f);
@@ -492,7 +492,7 @@
// Keep expanded viewport but mark it valid. Should update tile viewport.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
resourceless_software_draw = false;
host_impl_.SetExternalDrawConstraints(transform,
viewport,
@@ -1561,7 +1561,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
EXPECT_EQ(HIGH_RESOLUTION, tiling->resolution());
@@ -1589,7 +1589,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -1625,7 +1625,7 @@
pending_layer_->draw_properties().visible_content_rect = visible_content_rect;
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
// Intersect the two rects. Any tile outside should not be required for
@@ -1678,7 +1678,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
@@ -1714,7 +1714,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
@@ -1745,7 +1745,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
@@ -1779,7 +1779,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
@@ -1822,7 +1822,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
@@ -1890,6 +1890,9 @@
TEST_F(PictureLayerImplTest, HighResRequiredWhenUnsharedActiveAllReady) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
+
+ host_impl_.SetViewportSize(layer_bounds);
+
SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
// No tiles shared.
@@ -1911,6 +1914,9 @@
TEST_F(PictureLayerImplTest, HighResRequiredWhenMissingHighResFlagOn) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
+
+ host_impl_.SetViewportSize(layer_bounds);
+
SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
// All tiles shared (no invalidation).
@@ -1935,6 +1941,9 @@
TEST_F(PictureLayerImplTest, AllHighResRequiredEvenIfShared) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
+
+ host_impl_.SetViewportSize(layer_bounds);
+
SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
CreateHighLowResAndSetAllTilesVisible();
@@ -2009,6 +2018,9 @@
TEST_F(PictureLayerImplTest, HighResRequiredIfActiveCantHaveTiles) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
+
+ host_impl_.SetViewportSize(layer_bounds);
+
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
@@ -2767,7 +2779,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
@@ -2837,7 +2849,7 @@
// No NOW tiles.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
pending_layer_->draw_properties().visible_content_rect =
gfx::Rect(1100, 1100, 500, 500);
@@ -2868,7 +2880,7 @@
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
pending_layer_->draw_properties().visible_content_rect =
gfx::Rect(0, 0, 500, 500);
@@ -2903,7 +2915,7 @@
EXPECT_EQ(0u, high_res_tile_count);
}
-TEST_F(PictureLayerImplTest, LayerEvictionTileIterator) {
+TEST_F(PictureLayerImplTest, TilingSetEvictionQueue) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
@@ -2964,14 +2976,10 @@
EXPECT_GT(number_of_marked_tiles, 1u);
EXPECT_GT(number_of_unmarked_tiles, 1u);
- // Empty iterator.
- PictureLayerImpl::LayerEvictionTileIterator it;
- EXPECT_FALSE(it);
-
// Tiles don't have resources yet.
- it = PictureLayerImpl::LayerEvictionTileIterator(
- pending_layer_, SAME_PRIORITY_FOR_BOTH_TREES);
- EXPECT_FALSE(it);
+ scoped_ptr<TilingSetEvictionQueue> queue =
+ pending_layer_->CreateEvictionQueue(SAME_PRIORITY_FOR_BOTH_TREES);
+ EXPECT_TRUE(queue->IsEmpty());
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
@@ -2980,11 +2988,9 @@
size_t scale_index = 0;
bool reached_visible = false;
Tile* last_tile = nullptr;
- for (it = PictureLayerImpl::LayerEvictionTileIterator(
- pending_layer_, SAME_PRIORITY_FOR_BOTH_TREES);
- it;
- ++it) {
- Tile* tile = *it;
+ queue = pending_layer_->CreateEvictionQueue(SAME_PRIORITY_FOR_BOTH_TREES);
+ while (!queue->IsEmpty()) {
+ Tile* tile = queue->Top();
if (!last_tile)
last_tile = tile;
@@ -3022,6 +3028,7 @@
}
last_tile = tile;
+ queue->Pop();
}
EXPECT_TRUE(reached_visible);
@@ -3029,8 +3036,8 @@
scale_index = 0;
bool reached_required = false;
- for (; it; ++it) {
- Tile* tile = *it;
+ while (!queue->IsEmpty()) {
+ Tile* tile = queue->Top();
EXPECT_TRUE(tile);
TilePriority priority = tile->priority(PENDING_TREE);
@@ -3051,6 +3058,7 @@
EXPECT_FLOAT_EQ(tile->contents_scale(), expected_scales[scale_index]);
unique_tiles.insert(tile);
+ queue->Pop();
}
EXPECT_TRUE(reached_required);
@@ -3155,6 +3163,8 @@
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+
SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
// Make sure some tiles are not shared.
@@ -3182,6 +3192,8 @@
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+
SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
// Make sure some tiles are not shared.
@@ -3205,6 +3217,8 @@
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+
SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
// Make sure some tiles are not shared.
@@ -3229,6 +3243,8 @@
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+
SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
// Make sure some tiles are not shared.
@@ -3316,6 +3332,9 @@
TEST_F(NoLowResPictureLayerImplTest, AllHighResRequiredEvenIfShared) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
+
+ host_impl_.SetViewportSize(layer_bounds);
+
SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
CreateHighLowResAndSetAllTilesVisible();
@@ -3374,7 +3393,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -3416,7 +3435,7 @@
// Should update viewport and transform, but not update visible rect.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
resourceless_software_draw = true;
viewport = gfx::ScaleToEnclosingRect(viewport, 2);
transform.Translate(1.f, 1.f);
@@ -3440,7 +3459,7 @@
// Keep expanded viewport but mark it valid. Should update tile viewport.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
resourceless_software_draw = false;
host_impl_.SetExternalDrawConstraints(transform,
viewport,
@@ -3677,6 +3696,8 @@
gfx::Size tile_size(400, 400);
gfx::Size layer_bounds(1000, 2000);
+ host_impl_.SetViewportSize(layer_bounds);
+
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
@@ -3841,12 +3862,10 @@
size_t occluded_tile_count = 0u;
Tile* last_tile = nullptr;
- for (PictureLayerImpl::LayerEvictionTileIterator it =
- PictureLayerImpl::LayerEvictionTileIterator(layer,
- tree_priority);
- it;
- ++it) {
- Tile* tile = *it;
+ scoped_ptr<TilingSetEvictionQueue> queue =
+ layer->CreateEvictionQueue(tree_priority);
+ while (!queue->IsEmpty()) {
+ Tile* tile = queue->Top();
if (!last_tile)
last_tile = tile;
@@ -3874,6 +3893,7 @@
}
}
last_tile = tile;
+ queue->Pop();
}
EXPECT_EQ(expected_occluded_tile_count[priority_count],
occluded_tile_count);
@@ -3886,7 +3906,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(102, 102);
gfx::Size layer_bounds(1000, 1000);
@@ -3932,7 +3952,7 @@
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
host_impl_.pending_tree()->UpdateDrawProperties();
unoccluded_tile_count = 0;
@@ -3956,7 +3976,7 @@
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
host_impl_.pending_tree()->UpdateDrawProperties();
unoccluded_tile_count = 0;
@@ -3981,7 +4001,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(102, 102);
gfx::Size layer_bounds(1000, 1000);
@@ -4032,7 +4052,7 @@
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
host_impl_.pending_tree()->UpdateDrawProperties();
for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
@@ -4072,7 +4092,7 @@
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
host_impl_.pending_tree()->UpdateDrawProperties();
for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
@@ -4501,7 +4521,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
@@ -4568,7 +4588,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
@@ -4625,7 +4645,7 @@
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 4000);
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
index 3f81ef8..ac20e4c 100644
--- a/cc/layers/picture_layer_unittest.cc
+++ b/cc/layers/picture_layer_unittest.cc
@@ -24,6 +24,12 @@
SkCanvas* canvas,
const gfx::Rect& clip,
ContentLayerClient::GraphicsContextStatus gc_status) override {}
+ scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) override {
+ NOTIMPLEMENTED();
+ return DisplayItemList::Create();
+ }
bool FillsBoundsCompletely() const override { return false; };
};
@@ -73,6 +79,9 @@
TEST(PictureLayerTest, SuitableForGpuRasterization) {
MockContentLayerClient client;
scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
+ FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
+ scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&host_client);
+ host->SetRootLayer(layer);
RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
// Layer is suitable for gpu rasterization by default.
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index 908d428..512fa51 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -261,6 +261,8 @@
};
TEST_F(TiledLayerTest, PushDirtyTiles) {
+ layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
scoped_refptr<FakeTiledLayer> layer =
make_scoped_refptr(new FakeTiledLayer(resource_manager_.get()));
scoped_ptr<FakeTiledLayerImpl> layer_impl =
@@ -290,6 +292,8 @@
}
TEST_F(TiledLayerTest, Scale) {
+ layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
layer_tree_host_->SetDeviceScaleFactor(1.5);
scoped_refptr<FakeTiledLayer> layer =
@@ -352,6 +356,8 @@
}
TEST_F(TiledLayerTest, PushDeletedTiles) {
+ layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
scoped_refptr<FakeTiledLayer> layer =
make_scoped_refptr(new FakeTiledLayer(resource_manager_.get()));
scoped_ptr<FakeTiledLayerImpl> layer_impl =
@@ -1201,6 +1207,8 @@
}
TEST_F(TiledLayerTest, TilesPaintedWithoutOcclusion) {
+ layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
scoped_refptr<FakeTiledLayer> layer =
make_scoped_refptr(new FakeTiledLayer(resource_manager_.get()));
RenderSurfaceLayerList render_surface_layer_list;
diff --git a/cc/output/begin_frame_args.cc b/cc/output/begin_frame_args.cc
index 0be9318..5744d9d 100644
--- a/cc/output/begin_frame_args.cc
+++ b/cc/output/begin_frame_args.cc
@@ -41,12 +41,19 @@
type(type) {
}
-BeginFrameArgs BeginFrameArgs::Create(base::TimeTicks frame_time,
+BeginFrameArgs BeginFrameArgs::Create(BeginFrameArgs::CreationLocation location,
+ base::TimeTicks frame_time,
base::TimeTicks deadline,
base::TimeDelta interval,
BeginFrameArgs::BeginFrameArgsType type) {
DCHECK_NE(type, BeginFrameArgs::INVALID);
+#ifdef NDEBUG
return BeginFrameArgs(frame_time, deadline, interval, type);
+#else
+ BeginFrameArgs args = BeginFrameArgs(frame_time, deadline, interval, type);
+ args.created_from = location;
+ return args;
+#endif
}
scoped_refptr<base::debug::ConvertableToTraceFormat> BeginFrameArgs::AsValue()
@@ -63,6 +70,9 @@
state->SetDouble("frame_time_us", frame_time.ToInternalValue());
state->SetDouble("deadline_us", deadline.ToInternalValue());
state->SetDouble("interval_us", interval.InMicroseconds());
+#ifndef NDEBUG
+ state->SetString("created_from", created_from.ToString());
+#endif
}
// This is a hard-coded deadline adjustment that assumes 60Hz, to be used in
diff --git a/cc/output/begin_frame_args.h b/cc/output/begin_frame_args.h
index 0be5241..ba29523 100644
--- a/cc/output/begin_frame_args.h
+++ b/cc/output/begin_frame_args.h
@@ -5,6 +5,7 @@
#ifndef CC_OUTPUT_BEGIN_FRAME_ARGS_H_
#define CC_OUTPUT_BEGIN_FRAME_ARGS_H_
+#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "base/values.h"
@@ -17,6 +18,22 @@
}
}
+/**
+ * In debug builds we trace the creation origin of BeginFrameArgs objects. We
+ * reuse the tracked_objects::Location system to do that.
+ *
+ * However, in release builds we don't want this as it doubles the size of the
+ * BeginFrameArgs object. As well it adds a number of largish strings to the
+ * binary. Despite the argument being unused, most compilers are unable to
+ * optimise it away even when unused. Instead we use the BEGINFRAME_FROM_HERE
+ * macro to prevent the data even getting referenced.
+ */
+#ifdef NDEBUG
+#define BEGINFRAME_FROM_HERE nullptr
+#else
+#define BEGINFRAME_FROM_HERE FROM_HERE
+#endif
+
namespace cc {
struct CC_EXPORT BeginFrameArgs {
@@ -31,9 +48,18 @@
// Creates an invalid set of values.
BeginFrameArgs();
+#ifdef NDEBUG
+ typedef const void* CreationLocation;
+#else
+ typedef const tracked_objects::Location& CreationLocation;
+ tracked_objects::Location created_from;
+#endif
+
// You should be able to find all instances where a BeginFrame has been
// created by searching for "BeginFrameArgs::Create".
- static BeginFrameArgs Create(base::TimeTicks frame_time,
+ // The location argument should **always** be BEGINFRAME_FROM_HERE macro.
+ static BeginFrameArgs Create(CreationLocation location,
+ base::TimeTicks frame_time,
base::TimeTicks deadline,
base::TimeDelta interval,
BeginFrameArgsType type);
diff --git a/cc/output/begin_frame_args_unittest.cc b/cc/output/begin_frame_args_unittest.cc
index 9d77a45..877a857 100644
--- a/cc/output/begin_frame_args_unittest.cc
+++ b/cc/output/begin_frame_args_unittest.cc
@@ -15,26 +15,29 @@
TEST(BeginFrameArgsTest, Helpers) {
// Quick create methods work
- BeginFrameArgs args0 = CreateBeginFrameArgsForTesting();
+ BeginFrameArgs args0 = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
EXPECT_TRUE(args0.IsValid()) << args0;
- BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(0, 0, -1);
+ BeginFrameArgs args1 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 0, -1);
EXPECT_FALSE(args1.IsValid()) << args1;
- BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(1, 2, 3);
+ BeginFrameArgs args2 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 1, 2, 3);
EXPECT_TRUE(args2.IsValid()) << args2;
EXPECT_EQ(1, args2.frame_time.ToInternalValue());
EXPECT_EQ(2, args2.deadline.ToInternalValue());
EXPECT_EQ(3, args2.interval.ToInternalValue());
EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type);
- BeginFrameArgs args3 = CreateExpiredBeginFrameArgsForTesting();
+ BeginFrameArgs args3 =
+ CreateExpiredBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
EXPECT_TRUE(args3.IsValid()) << args3;
EXPECT_GT(gfx::FrameTime::Now(), args3.deadline);
EXPECT_EQ(BeginFrameArgs::NORMAL, args3.type);
- BeginFrameArgs args4 =
- CreateBeginFrameArgsForTesting(1, 2, 3, BeginFrameArgs::MISSED);
+ BeginFrameArgs args4 = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 1, 2, 3, BeginFrameArgs::MISSED);
EXPECT_TRUE(args4.IsValid()) << args4;
EXPECT_EQ(1, args4.frame_time.ToInternalValue());
EXPECT_EQ(2, args4.deadline.ToInternalValue());
@@ -42,16 +45,19 @@
EXPECT_EQ(BeginFrameArgs::MISSED, args4.type);
// operator==
- EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6),
- CreateBeginFrameArgsForTesting(4, 5, 6));
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6));
EXPECT_NONFATAL_FAILURE(
- EXPECT_EQ(CreateBeginFrameArgsForTesting(7, 8, 9, BeginFrameArgs::MISSED),
- CreateBeginFrameArgsForTesting(7, 8, 9)),
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9,
+ BeginFrameArgs::MISSED),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9)),
"");
- EXPECT_NONFATAL_FAILURE(EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6),
- CreateBeginFrameArgsForTesting(7, 8, 9)),
- "");
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9)),
+ "");
// operator<<
std::stringstream out1;
@@ -74,7 +80,7 @@
EXPECT_FALSE(args1.IsValid()) << args1;
BeginFrameArgs args2 = BeginFrameArgs::Create(
- base::TimeTicks::FromInternalValue(1),
+ BEGINFRAME_FROM_HERE, base::TimeTicks::FromInternalValue(1),
base::TimeTicks::FromInternalValue(2),
base::TimeDelta::FromInternalValue(3), BeginFrameArgs::NORMAL);
EXPECT_TRUE(args2.IsValid()) << args2;
@@ -84,5 +90,14 @@
EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type) << args2;
}
+#ifndef NDEBUG
+TEST(BeginFrameArgsTest, Location) {
+ tracked_objects::Location expected_location = BEGINFRAME_FROM_HERE;
+
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(expected_location);
+ EXPECT_EQ(expected_location.ToString(), args.created_from.ToString());
+}
+#endif
+
} // namespace
} // namespace cc
diff --git a/cc/output/renderer_settings.cc b/cc/output/renderer_settings.cc
index bacde5b..2277af3 100644
--- a/cc/output/renderer_settings.cc
+++ b/cc/output/renderer_settings.cc
@@ -15,6 +15,7 @@
force_antialiasing(false),
force_blending_with_shaders(false),
partial_swap_enabled(false),
+ finish_rendering_on_resize(false),
should_clear_root_render_pass(true),
refresh_rate(60.0),
highp_threshold_min(0),
diff --git a/cc/output/renderer_settings.h b/cc/output/renderer_settings.h
index 748d230..6da0238 100644
--- a/cc/output/renderer_settings.h
+++ b/cc/output/renderer_settings.h
@@ -19,6 +19,7 @@
bool force_antialiasing;
bool force_blending_with_shaders;
bool partial_swap_enabled;
+ bool finish_rendering_on_resize;
bool should_clear_root_render_pass;
double refresh_rate;
int highp_threshold_min;
diff --git a/cc/quads/largest_draw_quad.cc b/cc/quads/largest_draw_quad.cc
index 55fcb22..6445204 100644
--- a/cc/quads/largest_draw_quad.cc
+++ b/cc/quads/largest_draw_quad.cc
@@ -6,15 +6,62 @@
#include <algorithm>
+#include "cc/quads/checkerboard_draw_quad.h"
+#include "cc/quads/debug_border_draw_quad.h"
+#include "cc/quads/io_surface_draw_quad.h"
+#include "cc/quads/picture_draw_quad.h"
#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/stream_video_draw_quad.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "cc/quads/tile_draw_quad.h"
+#include "cc/quads/yuv_video_draw_quad.h"
+
+namespace {
+const size_t kLargestDrawQuadSize =
+ sizeof(cc::RenderPassDrawQuad) > sizeof(cc::StreamVideoDrawQuad)
+ ? sizeof(cc::RenderPassDrawQuad)
+ : sizeof(cc::StreamVideoDrawQuad);
+} // namespace
namespace cc {
size_t LargestDrawQuadSize() {
- // The largest quad is either a RenderPassDrawQuad or a StreamVideoDrawQuad
- // depends on hardware structure.
- return std::max(sizeof(RenderPassDrawQuad), sizeof(StreamVideoDrawQuad));
+ // Currently the largest quad is either a RenderPassDrawQuad or a
+ // StreamVideoDrawQuad depends on hardware structure.
+
+ // Use compile assert to make sure largest is actually larger than all other
+ // type of draw quads.
+ COMPILE_ASSERT(sizeof(CheckerboardDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. CheckerboardDrawQuad is "
+ "currently largest.");
+ COMPILE_ASSERT(sizeof(DebugBorderDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. DebugBorderDrawQuad is "
+ "currently largest.");
+ COMPILE_ASSERT(sizeof(IOSurfaceDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. IOSurfaceDrawQuad is "
+ "currently largest.");
+ COMPILE_ASSERT(sizeof(PictureDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. PictureDrawQuad is "
+ "currently largest.");
+ COMPILE_ASSERT(sizeof(TextureDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. TextureDrawQuad is "
+ "currently largest.");
+ COMPILE_ASSERT(sizeof(SolidColorDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. SolidColorDrawQuad is "
+ "currently largest.");
+ COMPILE_ASSERT(sizeof(SurfaceDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. SurfaceDrawQuad is "
+ "currently largest.");
+ COMPILE_ASSERT(sizeof(TileDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. TileDrawQuad is "
+ "currently largest.");
+ COMPILE_ASSERT(sizeof(YUVVideoDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. YUVVideoDrawQuad is "
+ "currently largest.");
+
+ return kLargestDrawQuadSize;
}
} // namespace cc
diff --git a/cc/resources/clip_display_item.cc b/cc/resources/clip_display_item.cc
new file mode 100644
index 0000000..731c605
--- /dev/null
+++ b/cc/resources/clip_display_item.cc
@@ -0,0 +1,74 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/clip_display_item.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace cc {
+
+ClipDisplayItem::ClipDisplayItem(gfx::Rect clip_rect,
+ const std::vector<SkRRect>& rounded_clip_rects)
+ : clip_rect_(clip_rect), rounded_clip_rects_(rounded_clip_rects) {
+}
+
+ClipDisplayItem::~ClipDisplayItem() {
+}
+
+void ClipDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->save();
+ canvas->clipRect(SkRect::MakeXYWH(clip_rect_.x(), clip_rect_.y(),
+ clip_rect_.width(), clip_rect_.height()));
+ for (size_t i = 0; i < rounded_clip_rects_.size(); ++i) {
+ if (rounded_clip_rects_[i].isRect()) {
+ canvas->clipRect(rounded_clip_rects_[i].rect());
+ } else {
+ bool antialiased = true;
+ canvas->clipRRect(rounded_clip_rects_[i], SkRegion::kIntersect_Op,
+ antialiased);
+ }
+ }
+}
+
+bool ClipDisplayItem::IsSuitableForGpuRasterization() const {
+ return true;
+}
+
+int ClipDisplayItem::ApproximateOpCount() const {
+ return 1;
+}
+
+size_t ClipDisplayItem::PictureMemoryUsage() const {
+ size_t total_size = sizeof(gfx::Rect);
+ for (size_t i = 0; i < rounded_clip_rects_.size(); ++i) {
+ total_size += sizeof(rounded_clip_rects_[i]);
+ }
+ return total_size;
+}
+
+EndClipDisplayItem::EndClipDisplayItem() {
+}
+
+EndClipDisplayItem::~EndClipDisplayItem() {
+}
+
+void EndClipDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->restore();
+}
+
+bool EndClipDisplayItem::IsSuitableForGpuRasterization() const {
+ return true;
+}
+
+int EndClipDisplayItem::ApproximateOpCount() const {
+ return 0;
+}
+
+size_t EndClipDisplayItem::PictureMemoryUsage() const {
+ return 0;
+}
+
+} // namespace cc
diff --git a/cc/resources/clip_display_item.h b/cc/resources/clip_display_item.h
new file mode 100644
index 0000000..55c1ffd
--- /dev/null
+++ b/cc/resources/clip_display_item.h
@@ -0,0 +1,66 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_CLIP_DISPLAY_ITEM_H_
+#define CC_RESOURCES_CLIP_DISPLAY_ITEM_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "third_party/skia/include/core/SkRRect.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT ClipDisplayItem : public DisplayItem {
+ public:
+ virtual ~ClipDisplayItem();
+
+ static scoped_ptr<ClipDisplayItem> Create(
+ gfx::Rect clip_rect,
+ const std::vector<SkRRect>& rounded_clip_rects) {
+ return make_scoped_ptr(new ClipDisplayItem(clip_rect, rounded_clip_rects));
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+ bool IsSuitableForGpuRasterization() const override;
+ int ApproximateOpCount() const override;
+ size_t PictureMemoryUsage() const override;
+
+ protected:
+ ClipDisplayItem(gfx::Rect clip_rect,
+ const std::vector<SkRRect>& rounded_clip_rects);
+
+ private:
+ gfx::Rect clip_rect_;
+ std::vector<SkRRect> rounded_clip_rects_;
+};
+
+class CC_EXPORT EndClipDisplayItem : public DisplayItem {
+ public:
+ virtual ~EndClipDisplayItem();
+
+ static scoped_ptr<EndClipDisplayItem> Create() {
+ return make_scoped_ptr(new EndClipDisplayItem());
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+ bool IsSuitableForGpuRasterization() const override;
+ int ApproximateOpCount() const override;
+ size_t PictureMemoryUsage() const override;
+
+ protected:
+ EndClipDisplayItem();
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_CLIP_DISPLAY_ITEM_H_
diff --git a/cc/resources/display_item.cc b/cc/resources/display_item.cc
new file mode 100644
index 0000000..33069a5
--- /dev/null
+++ b/cc/resources/display_item.cc
@@ -0,0 +1,12 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/display_item.h"
+
+namespace cc {
+
+DisplayItem::DisplayItem() {
+}
+
+} // namespace cc
diff --git a/cc/resources/display_item.h b/cc/resources/display_item.h
new file mode 100644
index 0000000..6f1b5f7
--- /dev/null
+++ b/cc/resources/display_item.h
@@ -0,0 +1,34 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_DISPLAY_ITEM_H_
+#define CC_RESOURCES_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "ui/gfx/rect.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT DisplayItem {
+ public:
+ virtual ~DisplayItem() {}
+
+ virtual void Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const = 0;
+
+ virtual bool IsSuitableForGpuRasterization() const = 0;
+ virtual int ApproximateOpCount() const = 0;
+ virtual size_t PictureMemoryUsage() const = 0;
+
+ protected:
+ DisplayItem();
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_DISPLAY_ITEM_H_
diff --git a/cc/resources/display_item_list.cc b/cc/resources/display_item_list.cc
new file mode 100644
index 0000000..2ead28d
--- /dev/null
+++ b/cc/resources/display_item_list.cc
@@ -0,0 +1,79 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/display_item_list.h"
+
+#include "base/debug/trace_event.h"
+#include "base/debug/trace_event_argument.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace cc {
+
+DisplayItemList::DisplayItemList()
+ : is_suitable_for_gpu_rasterization_(true), approximate_op_count_(0) {
+}
+
+scoped_refptr<DisplayItemList> DisplayItemList::Create() {
+ return make_scoped_refptr(new DisplayItemList());
+}
+
+DisplayItemList::~DisplayItemList() {
+}
+
+void DisplayItemList::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ float contents_scale) const {
+ canvas->save();
+ canvas->scale(contents_scale, contents_scale);
+ for (size_t i = 0; i < items_.size(); ++i) {
+ items_[i]->Raster(canvas, callback);
+ }
+ canvas->restore();
+}
+
+void DisplayItemList::AppendItem(scoped_ptr<DisplayItem> item) {
+ is_suitable_for_gpu_rasterization_ &= item->IsSuitableForGpuRasterization();
+ approximate_op_count_ += item->ApproximateOpCount();
+ items_.push_back(item.Pass());
+}
+
+bool DisplayItemList::IsSuitableForGpuRasterization() const {
+ // This is more permissive than Picture's implementation, since none of the
+ // items might individually trigger a veto even though they collectively have
+ // enough "bad" operations that a corresponding Picture would get vetoed.
+ return is_suitable_for_gpu_rasterization_;
+}
+
+int DisplayItemList::ApproximateOpCount() const {
+ return approximate_op_count_;
+}
+
+size_t DisplayItemList::PictureMemoryUsage() const {
+ size_t total_size = 0;
+
+ for (const auto& item : items_) {
+ total_size += item->PictureMemoryUsage();
+ }
+
+ return total_size;
+}
+
+scoped_refptr<base::debug::ConvertableToTraceFormat> DisplayItemList::AsValue()
+ const {
+ scoped_refptr<base::debug::TracedValue> state =
+ new base::debug::TracedValue();
+
+ // TODO(ajuma): Include the value of each item.
+ state->SetInteger("length", items_.size());
+ return state;
+}
+
+void DisplayItemList::EmitTraceSnapshot() const {
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
+ "devtools.timeline.picture"),
+ "cc::DisplayItemList", this, AsValue());
+}
+
+} // namespace cc
diff --git a/cc/resources/display_item_list.h b/cc/resources/display_item_list.h
new file mode 100644
index 0000000..10d052f
--- /dev/null
+++ b/cc/resources/display_item_list.h
@@ -0,0 +1,53 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_DISPLAY_ITEM_LIST_H_
+#define CC_RESOURCES_DISPLAY_ITEM_LIST_H_
+
+#include "base/debug/trace_event.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/base/scoped_ptr_vector.h"
+#include "cc/resources/display_item.h"
+#include "ui/gfx/rect.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT DisplayItemList
+ : public base::RefCountedThreadSafe<DisplayItemList> {
+ public:
+ static scoped_refptr<DisplayItemList> Create();
+
+ void Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ float contents_scale) const;
+
+ void AppendItem(scoped_ptr<DisplayItem> item);
+
+ bool IsSuitableForGpuRasterization() const;
+ int ApproximateOpCount() const;
+ size_t PictureMemoryUsage() const;
+
+ scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
+
+ void EmitTraceSnapshot() const;
+
+ private:
+ DisplayItemList();
+ ~DisplayItemList();
+ ScopedPtrVector<DisplayItem> items_;
+ bool is_suitable_for_gpu_rasterization_;
+ int approximate_op_count_;
+
+ friend class base::RefCountedThreadSafe<DisplayItemList>;
+ DISALLOW_COPY_AND_ASSIGN(DisplayItemList);
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_DISPLAY_ITEM_LIST_H_
diff --git a/cc/resources/display_item_list_unittest.cc b/cc/resources/display_item_list_unittest.cc
new file mode 100644
index 0000000..d6455a2
--- /dev/null
+++ b/cc/resources/display_item_list_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/display_item_list.h"
+
+#include <vector>
+
+#include "cc/resources/clip_display_item.h"
+#include "cc/resources/drawing_display_item.h"
+#include "cc/resources/transform_display_item.h"
+#include "cc/test/skia_common.h"
+#include "skia/ext/refptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+namespace {
+
+TEST(DisplayItemListTest, SingleDrawingItem) {
+ gfx::Rect layer_rect(100, 100);
+ SkPictureRecorder recorder;
+ skia::RefPtr<SkCanvas> canvas;
+ skia::RefPtr<SkPicture> picture;
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ SkPaint red_paint;
+ red_paint.setColor(SK_ColorRED);
+ unsigned char pixels[4 * 100 * 100] = {0};
+ scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+
+ canvas = skia::SharePtr(
+ recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+ canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
+ canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
+ picture = skia::AdoptRef(recorder.endRecording());
+ gfx::PointF offset(8.f, 9.f);
+ list->AppendItem(DrawingDisplayItem::Create(picture, offset));
+ DrawDisplayList(pixels, layer_rect, list);
+
+ SkBitmap expected_bitmap;
+ unsigned char expected_pixels[4 * 100 * 100] = {0};
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+ expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
+ SkCanvas expected_canvas(expected_bitmap);
+ expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
+ expected_canvas.drawRectCoords(0.f + offset.x(), 0.f + offset.y(),
+ 60.f + offset.x(), 60.f + offset.y(),
+ red_paint);
+ expected_canvas.drawRectCoords(50.f + offset.x(), 50.f + offset.y(),
+ 75.f + offset.x(), 75.f + offset.y(),
+ blue_paint);
+
+ EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+TEST(DisplayItemListTest, ClipItem) {
+ gfx::Rect layer_rect(100, 100);
+ SkPictureRecorder recorder;
+ skia::RefPtr<SkCanvas> canvas;
+ skia::RefPtr<SkPicture> picture;
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ SkPaint red_paint;
+ red_paint.setColor(SK_ColorRED);
+ unsigned char pixels[4 * 100 * 100] = {0};
+ scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+
+ canvas = skia::SharePtr(
+ recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+ canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
+ picture = skia::AdoptRef(recorder.endRecording());
+ gfx::PointF first_offset(8.f, 9.f);
+ list->AppendItem(DrawingDisplayItem::Create(picture, first_offset));
+
+ gfx::Rect clip_rect(60, 60, 10, 10);
+ list->AppendItem(ClipDisplayItem::Create(clip_rect, std::vector<SkRRect>()));
+
+ canvas = skia::SharePtr(
+ recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+ canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
+ picture = skia::AdoptRef(recorder.endRecording());
+ gfx::PointF second_offset(2.f, 3.f);
+ list->AppendItem(DrawingDisplayItem::Create(picture, second_offset));
+
+ list->AppendItem(EndClipDisplayItem::Create());
+
+ DrawDisplayList(pixels, layer_rect, list);
+
+ SkBitmap expected_bitmap;
+ unsigned char expected_pixels[4 * 100 * 100] = {0};
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+ expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
+ SkCanvas expected_canvas(expected_bitmap);
+ expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
+ expected_canvas.drawRectCoords(0.f + first_offset.x(), 0.f + first_offset.y(),
+ 60.f + first_offset.x(),
+ 60.f + first_offset.y(), red_paint);
+ expected_canvas.clipRect(gfx::RectToSkRect(clip_rect));
+ expected_canvas.drawRectCoords(
+ 50.f + second_offset.x(), 50.f + second_offset.y(),
+ 75.f + second_offset.x(), 75.f + second_offset.y(), blue_paint);
+
+ EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+TEST(DisplayItemListTest, TransformItem) {
+ gfx::Rect layer_rect(100, 100);
+ SkPictureRecorder recorder;
+ skia::RefPtr<SkCanvas> canvas;
+ skia::RefPtr<SkPicture> picture;
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ SkPaint red_paint;
+ red_paint.setColor(SK_ColorRED);
+ unsigned char pixels[4 * 100 * 100] = {0};
+ scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+
+ canvas = skia::SharePtr(
+ recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+ canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
+ picture = skia::AdoptRef(recorder.endRecording());
+ gfx::PointF first_offset(8.f, 9.f);
+ list->AppendItem(DrawingDisplayItem::Create(picture, first_offset));
+
+ gfx::Transform transform;
+ transform.Rotate(45.0);
+ list->AppendItem(TransformDisplayItem::Create(transform));
+
+ canvas = skia::SharePtr(
+ recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+ canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
+ picture = skia::AdoptRef(recorder.endRecording());
+ gfx::PointF second_offset(2.f, 3.f);
+ list->AppendItem(DrawingDisplayItem::Create(picture, second_offset));
+
+ list->AppendItem(EndTransformDisplayItem::Create());
+
+ DrawDisplayList(pixels, layer_rect, list);
+
+ SkBitmap expected_bitmap;
+ unsigned char expected_pixels[4 * 100 * 100] = {0};
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+ expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
+ SkCanvas expected_canvas(expected_bitmap);
+ expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
+ expected_canvas.drawRectCoords(0.f + first_offset.x(), 0.f + first_offset.y(),
+ 60.f + first_offset.x(),
+ 60.f + first_offset.y(), red_paint);
+ expected_canvas.setMatrix(transform.matrix());
+ expected_canvas.drawRectCoords(
+ 50.f + second_offset.x(), 50.f + second_offset.y(),
+ 75.f + second_offset.x(), 75.f + second_offset.y(), blue_paint);
+
+ EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+} // namespace
+} // namespace cc
diff --git a/cc/resources/display_list_raster_source.cc b/cc/resources/display_list_raster_source.cc
new file mode 100644
index 0000000..f3ff816
--- /dev/null
+++ b/cc/resources/display_list_raster_source.cc
@@ -0,0 +1,208 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/display_list_raster_source.h"
+
+#include "base/debug/trace_event.h"
+#include "cc/base/region.h"
+#include "cc/debug/debug_colors.h"
+#include "cc/resources/display_item_list.h"
+#include "cc/resources/raster_source_helper.h"
+#include "skia/ext/analysis_canvas.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+
+namespace {
+
+#ifdef NDEBUG
+const bool kDefaultClearCanvasSetting = false;
+#else
+const bool kDefaultClearCanvasSetting = true;
+#endif
+
+} // namespace
+
+namespace cc {
+
+scoped_refptr<DisplayListRasterSource> DisplayListRasterSource::Create() {
+ return make_scoped_refptr(new DisplayListRasterSource);
+}
+
+scoped_refptr<DisplayListRasterSource>
+DisplayListRasterSource::CreateFromDisplayListRecordingSource(
+ const DisplayListRecordingSource* other) {
+ return make_scoped_refptr(new DisplayListRasterSource(other));
+}
+
+DisplayListRasterSource::DisplayListRasterSource()
+ : background_color_(SK_ColorTRANSPARENT),
+ requires_clear_(true),
+ can_use_lcd_text_(true),
+ is_solid_color_(false),
+ solid_color_(SK_ColorTRANSPARENT),
+ clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+ slow_down_raster_scale_factor_for_debug_(0),
+ should_attempt_to_use_distance_field_text_(false) {
+}
+
+DisplayListRasterSource::DisplayListRasterSource(
+ const DisplayListRecordingSource* other)
+ : display_list_(other->display_list_),
+ background_color_(SK_ColorTRANSPARENT),
+ requires_clear_(true),
+ can_use_lcd_text_(other->can_use_lcd_text_),
+ is_solid_color_(other->is_solid_color_),
+ solid_color_(other->solid_color_),
+ recorded_viewport_(other->recorded_viewport_),
+ size_(other->size_),
+ clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+ slow_down_raster_scale_factor_for_debug_(
+ other->slow_down_raster_scale_factor_for_debug_),
+ should_attempt_to_use_distance_field_text_(false) {
+}
+
+DisplayListRasterSource::~DisplayListRasterSource() {
+}
+
+void DisplayListRasterSource::PlaybackToSharedCanvas(
+ SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
+ RasterCommon(canvas, NULL, canvas_rect, contents_scale, false);
+}
+
+void DisplayListRasterSource::RasterForAnalysis(skia::AnalysisCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
+ RasterCommon(canvas, canvas, canvas_rect, contents_scale, true);
+}
+
+void DisplayListRasterSource::PlaybackToCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
+ RasterSourceHelper::PrepareForPlaybackToCanvas(
+ canvas, canvas_rect, gfx::Rect(size_), contents_scale, background_color_,
+ clear_canvas_with_debug_color_, requires_clear_);
+
+ RasterCommon(canvas, NULL, canvas_rect, contents_scale, false);
+}
+
+void DisplayListRasterSource::RasterCommon(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ const gfx::Rect& canvas_rect,
+ float contents_scale,
+ bool is_analysis) const {
+ canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+ gfx::Rect content_rect =
+ gfx::ToEnclosingRect(gfx::ScaleRect(gfx::Rect(size_), contents_scale));
+ content_rect.Intersect(canvas_rect);
+
+ canvas->clipRect(gfx::RectToSkRect(content_rect), SkRegion::kIntersect_Op);
+
+ DCHECK(display_list_.get());
+ display_list_->Raster(canvas, callback, contents_scale);
+}
+
+skia::RefPtr<SkPicture> DisplayListRasterSource::GetFlattenedPicture() {
+ TRACE_EVENT0("cc", "DisplayListRasterSource::GetFlattenedPicture");
+
+ gfx::Rect display_list_rect(size_);
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(display_list_rect.width(),
+ display_list_rect.height());
+ if (!display_list_rect.IsEmpty())
+ PlaybackToCanvas(canvas, display_list_rect, 1.0);
+ skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
+
+ return picture;
+}
+
+size_t DisplayListRasterSource::GetPictureMemoryUsage() const {
+ return display_list_->PictureMemoryUsage();
+}
+
+void DisplayListRasterSource::PerformSolidColorAnalysis(
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ RasterSource::SolidColorAnalysis* analysis) const {
+ DCHECK(analysis);
+ TRACE_EVENT0("cc", "DisplayListRasterSource::PerformSolidColorAnalysis");
+
+ gfx::Rect layer_rect =
+ gfx::ScaleToEnclosingRect(content_rect, 1.0f / contents_scale);
+
+ layer_rect.Intersect(gfx::Rect(size_));
+ skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height());
+ RasterForAnalysis(&canvas, layer_rect, 1.0f);
+ analysis->is_solid_color = canvas.GetColorIfSolid(&analysis->solid_color);
+}
+
+void DisplayListRasterSource::GatherPixelRefs(
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ std::vector<SkPixelRef*>* pixel_refs) const {
+ // TODO(ajuma): Implement this.
+}
+
+bool DisplayListRasterSource::CoversRect(const gfx::Rect& content_rect,
+ float contents_scale) const {
+ if (size_.IsEmpty())
+ return false;
+ gfx::Rect layer_rect =
+ gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale);
+ layer_rect.Intersect(gfx::Rect(size_));
+
+ return recorded_viewport_.Contains(layer_rect);
+}
+
+gfx::Size DisplayListRasterSource::GetSize() const {
+ return size_;
+}
+
+bool DisplayListRasterSource::IsSolidColor() const {
+ return is_solid_color_;
+}
+
+SkColor DisplayListRasterSource::GetSolidColor() const {
+ DCHECK(IsSolidColor());
+ return solid_color_;
+}
+
+bool DisplayListRasterSource::HasRecordings() const {
+ return !!display_list_.get();
+}
+
+void DisplayListRasterSource::SetShouldAttemptToUseDistanceFieldText() {
+ should_attempt_to_use_distance_field_text_ = true;
+}
+
+void DisplayListRasterSource::SetBackgoundColor(SkColor background_color) {
+ background_color_ = background_color;
+}
+
+void DisplayListRasterSource::SetRequiresClear(bool requires_clear) {
+ requires_clear_ = requires_clear;
+}
+
+bool DisplayListRasterSource::ShouldAttemptToUseDistanceFieldText() const {
+ return should_attempt_to_use_distance_field_text_;
+}
+
+void DisplayListRasterSource::AsValueInto(
+ base::debug::TracedValue* array) const {
+ if (display_list_.get())
+ TracedValue::AppendIDRef(display_list_.get(), array);
+}
+
+void DisplayListRasterSource::DidBeginTracing() {
+ if (display_list_.get())
+ display_list_->EmitTraceSnapshot();
+}
+
+bool DisplayListRasterSource::CanUseLCDText() const {
+ return can_use_lcd_text_;
+}
+
+} // namespace cc
diff --git a/cc/resources/display_list_raster_source.h b/cc/resources/display_list_raster_source.h
new file mode 100644
index 0000000..8f1fd12
--- /dev/null
+++ b/cc/resources/display_list_raster_source.h
@@ -0,0 +1,94 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_DISPLAY_LIST_RASTER_SOURCE_H_
+#define CC_RESOURCES_DISPLAY_LIST_RASTER_SOURCE_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/debug/rendering_stats_instrumentation.h"
+#include "cc/resources/display_list_recording_source.h"
+#include "cc/resources/raster_source.h"
+#include "skia/ext/analysis_canvas.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkPicture.h"
+
+namespace cc {
+class DisplayItemList;
+
+class CC_EXPORT DisplayListRasterSource : public RasterSource {
+ public:
+ static scoped_refptr<DisplayListRasterSource> Create();
+ static scoped_refptr<DisplayListRasterSource>
+ CreateFromDisplayListRecordingSource(const DisplayListRecordingSource* other);
+
+ // RasterSource overrides.
+ void PlaybackToCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const override;
+ void PlaybackToSharedCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const override;
+ void PerformSolidColorAnalysis(
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ RasterSource::SolidColorAnalysis* analysis) const override;
+ bool IsSolidColor() const override;
+ SkColor GetSolidColor() const override;
+ gfx::Size GetSize() const override;
+ void GatherPixelRefs(const gfx::Rect& content_rect,
+ float contents_scale,
+ std::vector<SkPixelRef*>* pixel_refs) const override;
+ bool CoversRect(const gfx::Rect& content_rect,
+ float contents_scale) const override;
+ bool HasRecordings() const override;
+ void SetShouldAttemptToUseDistanceFieldText() override;
+ void SetBackgoundColor(SkColor background_color) override;
+ void SetRequiresClear(bool requires_clear) override;
+ bool ShouldAttemptToUseDistanceFieldText() const override;
+ void DidBeginTracing() override;
+ void AsValueInto(base::debug::TracedValue* array) const override;
+ skia::RefPtr<SkPicture> GetFlattenedPicture() override;
+ size_t GetPictureMemoryUsage() const override;
+ bool CanUseLCDText() const override;
+
+ protected:
+ DisplayListRasterSource();
+ explicit DisplayListRasterSource(const DisplayListRecordingSource* other);
+ ~DisplayListRasterSource() override;
+
+ scoped_refptr<DisplayItemList> display_list_;
+ SkColor background_color_;
+ bool requires_clear_;
+ bool can_use_lcd_text_;
+ bool is_solid_color_;
+ SkColor solid_color_;
+ gfx::Rect recorded_viewport_;
+ gfx::Size size_;
+ bool clear_canvas_with_debug_color_;
+ int slow_down_raster_scale_factor_for_debug_;
+
+ private:
+ // Called when analyzing a tile. We can use AnalysisCanvas as
+ // SkDrawPictureCallback, which allows us to early out from analysis.
+ void RasterForAnalysis(skia::AnalysisCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const;
+
+ void RasterCommon(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ const gfx::Rect& canvas_rect,
+ float contents_scale,
+ bool is_analysis) const;
+
+ bool should_attempt_to_use_distance_field_text_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayListRasterSource);
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_DISPLAY_LIST_RASTER_SOURCE_H_
diff --git a/cc/resources/display_list_recording_source.cc b/cc/resources/display_list_recording_source.cc
new file mode 100644
index 0000000..3c0e0e4
--- /dev/null
+++ b/cc/resources/display_list_recording_source.cc
@@ -0,0 +1,158 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/display_list_recording_source.h"
+
+#include <algorithm>
+
+#include "cc/base/region.h"
+#include "cc/layers/content_layer_client.h"
+#include "cc/resources/display_item_list.h"
+#include "cc/resources/display_list_raster_source.h"
+#include "skia/ext/analysis_canvas.h"
+
+namespace {
+
+// Layout pixel buffer around the visible layer rect to record. Any base
+// picture that intersects the visible layer rect expanded by this distance
+// will be recorded.
+const int kPixelDistanceToRecord = 8000;
+// We don't perform solid color analysis on images that have more than 10 skia
+// operations.
+const int kOpCountThatIsOkToAnalyze = 10;
+
+} // namespace
+
+namespace cc {
+
+DisplayListRecordingSource::DisplayListRecordingSource()
+ : slow_down_raster_scale_factor_for_debug_(0),
+ can_use_lcd_text_(true),
+ is_solid_color_(false),
+ solid_color_(SK_ColorTRANSPARENT),
+ pixel_record_distance_(kPixelDistanceToRecord),
+ is_suitable_for_gpu_rasterization_(true) {
+}
+
+DisplayListRecordingSource::~DisplayListRecordingSource() {
+}
+
+bool DisplayListRecordingSource::UpdateAndExpandInvalidation(
+ ContentLayerClient* painter,
+ Region* invalidation,
+ bool can_use_lcd_text,
+ const gfx::Size& layer_size,
+ const gfx::Rect& visible_layer_rect,
+ int frame_number,
+ Picture::RecordingMode recording_mode) {
+ bool updated = false;
+
+ if (size_ != layer_size) {
+ size_ = layer_size;
+ updated = true;
+ }
+
+ if (can_use_lcd_text_ != can_use_lcd_text) {
+ can_use_lcd_text_ = can_use_lcd_text;
+ invalidation->Union(gfx::Rect(GetSize()));
+ updated = true;
+ }
+
+ gfx::Rect old_recorded_viewport = recorded_viewport_;
+ recorded_viewport_ = visible_layer_rect;
+ recorded_viewport_.Inset(-pixel_record_distance_, -pixel_record_distance_);
+ recorded_viewport_.Intersect(gfx::Rect(GetSize()));
+
+ if (recorded_viewport_ != old_recorded_viewport) {
+ // Invalidate newly-exposed and no-longer-exposed areas.
+ Region newly_exposed_region(recorded_viewport_);
+ newly_exposed_region.Subtract(old_recorded_viewport);
+ invalidation->Union(newly_exposed_region);
+
+ Region no_longer_exposed_region(old_recorded_viewport);
+ no_longer_exposed_region.Subtract(recorded_viewport_);
+ invalidation->Union(no_longer_exposed_region);
+
+ updated = true;
+ }
+
+ if (!updated && !invalidation->Intersects(recorded_viewport_))
+ return false;
+
+ // TODO(ajuma): Does repeating this way really makes sense with display lists?
+ // With Blink caching recordings, repeated calls will not cause re-recording.
+ int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
+ for (int i = 0; i < repeat_count; ++i) {
+ display_list_ = painter->PaintContentsToDisplayList(
+ recorded_viewport_, ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
+ }
+ is_suitable_for_gpu_rasterization_ =
+ display_list_->IsSuitableForGpuRasterization();
+
+ DetermineIfSolidColor();
+ display_list_->EmitTraceSnapshot();
+ return true;
+}
+
+gfx::Size DisplayListRecordingSource::GetSize() const {
+ return size_;
+}
+
+void DisplayListRecordingSource::SetEmptyBounds() {
+ size_ = gfx::Size();
+ Clear();
+}
+
+void DisplayListRecordingSource::SetMinContentsScale(float min_contents_scale) {
+}
+
+void DisplayListRecordingSource::SetTileGridSize(
+ const gfx::Size& tile_grid_size) {
+}
+
+void DisplayListRecordingSource::SetSlowdownRasterScaleFactor(int factor) {
+ slow_down_raster_scale_factor_for_debug_ = factor;
+}
+
+void DisplayListRecordingSource::SetUnsuitableForGpuRasterizationForTesting() {
+ is_suitable_for_gpu_rasterization_ = false;
+}
+
+bool DisplayListRecordingSource::IsSuitableForGpuRasterization() const {
+ return is_suitable_for_gpu_rasterization_;
+}
+
+scoped_refptr<RasterSource> DisplayListRecordingSource::CreateRasterSource()
+ const {
+ return scoped_refptr<RasterSource>(
+ DisplayListRasterSource::CreateFromDisplayListRecordingSource(this));
+}
+
+SkTileGridFactory::TileGridInfo
+DisplayListRecordingSource::GetTileGridInfoForTesting() const {
+ return SkTileGridFactory::TileGridInfo();
+}
+
+void DisplayListRecordingSource::DetermineIfSolidColor() {
+ DCHECK(display_list_.get());
+ is_solid_color_ = false;
+ solid_color_ = SK_ColorTRANSPARENT;
+
+ if (display_list_->ApproximateOpCount() > kOpCountThatIsOkToAnalyze)
+ return;
+
+ skia::AnalysisCanvas canvas(recorded_viewport_.width(),
+ recorded_viewport_.height());
+ canvas.translate(-recorded_viewport_.x(), -recorded_viewport_.y());
+ display_list_->Raster(&canvas, nullptr, 1.f);
+ is_solid_color_ = canvas.GetColorIfSolid(&solid_color_);
+}
+
+void DisplayListRecordingSource::Clear() {
+ recorded_viewport_ = gfx::Rect();
+ display_list_ = NULL;
+ is_solid_color_ = false;
+}
+
+} // namespace cc
diff --git a/cc/resources/display_list_recording_source.h b/cc/resources/display_list_recording_source.h
new file mode 100644
index 0000000..6bc8208
--- /dev/null
+++ b/cc/resources/display_list_recording_source.h
@@ -0,0 +1,64 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_DISPLAY_LIST_RECORDING_SOURCE_H_
+#define CC_RESOURCES_DISPLAY_LIST_RECORDING_SOURCE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/resources/recording_source.h"
+
+namespace cc {
+class DisplayItemList;
+class DisplayListRasterSource;
+
+class CC_EXPORT DisplayListRecordingSource : public RecordingSource {
+ public:
+ DisplayListRecordingSource();
+ ~DisplayListRecordingSource() override;
+
+ // RecordingSource overrides.
+ bool UpdateAndExpandInvalidation(
+ ContentLayerClient* painter,
+ Region* invalidation,
+ bool can_use_lcd_text,
+ const gfx::Size& layer_size,
+ const gfx::Rect& visible_layer_rect,
+ int frame_number,
+ Picture::RecordingMode recording_mode) override;
+ scoped_refptr<RasterSource> CreateRasterSource() const override;
+ gfx::Size GetSize() const final;
+ void SetEmptyBounds() override;
+ void SetMinContentsScale(float min_contents_scale) override;
+ void SetSlowdownRasterScaleFactor(int factor) override;
+ bool IsSuitableForGpuRasterization() const override;
+ void SetTileGridSize(const gfx::Size& tile_grid_size) override;
+ void SetUnsuitableForGpuRasterizationForTesting() override;
+ SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const override;
+
+ protected:
+ void Clear();
+
+ gfx::Rect recorded_viewport_;
+ gfx::Size size_;
+ int slow_down_raster_scale_factor_for_debug_;
+ bool can_use_lcd_text_;
+ bool is_solid_color_;
+ SkColor solid_color_;
+ int pixel_record_distance_;
+
+ scoped_refptr<DisplayItemList> display_list_;
+
+ private:
+ friend class DisplayListRasterSource;
+
+ void DetermineIfSolidColor();
+
+ bool is_suitable_for_gpu_rasterization_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayListRecordingSource);
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_DISPLAY_LIST_RECORDING_SOURCE_H_
diff --git a/cc/resources/drawing_display_item.cc b/cc/resources/drawing_display_item.cc
new file mode 100644
index 0000000..9466d5c
--- /dev/null
+++ b/cc/resources/drawing_display_item.cc
@@ -0,0 +1,47 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/drawing_display_item.h"
+
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
+
+namespace cc {
+
+DrawingDisplayItem::DrawingDisplayItem(skia::RefPtr<SkPicture> picture,
+ gfx::PointF location)
+ : picture_(picture), location_(location) {
+}
+
+DrawingDisplayItem::~DrawingDisplayItem() {
+}
+
+void DrawingDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->save();
+ canvas->translate(location_.x(), location_.y());
+ if (callback)
+ picture_->draw(canvas, callback);
+ else
+ canvas->drawPicture(picture_.get());
+ canvas->restore();
+}
+
+bool DrawingDisplayItem::IsSuitableForGpuRasterization() const {
+ return picture_->suitableForGpuRasterization(NULL);
+}
+
+int DrawingDisplayItem::ApproximateOpCount() const {
+ return picture_->approximateOpCount() + sizeof(gfx::PointF);
+}
+
+size_t DrawingDisplayItem::PictureMemoryUsage() const {
+ DCHECK(picture_);
+ return SkPictureUtils::ApproximateBytesUsed(picture_.get());
+}
+
+} // namespace cc
diff --git a/cc/resources/drawing_display_item.h b/cc/resources/drawing_display_item.h
new file mode 100644
index 0000000..544e4eb
--- /dev/null
+++ b/cc/resources/drawing_display_item.h
@@ -0,0 +1,45 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_DRAWING_DISPLAY_ITEM_H_
+#define CC_RESOURCES_DRAWING_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "skia/ext/refptr.h"
+#include "ui/gfx/geometry/point_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+class SkPicture;
+
+namespace cc {
+
+class CC_EXPORT DrawingDisplayItem : public DisplayItem {
+ public:
+ virtual ~DrawingDisplayItem();
+
+ static scoped_ptr<DrawingDisplayItem> Create(skia::RefPtr<SkPicture> picture,
+ gfx::PointF location) {
+ return make_scoped_ptr(new DrawingDisplayItem(picture, location));
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+ bool IsSuitableForGpuRasterization() const override;
+ int ApproximateOpCount() const override;
+ size_t PictureMemoryUsage() const override;
+
+ protected:
+ DrawingDisplayItem(skia::RefPtr<SkPicture> picture, gfx::PointF location);
+
+ private:
+ skia::RefPtr<SkPicture> picture_;
+ gfx::PointF location_;
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_DRAWING_DISPLAY_ITEM_H_
diff --git a/cc/resources/eviction_tile_priority_queue.cc b/cc/resources/eviction_tile_priority_queue.cc
index 9f05e81..4d66987 100644
--- a/cc/resources/eviction_tile_priority_queue.cc
+++ b/cc/resources/eviction_tile_priority_queue.cc
@@ -14,8 +14,8 @@
: tree_priority_(tree_priority) {}
bool operator()(
- const EvictionTilePriorityQueue::PairedPictureLayerQueue* a,
- const EvictionTilePriorityQueue::PairedPictureLayerQueue* b) const {
+ const EvictionTilePriorityQueue::PairedTilingSetQueue* a,
+ const EvictionTilePriorityQueue::PairedTilingSetQueue* b) const {
// Note that in this function, we have to return true if and only if
// b is strictly lower priority than a. Note that for the sake of
// completeness, empty queue is considered to have lowest priority.
@@ -23,15 +23,15 @@
return b->IsEmpty() < a->IsEmpty();
WhichTree a_tree = a->NextTileIteratorTree(tree_priority_);
- const PictureLayerImpl::LayerEvictionTileIterator* a_iterator =
- a_tree == ACTIVE_TREE ? &a->active_iterator : &a->pending_iterator;
+ const TilingSetEvictionQueue* a_queue =
+ a_tree == ACTIVE_TREE ? a->active_queue.get() : a->pending_queue.get();
WhichTree b_tree = b->NextTileIteratorTree(tree_priority_);
- const PictureLayerImpl::LayerEvictionTileIterator* b_iterator =
- b_tree == ACTIVE_TREE ? &b->active_iterator : &b->pending_iterator;
+ const TilingSetEvictionQueue* b_queue =
+ b_tree == ACTIVE_TREE ? b->active_queue.get() : b->pending_queue.get();
- const Tile* a_tile = **a_iterator;
- const Tile* b_tile = **b_iterator;
+ const Tile* a_tile = a_queue->Top();
+ const Tile* b_tile = b_queue->Top();
const TilePriority& a_priority =
a_tile->priority_for_tree_priority(tree_priority_);
@@ -94,7 +94,7 @@
it != paired_layers.end();
++it) {
paired_queues_.push_back(
- make_scoped_ptr(new PairedPictureLayerQueue(*it, tree_priority_)));
+ make_scoped_ptr(new PairedTilingSetQueue(*it, tree_priority_)));
}
paired_queues_.make_heap(EvictionOrderComparator(tree_priority_));
@@ -117,94 +117,89 @@
DCHECK(!IsEmpty());
paired_queues_.pop_heap(EvictionOrderComparator(tree_priority_));
- PairedPictureLayerQueue* paired_queue = paired_queues_.back();
+ PairedTilingSetQueue* paired_queue = paired_queues_.back();
paired_queue->Pop(tree_priority_);
paired_queues_.push_heap(EvictionOrderComparator(tree_priority_));
}
-EvictionTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue() {
+EvictionTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue() {
}
-EvictionTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue(
+EvictionTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue(
const PictureLayerImpl::Pair& layer_pair,
- TreePriority tree_priority)
- : active_iterator(
- layer_pair.active
- ? PictureLayerImpl::LayerEvictionTileIterator(layer_pair.active,
- tree_priority)
- : PictureLayerImpl::LayerEvictionTileIterator()),
- pending_iterator(
- layer_pair.pending
- ? PictureLayerImpl::LayerEvictionTileIterator(layer_pair.pending,
- tree_priority)
- : PictureLayerImpl::LayerEvictionTileIterator()) {
+ TreePriority tree_priority) {
+ if (layer_pair.active)
+ active_queue = layer_pair.active->CreateEvictionQueue(tree_priority);
+ if (layer_pair.pending)
+ pending_queue = layer_pair.pending->CreateEvictionQueue(tree_priority);
}
-EvictionTilePriorityQueue::PairedPictureLayerQueue::~PairedPictureLayerQueue() {
+EvictionTilePriorityQueue::PairedTilingSetQueue::~PairedTilingSetQueue() {
}
-bool EvictionTilePriorityQueue::PairedPictureLayerQueue::IsEmpty() const {
- return !active_iterator && !pending_iterator;
+bool EvictionTilePriorityQueue::PairedTilingSetQueue::IsEmpty() const {
+ return (!active_queue || active_queue->IsEmpty()) &&
+ (!pending_queue || pending_queue->IsEmpty());
}
-Tile* EvictionTilePriorityQueue::PairedPictureLayerQueue::Top(
+Tile* EvictionTilePriorityQueue::PairedTilingSetQueue::Top(
TreePriority tree_priority) {
DCHECK(!IsEmpty());
WhichTree next_tree = NextTileIteratorTree(tree_priority);
- PictureLayerImpl::LayerEvictionTileIterator* next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
- DCHECK(*next_iterator);
+ TilingSetEvictionQueue* next_queue =
+ next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
+ DCHECK(next_queue && !next_queue->IsEmpty());
- Tile* tile = **next_iterator;
+ Tile* tile = next_queue->Top();
DCHECK(std::find(returned_shared_tiles.begin(),
returned_shared_tiles.end(),
tile) == returned_shared_tiles.end());
return tile;
}
-void EvictionTilePriorityQueue::PairedPictureLayerQueue::Pop(
+void EvictionTilePriorityQueue::PairedTilingSetQueue::Pop(
TreePriority tree_priority) {
DCHECK(!IsEmpty());
WhichTree next_tree = NextTileIteratorTree(tree_priority);
- PictureLayerImpl::LayerEvictionTileIterator* next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
- DCHECK(*next_iterator);
- returned_shared_tiles.push_back(**next_iterator);
- ++(*next_iterator);
+ TilingSetEvictionQueue* next_queue =
+ next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
+ DCHECK(next_queue && !next_queue->IsEmpty());
+ returned_shared_tiles.push_back(next_queue->Top());
+ next_queue->Pop();
if (IsEmpty())
return;
next_tree = NextTileIteratorTree(tree_priority);
- next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
+ next_queue =
+ next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
while (std::find(returned_shared_tiles.begin(),
returned_shared_tiles.end(),
- **next_iterator) != returned_shared_tiles.end()) {
- ++(*next_iterator);
+ next_queue->Top()) != returned_shared_tiles.end()) {
+ next_queue->Pop();
if (IsEmpty())
break;
next_tree = NextTileIteratorTree(tree_priority);
- next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
+ next_queue =
+ next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
}
}
WhichTree
-EvictionTilePriorityQueue::PairedPictureLayerQueue::NextTileIteratorTree(
+EvictionTilePriorityQueue::PairedTilingSetQueue::NextTileIteratorTree(
TreePriority tree_priority) const {
DCHECK(!IsEmpty());
// If we only have one iterator with tiles, return it.
- if (!active_iterator)
+ if (!active_queue || active_queue->IsEmpty())
return PENDING_TREE;
- if (!pending_iterator)
+ if (!pending_queue || pending_queue->IsEmpty())
return ACTIVE_TREE;
- const Tile* active_tile = *active_iterator;
- const Tile* pending_tile = *pending_iterator;
+ const Tile* active_tile = active_queue->Top();
+ const Tile* pending_tile = pending_queue->Top();
if (active_tile == pending_tile)
return ACTIVE_TREE;
diff --git a/cc/resources/eviction_tile_priority_queue.h b/cc/resources/eviction_tile_priority_queue.h
index e91f0d2..6f5d964 100644
--- a/cc/resources/eviction_tile_priority_queue.h
+++ b/cc/resources/eviction_tile_priority_queue.h
@@ -11,16 +11,17 @@
#include "cc/base/cc_export.h"
#include "cc/layers/picture_layer_impl.h"
#include "cc/resources/tile_priority.h"
+#include "cc/resources/tiling_set_eviction_queue.h"
namespace cc {
class CC_EXPORT EvictionTilePriorityQueue {
public:
- struct PairedPictureLayerQueue {
- PairedPictureLayerQueue();
- PairedPictureLayerQueue(const PictureLayerImpl::Pair& layer_pair,
- TreePriority tree_priority);
- ~PairedPictureLayerQueue();
+ struct PairedTilingSetQueue {
+ PairedTilingSetQueue();
+ PairedTilingSetQueue(const PictureLayerImpl::Pair& layer_pair,
+ TreePriority tree_priority);
+ ~PairedTilingSetQueue();
bool IsEmpty() const;
Tile* Top(TreePriority tree_priority);
@@ -28,8 +29,8 @@
WhichTree NextTileIteratorTree(TreePriority tree_priority) const;
- PictureLayerImpl::LayerEvictionTileIterator active_iterator;
- PictureLayerImpl::LayerEvictionTileIterator pending_iterator;
+ scoped_ptr<TilingSetEvictionQueue> active_queue;
+ scoped_ptr<TilingSetEvictionQueue> pending_queue;
// TODO(vmpstr): Investigate removing this.
std::vector<Tile*> returned_shared_tiles;
@@ -48,9 +49,9 @@
private:
// TODO(vmpstr): This is potentially unnecessary if it becomes the case that
- // PairedPictureLayerQueue is fast enough to copy. In that case, we can use
- // objects directly (ie std::vector<PairedPictureLayerQueue>).
- ScopedPtrVector<PairedPictureLayerQueue> paired_queues_;
+ // PairedTilingSetQueue is fast enough to copy. In that case, we can use
+ // objects directly (ie std::vector<PairedTilingSetQueue>).
+ ScopedPtrVector<PairedTilingSetQueue> paired_queues_;
TreePriority tree_priority_;
DISALLOW_COPY_AND_ASSIGN(EvictionTilePriorityQueue);
diff --git a/cc/resources/filter_display_item.cc b/cc/resources/filter_display_item.cc
new file mode 100644
index 0000000..63bfeee
--- /dev/null
+++ b/cc/resources/filter_display_item.cc
@@ -0,0 +1,75 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/filter_display_item.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+FilterDisplayItem::FilterDisplayItem(skia::RefPtr<SkImageFilter> filter,
+ gfx::RectF bounds)
+ : filter_(filter), bounds_(bounds) {
+}
+
+FilterDisplayItem::~FilterDisplayItem() {
+}
+
+void FilterDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->save();
+ SkRect boundaries;
+ filter_->computeFastBounds(gfx::RectFToSkRect(bounds_), &boundaries);
+ canvas->translate(bounds_.x(), bounds_.y());
+ boundaries.offset(-bounds_.x(), -bounds_.y());
+
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+ paint.setImageFilter(filter_.get());
+ canvas->saveLayer(&boundaries, &paint);
+
+ canvas->translate(-bounds_.x(), -bounds_.y());
+}
+
+bool FilterDisplayItem::IsSuitableForGpuRasterization() const {
+ return true;
+}
+
+int FilterDisplayItem::ApproximateOpCount() const {
+ return 1;
+}
+
+size_t FilterDisplayItem::PictureMemoryUsage() const {
+ return sizeof(skia::RefPtr<SkImageFilter>) + sizeof(gfx::RectF);
+}
+
+EndFilterDisplayItem::EndFilterDisplayItem() {
+}
+
+EndFilterDisplayItem::~EndFilterDisplayItem() {
+}
+
+void EndFilterDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->restore();
+ canvas->restore();
+}
+
+bool EndFilterDisplayItem::IsSuitableForGpuRasterization() const {
+ return true;
+}
+
+int EndFilterDisplayItem::ApproximateOpCount() const {
+ return 0;
+}
+
+size_t EndFilterDisplayItem::PictureMemoryUsage() const {
+ return 0;
+}
+
+} // namespace cc
diff --git a/cc/resources/filter_display_item.h b/cc/resources/filter_display_item.h
new file mode 100644
index 0000000..4c1b265
--- /dev/null
+++ b/cc/resources/filter_display_item.h
@@ -0,0 +1,64 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_FILTER_DISPLAY_ITEM_H_
+#define CC_RESOURCES_FILTER_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "skia/ext/refptr.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+class SkImageFilter;
+
+namespace cc {
+
+class CC_EXPORT FilterDisplayItem : public DisplayItem {
+ public:
+ virtual ~FilterDisplayItem();
+
+ static scoped_ptr<FilterDisplayItem> Create(
+ skia::RefPtr<SkImageFilter> filter,
+ gfx::RectF bounds) {
+ return make_scoped_ptr(new FilterDisplayItem(filter, bounds));
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+ bool IsSuitableForGpuRasterization() const override;
+ int ApproximateOpCount() const override;
+ size_t PictureMemoryUsage() const override;
+
+ protected:
+ FilterDisplayItem(skia::RefPtr<SkImageFilter> filter, gfx::RectF bounds);
+
+ private:
+ skia::RefPtr<SkImageFilter> filter_;
+ gfx::RectF bounds_;
+};
+
+class CC_EXPORT EndFilterDisplayItem : public DisplayItem {
+ public:
+ virtual ~EndFilterDisplayItem();
+
+ static scoped_ptr<EndFilterDisplayItem> Create() {
+ return make_scoped_ptr(new EndFilterDisplayItem());
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+ bool IsSuitableForGpuRasterization() const override;
+ int ApproximateOpCount() const override;
+ size_t PictureMemoryUsage() const override;
+
+ protected:
+ EndFilterDisplayItem();
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_FILTER_DISPLAY_ITEM_H_
diff --git a/cc/resources/managed_tile_state.cc b/cc/resources/managed_tile_state.cc
index 2841711..a60c28af 100644
--- a/cc/resources/managed_tile_state.cc
+++ b/cc/resources/managed_tile_state.cc
@@ -12,38 +12,9 @@
namespace cc {
-std::string ManagedTileBinToString(ManagedTileBin bin) {
- switch (bin) {
- case NOW_AND_READY_TO_DRAW_BIN:
- return "NOW_AND_READY_TO_DRAW_BIN";
- case NOW_BIN:
- return "NOW_BIN";
- case SOON_BIN:
- return "SOON_BIN";
- case EVENTUALLY_AND_ACTIVE_BIN:
- return "EVENTUALLY_AND_ACTIVE_BIN";
- case EVENTUALLY_BIN:
- return "EVENTUALLY_BIN";
- case AT_LAST_AND_ACTIVE_BIN:
- return "AT_LAST_AND_ACTIVE_BIN";
- case AT_LAST_BIN:
- return "AT_LAST_BIN";
- case NEVER_BIN:
- return "NEVER_BIN";
- case NUM_BINS:
- NOTREACHED();
- return "Invalid Bin (NUM_BINS)";
- }
- return "Invalid Bin (UNKNOWN)";
-}
-
ManagedTileState::ManagedTileState()
- : bin(NEVER_BIN),
- resolution(NON_IDEAL_RESOLUTION),
- required_for_activation(false),
+ : resolution(NON_IDEAL_RESOLUTION),
priority_bin(TilePriority::EVENTUALLY),
- distance_to_visible(std::numeric_limits<float>::infinity()),
- visible_and_ready_to_draw(false),
scheduled_priority(0) {
}
@@ -77,12 +48,8 @@
state->SetBoolean("has_resource", has_resource);
state->SetBoolean("is_using_gpu_memory", is_using_gpu_memory);
- state->SetString("bin", ManagedTileBinToString(bin));
state->SetString("resolution", TileResolutionToString(resolution));
state->SetString("priority_bin", TilePriorityBinToString(priority_bin));
- state->SetDouble("distance_to_visible",
- MathUtil::AsFloatSafely(distance_to_visible));
- state->SetBoolean("required_for_activation", required_for_activation);
state->SetBoolean("is_solid_color",
draw_info.mode_ == DrawInfo::SOLID_COLOR_MODE);
state->SetBoolean("is_transparent",
diff --git a/cc/resources/managed_tile_state.h b/cc/resources/managed_tile_state.h
index 58b77c6..a0905c7 100644
--- a/cc/resources/managed_tile_state.h
+++ b/cc/resources/managed_tile_state.h
@@ -15,24 +15,6 @@
namespace cc {
-class TileManager;
-
-// Tile manager classifying tiles into a few basic bins:
-enum ManagedTileBin {
- NOW_AND_READY_TO_DRAW_BIN = 0, // Ready to draw and within viewport.
- NOW_BIN = 1, // Needed ASAP.
- SOON_BIN = 2, // Impl-side version of prepainting.
- EVENTUALLY_AND_ACTIVE_BIN = 3, // Nice to have, and has a task or resource.
- EVENTUALLY_BIN = 4, // Nice to have, if we've got memory and time.
- AT_LAST_AND_ACTIVE_BIN = 5, // Only do this after all other bins.
- AT_LAST_BIN = 6, // Only do this after all other bins.
- NEVER_BIN = 7, // Dont bother.
- NUM_BINS = 8
- // NOTE: Be sure to update ManagedTileBinAsValue and kBinPolicyMap when adding
- // or reordering fields.
-};
-scoped_ptr<base::Value> ManagedTileBinAsValue(ManagedTileBin bin);
-
// This is state that is specific to a tile that is
// managed by the TileManager.
class CC_EXPORT ManagedTileState {
@@ -107,13 +89,8 @@
DrawInfo draw_info;
scoped_refptr<RasterTask> raster_task;
- ManagedTileBin bin;
-
TileResolution resolution;
- bool required_for_activation;
TilePriority::PriorityBin priority_bin;
- float distance_to_visible;
- bool visible_and_ready_to_draw;
// Priority for this state from the last time we assigned memory.
unsigned scheduled_priority;
diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc
index 9a45ad1..5b90571 100644
--- a/cc/resources/picture.cc
+++ b/cc/resources/picture.cc
@@ -25,6 +25,7 @@
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/utils/SkNullCanvas.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -192,6 +193,11 @@
return picture_->approximateOpCount();
}
+size_t Picture::ApproximateMemoryUsage() const {
+ DCHECK(picture_);
+ return SkPictureUtils::ApproximateBytesUsed(picture_.get());
+}
+
bool Picture::HasText() const {
DCHECK(picture_);
return picture_->hasText();
diff --git a/cc/resources/picture.h b/cc/resources/picture.h
index 1677309..771d715 100644
--- a/cc/resources/picture.h
+++ b/cc/resources/picture.h
@@ -67,6 +67,7 @@
bool IsSuitableForGpuRasterization() const;
int ApproximateOpCount() const;
+ size_t ApproximateMemoryUsage() const;
bool HasText() const;
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index 9d8ea84..e9e3b86 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -1216,50 +1216,4 @@
return *this;
}
-PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator()
- : eviction_tiles_(NULL), current_eviction_tiles_index_(0u) {
-}
-
-PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator(
- PictureLayerTiling* tiling,
- TreePriority tree_priority,
- EvictionCategory category)
- : eviction_tiles_(tiling->GetEvictionTiles(tree_priority, category)),
- // Note: initializing to "0 - 1" works as overflow is well defined for
- // unsigned integers.
- current_eviction_tiles_index_(static_cast<size_t>(0) - 1) {
- DCHECK(eviction_tiles_);
- ++(*this);
-}
-
-PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {
-}
-
-PictureLayerTiling::TilingEvictionTileIterator::operator bool() const {
- return eviction_tiles_ &&
- current_eviction_tiles_index_ != eviction_tiles_->size();
-}
-
-Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() {
- DCHECK(*this);
- return (*eviction_tiles_)[current_eviction_tiles_index_];
-}
-
-const Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() const {
- DCHECK(*this);
- return (*eviction_tiles_)[current_eviction_tiles_index_];
-}
-
-PictureLayerTiling::TilingEvictionTileIterator&
-PictureLayerTiling::TilingEvictionTileIterator::
-operator++() {
- DCHECK(*this);
- do {
- ++current_eviction_tiles_index_;
- } while (current_eviction_tiles_index_ != eviction_tiles_->size() &&
- !(*eviction_tiles_)[current_eviction_tiles_index_]->HasResources());
-
- return *this;
-}
-
} // namespace cc
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index e1ccde4..daa0485 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -118,24 +118,6 @@
TilingData::SpiralDifferenceIterator spiral_iterator_;
};
- class CC_EXPORT TilingEvictionTileIterator {
- public:
- TilingEvictionTileIterator();
- TilingEvictionTileIterator(PictureLayerTiling* tiling,
- TreePriority tree_priority,
- EvictionCategory category);
- ~TilingEvictionTileIterator();
-
- operator bool() const;
- const Tile* operator*() const;
- Tile* operator*();
- TilingEvictionTileIterator& operator++();
-
- private:
- const std::vector<Tile*>* eviction_tiles_;
- size_t current_eviction_tiles_index_;
- };
-
~PictureLayerTiling();
// Create a tiling with no tiles. CreateTiles must be called to add some.
@@ -299,7 +281,7 @@
protected:
friend class CoverageIterator;
friend class TilingRasterTileIterator;
- friend class TilingEvictionTileIterator;
+ friend class TilingSetEvictionQueue;
typedef std::pair<int, int> TileMapKey;
typedef base::hash_map<TileMapKey, scoped_refptr<Tile>> TileMap;
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index 55d495b..3944e46 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -178,98 +178,6 @@
true);
}
- void RunEvictionIteratorConstructTest(const std::string& test_name,
- const gfx::Rect& viewport) {
- gfx::Size bounds(viewport.size());
- picture_layer_tiling_ =
- PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
- picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
- picture_layer_tiling_->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
- Occlusion());
-
- timer_.Reset();
- TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
- SMOOTHNESS_TAKES_PRIORITY,
- NEW_CONTENT_TAKES_PRIORITY};
- int priority_count = 0;
- do {
- PictureLayerTiling::TilingEvictionTileIterator it(
- picture_layer_tiling_.get(),
- priorities[priority_count],
- PictureLayerTiling::NOW);
- priority_count = (priority_count + 1) % arraysize(priorities);
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- perf_test::PrintResult("tiling_eviction_tile_iterator_construct",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
- }
-
- void RunEvictionIteratorConstructAndIterateTest(const std::string& test_name,
- int num_tiles,
- const gfx::Rect& viewport) {
- gfx::Size bounds(10000, 10000);
- picture_layer_tiling_ =
- PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
- picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
- picture_layer_tiling_->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
- Occlusion());
-
- TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
- SMOOTHNESS_TAKES_PRIORITY,
- NEW_CONTENT_TAKES_PRIORITY};
-
- // Ensure all tiles have resources.
- std::vector<Tile*> all_tiles = picture_layer_tiling_->AllTilesForTesting();
- for (std::vector<Tile*>::iterator tile_it = all_tiles.begin();
- tile_it != all_tiles.end();
- ++tile_it) {
- Tile* tile = *tile_it;
- ManagedTileState::DrawInfo& draw_info = tile->draw_info();
- draw_info.SetResourceForTesting(
- ScopedResource::Create(resource_provider_.get()).Pass());
- }
-
- int priority_count = 0;
- timer_.Reset();
- do {
- int count = num_tiles;
- PictureLayerTiling::TilingEvictionTileIterator it(
- picture_layer_tiling_.get(),
- priorities[priority_count],
- PictureLayerTiling::EVENTUALLY);
- while (count--) {
- ASSERT_TRUE(it) << "count: " << count;
- ASSERT_TRUE(*it != NULL) << "count: " << count;
- ++it;
- }
- priority_count = (priority_count + 1) % arraysize(priorities);
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- // Remove all resources from tiles to make sure the tile version destructor
- // doesn't complain.
- for (std::vector<Tile*>::iterator tile_it = all_tiles.begin();
- tile_it != all_tiles.end();
- ++tile_it) {
- Tile* tile = *tile_it;
- ManagedTileState::DrawInfo& draw_info = tile->draw_info();
- draw_info.SetResourceForTesting(nullptr);
- }
-
- perf_test::PrintResult(
- "tiling_eviction_tile_iterator_construct_and_iterate",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
- }
-
private:
FakePictureLayerTilingClient picture_layer_tiling_client_;
scoped_ptr<PictureLayerTiling> picture_layer_tiling_;
@@ -333,27 +241,6 @@
"64_500x500", 64, gfx::Rect(0, 0, 500, 500));
}
-TEST_F(PictureLayerTilingPerfTest, TilingEvictionTileIteratorConstruct) {
- RunEvictionIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
- RunEvictionIteratorConstructTest("50_0_100x100", gfx::Rect(50, 0, 100, 100));
- RunEvictionIteratorConstructTest("100_0_100x100",
- gfx::Rect(100, 0, 100, 100));
- RunEvictionIteratorConstructTest("150_0_100x100",
- gfx::Rect(150, 0, 100, 100));
-}
-
-TEST_F(PictureLayerTilingPerfTest,
- TilingEvictionTileIteratorConstructAndIterate) {
- RunEvictionIteratorConstructAndIterateTest(
- "32_100x100", 32, gfx::Rect(0, 0, 100, 100));
- RunEvictionIteratorConstructAndIterateTest(
- "32_500x500", 32, gfx::Rect(0, 0, 500, 500));
- RunEvictionIteratorConstructAndIterateTest(
- "64_100x100", 64, gfx::Rect(0, 0, 100, 100));
- RunEvictionIteratorConstructAndIterateTest(
- "64_500x500", 64, gfx::Rect(0, 0, 500, 500));
-}
-
} // namespace
} // namespace cc
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index b982dc1..9190b98 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -1247,102 +1247,6 @@
EXPECT_EQ(exists, tile != NULL) << geometry_rect.ToString();
}
-TEST(PictureLayerTilingTest, TilingEvictionTileIteratorStaticViewport) {
- FakeOutputSurfaceClient output_surface_client;
- scoped_ptr<FakeOutputSurface> output_surface = FakeOutputSurface::Create3d();
- CHECK(output_surface->BindToClient(&output_surface_client));
- TestSharedBitmapManager shared_bitmap_manager;
- scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create(
- output_surface.get(), &shared_bitmap_manager, NULL, NULL, 0, false, 1);
-
- FakePictureLayerTilingClient client(resource_provider.get());
- scoped_ptr<TestablePictureLayerTiling> tiling;
-
- gfx::Rect viewport(50, 50, 100, 100);
- gfx::Size layer_bounds(2000, 2000);
-
- client.SetTileSize(gfx::Size(30, 30));
- client.set_tree(ACTIVE_TREE);
-
- tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(viewport, 1.0f, 1.0, Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
-
- PictureLayerTiling::TilingRasterTileIterator empty_iterator;
- EXPECT_FALSE(empty_iterator);
-
- std::vector<Tile*> all_tiles = tiling->AllTilesForTesting();
-
- PictureLayerTiling::TilingEvictionTileIterator it(
- tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::NOW);
-
- // Tiles don't have resources to evict.
- EXPECT_FALSE(it);
-
- // Sanity check.
- EXPECT_EQ(5184u, all_tiles.size());
-
- client.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
-
- std::set<Tile*> all_tiles_set(all_tiles.begin(), all_tiles.end());
-
- std::set<Tile*> eviction_tiles;
-
- it = PictureLayerTiling::TilingEvictionTileIterator(
- tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::EVENTUALLY);
- EXPECT_TRUE(it);
- for (; it; ++it) {
- Tile* tile = *it;
- EXPECT_TRUE(tile);
- EXPECT_EQ(TilePriority::EVENTUALLY,
- tile->priority(ACTIVE_TREE).priority_bin);
- EXPECT_FALSE(tile->required_for_activation());
- eviction_tiles.insert(tile);
- }
-
- it = PictureLayerTiling::TilingEvictionTileIterator(
- tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::SOON);
- EXPECT_TRUE(it);
- for (; it; ++it) {
- Tile* tile = *it;
- EXPECT_TRUE(tile);
- EXPECT_EQ(TilePriority::SOON, tile->priority(ACTIVE_TREE).priority_bin);
- EXPECT_FALSE(tile->required_for_activation());
- eviction_tiles.insert(tile);
- }
-
- it = PictureLayerTiling::TilingEvictionTileIterator(
- tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::NOW);
- EXPECT_TRUE(it);
- for (; it; ++it) {
- Tile* tile = *it;
- EXPECT_TRUE(tile);
- EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin);
- EXPECT_FALSE(tile->required_for_activation());
- eviction_tiles.insert(tile);
- }
-
- it = PictureLayerTiling::TilingEvictionTileIterator(
- tiling.get(),
- SMOOTHNESS_TAKES_PRIORITY,
- PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION);
- EXPECT_FALSE(it);
-
- EXPECT_GT(all_tiles_set.size(), 0u);
- EXPECT_EQ(all_tiles_set, eviction_tiles);
-
- EXPECT_TRUE(tiling->eviction_tiles_cache_valid());
- tiling->RemoveTileAt(0, 0, nullptr);
- EXPECT_FALSE(tiling->eviction_tiles_cache_valid());
-
- it = PictureLayerTiling::TilingEvictionTileIterator(
- tiling.get(), SMOOTHNESS_TAKES_PRIORITY,
- PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION);
- EXPECT_TRUE(tiling->eviction_tiles_cache_valid());
- tiling->Reset();
- EXPECT_FALSE(tiling->eviction_tiles_cache_valid());
-}
-
TEST_F(PictureLayerTilingIteratorTest, TilesExist) {
gfx::Size layer_bounds(1099, 801);
Initialize(gfx::Size(100, 100), 1.f, layer_bounds);
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index 2655d24..5cd7bd6 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -4,11 +4,13 @@
#include <algorithm>
#include <limits>
+#include <set>
#include "base/debug/trace_event.h"
#include "cc/base/region.h"
#include "cc/debug/debug_colors.h"
#include "cc/resources/picture_pile_impl.h"
+#include "cc/resources/raster_source_helper.h"
#include "skia/ext/analysis_canvas.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
@@ -87,62 +89,9 @@
void PicturePileImpl::PlaybackToCanvas(SkCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const {
- canvas->discard();
- if (clear_canvas_with_debug_color_) {
- // Any non-painted areas in the content bounds will be left in this color.
- canvas->clear(DebugColors::NonPaintedFillColor());
- }
-
- // If this picture has opaque contents, it is guaranteeing that it will
- // draw an opaque rect the size of the layer. If it is not, then we must
- // clear this canvas ourselves.
- if (requires_clear_) {
- TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
- // Clearing is about ~4x faster than drawing a rect even if the content
- // isn't covering a majority of the canvas.
- canvas->clear(SK_ColorTRANSPARENT);
- } else {
- // Even if completely covered, for rasterizations that touch the edge of the
- // layer, we also need to raster the background color underneath the last
- // texel (since the recording won't cover it) and outside the last texel
- // (due to linear filtering when using this texture).
- gfx::Rect content_tiling_rect = gfx::ToEnclosingRect(
- gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale));
-
- // The final texel of content may only be partially covered by a
- // rasterization; this rect represents the content rect that is fully
- // covered by content.
- gfx::Rect deflated_content_tiling_rect = content_tiling_rect;
- deflated_content_tiling_rect.Inset(0, 0, 1, 1);
- if (!deflated_content_tiling_rect.Contains(canvas_rect)) {
- if (clear_canvas_with_debug_color_) {
- // Any non-painted areas outside of the content bounds are left in
- // this color. If this is seen then it means that cc neglected to
- // rerasterize a tile that used to intersect with the content rect
- // after the content bounds grew.
- canvas->save();
- canvas->translate(-canvas_rect.x(), -canvas_rect.y());
- canvas->clipRect(gfx::RectToSkRect(content_tiling_rect),
- SkRegion::kDifference_Op);
- canvas->drawColor(DebugColors::MissingResizeInvalidations(),
- SkXfermode::kSrc_Mode);
- canvas->restore();
- }
-
- // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X
- // faster than clearing, so special case this.
- canvas->save();
- canvas->translate(-canvas_rect.x(), -canvas_rect.y());
- gfx::Rect inflated_content_tiling_rect = content_tiling_rect;
- inflated_content_tiling_rect.Inset(0, 0, -1, -1);
- canvas->clipRect(gfx::RectToSkRect(inflated_content_tiling_rect),
- SkRegion::kReplace_Op);
- canvas->clipRect(gfx::RectToSkRect(deflated_content_tiling_rect),
- SkRegion::kDifference_Op);
- canvas->drawColor(background_color_, SkXfermode::kSrc_Mode);
- canvas->restore();
- }
- }
+ RasterSourceHelper::PrepareForPlaybackToCanvas(
+ canvas, canvas_rect, gfx::Rect(tiling_.tiling_size()), contents_scale,
+ background_color_, clear_canvas_with_debug_color_, requires_clear_);
RasterCommon(canvas,
NULL,
@@ -319,6 +268,19 @@
return picture;
}
+size_t PicturePileImpl::GetPictureMemoryUsage() const {
+ // Place all pictures in a set to de-dupe.
+ size_t total_size = 0;
+ std::set<const Picture*> pictures_seen;
+ for (const auto& map_value : picture_map_) {
+ const Picture* picture = map_value.second.GetPicture();
+ if (picture && pictures_seen.insert(picture).second)
+ total_size += picture->ApproximateMemoryUsage();
+ }
+
+ return total_size;
+}
+
void PicturePileImpl::PerformSolidColorAnalysis(
const gfx::Rect& content_rect,
float contents_scale,
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index d7d0399..3e0dd78 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -67,6 +67,7 @@
void DidBeginTracing() override;
void AsValueInto(base::debug::TracedValue* array) const override;
skia::RefPtr<SkPicture> GetFlattenedPicture() override;
+ size_t GetPictureMemoryUsage() const override;
// Iterator used to return SkPixelRefs from this picture pile.
// Public for testing.
diff --git a/cc/resources/raster_source.h b/cc/resources/raster_source.h
index 3584436..88c9962 100644
--- a/cc/resources/raster_source.h
+++ b/cc/resources/raster_source.h
@@ -18,6 +18,8 @@
namespace cc {
+class Picture;
+
class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
public:
struct CC_EXPORT SolidColorAnalysis {
@@ -92,6 +94,7 @@
virtual void DidBeginTracing() = 0;
virtual void AsValueInto(base::debug::TracedValue* array) const = 0;
virtual skia::RefPtr<SkPicture> GetFlattenedPicture() = 0;
+ virtual size_t GetPictureMemoryUsage() const = 0;
// Return true if LCD anti-aliasing may be used when rastering text.
virtual bool CanUseLCDText() const = 0;
diff --git a/cc/resources/raster_source_helper.cc b/cc/resources/raster_source_helper.cc
new file mode 100644
index 0000000..f7ef305
--- /dev/null
+++ b/cc/resources/raster_source_helper.cc
@@ -0,0 +1,81 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/raster_source_helper.h"
+
+#include "base/debug/trace_event.h"
+#include "cc/debug/debug_colors.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+void RasterSourceHelper::PrepareForPlaybackToCanvas(
+ SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ const gfx::Rect& source_rect,
+ float contents_scale,
+ SkColor background_color,
+ bool clear_canvas_with_debug_color,
+ bool requires_clear) {
+ canvas->discard();
+ if (clear_canvas_with_debug_color) {
+ // Any non-painted areas in the content bounds will be left in this color.
+ canvas->clear(DebugColors::NonPaintedFillColor());
+ }
+
+ // If this raster source has opaque contents, it is guaranteeing that it will
+ // draw an opaque rect the size of the layer. If it is not, then we must
+ // clear this canvas ourselves.
+ if (requires_clear) {
+ TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
+ // Clearing is about ~4x faster than drawing a rect even if the content
+ // isn't covering a majority of the canvas.
+ canvas->clear(SK_ColorTRANSPARENT);
+ } else {
+ // Even if completely covered, for rasterizations that touch the edge of the
+ // layer, we also need to raster the background color underneath the last
+ // texel (since the recording won't cover it) and outside the last texel
+ // (due to linear filtering when using this texture).
+ gfx::Rect content_rect =
+ gfx::ToEnclosingRect(gfx::ScaleRect(source_rect, contents_scale));
+
+ // The final texel of content may only be partially covered by a
+ // rasterization; this rect represents the content rect that is fully
+ // covered by content.
+ gfx::Rect deflated_content_rect = content_rect;
+ deflated_content_rect.Inset(0, 0, 1, 1);
+ if (!deflated_content_rect.Contains(canvas_rect)) {
+ if (clear_canvas_with_debug_color) {
+ // Any non-painted areas outside of the content bounds are left in
+ // this color. If this is seen then it means that cc neglected to
+ // rerasterize a tile that used to intersect with the content rect
+ // after the content bounds grew.
+ canvas->save();
+ canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+ canvas->clipRect(gfx::RectToSkRect(content_rect),
+ SkRegion::kDifference_Op);
+ canvas->drawColor(DebugColors::MissingResizeInvalidations(),
+ SkXfermode::kSrc_Mode);
+ canvas->restore();
+ }
+
+ // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X
+ // faster than clearing, so special case this.
+ canvas->save();
+ canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+ gfx::Rect inflated_content_rect = content_rect;
+ inflated_content_rect.Inset(0, 0, -1, -1);
+ canvas->clipRect(gfx::RectToSkRect(inflated_content_rect),
+ SkRegion::kReplace_Op);
+ canvas->clipRect(gfx::RectToSkRect(deflated_content_rect),
+ SkRegion::kDifference_Op);
+ canvas->drawColor(background_color, SkXfermode::kSrc_Mode);
+ canvas->restore();
+ }
+ }
+}
+
+} // namespace cc
diff --git a/cc/resources/raster_source_helper.h b/cc/resources/raster_source_helper.h
new file mode 100644
index 0000000..abdea3e
--- /dev/null
+++ b/cc/resources/raster_source_helper.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_RASTER_SOURCE_HELPER_H_
+#define CC_RESOURCES_RASTER_SOURCE_HELPER_H_
+
+#include "cc/base/cc_export.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkCanvas;
+
+namespace cc {
+
+class CC_EXPORT RasterSourceHelper {
+ public:
+ static void PrepareForPlaybackToCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ const gfx::Rect& source_rect,
+ float contents_scale,
+ SkColor background_color,
+ bool clear_canvas_with_debug_color,
+ bool requires_clear);
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_RASTER_SOURCE_HELPER_H_
diff --git a/cc/resources/raster_worker_pool.cc b/cc/resources/raster_worker_pool.cc
index 4511f9d..ca951f6 100644
--- a/cc/resources/raster_worker_pool.cc
+++ b/cc/resources/raster_worker_pool.cc
@@ -206,6 +206,7 @@
case LUMINANCE_8:
case RGB_565:
case ETC1:
+ case RED_8:
return false;
}
NOTREACHED();
diff --git a/cc/resources/resource_format.cc b/cc/resources/resource_format.cc
index 6cd0a93..45581b8 100644
--- a/cc/resources/resource_format.cc
+++ b/cc/resources/resource_format.cc
@@ -17,6 +17,7 @@
case ALPHA_8:
case LUMINANCE_8:
case RGB_565:
+ case RED_8:
NOTREACHED();
break;
}
diff --git a/cc/resources/resource_format.h b/cc/resources/resource_format.h
index b51ac7c..d785ab7 100644
--- a/cc/resources/resource_format.h
+++ b/cc/resources/resource_format.h
@@ -19,7 +19,8 @@
LUMINANCE_8,
RGB_565,
ETC1,
- RESOURCE_FORMAT_MAX = ETC1,
+ RED_8,
+ RESOURCE_FORMAT_MAX = RED_8,
};
SkColorType ResourceFormatToSkColorType(ResourceFormat format);
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 636e797..fe7cc00 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -76,6 +76,7 @@
case LUMINANCE_8:
case RGB_565:
case ETC1:
+ case RED_8:
NOTREACHED();
break;
}
@@ -94,6 +95,7 @@
case LUMINANCE_8:
case RGB_565:
case ETC1:
+ case RED_8:
return false;
}
return false;
@@ -125,6 +127,7 @@
case LUMINANCE_8:
case RGB_565:
case ETC1:
+ case RED_8:
break;
}
NOTREACHED();
@@ -1216,6 +1219,7 @@
use_texture_format_bgra_(false),
use_texture_usage_hint_(false),
use_compressed_texture_etc1_(false),
+ yuv_resource_format_(LUMINANCE_8),
max_texture_size_(0),
best_texture_format_(RGBA_8888),
use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
@@ -1254,6 +1258,7 @@
use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
use_texture_usage_hint_ = caps.gpu.texture_usage;
use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
+ yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
use_sync_query_ = caps.gpu.sync_query;
GLES2Interface* gl = ContextGL();
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index bfd3ebb..3a8d2e0 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -99,6 +99,7 @@
return use_rgba_4444_texture_format_ ? RGBA_4444 : best_texture_format_;
}
ResourceFormat best_texture_format() const { return best_texture_format_; }
+ ResourceFormat yuv_resource_format() const { return yuv_resource_format_; }
bool use_sync_query() const { return use_sync_query_; }
size_t num_resources() const { return resources_.size(); }
@@ -578,6 +579,7 @@
bool use_texture_format_bgra_;
bool use_texture_usage_hint_;
bool use_compressed_texture_etc1_;
+ ResourceFormat yuv_resource_format_;
scoped_ptr<TextureUploader> texture_uploader_;
int max_texture_size_;
ResourceFormat best_texture_format_;
@@ -610,6 +612,7 @@
return 16;
case ALPHA_8:
case LUMINANCE_8:
+ case RED_8:
return 8;
case ETC1:
return 4;
@@ -621,13 +624,14 @@
inline GLenum GLDataType(ResourceFormat format) {
DCHECK_LE(format, RESOURCE_FORMAT_MAX);
static const unsigned format_gl_data_type[RESOURCE_FORMAT_MAX + 1] = {
- GL_UNSIGNED_BYTE, // RGBA_8888
- GL_UNSIGNED_SHORT_4_4_4_4, // RGBA_4444
- GL_UNSIGNED_BYTE, // BGRA_8888
- GL_UNSIGNED_BYTE, // ALPHA_8
- GL_UNSIGNED_BYTE, // LUMINANCE_8
- GL_UNSIGNED_SHORT_5_6_5, // RGB_565,
- GL_UNSIGNED_BYTE // ETC1
+ GL_UNSIGNED_BYTE, // RGBA_8888
+ GL_UNSIGNED_SHORT_4_4_4_4, // RGBA_4444
+ GL_UNSIGNED_BYTE, // BGRA_8888
+ GL_UNSIGNED_BYTE, // ALPHA_8
+ GL_UNSIGNED_BYTE, // LUMINANCE_8
+ GL_UNSIGNED_SHORT_5_6_5, // RGB_565,
+ GL_UNSIGNED_BYTE, // ETC1
+ GL_UNSIGNED_BYTE // RED_8
};
return format_gl_data_type[format];
}
@@ -635,13 +639,14 @@
inline GLenum GLDataFormat(ResourceFormat format) {
DCHECK_LE(format, RESOURCE_FORMAT_MAX);
static const unsigned format_gl_data_format[RESOURCE_FORMAT_MAX + 1] = {
- GL_RGBA, // RGBA_8888
- GL_RGBA, // RGBA_4444
- GL_BGRA_EXT, // BGRA_8888
- GL_ALPHA, // ALPHA_8
- GL_LUMINANCE, // LUMINANCE_8
- GL_RGB, // RGB_565
- GL_ETC1_RGB8_OES // ETC1
+ GL_RGBA, // RGBA_8888
+ GL_RGBA, // RGBA_4444
+ GL_BGRA_EXT, // BGRA_8888
+ GL_ALPHA, // ALPHA_8
+ GL_LUMINANCE, // LUMINANCE_8
+ GL_RGB, // RGB_565
+ GL_ETC1_RGB8_OES, // ETC1
+ GL_RED_EXT // RED_8
};
return format_gl_data_format[format];
}
diff --git a/cc/resources/shared_bitmap.cc b/cc/resources/shared_bitmap.cc
index 31cf245..1ac0323 100644
--- a/cc/resources/shared_bitmap.cc
+++ b/cc/resources/shared_bitmap.cc
@@ -10,25 +10,13 @@
namespace cc {
-SharedBitmap::SharedBitmap(
- base::SharedMemory* memory,
- const SharedBitmapId& id,
- const base::Callback<void(SharedBitmap* bitmap)>& free_callback)
- : memory_(memory),
- pixels_(static_cast<uint8*>(memory_->memory())),
- id_(id),
- free_callback_(free_callback) {
+SharedBitmap::SharedBitmap(uint8* pixels, const SharedBitmapId& id)
+ : pixels_(pixels), id_(id) {
}
-SharedBitmap::SharedBitmap(
- uint8* pixels,
- const SharedBitmapId& id,
- const base::Callback<void(SharedBitmap* bitmap)>& free_callback)
- : memory_(NULL), pixels_(pixels), id_(id), free_callback_(free_callback) {
+SharedBitmap::~SharedBitmap() {
}
-SharedBitmap::~SharedBitmap() { free_callback_.Run(this); }
-
// static
bool SharedBitmap::SizeInBytes(const gfx::Size& size, size_t* size_in_bytes) {
if (size.IsEmpty())
diff --git a/cc/resources/shared_bitmap.h b/cc/resources/shared_bitmap.h
index ca12710..bbf0823 100644
--- a/cc/resources/shared_bitmap.h
+++ b/cc/resources/shared_bitmap.h
@@ -6,8 +6,7 @@
#define CC_RESOURCES_SHARED_BITMAP_H_
#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/memory/shared_memory.h"
+#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "ui/gfx/geometry/size.h"
@@ -19,29 +18,15 @@
class CC_EXPORT SharedBitmap {
public:
- SharedBitmap(base::SharedMemory* memory,
- const SharedBitmapId& id,
- const base::Callback<void(SharedBitmap* bitmap)>& free_callback);
+ SharedBitmap(uint8* pixels, const SharedBitmapId& id);
- SharedBitmap(uint8* pixels,
- const SharedBitmapId& id,
- const base::Callback<void(SharedBitmap* bitmap)>& free_callback);
-
- ~SharedBitmap();
-
- bool operator<(const SharedBitmap& right) const {
- if (memory_ < right.memory_)
- return true;
- if (memory_ > right.memory_)
- return false;
- return id_ < right.id_;
- }
+ virtual ~SharedBitmap();
uint8* pixels() { return pixels_; }
- base::SharedMemory* memory() { return memory_; }
+ virtual base::SharedMemory* memory() = 0;
- SharedBitmapId id() { return id_; }
+ const SharedBitmapId& id() { return id_; }
// Returns true if the size is valid and false otherwise.
static bool SizeInBytes(const gfx::Size& size, size_t* size_in_bytes);
@@ -57,10 +42,8 @@
static SharedBitmapId GenerateId();
private:
- base::SharedMemory* memory_;
uint8* pixels_;
SharedBitmapId id_;
- base::Callback<void(SharedBitmap* bitmap)> free_callback_;
DISALLOW_COPY_AND_ASSIGN(SharedBitmap);
};
diff --git a/cc/resources/texture_uploader_unittest.cc b/cc/resources/texture_uploader_unittest.cc
index 7249172..b168962 100644
--- a/cc/resources/texture_uploader_unittest.cc
+++ b/cc/resources/texture_uploader_unittest.cc
@@ -111,6 +111,14 @@
EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
bytes_per_pixel = 2;
break;
+ case GL_RED_EXT:
+ EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+ bytes_per_pixel = 1;
+ break;
+ case GL_RG_EXT:
+ EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+ bytes_per_pixel = 2;
+ break;
}
// If NULL, we aren't checking texture contents.
@@ -232,6 +240,15 @@
buffer[(i + 1) * 82 - 1] = 0x2;
}
UploadTexture(uploader.get(), LUMINANCE_8, gfx::Size(82, 86), buffer);
+
+ // Upload a tightly packed 82x86 RED texture.
+ memset(buffer, 0, sizeof(buffer));
+ for (int i = 0; i < 86; ++i) {
+ // Mark the beginning and end of each row, for the test.
+ buffer[i * 1 * 82] = 0x1;
+ buffer[(i + 1) * 82 - 1] = 0x2;
+ }
+ UploadTexture(uploader.get(), RED_8, gfx::Size(82, 86), buffer);
}
} // namespace
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index 042d5ae..a35cffe 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -15,6 +15,8 @@
namespace cc {
+class TileManager;
+
class CC_EXPORT Tile : public RefCountedManaged<Tile> {
public:
enum TileRasterFlags { USE_PICTURE_ANALYSIS = 1 << 0 };
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index d83b824..66f95da 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -239,9 +239,11 @@
task_runner_.get(),
base::Bind(&TileManager::CheckIfReadyToActivate,
base::Unretained(this))),
- ready_to_draw_check_notifier_(task_runner_.get(),
- base::Bind(&TileManager::CheckIfReadyToDraw,
- base::Unretained(this))) {
+ ready_to_draw_check_notifier_(
+ task_runner_.get(),
+ base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))),
+ did_notify_ready_to_activate_(false),
+ did_notify_ready_to_draw_(false) {
rasterizer_->SetClient(this);
}
@@ -416,9 +418,12 @@
TileVector tiles_that_need_to_be_rasterized;
AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
- // Finally, schedule rasterizer tasks.
+ // Schedule rasterizer tasks.
ScheduleTasks(tiles_that_need_to_be_rasterized);
+ did_notify_ready_to_activate_ = false;
+ did_notify_ready_to_draw_ = false;
+
TRACE_EVENT_INSTANT1("cc",
"DidManage",
TRACE_EVENT_SCOPE_THREAD,
@@ -882,8 +887,13 @@
rasterizer_->CheckForCompletedTasks();
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
- if (IsReadyToActivate())
- client_->NotifyReadyToActivate();
+ if (did_notify_ready_to_activate_)
+ return;
+ if (!IsReadyToActivate())
+ return;
+
+ client_->NotifyReadyToActivate();
+ did_notify_ready_to_activate_ = true;
}
void TileManager::CheckIfReadyToDraw() {
@@ -892,8 +902,13 @@
rasterizer_->CheckForCompletedTasks();
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
- if (IsReadyToDraw())
- client_->NotifyReadyToDraw();
+ if (did_notify_ready_to_draw_)
+ return;
+ if (!IsReadyToDraw())
+ return;
+
+ client_->NotifyReadyToDraw();
+ did_notify_ready_to_draw_ = true;
}
TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index e94fb7c..8d19520 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -162,6 +162,10 @@
return tiles;
}
+ void SetScheduledRasterTaskLimitForTesting(size_t limit) {
+ scheduled_raster_task_limit_ = limit;
+ }
+
protected:
TileManager(TileManagerClient* client,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
@@ -243,7 +247,7 @@
ResourcePool* resource_pool_;
Rasterizer* rasterizer_;
GlobalStateThatImpactsTilePriority global_state_;
- const size_t scheduled_raster_task_limit_;
+ size_t scheduled_raster_task_limit_;
typedef base::hash_map<Tile::Id, Tile*> TileMap;
TileMap tiles_;
@@ -282,6 +286,9 @@
EvictionTilePriorityQueue eviction_priority_queue_;
bool eviction_priority_queue_is_up_to_date_;
+ bool did_notify_ready_to_activate_;
+ bool did_notify_ready_to_draw_;
+
DISALLOW_COPY_AND_ASSIGN(TileManager);
};
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 7b096bd..2204ab8 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -400,7 +400,8 @@
timer_.Reset();
bool resourceless_software_draw = false;
do {
- BeginFrameArgs args = CreateBeginFrameArgsForTesting();
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
host_impl_.UpdateCurrentBeginFrameArgs(args);
for (unsigned i = 0; i < layers.size(); ++i) {
layers[i]->UpdateTiles(Occlusion(), resourceless_software_draw);
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 49a93d3..fdd876e 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -149,7 +149,9 @@
};
TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueue) {
- SetupDefaultTrees(gfx::Size(1000, 1000));
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
active_layer_->CreateDefaultTilingsAndTiles();
pending_layer_->CreateDefaultTilingsAndTiles();
@@ -391,7 +393,9 @@
}
TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) {
- SetupDefaultTrees(gfx::Size(1000, 1000));
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
active_layer_->CreateDefaultTilingsAndTiles();
pending_layer_->CreateDefaultTilingsAndTiles();
@@ -560,6 +564,8 @@
gfx::Size tile_size(102, 102);
gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupPendingTree(pending_pile);
@@ -768,7 +774,9 @@
}
TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueEmptyLayers) {
- SetupDefaultTrees(gfx::Size(1000, 1000));
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
active_layer_->CreateDefaultTilingsAndTiles();
pending_layer_->CreateDefaultTilingsAndTiles();
@@ -815,7 +823,9 @@
}
TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueueEmptyLayers) {
- SetupDefaultTrees(gfx::Size(1000, 1000));
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
active_layer_->CreateDefaultTilingsAndTiles();
pending_layer_->CreateDefaultTilingsAndTiles();
diff --git a/cc/resources/tiling_set_eviction_queue.cc b/cc/resources/tiling_set_eviction_queue.cc
new file mode 100644
index 0000000..8c5ff52
--- /dev/null
+++ b/cc/resources/tiling_set_eviction_queue.cc
@@ -0,0 +1,197 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/tiling_set_eviction_queue.h"
+
+namespace cc {
+
+TilingSetEvictionQueue::TilingSetEvictionQueue()
+ : tiling_set_(nullptr),
+ tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES),
+ current_category_(PictureLayerTiling::EVENTUALLY),
+ current_tiling_index_(0u),
+ current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
+ current_eviction_tile_(nullptr),
+ eviction_tiles_(nullptr),
+ next_eviction_tile_index_(0u) {
+}
+
+TilingSetEvictionQueue::TilingSetEvictionQueue(
+ PictureLayerTilingSet* tiling_set,
+ TreePriority tree_priority)
+ : tiling_set_(tiling_set),
+ tree_priority_(tree_priority),
+ current_category_(PictureLayerTiling::EVENTUALLY),
+ current_tiling_index_(0u),
+ current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
+ current_eviction_tile_(nullptr),
+ eviction_tiles_(nullptr),
+ next_eviction_tile_index_(0u) {
+ DCHECK(tiling_set_);
+
+ // Early out if the layer has no tilings.
+ if (!tiling_set_->num_tilings())
+ return;
+
+ current_tiling_index_ = CurrentTilingRange().start - 1u;
+ AdvanceToNextValidTiling();
+}
+
+TilingSetEvictionQueue::~TilingSetEvictionQueue() {
+}
+
+bool TilingSetEvictionQueue::IsEmpty() const {
+ return !current_eviction_tile_;
+}
+
+void TilingSetEvictionQueue::Pop() {
+ DCHECK(!IsEmpty());
+
+ if (!AdvanceToNextEvictionTile())
+ AdvanceToNextValidTiling();
+}
+
+Tile* TilingSetEvictionQueue::Top() {
+ DCHECK(!IsEmpty());
+ return current_eviction_tile_;
+}
+
+const Tile* TilingSetEvictionQueue::Top() const {
+ DCHECK(!IsEmpty());
+ return current_eviction_tile_;
+}
+
+bool TilingSetEvictionQueue::AdvanceToNextCategory() {
+ // Advance to the next category. This is done only after all tiling range
+ // types within the previous category have been gone through.
+ DCHECK_EQ(current_tiling_range_type_, PictureLayerTilingSet::HIGH_RES);
+
+ switch (current_category_) {
+ case PictureLayerTiling::EVENTUALLY:
+ current_category_ =
+ PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION;
+ return true;
+ case PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
+ current_category_ = PictureLayerTiling::SOON;
+ return true;
+ case PictureLayerTiling::SOON:
+ current_category_ = PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION;
+ return true;
+ case PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION:
+ current_category_ = PictureLayerTiling::NOW;
+ return true;
+ case PictureLayerTiling::NOW:
+ current_category_ = PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION;
+ return true;
+ case PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION:
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool TilingSetEvictionQueue::AdvanceToNextEvictionTile() {
+ // Advance to the next eviction tile within the current category and tiling.
+ // This is done while advancing to a new tiling (in which case the next
+ // eviction tile index is 0) and while popping the current tile (in which
+ // case the next eviction tile index is greater than 0).
+ DCHECK_EQ(next_eviction_tile_index_ > 0, current_eviction_tile_ != nullptr);
+
+ while (next_eviction_tile_index_ < eviction_tiles_->size()) {
+ Tile* tile = (*eviction_tiles_)[next_eviction_tile_index_];
+ ++next_eviction_tile_index_;
+ if (tile->HasResources()) {
+ current_eviction_tile_ = tile;
+ return true;
+ }
+ }
+
+ current_eviction_tile_ = nullptr;
+ return false;
+}
+
+bool TilingSetEvictionQueue::AdvanceToNextTilingRangeType() {
+ // Advance to the next tiling range type within the current category or to
+ // the first tiling range type within the next category. This is done only
+ // after all tilings within the previous tiling range type have been gone
+ // through.
+ DCHECK_EQ(current_tiling_index_, CurrentTilingRange().end);
+
+ switch (current_tiling_range_type_) {
+ case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
+ current_tiling_range_type_ = PictureLayerTilingSet::LOWER_THAN_LOW_RES;
+ return true;
+ case PictureLayerTilingSet::LOWER_THAN_LOW_RES:
+ current_tiling_range_type_ =
+ PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES;
+ return true;
+ case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
+ current_tiling_range_type_ = PictureLayerTilingSet::LOW_RES;
+ return true;
+ case PictureLayerTilingSet::LOW_RES:
+ current_tiling_range_type_ = PictureLayerTilingSet::HIGH_RES;
+ return true;
+ case PictureLayerTilingSet::HIGH_RES:
+ if (!AdvanceToNextCategory())
+ return false;
+
+ current_tiling_range_type_ = PictureLayerTilingSet::HIGHER_THAN_HIGH_RES;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool TilingSetEvictionQueue::AdvanceToNextValidTiling() {
+ // Advance to the next tiling within current tiling range type or to
+ // the first tiling within the next tiling range type or category until
+ // the next eviction tile is found. This is done only after all eviction
+ // tiles within the previous tiling within the current category and tiling
+ // range type have been gone through.
+ DCHECK(!current_eviction_tile_);
+ DCHECK_NE(current_tiling_index_, CurrentTilingRange().end);
+
+ for (;;) {
+ ++current_tiling_index_;
+ while (current_tiling_index_ == CurrentTilingRange().end) {
+ if (!AdvanceToNextTilingRangeType())
+ return false;
+ current_tiling_index_ = CurrentTilingRange().start;
+ }
+
+ PictureLayerTiling* tiling = tiling_set_->tiling_at(CurrentTilingIndex());
+ eviction_tiles_ =
+ tiling->GetEvictionTiles(tree_priority_, current_category_);
+ next_eviction_tile_index_ = 0u;
+ if (AdvanceToNextEvictionTile())
+ return true;
+ }
+}
+
+PictureLayerTilingSet::TilingRange
+TilingSetEvictionQueue::CurrentTilingRange() const {
+ return tiling_set_->GetTilingRange(current_tiling_range_type_);
+}
+
+size_t TilingSetEvictionQueue::CurrentTilingIndex() const {
+ DCHECK_NE(current_tiling_index_, CurrentTilingRange().end);
+ switch (current_tiling_range_type_) {
+ case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
+ case PictureLayerTilingSet::LOW_RES:
+ case PictureLayerTilingSet::HIGH_RES:
+ return current_tiling_index_;
+ // Tilings in the following ranges are accessed in reverse order.
+ case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
+ case PictureLayerTilingSet::LOWER_THAN_LOW_RES: {
+ PictureLayerTilingSet::TilingRange tiling_range = CurrentTilingRange();
+ size_t current_tiling_range_offset =
+ current_tiling_index_ - tiling_range.start;
+ return tiling_range.end - 1 - current_tiling_range_offset;
+ }
+ }
+ NOTREACHED();
+ return 0;
+}
+
+}
diff --git a/cc/resources/tiling_set_eviction_queue.h b/cc/resources/tiling_set_eviction_queue.h
new file mode 100644
index 0000000..f88ce3b
--- /dev/null
+++ b/cc/resources/tiling_set_eviction_queue.h
@@ -0,0 +1,48 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_TILING_SET_EVICTION_QUEUE_H_
+#define CC_RESOURCES_TILING_SET_EVICTION_QUEUE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/resources/picture_layer_tiling_set.h"
+
+namespace cc {
+
+class CC_EXPORT TilingSetEvictionQueue {
+ public:
+ TilingSetEvictionQueue();
+ TilingSetEvictionQueue(PictureLayerTilingSet* tiling_set,
+ TreePriority tree_priority);
+ ~TilingSetEvictionQueue();
+
+ Tile* Top();
+ const Tile* Top() const;
+ void Pop();
+ bool IsEmpty() const;
+
+ private:
+ bool AdvanceToNextCategory();
+ bool AdvanceToNextEvictionTile();
+ bool AdvanceToNextTilingRangeType();
+ bool AdvanceToNextValidTiling();
+
+ PictureLayerTilingSet::TilingRange CurrentTilingRange() const;
+ size_t CurrentTilingIndex() const;
+
+ PictureLayerTilingSet* tiling_set_;
+ TreePriority tree_priority_;
+
+ PictureLayerTiling::EvictionCategory current_category_;
+ size_t current_tiling_index_;
+ PictureLayerTilingSet::TilingRangeType current_tiling_range_type_;
+ Tile* current_eviction_tile_;
+
+ const std::vector<Tile*>* eviction_tiles_;
+ size_t next_eviction_tile_index_;
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_TILING_SET_RASTER_QUEUE_H_
diff --git a/cc/resources/transform_display_item.cc b/cc/resources/transform_display_item.cc
new file mode 100644
index 0000000..c7f4d60
--- /dev/null
+++ b/cc/resources/transform_display_item.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/transform_display_item.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace cc {
+
+TransformDisplayItem::TransformDisplayItem(const gfx::Transform& transform)
+ : transform_(transform) {
+}
+
+TransformDisplayItem::~TransformDisplayItem() {
+}
+
+void TransformDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->save();
+ if (!transform_.IsIdentity())
+ canvas->concat(transform_.matrix());
+}
+
+bool TransformDisplayItem::IsSuitableForGpuRasterization() const {
+ return true;
+}
+
+int TransformDisplayItem::ApproximateOpCount() const {
+ return 1;
+}
+
+size_t TransformDisplayItem::PictureMemoryUsage() const {
+ return sizeof(gfx::Transform);
+}
+
+EndTransformDisplayItem::EndTransformDisplayItem() {
+}
+
+EndTransformDisplayItem::~EndTransformDisplayItem() {
+}
+
+void EndTransformDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->restore();
+}
+
+bool EndTransformDisplayItem::IsSuitableForGpuRasterization() const {
+ return true;
+}
+
+int EndTransformDisplayItem::ApproximateOpCount() const {
+ return 0;
+}
+
+size_t EndTransformDisplayItem::PictureMemoryUsage() const {
+ return 0;
+}
+
+} // namespace cc
diff --git a/cc/resources/transform_display_item.h b/cc/resources/transform_display_item.h
new file mode 100644
index 0000000..1671f49
--- /dev/null
+++ b/cc/resources/transform_display_item.h
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_TRANSFORM_DISPLAY_ITEM_H_
+#define CC_RESOURCES_TRANSFORM_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "ui/gfx/transform.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT TransformDisplayItem : public DisplayItem {
+ public:
+ virtual ~TransformDisplayItem();
+
+ static scoped_ptr<TransformDisplayItem> Create(
+ const gfx::Transform& transform) {
+ return make_scoped_ptr(new TransformDisplayItem(transform));
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+ bool IsSuitableForGpuRasterization() const override;
+ int ApproximateOpCount() const override;
+ size_t PictureMemoryUsage() const override;
+
+ protected:
+ explicit TransformDisplayItem(const gfx::Transform& transform);
+
+ private:
+ gfx::Transform transform_;
+};
+
+class CC_EXPORT EndTransformDisplayItem : public DisplayItem {
+ public:
+ virtual ~EndTransformDisplayItem();
+
+ static scoped_ptr<EndTransformDisplayItem> Create() {
+ return make_scoped_ptr(new EndTransformDisplayItem());
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+ bool IsSuitableForGpuRasterization() const override;
+ int ApproximateOpCount() const override;
+ size_t PictureMemoryUsage() const override;
+
+ protected:
+ EndTransformDisplayItem();
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_TRANSFORM_DISPLAY_ITEM_H_
diff --git a/cc/resources/transparency_display_item.cc b/cc/resources/transparency_display_item.cc
new file mode 100644
index 0000000..0401d90
--- /dev/null
+++ b/cc/resources/transparency_display_item.cc
@@ -0,0 +1,65 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/transparency_display_item.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+TransparencyDisplayItem::TransparencyDisplayItem(float opacity,
+ SkXfermode::Mode blend_mode)
+ : opacity_(opacity), blend_mode_(blend_mode) {
+}
+
+TransparencyDisplayItem::~TransparencyDisplayItem() {
+}
+
+void TransparencyDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ SkPaint paint;
+ paint.setXfermodeMode(blend_mode_);
+ paint.setAlpha(opacity_ * 255);
+ canvas->saveLayer(NULL, &paint);
+}
+
+bool TransparencyDisplayItem::IsSuitableForGpuRasterization() const {
+ return true;
+}
+
+int TransparencyDisplayItem::ApproximateOpCount() const {
+ return 1;
+}
+
+size_t TransparencyDisplayItem::PictureMemoryUsage() const {
+ return sizeof(float) + sizeof(SkXfermode::Mode);
+}
+
+EndTransparencyDisplayItem::EndTransparencyDisplayItem() {
+}
+
+EndTransparencyDisplayItem::~EndTransparencyDisplayItem() {
+}
+
+void EndTransparencyDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->restore();
+}
+
+bool EndTransparencyDisplayItem::IsSuitableForGpuRasterization() const {
+ return true;
+}
+
+int EndTransparencyDisplayItem::ApproximateOpCount() const {
+ return 0;
+}
+
+size_t EndTransparencyDisplayItem::PictureMemoryUsage() const {
+ return 0;
+}
+
+} // namespace cc
diff --git a/cc/resources/transparency_display_item.h b/cc/resources/transparency_display_item.h
new file mode 100644
index 0000000..6766d91
--- /dev/null
+++ b/cc/resources/transparency_display_item.h
@@ -0,0 +1,64 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_TRANSPARENCY_DISPLAY_ITEM_H_
+#define CC_RESOURCES_TRANSPARENCY_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT TransparencyDisplayItem : public DisplayItem {
+ public:
+ virtual ~TransparencyDisplayItem();
+
+ static scoped_ptr<TransparencyDisplayItem> Create(
+ float opacity,
+ SkXfermode::Mode blend_mode) {
+ return make_scoped_ptr(new TransparencyDisplayItem(opacity, blend_mode));
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+ bool IsSuitableForGpuRasterization() const override;
+ int ApproximateOpCount() const override;
+ size_t PictureMemoryUsage() const override;
+
+ protected:
+ TransparencyDisplayItem(float opacity, SkXfermode::Mode blend_mode);
+
+ private:
+ float opacity_;
+ SkXfermode::Mode blend_mode_;
+};
+
+class CC_EXPORT EndTransparencyDisplayItem : public DisplayItem {
+ public:
+ virtual ~EndTransparencyDisplayItem();
+
+ static scoped_ptr<EndTransparencyDisplayItem> Create() {
+ return make_scoped_ptr(new EndTransparencyDisplayItem());
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+ bool IsSuitableForGpuRasterization() const override;
+ int ApproximateOpCount() const override;
+ size_t PictureMemoryUsage() const override;
+
+ protected:
+ EndTransparencyDisplayItem();
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_TRANSPARENCY_DISPLAY_ITEM_H_
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 7a775d9..2c9a688 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -20,7 +20,6 @@
namespace {
-const ResourceFormat kYUVResourceFormat = LUMINANCE_8;
const ResourceFormat kRGBResourceFormat = RGBA_8888;
class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
@@ -40,6 +39,37 @@
} // namespace
+VideoResourceUpdater::PlaneResource::PlaneResource(
+ unsigned int resource_id,
+ const gfx::Size& resource_size,
+ ResourceFormat resource_format,
+ gpu::Mailbox mailbox)
+ : resource_id(resource_id),
+ resource_size(resource_size),
+ resource_format(resource_format),
+ mailbox(mailbox),
+ frame_ptr(nullptr),
+ plane_index(0) {
+}
+
+bool VideoResourceUpdater::PlaneResourceMatchesUniqueID(
+ const PlaneResource& plane_resource,
+ const media::VideoFrame* video_frame,
+ int plane_index) {
+ return plane_resource.frame_ptr == video_frame &&
+ plane_resource.plane_index == plane_index &&
+ plane_resource.timestamp == video_frame->timestamp();
+}
+
+void VideoResourceUpdater::SetPlaneResourceUniqueId(
+ const media::VideoFrame* video_frame,
+ int plane_index,
+ PlaneResource* plane_resource) {
+ plane_resource->frame_ptr = video_frame;
+ plane_resource->plane_index = plane_index;
+ plane_resource->timestamp = video_frame->timestamp();
+}
+
VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {}
VideoFrameExternalResources::~VideoFrameExternalResources() {}
@@ -104,14 +134,12 @@
// each plane in the frame.
static gfx::Size SoftwarePlaneDimension(
const scoped_refptr<media::VideoFrame>& input_frame,
- ResourceFormat output_resource_format,
+ bool software_compositor,
size_t plane_index) {
- if (output_resource_format == kYUVResourceFormat) {
+ if (!software_compositor) {
return media::VideoFrame::PlaneSize(
input_frame->format(), plane_index, input_frame->coded_size());
}
-
- DCHECK_EQ(output_resource_format, kRGBResourceFormat);
return input_frame->coded_size();
}
@@ -145,7 +173,8 @@
bool software_compositor = context_provider_ == NULL;
- ResourceFormat output_resource_format = kYUVResourceFormat;
+ ResourceFormat output_resource_format =
+ resource_provider_->yuv_resource_format();
size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format);
// TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB
@@ -163,7 +192,7 @@
for (size_t i = 0; i < output_plane_count; ++i) {
gfx::Size output_plane_resource_size =
- SoftwarePlaneDimension(video_frame, output_resource_format, i);
+ SoftwarePlaneDimension(video_frame, software_compositor, i);
if (output_plane_resource_size.IsEmpty() ||
output_plane_resource_size.width() > max_resource_size ||
output_plane_resource_size.height() > max_resource_size) {
@@ -171,57 +200,56 @@
break;
}
- ResourceProvider::ResourceId resource_id = 0;
- gpu::Mailbox mailbox;
-
// Try recycle a previously-allocated resource.
- for (size_t i = 0; i < recycled_resources_.size(); ++i) {
- bool resource_matches =
- recycled_resources_[i].resource_format == output_resource_format &&
- recycled_resources_[i].resource_size == output_plane_resource_size;
- bool not_in_use =
- !software_compositor || !resource_provider_->InUseByConsumer(
- recycled_resources_[i].resource_id);
- if (resource_matches && not_in_use) {
- resource_id = recycled_resources_[i].resource_id;
- mailbox = recycled_resources_[i].mailbox;
- recycled_resources_.erase(recycled_resources_.begin() + i);
- break;
+ auto recycled_it = recycled_resources_.end();
+ for (auto it = recycled_resources_.begin(); it != recycled_resources_.end();
+ ++it) {
+ const bool resource_matches =
+ it->resource_format == output_resource_format &&
+ it->resource_size == output_plane_resource_size;
+ const bool in_use = software_compositor &&
+ resource_provider_->InUseByConsumer(it->resource_id);
+ if (resource_matches && !in_use) {
+ // We found a recycled resource with the allocation size and format we
+ // are looking for.
+ recycled_it = it;
+ // Keep looking for a recycled resource that also contains the data we
+ // are planning to put in it.
+ if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i))
+ break;
}
}
- if (resource_id == 0) {
- // TODO(danakj): Abstract out hw/sw resource create/delete from
- // ResourceProvider and stop using ResourceProvider in this class.
- resource_id = resource_provider_->CreateResource(
- output_plane_resource_size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- output_resource_format);
-
- DCHECK(mailbox.IsZero());
-
- if (!software_compositor) {
- DCHECK(context_provider_);
-
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
-
- GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
- ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
- resource_id);
- GLC(gl,
- gl->ProduceTextureDirectCHROMIUM(
- lock.texture_id(), GL_TEXTURE_2D, mailbox.name));
- }
-
- if (resource_id)
- all_resources_.push_back(resource_id);
+ // Check if we can avoid allocating a new resource.
+ if (recycled_it != recycled_resources_.end()) {
+ plane_resources.push_back(*recycled_it);
+ recycled_resources_.erase(recycled_it);
+ continue;
}
+ // TODO(danakj): Abstract out hw/sw resource create/delete from
+ // ResourceProvider and stop using ResourceProvider in this class.
+ const ResourceProvider::ResourceId resource_id =
+ resource_provider_->CreateResource(
+ output_plane_resource_size, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TextureHintImmutable, output_resource_format);
if (resource_id == 0) {
allocation_success = false;
break;
}
+ all_resources_.push_back(resource_id);
+
+ gpu::Mailbox mailbox;
+ if (!software_compositor) {
+ DCHECK(context_provider_);
+
+ gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+
+ GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
+ ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id);
+ GLC(gl, gl->ProduceTextureDirectCHROMIUM(lock.texture_id(), GL_TEXTURE_2D,
+ mailbox.name));
+ }
DCHECK(software_compositor || !mailbox.IsZero());
plane_resources.push_back(PlaneResource(resource_id,
@@ -243,26 +271,23 @@
DCHECK_EQ(plane_resources[0].resource_format, kRGBResourceFormat);
DCHECK(plane_resources[0].mailbox.IsZero());
- if (!video_renderer_)
- video_renderer_.reset(new media::SkCanvasVideoRenderer);
+ if (!PlaneResourceMatchesUniqueID(plane_resources[0], video_frame.get(),
+ 0)) {
+ // We need to transfer data from |video_frame| to the plane resource.
+ if (!video_renderer_)
+ video_renderer_.reset(new media::SkCanvasVideoRenderer);
- {
ResourceProvider::ScopedWriteLockSoftware lock(
resource_provider_, plane_resources[0].resource_id);
SkCanvas canvas(lock.sk_bitmap());
video_renderer_->Copy(video_frame, &canvas);
+ SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resources[0]);
}
- RecycleResourceData recycle_data = {
- plane_resources[0].resource_id,
- plane_resources[0].resource_size,
- plane_resources[0].resource_format,
- gpu::Mailbox()
- };
external_resources.software_resources.push_back(
plane_resources[0].resource_id);
external_resources.software_release_callback =
- base::Bind(&RecycleResource, AsWeakPtr(), recycle_data);
+ base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[0]);
external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
return external_resources;
@@ -270,32 +295,27 @@
for (size_t i = 0; i < plane_resources.size(); ++i) {
// Update each plane's resource id with its content.
- DCHECK_EQ(plane_resources[i].resource_format, kYUVResourceFormat);
+ DCHECK_EQ(plane_resources[i].resource_format,
+ resource_provider_->yuv_resource_format());
- const uint8_t* input_plane_pixels = video_frame->data(i);
+ if (!PlaneResourceMatchesUniqueID(plane_resources[i], video_frame.get(),
+ i)) {
+ // We need to transfer data from |video_frame| to the plane resource.
+ const uint8_t* input_plane_pixels = video_frame->data(i);
- gfx::Rect image_rect(0,
- 0,
- video_frame->stride(i),
- plane_resources[i].resource_size.height());
- gfx::Rect source_rect(plane_resources[i].resource_size);
- resource_provider_->SetPixels(plane_resources[i].resource_id,
- input_plane_pixels,
- image_rect,
- source_rect,
- gfx::Vector2d());
-
- RecycleResourceData recycle_data = {
- plane_resources[i].resource_id,
- plane_resources[i].resource_size,
- plane_resources[i].resource_format,
- plane_resources[i].mailbox
- };
+ gfx::Rect image_rect(0, 0, video_frame->stride(i),
+ plane_resources[i].resource_size.height());
+ gfx::Rect source_rect(plane_resources[i].resource_size);
+ resource_provider_->SetPixels(plane_resources[i].resource_id,
+ input_plane_pixels, image_rect, source_rect,
+ gfx::Vector2d());
+ SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resources[i]);
+ }
external_resources.mailboxes.push_back(
TextureMailbox(plane_resources[i].mailbox, GL_TEXTURE_2D, 0));
external_resources.release_callbacks.push_back(
- base::Bind(&RecycleResource, AsWeakPtr(), recycle_data));
+ base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[i]));
}
external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
@@ -362,7 +382,7 @@
// static
void VideoResourceUpdater::RecycleResource(
base::WeakPtr<VideoResourceUpdater> updater,
- RecycleResourceData data,
+ PlaneResource data,
uint32 sync_point,
bool lost_resource,
BlockingTaskRunner* main_thread_task_runner) {
@@ -385,16 +405,12 @@
// Drop recycled resources that are the wrong format.
while (!updater->recycled_resources_.empty() &&
updater->recycled_resources_.back().resource_format !=
- data.resource_format) {
+ data.resource_format) {
updater->DeleteResource(updater->recycled_resources_.back().resource_id);
updater->recycled_resources_.pop_back();
}
- PlaneResource recycled_resource(data.resource_id,
- data.resource_size,
- data.resource_format,
- data.mailbox);
- updater->recycled_resources_.push_back(recycled_resource);
+ updater->recycled_resources_.push_back(data);
}
} // namespace cc
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index 99800b4..38f6033 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/resources/release_callback_impl.h"
#include "cc/resources/resource_format.h"
@@ -77,17 +78,28 @@
gfx::Size resource_size;
ResourceFormat resource_format;
gpu::Mailbox mailbox;
+ // These last three members will be used for identifying the data stored in
+ // this resource, and uniquely identifies a media::VideoFrame plane. The
+ // frame pointer will only be used for pointer comparison, i.e. the
+ // underlying data will not be accessed.
+ const void* frame_ptr;
+ int plane_index;
+ base::TimeDelta timestamp;
PlaneResource(unsigned resource_id,
const gfx::Size& resource_size,
ResourceFormat resource_format,
- gpu::Mailbox mailbox)
- : resource_id(resource_id),
- resource_size(resource_size),
- resource_format(resource_format),
- mailbox(mailbox) {}
+ gpu::Mailbox mailbox);
};
+ static bool PlaneResourceMatchesUniqueID(const PlaneResource& plane_resource,
+ const media::VideoFrame* video_frame,
+ int plane_index);
+
+ static void SetPlaneResourceUniqueId(const media::VideoFrame* video_frame,
+ int plane_index,
+ PlaneResource* plane_resource);
+
void DeleteResource(unsigned resource_id);
bool VerifyFrame(const scoped_refptr<media::VideoFrame>& video_frame);
VideoFrameExternalResources CreateForHardwarePlanes(
@@ -95,14 +107,8 @@
VideoFrameExternalResources CreateForSoftwarePlanes(
const scoped_refptr<media::VideoFrame>& video_frame);
- struct RecycleResourceData {
- unsigned resource_id;
- gfx::Size resource_size;
- ResourceFormat resource_format;
- gpu::Mailbox mailbox;
- };
static void RecycleResource(base::WeakPtr<VideoResourceUpdater> updater,
- RecycleResourceData data,
+ PlaneResource data,
uint32 sync_point,
bool lost_resource,
BlockingTaskRunner* main_thread_task_runner);
@@ -117,6 +123,8 @@
scoped_ptr<media::SkCanvasVideoRenderer> video_renderer_;
std::vector<unsigned> all_resources_;
+ // Recycle resources so that we can reduce the number of allocations and
+ // data transfers.
std::vector<PlaneResource> recycled_resources_;
DISALLOW_COPY_AND_ASSIGN(VideoResourceUpdater);
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index c0a4af4..1e3481b 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -17,11 +17,33 @@
namespace cc {
namespace {
+class WebGraphicsContext3DUploadCounter : public TestWebGraphicsContext3D {
+ public:
+ void texSubImage2D(GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const void* pixels) override {
+ ++upload_count_;
+ }
+
+ int UploadCount() { return upload_count_; }
+ void ResetUploadCount() { upload_count_ = 0; }
+
+ private:
+ int upload_count_;
+};
+
class VideoResourceUpdaterTest : public testing::Test {
protected:
VideoResourceUpdaterTest() {
- scoped_ptr<TestWebGraphicsContext3D> context3d =
- TestWebGraphicsContext3D::Create();
+ scoped_ptr<WebGraphicsContext3DUploadCounter> context3d(
+ new WebGraphicsContext3DUploadCounter());
+
context3d_ = context3d.get();
output_surface3d_ =
@@ -60,7 +82,7 @@
base::Closure()); // no_longer_needed_cb
}
- TestWebGraphicsContext3D* context3d_;
+ WebGraphicsContext3DUploadCounter* context3d_;
FakeOutputSurfaceClient client_;
scoped_ptr<FakeOutputSurface> output_surface3d_;
scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
@@ -77,5 +99,52 @@
EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
}
+TEST_F(VideoResourceUpdaterTest, ReuseResource) {
+ VideoResourceUpdater updater(output_surface3d_->context_provider(),
+ resource_provider3d_.get());
+ scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
+ video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
+
+ // Allocate the resources for a YUV video frame.
+ context3d_->ResetUploadCount();
+ VideoFrameExternalResources resources =
+ updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ EXPECT_EQ(size_t(3), resources.mailboxes.size());
+ EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+ // Expect exactly three texture uploads, one for each plane.
+ EXPECT_EQ(3, context3d_->UploadCount());
+
+ const ResourceProvider::ResourceId y_resource =
+ resource_provider3d_->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kYPlane],
+ SingleReleaseCallbackImpl::Create(
+ resources.release_callbacks[media::VideoFrame::kYPlane]));
+ const ResourceProvider::ResourceId u_resource =
+ resource_provider3d_->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kUPlane],
+ SingleReleaseCallbackImpl::Create(
+ resources.release_callbacks[media::VideoFrame::kUPlane]));
+ const ResourceProvider::ResourceId v_resource =
+ resource_provider3d_->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kVPlane],
+ SingleReleaseCallbackImpl::Create(
+ resources.release_callbacks[media::VideoFrame::kVPlane]));
+
+ // Delete the resources.
+ resource_provider3d_->DeleteResource(y_resource);
+ resource_provider3d_->DeleteResource(u_resource);
+ resource_provider3d_->DeleteResource(v_resource);
+
+ // Allocate resources for the same frame.
+ context3d_->ResetUploadCount();
+ resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ EXPECT_EQ(size_t(3), resources.mailboxes.size());
+ EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+ // The data should be reused so expect no texture uploads.
+ EXPECT_EQ(0, context3d_->UploadCount());
+}
+
} // namespace
} // namespace cc
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc
index 5252dcc..89b794e 100644
--- a/cc/scheduler/begin_frame_source.cc
+++ b/cc/scheduler/begin_frame_source.cc
@@ -7,6 +7,7 @@
#include "base/auto_reset.h"
#include "base/debug/trace_event.h"
#include "base/debug/trace_event_argument.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "cc/scheduler/delay_based_time_source.h"
@@ -182,7 +183,7 @@
base::TimeTicks now = Now();
BeginFrameArgs args = BeginFrameArgs::Create(
- now, now + BeginFrameArgs::DefaultInterval(),
+ BEGINFRAME_FROM_HERE, now, now + BeginFrameArgs::DefaultInterval(),
BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
CallOnBeginFrame(args);
}
@@ -242,8 +243,8 @@
base::TimeTicks frame_time,
BeginFrameArgs::BeginFrameArgsType type) {
base::TimeTicks deadline = time_source_->NextTickTime();
- return BeginFrameArgs::Create(frame_time, deadline, time_source_->Interval(),
- type);
+ return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
+ time_source_->Interval(), type);
}
// TimeSourceClient support
diff --git a/cc/scheduler/begin_frame_source_unittest.cc b/cc/scheduler/begin_frame_source_unittest.cc
index 498d10b..0972762 100644
--- a/cc/scheduler/begin_frame_source_unittest.cc
+++ b/cc/scheduler/begin_frame_source_unittest.cc
@@ -15,19 +15,18 @@
#include "testing/gtest/include/gtest/gtest.h"
// Macros to help set up expected calls on the MockBeginFrameObserver.
-#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval) \
- { \
- ::testing::Expectation exp = \
- EXPECT_CALL((obs), \
- OnBeginFrame(CreateBeginFrameArgsForTesting( \
- frame_time, deadline, interval))) \
- .InSequence((obs).sequence); \
+#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval) \
+ { \
+ ::testing::Expectation exp = \
+ EXPECT_CALL((obs), OnBeginFrame(CreateBeginFrameArgsForTesting( \
+ BEGINFRAME_FROM_HERE, frame_time, deadline, \
+ interval))).InSequence((obs).sequence); \
}
#define EXPECT_BEGIN_FRAME_USED(obs, frame_time, deadline, interval) \
{ \
- BeginFrameArgs args = \
- CreateBeginFrameArgsForTesting(frame_time, deadline, interval); \
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting( \
+ BEGINFRAME_FROM_HERE, frame_time, deadline, interval); \
::testing::Expectation exp = \
EXPECT_CALL((obs), OnBeginFrame(args)).InSequence((obs).sequence); \
EXPECT_CALL((obs), LastUsedBeginFrameArgs()) \
@@ -38,15 +37,15 @@
// Macros to send BeginFrameArgs on a FakeBeginFrameSink (and verify resulting
// observer behaviour).
-#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline, \
- interval) \
- { \
- BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs(); \
- BeginFrameArgs new_args = \
- CreateBeginFrameArgsForTesting(frame_time, deadline, interval); \
- ASSERT_FALSE(old_args == new_args); \
- (source).TestOnBeginFrame(new_args); \
- EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs()); \
+#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline, \
+ interval) \
+ { \
+ BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs(); \
+ BeginFrameArgs new_args = CreateBeginFrameArgsForTesting( \
+ BEGINFRAME_FROM_HERE, frame_time, deadline, interval); \
+ ASSERT_FALSE(old_args == new_args); \
+ (source).TestOnBeginFrame(new_args); \
+ EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs()); \
}
// When dropping LastUsedBeginFrameArgs **shouldn't** change.
@@ -99,19 +98,25 @@
MockBeginFrameObserver::kDefaultBeginFrameArgs);
obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
- 100, 200, 300)); // One call to LastUsedBeginFrameArgs
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ BEGINFRAME_FROM_HERE, 100, 200,
+ 300)); // One call to LastUsedBeginFrameArgs
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
- 400, 600, 300)); // Multiple calls to LastUsedBeginFrameArgs
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(400, 600, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(400, 600, 300));
+ BEGINFRAME_FROM_HERE, 400, 600,
+ 300)); // Multiple calls to LastUsedBeginFrameArgs
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
- 700, 900, 300)); // No calls to LastUsedBeginFrameArgs
+ BEGINFRAME_FROM_HERE, 700, 900,
+ 300)); // No calls to LastUsedBeginFrameArgs
}
TEST(MockBeginFrameObserverTest, ExpectOnBeginFrameStatus) {
@@ -125,28 +130,45 @@
MockBeginFrameObserver::kDefaultBeginFrameArgs);
// Used
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(100, 200, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
// Dropped
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(400, 600, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
// Dropped
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(450, 650, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 450, 650, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
// Used
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(700, 900, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(700, 900, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
}
const BeginFrameArgs MockBeginFrameObserver::kDefaultBeginFrameArgs =
- CreateBeginFrameArgsForTesting(-1, -1, -1);
+ CreateBeginFrameArgsForTesting(
+#ifdef NDEBUG
+ nullptr,
+#else
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "MockBeginFrameObserver::kDefaultBeginFrameArgs"),
+#endif
+ -1,
+ -1,
+ -1);
// BeginFrameObserverMixIn testing ---------------------------------------
class MockMinimalBeginFrameObserverMixIn : public BeginFrameObserverMixIn {
@@ -168,25 +190,31 @@
EXPECT_DEATH({ obs.OnBeginFrame(BeginFrameArgs()); }, "");
#endif
- BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(100, 200, 300);
+ BeginFrameArgs args1 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300);
EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args1)).WillOnce(Return(true));
obs.OnBeginFrame(args1);
EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs());
EXPECT_EQ(0, obs.dropped_begin_frame_args());
#ifndef NDEBUG
- EXPECT_DEATH(
- { obs.OnBeginFrame(CreateBeginFrameArgsForTesting(50, 200, 300)); }, "");
+ EXPECT_DEATH({
+ obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 50, 200, 300));
+ },
+ "");
#endif
// Returning false shouldn't update the LastUsedBeginFrameArgs value.
- BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(200, 300, 400);
+ BeginFrameArgs args2 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 200, 300, 400);
EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args2)).WillOnce(Return(false));
obs.OnBeginFrame(args2);
EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs());
EXPECT_EQ(1, obs.dropped_begin_frame_args());
- BeginFrameArgs args3 = CreateBeginFrameArgsForTesting(150, 300, 400);
+ BeginFrameArgs args3 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 150, 300, 400);
EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args3)).WillOnce(Return(true));
obs.OnBeginFrame(args3);
EXPECT_EQ(args3, obs.LastUsedBeginFrameArgs());
@@ -495,7 +523,8 @@
SetNeedsBeginFramesCallsOnBeginFrameWithMissedTick) {
now_src_->SetNowMicroseconds(10010);
EXPECT_CALL((*obs_), OnBeginFrame(CreateBeginFrameArgsForTesting(
- 10000, 20000, 10000, BeginFrameArgs::MISSED)));
+ BEGINFRAME_FROM_HERE, 10000, 20000, 10000,
+ BeginFrameArgs::MISSED)));
source_->SetNeedsBeginFrames(true); // Should cause the last tick to be sent
// No tasks should need to be run for this to occur.
}
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 3e6f6c6..0cce5dc 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -470,20 +470,16 @@
// draining the queue if we don't catch up. If we consistently can't catch
// up, our fallback should be to lower our frame rate.
base::TimeTicks now = Now();
- base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
- while (!begin_retro_frame_args_.empty()) {
- base::TimeTicks adjusted_deadline = AdjustedBeginImplFrameDeadline(
- begin_retro_frame_args_.front(), draw_duration_estimate);
- if (now <= adjusted_deadline)
- break;
- TRACE_EVENT_INSTANT2("cc",
- "Scheduler::BeginRetroFrame discarding",
- TRACE_EVENT_SCOPE_THREAD,
- "deadline - now",
- (adjusted_deadline - now).InMicroseconds(),
- "BeginFrameArgs",
- begin_retro_frame_args_.front().AsValue());
+ while (!begin_retro_frame_args_.empty()) {
+ const BeginFrameArgs& args = begin_retro_frame_args_.front();
+ base::TimeTicks expiration_time = args.frame_time + args.interval;
+ if (now <= expiration_time)
+ break;
+ TRACE_EVENT_INSTANT2(
+ "cc", "Scheduler::BeginRetroFrame discarding", TRACE_EVENT_SCOPE_THREAD,
+ "expiration_time - now", (expiration_time - now).InMillisecondsF(),
+ "BeginFrameArgs", begin_retro_frame_args_.front().AsValue());
begin_retro_frame_args_.pop_front();
frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
}
@@ -564,19 +560,38 @@
ProcessScheduledActions();
state_machine_.OnBeginImplFrameDeadlinePending();
- ScheduleBeginImplFrameDeadline(
- AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
+
+ if (settings_.using_synchronous_renderer_compositor) {
+ // The synchronous renderer compositor has to make its GL calls
+ // within this call.
+ // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
+ // so the synchronous renderer compositor can take advantage of splitting
+ // up the BeginImplFrame and deadline as well.
+ OnBeginImplFrameDeadline();
+ } else {
+ ScheduleBeginImplFrameDeadline(
+ AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
+ }
}
base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline(
const BeginFrameArgs& args,
base::TimeDelta draw_duration_estimate) const {
- if (settings_.using_synchronous_renderer_compositor) {
- // The synchronous compositor needs to draw right away.
+ // The synchronous compositor does not post a deadline task.
+ DCHECK(!settings_.using_synchronous_renderer_compositor);
+ if (settings_.main_thread_should_always_be_low_latency) {
+ // In main thread low latency mode, always start deadline early.
return base::TimeTicks();
} else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
// We are ready to draw a new active tree immediately.
+ // We don't use Now() here because it's somewhat expensive to call.
return base::TimeTicks();
+ } else if (settings_.main_thread_should_always_be_low_latency) {
+ // Post long deadline to keep advancing during idle period. After activation
+ // we will be able to trigger deadline early.
+ // TODO(weiliangc): Don't post deadline once input is deferred with
+ // BeginRetroFrames.
+ return args.frame_time + args.interval;
} else if (state_machine_.needs_redraw()) {
// We have an animation or fast input path on the impl thread that wants
// to draw, so don't wait too long for a new active tree.
@@ -596,15 +611,6 @@
void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
TRACE_EVENT1(
"cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline);
- if (settings_.using_synchronous_renderer_compositor) {
- // The synchronous renderer compositor has to make its GL calls
- // within this call.
- // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
- // so the sychronous renderer compositor can take advantage of splitting
- // up the BeginImplFrame and deadline as well.
- OnBeginImplFrameDeadline();
- return;
- }
begin_impl_frame_deadline_task_.Cancel();
begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
@@ -618,7 +624,6 @@
void Scheduler::OnBeginImplFrameDeadline() {
TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
begin_impl_frame_deadline_task_.Cancel();
-
// We split the deadline actions up into two phases so the state machine
// has a chance to trigger actions that should occur durring and after
// the deadline separately. For example:
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc
index 84f0fcd..53abe7b 100644
--- a/cc/scheduler/scheduler_settings.cc
+++ b/cc/scheduler/scheduler_settings.cc
@@ -19,6 +19,7 @@
using_synchronous_renderer_compositor(false),
throttle_frame_production(true),
disable_hi_res_timer_tasks_on_battery(false),
+ main_thread_should_always_be_low_latency(false),
background_frame_interval(base::TimeDelta::FromSeconds(1)) {
}
@@ -38,6 +39,8 @@
throttle_frame_production(settings.throttle_frame_production),
disable_hi_res_timer_tasks_on_battery(
settings.disable_hi_res_timer_tasks_on_battery),
+ main_thread_should_always_be_low_latency(
+ settings.main_thread_should_always_be_low_latency),
background_frame_interval(base::TimeDelta::FromSecondsD(
1.0 / settings.background_animation_rate)) {
}
@@ -64,6 +67,8 @@
state->SetBoolean("throttle_frame_production", throttle_frame_production);
state->SetBoolean("disable_hi_res_timer_tasks_on_battery",
disable_hi_res_timer_tasks_on_battery);
+ state->SetBoolean("main_thread_should_always_be_low_latency",
+ main_thread_should_always_be_low_latency);
state->SetInteger("background_frame_interval",
background_frame_interval.InMicroseconds());
return state;
diff --git a/cc/scheduler/scheduler_settings.h b/cc/scheduler/scheduler_settings.h
index e3fd425..4ff3c7e 100644
--- a/cc/scheduler/scheduler_settings.h
+++ b/cc/scheduler/scheduler_settings.h
@@ -35,6 +35,12 @@
bool throttle_frame_production;
bool disable_hi_res_timer_tasks_on_battery;
+ // In main thread low latency mode the entire
+ // BeginMainFrame->Commit->Activation->Draw cycle should complete before
+ // starting the next cycle. Additionally, BeginMainFrame and Commit are
+ // completed atomically with no other tasks or actions occuring between them.
+ bool main_thread_should_always_be_low_latency;
+
base::TimeDelta background_frame_interval;
scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 5f56255..2946a2c 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -97,6 +97,8 @@
return "COMMIT_STATE_READY_TO_COMMIT";
case COMMIT_STATE_WAITING_FOR_ACTIVATION:
return "COMMIT_STATE_WAITING_FOR_ACTIVATION";
+ case COMMIT_STATE_WAITING_FOR_DRAW:
+ return "COMMIT_STATE_WAITING_FOR_DRAW";
}
NOTREACHED();
return "???";
@@ -592,9 +594,11 @@
if (commit_was_aborted || settings_.main_frame_before_activation_enabled) {
commit_state_ = COMMIT_STATE_IDLE;
+ } else if (settings_.impl_side_painting) {
+ commit_state_ = COMMIT_STATE_WAITING_FOR_ACTIVATION;
} else {
- commit_state_ = settings_.impl_side_painting
- ? COMMIT_STATE_WAITING_FOR_ACTIVATION
+ commit_state_ = settings_.main_thread_should_always_be_low_latency
+ ? COMMIT_STATE_WAITING_FOR_DRAW
: COMMIT_STATE_IDLE;
}
@@ -637,8 +641,11 @@
}
void SchedulerStateMachine::UpdateStateOnActivation() {
- if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION)
- commit_state_ = COMMIT_STATE_IDLE;
+ if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION) {
+ commit_state_ = settings_.main_thread_should_always_be_low_latency
+ ? COMMIT_STATE_WAITING_FOR_DRAW
+ : COMMIT_STATE_IDLE;
+ }
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
@@ -656,6 +663,9 @@
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
+ if (commit_state_ == COMMIT_STATE_WAITING_FOR_DRAW)
+ commit_state_ = COMMIT_STATE_IDLE;
+
needs_redraw_ = false;
active_tree_needs_first_draw_ = false;
@@ -991,6 +1001,11 @@
DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED)
<< AsValue()->ToString();
commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
+ // In main thread low latency mode, commit should happen right after
+ // BeginFrame, meaning when this function is called, next action should be
+ // commit.
+ if (settings_.main_thread_should_always_be_low_latency)
+ DCHECK(ShouldCommit());
}
void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index c69c959..12f8635 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -68,6 +68,7 @@
COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED,
COMMIT_STATE_READY_TO_COMMIT,
COMMIT_STATE_WAITING_FOR_ACTIVATION,
+ COMMIT_STATE_WAITING_FOR_DRAW,
};
static const char* CommitStateToString(CommitState state);
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index af6d83a..f46389b 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -44,7 +44,8 @@
SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED,
SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION};
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW};
// Exposes the protected state fields of the SchedulerStateMachine for testing
class StateMachine : public SchedulerStateMachine {
@@ -122,7 +123,8 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -140,7 +142,8 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
}
@@ -158,7 +161,8 @@
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -195,7 +199,7 @@
EXPECT_TRUE(state.BeginFrameNeeded());
// Commit to the pending tree.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -211,7 +215,7 @@
// Verify that the next commit starts while there is still a pending tree.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -252,7 +256,7 @@
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -269,7 +273,7 @@
// Failing the draw makes us require a commit.
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -289,7 +293,7 @@
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -303,7 +307,7 @@
// Missing high res content requires a commit (but not a redraw)
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_FALSE(state.RedrawPending());
@@ -323,7 +327,7 @@
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -344,7 +348,7 @@
// Failing the draw for animation checkerboards makes us require a commit.
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -365,7 +369,7 @@
// Start a commit.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -395,7 +399,7 @@
EXPECT_TRUE(state.RedrawPending());
// The redraw should be forced at the end of the next BeginImplFrame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -423,7 +427,7 @@
// Start a commit.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -480,7 +484,7 @@
// Start a draw.
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -497,7 +501,7 @@
// We should not be trying to draw again now, but we have a commit pending.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -523,7 +527,7 @@
// Draw the first frame.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -542,7 +546,7 @@
// Move to another frame. This should now draw.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -680,7 +684,8 @@
state.SetVisible(false);
state.SetNeedsRedraw(true);
if (j == 1)
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
state.SetCanDraw(false);
EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
@@ -702,7 +707,7 @@
state.SetNeedsRedraw(true);
state.SetVisible(true);
state.SetCanDraw(false);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
EXPECT_ACTION_UPDATE_STATE(
@@ -730,7 +735,7 @@
EXPECT_TRUE(state.BeginFrameNeeded());
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
@@ -766,7 +771,7 @@
state.begin_impl_frame_state());
EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
state.begin_impl_frame_state());
EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
@@ -803,7 +808,7 @@
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
@@ -840,6 +845,160 @@
EXPECT_FALSE(state.needs_redraw());
}
+TEST(SchedulerStateMachineTest, TestFullCycleWithMainThreadLowLatencyMode) {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.main_thread_should_always_be_low_latency = true;
+ StateMachine state(scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetVisible(true);
+ state.SetCanDraw(true);
+
+ // Start clean and set commit.
+ state.SetNeedsCommit();
+
+ // Begin the frame.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
+ state.CommitState());
+ EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Tell the scheduler the frame finished.
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
+ state.CommitState());
+
+ // Commit.
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
+ EXPECT_TRUE(state.needs_redraw());
+
+ // Now commit should wait for draw.
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW,
+ state.CommitState());
+
+ // Swap throttled. Do not draw.
+ state.DidSwapBuffers();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.DidSwapBuffersComplete();
+
+ // Haven't draw since last commit, do not begin new main frame.
+ state.SetNeedsCommit();
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // At BeginImplFrame deadline, draw.
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
+
+ // Now will be able to start main frame.
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_FALSE(state.needs_redraw());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
+TEST(SchedulerStateMachineTest,
+ TestFullCycleWithMainThreadLowLatencyMode_ImplSidePaint) {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.main_thread_should_always_be_low_latency = true;
+ scheduler_settings.impl_side_painting = true;
+ StateMachine state(scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetVisible(true);
+ state.SetCanDraw(true);
+
+ // Start clean and set commit.
+ state.SetNeedsCommit();
+
+ // Begin the frame.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
+ state.CommitState());
+ EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Tell the scheduler the frame finished.
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
+ state.CommitState());
+
+ // Commit.
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+
+ // Now commit should wait for activation.
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
+ state.CommitState());
+
+ // No activation yet, so this commit is not drawn yet. Force to draw this
+ // frame, and still block BeginMainFrame.
+ state.SetNeedsRedraw(true);
+ state.SetNeedsCommit();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Cannot BeginMainFrame yet since last commit is not yet activated and drawn.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
+ state.CommitState());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Now activate sync tree.
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
+ EXPECT_TRUE(state.needs_redraw());
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW,
+ state.CommitState());
+
+ // Swap throttled. Do not draw.
+ state.DidSwapBuffers();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.DidSwapBuffersComplete();
+
+ // Haven't draw since last commit, do not begin new main frame.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // At BeginImplFrame deadline, draw. This draws unblocks BeginMainFrame.
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
+
+ // Now will be able to start main frame.
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_FALSE(state.needs_redraw());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
@@ -853,7 +1012,7 @@
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
@@ -894,7 +1053,7 @@
EXPECT_FALSE(state.needs_redraw());
// Next BeginImplFrame should initiate second commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -922,7 +1081,7 @@
state.SetNeedsCommit();
// Begin the frame while visible.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
@@ -952,7 +1111,7 @@
EXPECT_TRUE(state.NeedsCommit());
// Start a new frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -991,7 +1150,7 @@
// Start a new frame; draw because this is the first frame since output
// surface init'd.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -1043,7 +1202,7 @@
// Become visible and start a new frame.
state.SetVisible(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1108,7 +1267,7 @@
EXPECT_TRUE(state.NeedsCommit());
// We should get that commit when we begin the next frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1145,7 +1304,7 @@
EXPECT_TRUE(state.NeedsCommit());
// Begin a frame when not visible, the scheduler animates but does not commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
@@ -1171,14 +1330,14 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Check that the first init does not SetNeedsCommit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Check that a needs commit initiates a BeginMainFrame.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1208,7 +1367,7 @@
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
// When the context is recreated, we should begin a commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1232,14 +1391,14 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Once context recreation begins, nothing should happen.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// While context is recreating, commits shouldn't begin.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1265,7 +1424,7 @@
// Once the context is recreated, whether we draw should be based on
// SetCanDraw.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -1293,7 +1452,7 @@
// Set damage and expect a draw.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1328,7 +1487,7 @@
EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
state.NextAction());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
state.begin_impl_frame_state());
EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
@@ -1360,7 +1519,7 @@
// Set damage and expect a draw.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1395,7 +1554,7 @@
EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
state.NextAction());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
state.begin_impl_frame_state());
EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
@@ -1416,7 +1575,7 @@
// After we get a new output surface, the commit flow should start.
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1452,7 +1611,7 @@
state.DidCreateAndInitializeOutputSurface();
EXPECT_FALSE(state.RedrawPending());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
state.NextAction());
}
@@ -1584,7 +1743,7 @@
// This test mirrors what happens during the first frame of a scroll gesture.
// First we get the input event and a BeginFrame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
// As a response the compositor requests a redraw and a commit to tell the
// main thread about the new scroll offset.
@@ -1619,7 +1778,7 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1644,7 +1803,7 @@
// in prefer impl latency mode.
state.SetNeedsRedraw(true);
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1681,7 +1840,7 @@
// and did not just swap.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
state.OnBeginImplFrameDeadline();
@@ -1699,7 +1858,7 @@
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1726,7 +1885,7 @@
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
state.OnBeginImplFrameDeadlinePending();
@@ -1752,7 +1911,7 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1780,7 +1939,7 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1812,7 +1971,7 @@
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
state.SetNeedsAnimate();
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 636beb0..2992dbc 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -168,19 +168,32 @@
void AdvanceFrame() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
"FakeSchedulerClient::AdvanceFrame");
+ bool previous_deadline_pending =
+ scheduler_->BeginImplFrameDeadlinePending();
if (ExternalBeginFrame()) {
- // Creep the time forward so that any BeginFrameArgs is not equal to the
- // last one otherwise we violate the BeginFrameSource contract.
- now_src_->AdvanceNowMicroseconds(1);
- fake_external_begin_frame_source_->TestOnBeginFrame(
- CreateBeginFrameArgsForTesting(now_src_));
+ SendNextBeginFrame();
+ // This could be the previous deadline or a new one.
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
}
-
+ // Consume previous deadline first. It is important that we check for the
+ // existence of a previous deadline so that we do not consume the new one.
+ if (previous_deadline_pending) {
+ EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(true)));
+ }
+ // Then run tasks until new deadline is scheduled.
EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(false)));
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
}
+ void SendNextBeginFrame() {
+ DCHECK(ExternalBeginFrame());
+ // Creep the time forward so that any BeginFrameArgs is not equal to the
+ // last one otherwise we violate the BeginFrameSource contract.
+ now_src_->AdvanceNow(BeginFrameArgs::DefaultInterval());
+ fake_external_begin_frame_source_->TestOnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src_));
+ }
+
OrderedSimpleTaskRunner& task_runner() { return *task_runner_; }
TestNowSource* now_src() { return now_src_.get(); }
@@ -1167,7 +1180,8 @@
scheduler->NotifyReadyToCommit();
scheduler->SetNeedsRedraw();
- BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src());
+ BeginFrameArgs frame_args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
frame_args.interval = base::TimeDelta::FromMilliseconds(1000);
client.fake_external_begin_frame_source()->TestOnBeginFrame(frame_args);
@@ -1240,7 +1254,8 @@
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
args.deadline += base::TimeDelta::FromHours(1);
client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
@@ -1318,7 +1333,8 @@
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
args.deadline += base::TimeDelta::FromHours(1);
client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
@@ -1387,6 +1403,131 @@
client.Reset();
}
+TEST(SchedulerTest, RetroFrameDoesNotExpireTooEarly) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_TRUE(client.needs_begin_frames());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+
+ client.Reset();
+ client.AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+
+ client.Reset();
+ client.SendNextBeginFrame();
+ // This BeginFrame is queued up as a retro frame.
+ EXPECT_NO_ACTION(client);
+ // The previous deadline is still pending.
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ // This commit should schedule the (previous) deadline to trigger immediately.
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+ client.Reset();
+ // The deadline task should trigger causing a draw.
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+
+ // Keep animating.
+ client.Reset();
+ scheduler->SetNeedsAnimate();
+ scheduler->SetNeedsRedraw();
+ EXPECT_NO_ACTION(client);
+
+ // Let's advance sufficiently past the next frame's deadline.
+ client.now_src()->AdvanceNow(
+ BeginFrameArgs::DefaultInterval() -
+ BeginFrameArgs::DefaultEstimatedParentDrawTime() +
+ base::TimeDelta::FromMicroseconds(1));
+
+ // The retro frame hasn't expired yet.
+ client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(false));
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ // This is an immediate deadline case.
+ client.Reset();
+ client.task_runner().RunPendingTasks();
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client);
+}
+
+TEST(SchedulerTest, RetroFrameDoesNotExpireTooLate) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_TRUE(client.needs_begin_frames());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+
+ client.Reset();
+ client.AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+
+ client.Reset();
+ client.SendNextBeginFrame();
+ // This BeginFrame is queued up as a retro frame.
+ EXPECT_NO_ACTION(client);
+ // The previous deadline is still pending.
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ // This commit should schedule the (previous) deadline to trigger immediately.
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+ client.Reset();
+ // The deadline task should trigger causing a draw.
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+
+ // Keep animating.
+ client.Reset();
+ scheduler->SetNeedsAnimate();
+ scheduler->SetNeedsRedraw();
+ EXPECT_NO_ACTION(client);
+
+ // Let's advance sufficiently past the next frame's deadline.
+ client.now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() +
+ base::TimeDelta::FromMicroseconds(1));
+
+ // The retro frame should've expired.
+ EXPECT_NO_ACTION(client);
+}
+
void BeginFramesNotFromClient(bool use_external_begin_frame_source,
bool throttle_frame_production) {
FakeSchedulerClient client;
@@ -1793,7 +1934,8 @@
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
client.Reset();
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
args.deadline += base::TimeDelta::FromHours(1);
client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
@@ -1852,7 +1994,8 @@
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
client.Reset();
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
args.deadline += base::TimeDelta::FromHours(1);
client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
diff --git a/cc/surfaces/BUILD.gn b/cc/surfaces/BUILD.gn
index a45e786..ea44068 100644
--- a/cc/surfaces/BUILD.gn
+++ b/cc/surfaces/BUILD.gn
@@ -2,6 +2,14 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+source_set("surface_id") {
+ sources = [
+ "surface_id.h",
+ ]
+
+ deps = [ "//base" ]
+}
+
component("surfaces") {
output_name = "cc_surfaces"
sources = [
@@ -15,7 +23,6 @@
"surface_factory.cc",
"surface_factory.h",
"surface_factory_client.h",
- "surface_id.h",
"surface_id_allocator.cc",
"surface_id_allocator.h",
"surface_manager.cc",
@@ -28,6 +35,7 @@
defines = [ "CC_SURFACES_IMPLEMENTATION=1" ]
deps = [
+ ":surface_id",
"//base",
"//base/third_party/dynamic_annotations",
"//cc",
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index a8ae27a..9257446 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -49,15 +49,23 @@
return output_surface_->BindToClient(this);
}
-void Display::Resize(SurfaceId id,
- const gfx::Size& size,
- float device_scale_factor) {
+void Display::SetSurfaceId(SurfaceId id, float device_scale_factor) {
current_surface_id_ = id;
- current_surface_size_ = size;
device_scale_factor_ = device_scale_factor;
client_->DisplayDamaged();
}
+void Display::Resize(const gfx::Size& size) {
+ if (size == current_surface_size_)
+ return;
+ // Need to ensure all pending swaps have executed before the window is
+ // resized, or D3D11 will scale the swap output.
+ if (renderer_ && settings_.finish_rendering_on_resize)
+ renderer_->Finish();
+ current_surface_size_ = size;
+ client_->DisplayDamaged();
+}
+
void Display::InitializeRenderer() {
if (resource_provider_)
return;
@@ -112,6 +120,9 @@
benchmark_instrumentation::IssueDisplayRenderingStatsEvent();
DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
+ gfx::Size surface_size =
+ frame_data->render_pass_list.back()->output_rect.size();
+
gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_);
gfx::Rect device_clip_rect = device_viewport_rect;
bool disable_picture_quad_image_filtering = false;
@@ -122,7 +133,14 @@
device_viewport_rect,
device_clip_rect,
disable_picture_quad_image_filtering);
- renderer_->SwapBuffers(frame->metadata);
+
+ bool disable_swap = surface_size != current_surface_size_;
+ if (disable_swap) {
+ DidSwapBuffers();
+ } else {
+ renderer_->SwapBuffers(frame->metadata);
+ }
+
for (SurfaceAggregator::SurfaceIndexMap::iterator it =
aggregator_->previous_contained_surfaces().begin();
it != aggregator_->previous_contained_surfaces().end();
@@ -131,6 +149,8 @@
if (surface)
surface->RunDrawCallbacks();
}
+ if (disable_swap)
+ DidSwapBuffersComplete();
return true;
}
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index a0bb62a..47c55bb 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -51,9 +51,8 @@
// device_scale_factor is used to communicate to the external window system
// what scale this was rendered at.
- void Resize(SurfaceId id,
- const gfx::Size& new_size,
- float device_scale_factor);
+ void SetSurfaceId(SurfaceId id, float device_scale_factor);
+ void Resize(const gfx::Size& new_size);
bool Draw();
SurfaceId CurrentSurfaceId();
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index 600455f..c7b1145 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -18,9 +18,8 @@
// completely damaged the first time they're drawn from.
static const int kFrameIndexStart = 2;
-Surface::Surface(SurfaceId id, const gfx::Size& size, SurfaceFactory* factory)
+Surface::Surface(SurfaceId id, SurfaceFactory* factory)
: surface_id_(id),
- size_(size),
factory_(factory->AsWeakPtr()),
frame_index_(kFrameIndexStart) {
}
diff --git a/cc/surfaces/surface.h b/cc/surfaces/surface.h
index 7b3fbc1..ed0061d 100644
--- a/cc/surfaces/surface.h
+++ b/cc/surfaces/surface.h
@@ -34,10 +34,9 @@
class CC_SURFACES_EXPORT Surface {
public:
- Surface(SurfaceId id, const gfx::Size& size, SurfaceFactory* factory);
+ Surface(SurfaceId id, SurfaceFactory* factory);
~Surface();
- const gfx::Size& size() const { return size_; }
SurfaceId surface_id() const { return surface_id_; }
void QueueFrame(scoped_ptr<CompositorFrame> frame,
@@ -74,7 +73,6 @@
void ClearCopyRequests();
SurfaceId surface_id_;
- gfx::Size size_;
base::WeakPtr<SurfaceFactory> factory_;
// TODO(jamesr): Support multiple frames in flight.
scoped_ptr<CompositorFrame> current_frame_;
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc
index f5689c5..2334d14 100644
--- a/cc/surfaces/surface_aggregator.cc
+++ b/cc/surfaces/surface_aggregator.cc
@@ -153,13 +153,14 @@
}
gfx::Rect SurfaceAggregator::DamageRectForSurface(const Surface* surface,
- const RenderPass& source) {
+ const RenderPass& source,
+ const gfx::Rect& full_rect) {
int previous_index = previous_contained_surfaces_[surface->surface_id()];
if (previous_index == surface->frame_index())
return gfx::Rect();
else if (previous_index == surface->frame_index() - 1)
return source.damage_rect;
- return gfx::Rect(surface->size());
+ return full_rect;
}
void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
@@ -267,7 +268,8 @@
gfx::UnionRects(dest_pass->damage_rect,
MathUtil::MapEnclosingClippedRect(
surface_quad->quadTransform(),
- DamageRectForSurface(surface, last_pass)));
+ DamageRectForSurface(surface, last_pass,
+ surface_quad->visible_rect)));
referenced_surfaces_.erase(it);
}
@@ -364,9 +366,8 @@
RenderPassId remapped_pass_id =
RemapPassId(source.id, surface->surface_id());
- copy_pass->SetAll(remapped_pass_id,
- source.output_rect,
- DamageRectForSurface(surface, source),
+ copy_pass->SetAll(remapped_pass_id, source.output_rect,
+ DamageRectForSurface(surface, source, source.output_rect),
source.transform_to_root_target,
source.has_transparent_background);
@@ -415,6 +416,9 @@
referenced_surfaces_.erase(it);
DCHECK(referenced_surfaces_.empty());
+ if (dest_pass_list_->empty())
+ return nullptr;
+
dest_pass_list_ = NULL;
RemoveUnreferencedChildren();
contained_surfaces_.swap(previous_contained_surfaces_);
diff --git a/cc/surfaces/surface_aggregator.h b/cc/surfaces/surface_aggregator.h
index 6965041..1e68643 100644
--- a/cc/surfaces/surface_aggregator.h
+++ b/cc/surfaces/surface_aggregator.h
@@ -63,7 +63,8 @@
RenderPassList* render_pass_list);
int ChildIdForSurface(Surface* surface);
gfx::Rect DamageRectForSurface(const Surface* surface,
- const RenderPass& source);
+ const RenderPass& source,
+ const gfx::Rect& full_rect);
SurfaceManager* manager_;
ResourceProvider* provider_;
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index 2e47708..1daff52 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -59,7 +59,7 @@
TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) {
SurfaceId one_id(7);
- factory_.Create(one_id, SurfaceSize());
+ factory_.Create(one_id);
scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(one_id);
EXPECT_FALSE(frame);
factory_.Destroy(one_id);
@@ -72,7 +72,7 @@
virtual void SetUp() {
SurfaceAggregatorTest::SetUp();
root_surface_id_ = allocator_.GenerateId();
- factory_.Create(root_surface_id_, SurfaceSize());
+ factory_.Create(root_surface_id_);
}
virtual void TearDown() {
@@ -157,7 +157,7 @@
TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) {
SurfaceId embedded_surface_id = allocator_.GenerateId();
- factory_.Create(embedded_surface_id, SurfaceSize());
+ factory_.Create(embedded_surface_id);
test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
test::Pass embedded_passes[] = {
@@ -190,9 +190,9 @@
TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCombinedWithNesting) {
SurfaceId surface_id1 = allocator_.GenerateId();
- factory_.Create(surface_id1, SurfaceSize());
+ factory_.Create(surface_id1);
SurfaceId surface_id2 = allocator_.GenerateId();
- factory_.Create(surface_id2, SurfaceSize());
+ factory_.Create(surface_id2);
// |surface_id1| is color quad.
{
@@ -258,7 +258,7 @@
// color quad should be aggregated into the final frame.
TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
SurfaceId embedded_surface_id = allocator_.GenerateId();
- factory_.Create(embedded_surface_id, SurfaceSize());
+ factory_.Create(embedded_surface_id);
test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
test::Pass embedded_passes[] = {
@@ -287,7 +287,7 @@
TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
SurfaceId embedded_surface_id = allocator_.GenerateId();
- factory_.Create(embedded_surface_id, SurfaceSize());
+ factory_.Create(embedded_surface_id);
test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
test::Pass embedded_passes[] = {
@@ -344,7 +344,7 @@
// Root surface may contain copy requests.
TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
SurfaceId embedded_surface_id = allocator_.GenerateId();
- factory_.Create(embedded_surface_id, SurfaceSize());
+ factory_.Create(embedded_surface_id);
test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
test::Pass embedded_passes[] = {
@@ -432,7 +432,7 @@
// This tests referencing a surface that has multiple render passes.
TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) {
SurfaceId embedded_surface_id = child_allocator_.GenerateId();
- factory_.Create(embedded_surface_id, SurfaceSize());
+ factory_.Create(embedded_surface_id);
RenderPassId pass_ids[] = {RenderPassId(1, 1), RenderPassId(1, 2),
RenderPassId(1, 3)};
@@ -590,7 +590,7 @@
// should also just be dropped.
TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) {
SurfaceId surface_with_no_frame_id = allocator_.GenerateId();
- factory_.Create(surface_with_no_frame_id, gfx::Size(5, 5));
+ factory_.Create(surface_with_no_frame_id);
test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
test::Quad::SurfaceQuad(surface_with_no_frame_id, 1.f),
test::Quad::SolidColorQuad(SK_ColorBLUE)};
@@ -628,7 +628,7 @@
// Tests a more complex cycle with one intermediate surface.
TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) {
SurfaceId child_surface_id = allocator_.GenerateId();
- factory_.Create(child_surface_id, SurfaceSize());
+ factory_.Create(child_surface_id);
test::Quad parent_quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE),
test::Quad::SurfaceQuad(child_surface_id, 1.f),
@@ -667,7 +667,7 @@
// namespace and update RenderPassDrawQuad's id references to match.
TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) {
SurfaceId child_surface_id = allocator_.GenerateId();
- factory_.Create(child_surface_id, SurfaceSize());
+ factory_.Create(child_surface_id);
RenderPassId child_pass_id[] = {RenderPassId(1, 1), RenderPassId(1, 2)};
test::Quad child_quad[][1] = {{test::Quad::SolidColorQuad(SK_ColorGREEN)},
@@ -795,7 +795,7 @@
RenderPassId pass_id(1, 1);
SurfaceId grandchild_surface_id = allocator_.GenerateId();
- factory_.Create(grandchild_surface_id, SurfaceSize());
+ factory_.Create(grandchild_surface_id);
scoped_ptr<RenderPass> grandchild_pass = RenderPass::Create();
gfx::Rect output_rect(SurfaceSize());
gfx::Rect damage_rect(SurfaceSize());
@@ -807,7 +807,7 @@
QueuePassAsFrame(grandchild_pass.Pass(), grandchild_surface_id);
SurfaceId child_one_surface_id = allocator_.GenerateId();
- factory_.Create(child_one_surface_id, SurfaceSize());
+ factory_.Create(child_one_surface_id);
scoped_ptr<RenderPass> child_one_pass = RenderPass::Create();
child_one_pass->SetNew(
@@ -825,7 +825,7 @@
QueuePassAsFrame(child_one_pass.Pass(), child_one_surface_id);
SurfaceId child_two_surface_id = allocator_.GenerateId();
- factory_.Create(child_two_surface_id, SurfaceSize());
+ factory_.Create(child_two_surface_id);
scoped_ptr<RenderPass> child_two_pass = RenderPass::Create();
child_two_pass->SetNew(
@@ -903,7 +903,7 @@
// affected.
TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
SurfaceId child_surface_id = allocator_.GenerateId();
- factory_.Create(child_surface_id, SurfaceSize());
+ factory_.Create(child_surface_id);
RenderPassId child_pass_id[] = {RenderPassId(1, 1), RenderPassId(1, 2)};
test::Quad child_quads[][1] = {
{test::Quad::SolidColorQuad(SK_ColorGREEN)},
@@ -1038,7 +1038,7 @@
// Tests that damage rects are aggregated correctly when surfaces change.
TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
SurfaceId child_surface_id = allocator_.GenerateId();
- factory_.Create(child_surface_id, SurfaceSize());
+ factory_.Create(child_surface_id);
RenderPassId child_pass_id = RenderPassId(1, 1);
test::Quad child_quads[] = {test::Quad::RenderPassQuad(child_pass_id)};
test::Pass child_passes[] = {
@@ -1300,7 +1300,7 @@
ResourceTrackingSurfaceFactoryClient client;
SurfaceFactory factory(&manager_, &client);
SurfaceId surface_id(7u);
- factory.Create(surface_id, SurfaceSize());
+ factory.Create(surface_id);
ResourceProvider::ResourceId ids[] = {11, 12, 13};
SubmitFrameWithResources(ids, arraysize(ids), &factory, surface_id);
@@ -1328,9 +1328,9 @@
ResourceTrackingSurfaceFactoryClient client;
SurfaceFactory factory(&manager_, &client);
SurfaceId surface_id(7u);
- factory.Create(surface_id, SurfaceSize());
+ factory.Create(surface_id);
SurfaceId surface_id2(8u);
- factory.Create(surface_id2, SurfaceSize());
+ factory.Create(surface_id2);
ResourceProvider::ResourceId ids[] = {11, 12, 13};
SubmitFrameWithResources(ids, arraysize(ids), &factory, surface_id);
diff --git a/cc/surfaces/surface_factory.cc b/cc/surfaces/surface_factory.cc
index 574f5d1..fd5a6d4 100644
--- a/cc/surfaces/surface_factory.cc
+++ b/cc/surfaces/surface_factory.cc
@@ -30,8 +30,8 @@
surface_map_.clear();
}
-void SurfaceFactory::Create(SurfaceId surface_id, const gfx::Size& size) {
- scoped_ptr<Surface> surface(new Surface(surface_id, size, this));
+void SurfaceFactory::Create(SurfaceId surface_id) {
+ scoped_ptr<Surface> surface(new Surface(surface_id, this));
manager_->RegisterSurface(surface.get());
DCHECK(!surface_map_.count(surface_id));
surface_map_.add(surface_id, surface.Pass());
diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h
index 8e9211c..eba32d2 100644
--- a/cc/surfaces/surface_factory.h
+++ b/cc/surfaces/surface_factory.h
@@ -38,7 +38,7 @@
SurfaceFactory(SurfaceManager* manager, SurfaceFactoryClient* client);
~SurfaceFactory();
- void Create(SurfaceId surface_id, const gfx::Size& size);
+ void Create(SurfaceId surface_id);
void Destroy(SurfaceId surface_id);
void DestroyAll();
// A frame can only be submitted to a surface created by this factory,
diff --git a/cc/surfaces/surface_factory_unittest.cc b/cc/surfaces/surface_factory_unittest.cc
index 14a25fd..84dcc5e 100644
--- a/cc/surfaces/surface_factory_unittest.cc
+++ b/cc/surfaces/surface_factory_unittest.cc
@@ -39,7 +39,7 @@
class SurfaceFactoryTest : public testing::Test {
public:
SurfaceFactoryTest() : factory_(&manager_, &client_), surface_id_(3) {
- factory_.Create(surface_id_, gfx::Size(5, 5));
+ factory_.Create(surface_id_);
}
virtual ~SurfaceFactoryTest() {
@@ -361,7 +361,7 @@
// Tests doing a DestroyAll before shutting down the factory;
TEST_F(SurfaceFactoryTest, DestroyAll) {
SurfaceId id(7);
- factory_.Create(id, gfx::Size(1, 1));
+ factory_.Create(id);
scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
TransferableResource resource;
@@ -378,7 +378,7 @@
TEST_F(SurfaceFactoryTest, DestroySequence) {
SurfaceId id2(5);
- factory_.Create(id2, gfx::Size(5, 5));
+ factory_.Create(id2);
// Check that waiting before the sequence is satisfied works.
manager_.GetSurfaceForId(id2)
@@ -395,7 +395,7 @@
DCHECK(!manager_.GetSurfaceForId(id2));
// Check that waiting after the sequence is satisfied works.
- factory_.Create(id2, gfx::Size(5, 5));
+ factory_.Create(id2);
DCHECK(manager_.GetSurfaceForId(id2));
manager_.GetSurfaceForId(id2)
->AddDestructionDependency(SurfaceSequence(0, 6));
diff --git a/cc/surfaces/surface_unittest.cc b/cc/surfaces/surface_unittest.cc
index b8990c5..7f2de36 100644
--- a/cc/surfaces/surface_unittest.cc
+++ b/cc/surfaces/surface_unittest.cc
@@ -17,7 +17,7 @@
SurfaceId surface_id(6);
{
- factory.Create(surface_id, gfx::Size(5, 5));
+ factory.Create(surface_id);
EXPECT_TRUE(!!manager.GetSurfaceForId(surface_id));
factory.Destroy(surface_id);
}
diff --git a/cc/surfaces/surfaces_pixeltest.cc b/cc/surfaces/surfaces_pixeltest.cc
index c70028b..bf9d483 100644
--- a/cc/surfaces/surfaces_pixeltest.cc
+++ b/cc/surfaces/surfaces_pixeltest.cc
@@ -85,7 +85,7 @@
root_frame->delegated_frame_data = delegated_frame_data.Pass();
SurfaceId root_surface_id = allocator_.GenerateId();
- factory_.Create(root_surface_id, device_viewport_size_);
+ factory_.Create(root_surface_id);
factory_.SubmitFrame(root_surface_id, root_frame.Pass(), base::Closure());
SurfaceAggregator aggregator(&manager_, resource_provider_.get());
@@ -107,8 +107,8 @@
gfx::Size child_size(200, 100);
SurfaceId child_surface_id = allocator_.GenerateId();
SurfaceId root_surface_id = allocator_.GenerateId();
- factory_.Create(child_surface_id, child_size);
- factory_.Create(root_surface_id, device_viewport_size_);
+ factory_.Create(child_surface_id);
+ factory_.Create(root_surface_id);
{
gfx::Rect rect(device_viewport_size_);
RenderPassId id(1, 1);
@@ -199,9 +199,9 @@
SurfaceId left_child_id = allocator_.GenerateId();
SurfaceId right_child_id = allocator_.GenerateId();
SurfaceId root_surface_id = allocator_.GenerateId();
- factory_.Create(left_child_id, child_size);
- factory_.Create(right_child_id, child_size);
- factory_.Create(root_surface_id, device_viewport_size_);
+ factory_.Create(left_child_id);
+ factory_.Create(right_child_id);
+ factory_.Create(root_surface_id);
{
gfx::Rect rect(device_viewport_size_);
diff --git a/cc/test/begin_frame_args_test.cc b/cc/test/begin_frame_args_test.cc
index f70d0c5..7b29748 100644
--- a/cc/test/begin_frame_args_test.cc
+++ b/cc/test/begin_frame_args_test.cc
@@ -10,57 +10,67 @@
namespace cc {
-BeginFrameArgs CreateBeginFrameArgsForTesting() {
- return CreateBeginFrameArgsForTesting(gfx::FrameTime::Now());
-}
-
-BeginFrameArgs CreateBeginFrameArgsForTesting(base::TimeTicks frame_time) {
- return BeginFrameArgs::Create(
- frame_time, frame_time + (BeginFrameArgs::DefaultInterval() / 2),
- BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
-}
-
-BeginFrameArgs CreateBeginFrameArgsForTesting(int64 frame_time,
- int64 deadline,
- int64 interval) {
- return BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(frame_time),
- base::TimeTicks::FromInternalValue(deadline),
- base::TimeDelta::FromInternalValue(interval),
- BeginFrameArgs::NORMAL);
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location) {
+ return CreateBeginFrameArgsForTesting(location, gfx::FrameTime::Now());
}
BeginFrameArgs CreateBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location,
+ base::TimeTicks frame_time) {
+ return BeginFrameArgs::Create(
+ location, frame_time,
+ frame_time + (BeginFrameArgs::DefaultInterval() / 2),
+ BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
+}
+
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location,
+ int64 frame_time,
+ int64 deadline,
+ int64 interval) {
+ return BeginFrameArgs::Create(
+ location, base::TimeTicks::FromInternalValue(frame_time),
+ base::TimeTicks::FromInternalValue(deadline),
+ base::TimeDelta::FromInternalValue(interval), BeginFrameArgs::NORMAL);
+}
+
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location,
int64 frame_time,
int64 deadline,
int64 interval,
BeginFrameArgs::BeginFrameArgsType type) {
- return BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(frame_time),
- base::TimeTicks::FromInternalValue(deadline),
- base::TimeDelta::FromInternalValue(interval),
- type);
+ return BeginFrameArgs::Create(
+ location, base::TimeTicks::FromInternalValue(frame_time),
+ base::TimeTicks::FromInternalValue(deadline),
+ base::TimeDelta::FromInternalValue(interval), type);
}
-BeginFrameArgs CreateExpiredBeginFrameArgsForTesting() {
+BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location) {
base::TimeTicks now = gfx::FrameTime::Now();
- return BeginFrameArgs::Create(now, now - BeginFrameArgs::DefaultInterval(),
- BeginFrameArgs::DefaultInterval(),
- BeginFrameArgs::NORMAL);
+ return BeginFrameArgs::Create(
+ location, now, now - BeginFrameArgs::DefaultInterval(),
+ BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
}
BeginFrameArgs CreateBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location,
scoped_refptr<TestNowSource> now_src) {
base::TimeTicks now = now_src->Now();
return BeginFrameArgs::Create(
- now, now + (BeginFrameArgs::DefaultInterval() / 2),
+ location, now, now + (BeginFrameArgs::DefaultInterval() / 2),
BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
}
BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location,
scoped_refptr<TestNowSource> now_src) {
base::TimeTicks now = now_src->Now();
- return BeginFrameArgs::Create(now, now - BeginFrameArgs::DefaultInterval(),
- BeginFrameArgs::DefaultInterval(),
- BeginFrameArgs::NORMAL);
+ return BeginFrameArgs::Create(
+ location, now, now - BeginFrameArgs::DefaultInterval(),
+ BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
}
bool operator==(const BeginFrameArgs& lhs, const BeginFrameArgs& rhs) {
diff --git a/cc/test/begin_frame_args_test.h b/cc/test/begin_frame_args_test.h
index ca4aa45..73aaf02 100644
--- a/cc/test/begin_frame_args_test.h
+++ b/cc/test/begin_frame_args_test.h
@@ -15,23 +15,32 @@
namespace cc {
// Functions for quickly creating BeginFrameArgs
-BeginFrameArgs CreateBeginFrameArgsForTesting();
-BeginFrameArgs CreateBeginFrameArgsForTesting(base::TimeTicks frame_time);
-BeginFrameArgs CreateBeginFrameArgsForTesting(int64 frame_time,
- int64 deadline,
- int64 interval);
BeginFrameArgs CreateBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location);
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location,
+ base::TimeTicks frame_time);
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location,
+ int64 frame_time,
+ int64 deadline,
+ int64 interval);
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location,
int64 frame_time,
int64 deadline,
int64 interval,
BeginFrameArgs::BeginFrameArgsType type);
-BeginFrameArgs CreateExpiredBeginFrameArgsForTesting();
+BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location);
// Creates a BeginFrameArgs using the fake Now value stored on the
// OrderSimpleTaskRunner.
BeginFrameArgs CreateBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location,
scoped_refptr<TestNowSource> now_src);
BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(
+ BeginFrameArgs::CreationLocation location,
scoped_refptr<TestNowSource> now_src);
// gtest helpers -- these *must* be in the same namespace as the types they
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc
index 5463aed..46d1baa 100644
--- a/cc/test/fake_content_layer_client.cc
+++ b/cc/test/fake_content_layer_client.cc
@@ -4,7 +4,10 @@
#include "cc/test/fake_content_layer_client.h"
+#include "cc/resources/clip_display_item.h"
+#include "cc/resources/drawing_display_item.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "ui/gfx/skia_util.h"
namespace cc {
@@ -52,6 +55,58 @@
}
}
+scoped_refptr<DisplayItemList>
+FakeContentLayerClient::PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) {
+ SkPictureRecorder recorder;
+ skia::RefPtr<SkCanvas> canvas;
+ skia::RefPtr<SkPicture> picture;
+ scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+ list->AppendItem(ClipDisplayItem::Create(clip, std::vector<SkRRect>()));
+
+ for (RectPaintVector::const_iterator it = draw_rects_.begin();
+ it != draw_rects_.end(); ++it) {
+ const gfx::RectF& draw_rect = it->first;
+ const SkPaint& paint = it->second;
+ canvas = skia::SharePtr(
+ recorder.beginRecording(draw_rect.width(), draw_rect.height()));
+ canvas->drawRectCoords(0.f, 0.f, draw_rect.width(), draw_rect.height(),
+ paint);
+ picture = skia::AdoptRef(recorder.endRecording());
+ list->AppendItem(DrawingDisplayItem::Create(
+ picture, gfx::PointF(draw_rect.x(), draw_rect.y())));
+ }
+
+ for (BitmapVector::const_iterator it = draw_bitmaps_.begin();
+ it != draw_bitmaps_.end(); ++it) {
+ canvas = skia::SharePtr(
+ recorder.beginRecording(it->bitmap.width(), it->bitmap.height()));
+ canvas->drawBitmap(it->bitmap, 0.f, 0.f, &it->paint);
+ picture = skia::AdoptRef(recorder.endRecording());
+ list->AppendItem(DrawingDisplayItem::Create(
+ picture, gfx::PointF(it->point.x(), it->point.y())));
+ }
+
+ if (fill_with_nonsolid_color_) {
+ gfx::RectF draw_rect = clip;
+ bool red = true;
+ while (!draw_rect.IsEmpty()) {
+ SkPaint paint;
+ paint.setColor(red ? SK_ColorRED : SK_ColorBLUE);
+ canvas =
+ skia::SharePtr(recorder.beginRecording(clip.width(), clip.height()));
+ canvas->drawRect(gfx::RectFToSkRect(draw_rect), paint);
+ picture = skia::AdoptRef(recorder.endRecording());
+ list->AppendItem(DrawingDisplayItem::Create(picture, gfx::PointF()));
+ draw_rect.Inset(1, 1);
+ }
+ }
+
+ list->AppendItem(EndClipDisplayItem::Create());
+ return list;
+}
+
bool FakeContentLayerClient::FillsBoundsCompletely() const { return false; }
} // namespace cc
diff --git a/cc/test/fake_content_layer_client.h b/cc/test/fake_content_layer_client.h
index 141bc97..1060d08 100644
--- a/cc/test/fake_content_layer_client.h
+++ b/cc/test/fake_content_layer_client.h
@@ -31,6 +31,9 @@
SkCanvas* canvas,
const gfx::Rect& rect,
ContentLayerClient::GraphicsContextStatus gc_status) override;
+ scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) override;
bool FillsBoundsCompletely() const override;
void set_fill_with_nonsolid_color(bool nonsolid) {
diff --git a/cc/test/fake_layer_tree_host_impl.cc b/cc/test/fake_layer_tree_host_impl.cc
index ea19e14..305b856 100644
--- a/cc/test/fake_layer_tree_host_impl.cc
+++ b/cc/test/fake_layer_tree_host_impl.cc
@@ -24,7 +24,8 @@
// Avoid using Now() as the frame time in unit tests.
base::TimeTicks time_ticks = base::TimeTicks::FromInternalValue(1);
- SetCurrentBeginFrameArgs(CreateBeginFrameArgsForTesting(time_ticks));
+ SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
}
FakeLayerTreeHostImpl::FakeLayerTreeHostImpl(const LayerTreeSettings& settings,
@@ -42,7 +43,8 @@
// Avoid using Now() as the frame time in unit tests.
base::TimeTicks time_ticks = base::TimeTicks::FromInternalValue(1);
- SetCurrentBeginFrameArgs(CreateBeginFrameArgsForTesting(time_ticks));
+ SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
}
FakeLayerTreeHostImpl::~FakeLayerTreeHostImpl() {}
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index 9bd75ac..1839643 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -159,7 +159,7 @@
case ZERO_COPY_RASTER_WORKER_POOL:
EXPECT_TRUE(context_provider);
EXPECT_EQ(PIXEL_TEST_GL, test_type_);
- EXPECT_TRUE(host_impl->CanUseZeroCopyRasterizer());
+ EXPECT_TRUE(host_impl->GetRendererCapabilities().using_image);
*resource_pool =
ResourcePool::Create(resource_provider,
draw_texture_target_,
@@ -173,7 +173,7 @@
case ONE_COPY_RASTER_WORKER_POOL:
EXPECT_TRUE(context_provider);
EXPECT_EQ(PIXEL_TEST_GL, test_type_);
- EXPECT_TRUE(host_impl->CanUseOneCopyRasterizer());
+ EXPECT_TRUE(host_impl->GetRendererCapabilities().using_image);
// We need to create a staging resource pool when using copy rasterizer.
*staging_resource_pool =
ResourcePool::Create(resource_provider,
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 80e9f11..9f08677 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -91,7 +91,7 @@
void TestOnBeginFrame() {
DCHECK(CalledOnValidThread());
- CallOnBeginFrame(CreateBeginFrameArgsForTesting());
+ CallOnBeginFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
}
private:
@@ -153,6 +153,11 @@
test_hooks_->ScheduledActionBeginOutputSurfaceCreation();
}
+ void ScheduledActionManageTiles() override {
+ ThreadProxy::ScheduledActionManageTiles();
+ test_hooks_->ScheduledActionManageTiles();
+ }
+
ThreadProxyForTest(
TestHooks* test_hooks,
LayerTreeHost* host,
@@ -780,6 +785,11 @@
RunTest(true, false, true);
}
+void LayerTreeTest::RunTestWithMainThreadLowLatency() {
+ settings_.main_thread_should_always_be_low_latency = true;
+ RunTest(false, false, false);
+}
+
void LayerTreeTest::RequestNewOutputSurface(bool fallback) {
layer_tree_host_->SetOutputSurface(CreateOutputSurface(fallback));
}
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 2914cfc..ba2ef69 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -98,6 +98,7 @@
virtual void ScheduledActionAnimate() {}
virtual void ScheduledActionCommit() {}
virtual void ScheduledActionBeginOutputSurfaceCreation() {}
+ virtual void ScheduledActionManageTiles() {}
// Implementation of AnimationDelegate:
void NotifyAnimationStarted(base::TimeTicks monotonic_time,
@@ -175,6 +176,7 @@
bool delegating_renderer,
bool impl_side_painting);
virtual void RunTestWithImplSidePainting();
+ virtual void RunTestWithMainThreadLowLatency();
bool HasImplThread() { return proxy() ? proxy()->HasImplThread() : false; }
base::SingleThreadTaskRunner* ImplThreadTaskRunner() {
@@ -235,7 +237,18 @@
} // namespace cc
+#define SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_MAIN_THREAD_LOW_LATENCY_TEST_F( \
+ TEST_FIXTURE_NAME) \
+ TEST_F( \
+ TEST_FIXTURE_NAME, \
+ RunSingleThread_DirectRenderer_MainThreadPaint_MainThreadLowLatency) { \
+ RunTestWithMainThreadLowLatency(); \
+ } \
+ class SingleThreadDirectNoImplLowLatencyNeedsSemicolon##TEST_FIXTURE_NAME {}
+
#define SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME) \
+ SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_MAIN_THREAD_LOW_LATENCY_TEST_F( \
+ TEST_FIXTURE_NAME); \
TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DirectRenderer_MainThreadPaint) { \
RunTest(false, false, false); \
} \
diff --git a/cc/test/skia_common.cc b/cc/test/skia_common.cc
index 1ccb2d1..ef61e21 100644
--- a/cc/test/skia_common.cc
+++ b/cc/test/skia_common.cc
@@ -4,6 +4,7 @@
#include "cc/test/skia_common.h"
+#include "cc/resources/display_item_list.h"
#include "cc/resources/picture.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -26,6 +27,18 @@
picture->Raster(&canvas, NULL, negated_content_region, 1.0f);
}
+void DrawDisplayList(unsigned char* buffer,
+ const gfx::Rect& layer_rect,
+ scoped_refptr<DisplayItemList> list) {
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+ SkBitmap bitmap;
+ bitmap.installPixels(info, buffer, info.minRowBytes());
+ SkCanvas canvas(bitmap);
+ canvas.clipRect(gfx::RectToSkRect(layer_rect));
+ list->Raster(&canvas, NULL, 1.0f);
+}
+
void CreateBitmap(const gfx::Size& size, const char* uri, SkBitmap* bitmap) {
SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
diff --git a/cc/test/skia_common.h b/cc/test/skia_common.h
index 3bafa0b..51ebcc5 100644
--- a/cc/test/skia_common.h
+++ b/cc/test/skia_common.h
@@ -18,11 +18,16 @@
namespace cc {
class Picture;
+class DisplayItemList;
void DrawPicture(unsigned char* buffer,
const gfx::Rect& layer_rect,
scoped_refptr<Picture> picture);
+void DrawDisplayList(unsigned char* buffer,
+ const gfx::Rect& layer_rect,
+ scoped_refptr<DisplayItemList> list);
+
void CreateBitmap(const gfx::Size& size, const char* uri, SkBitmap* bitmap);
} // namespace cc
diff --git a/cc/test/solid_color_content_layer_client.cc b/cc/test/solid_color_content_layer_client.cc
index 237dbb6..701f004 100644
--- a/cc/test/solid_color_content_layer_client.cc
+++ b/cc/test/solid_color_content_layer_client.cc
@@ -25,6 +25,14 @@
paint);
}
+scoped_refptr<DisplayItemList>
+SolidColorContentLayerClient::PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) {
+ NOTIMPLEMENTED();
+ return DisplayItemList::Create();
+}
+
bool SolidColorContentLayerClient::FillsBoundsCompletely() const {
return false;
}
diff --git a/cc/test/solid_color_content_layer_client.h b/cc/test/solid_color_content_layer_client.h
index 7a962cf..93fca84 100644
--- a/cc/test/solid_color_content_layer_client.h
+++ b/cc/test/solid_color_content_layer_client.h
@@ -20,6 +20,9 @@
SkCanvas* canvas,
const gfx::Rect& rect,
ContentLayerClient::GraphicsContextStatus gc_status) override;
+ scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) override;
bool FillsBoundsCompletely() const override;
private:
diff --git a/cc/test/test_shared_bitmap_manager.cc b/cc/test/test_shared_bitmap_manager.cc
index d7716dd..933dcd2 100644
--- a/cc/test/test_shared_bitmap_manager.cc
+++ b/cc/test/test_shared_bitmap_manager.cc
@@ -4,15 +4,41 @@
#include "cc/test/test_shared_bitmap_manager.h"
-#include "base/bind.h"
+#include "base/memory/shared_memory.h"
namespace cc {
-void FreeSharedBitmap(SharedBitmap* shared_bitmap) {
- delete shared_bitmap->memory();
-}
+namespace {
+class OwnedSharedBitmap : public SharedBitmap {
+ public:
+ OwnedSharedBitmap(scoped_ptr<base::SharedMemory> shared_memory,
+ const SharedBitmapId& id)
+ : SharedBitmap(static_cast<uint8*>(shared_memory->memory()), id),
+ shared_memory_(shared_memory.Pass()) {}
-void IgnoreSharedBitmap(SharedBitmap* shared_bitmap) {}
+ ~OwnedSharedBitmap() override {}
+
+ base::SharedMemory* memory() override { return shared_memory_.get(); }
+
+ private:
+ scoped_ptr<base::SharedMemory> shared_memory_;
+};
+
+class UnownedSharedBitmap : public SharedBitmap {
+ public:
+ UnownedSharedBitmap(base::SharedMemory* shared_memory,
+ const SharedBitmapId& id)
+ : SharedBitmap(static_cast<uint8*>(shared_memory->memory()), id),
+ shared_memory_(shared_memory) {}
+
+ ~UnownedSharedBitmap() override {}
+
+ base::SharedMemory* memory() override { return shared_memory_; }
+
+ private:
+ base::SharedMemory* shared_memory_;
+};
+} // namespace
TestSharedBitmapManager::TestSharedBitmapManager() {}
@@ -25,8 +51,7 @@
memory->CreateAndMapAnonymous(size.GetArea() * 4);
SharedBitmapId id = SharedBitmap::GenerateId();
bitmap_map_[id] = memory.get();
- return make_scoped_ptr(
- new SharedBitmap(memory.release(), id, base::Bind(&FreeSharedBitmap)));
+ return make_scoped_ptr(new OwnedSharedBitmap(memory.Pass(), id));
}
scoped_ptr<SharedBitmap> TestSharedBitmapManager::GetSharedBitmapFromId(
@@ -35,8 +60,7 @@
base::AutoLock lock(lock_);
if (bitmap_map_.find(id) == bitmap_map_.end())
return nullptr;
- return make_scoped_ptr(
- new SharedBitmap(bitmap_map_[id], id, base::Bind(&IgnoreSharedBitmap)));
+ return make_scoped_ptr(new UnownedSharedBitmap(bitmap_map_[id], id));
}
scoped_ptr<SharedBitmap> TestSharedBitmapManager::GetBitmapForSharedMemory(
@@ -44,8 +68,7 @@
base::AutoLock lock(lock_);
SharedBitmapId id = SharedBitmap::GenerateId();
bitmap_map_[id] = memory;
- return make_scoped_ptr(
- new SharedBitmap(memory, id, base::Bind(&IgnoreSharedBitmap)));
+ return make_scoped_ptr(new UnownedSharedBitmap(memory, id));
}
} // namespace cc
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h
index ff2c704..56c17c0 100644
--- a/cc/test/test_web_graphics_context_3d.h
+++ b/cc/test/test_web_graphics_context_3d.h
@@ -330,6 +330,9 @@
void set_support_image(bool support) {
test_capabilities_.gpu.image = support;
}
+ void set_support_texture_rectangle(bool support) {
+ test_capabilities_.gpu.texture_rectangle = support;
+ }
// When this context is lost, all contexts in its share group are also lost.
void add_share_group_context(TestWebGraphicsContext3D* context3d) {
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 6863850..6d75687 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -392,7 +392,7 @@
gfx::Rect visible_rect_in_target_surface_space =
layer->drawable_content_rect();
- if (!layer->render_target()->render_surface()->clip_rect().IsEmpty()) {
+ if (layer->render_target()->render_surface()->is_clipped()) {
// The |layer| L has a target T which owns a surface Ts. The surface Ts
// has a target TsT.
//
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 7a282c1..8c02bd3 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -59,6 +59,12 @@
SkCanvas* canvas,
const gfx::Rect& clip,
ContentLayerClient::GraphicsContextStatus gc_status) override {}
+ scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) override {
+ NOTIMPLEMENTED();
+ return DisplayItemList::Create();
+ }
bool FillsBoundsCompletely() const override { return false; }
};
@@ -2820,6 +2826,56 @@
}
TEST_F(LayerTreeHostCommonTest,
+ VisibleContentRectsForClippedSurfaceWithEmptyClip) {
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> child1 =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> child2 =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> child3 =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ root->AddChild(child1);
+ root->AddChild(child2);
+ root->AddChild(child3);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ gfx::Transform identity_matrix;
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(child1.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true,
+ false);
+ SetLayerPropertiesForTesting(child2.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true,
+ false);
+ SetLayerPropertiesForTesting(child3.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(125.f, 125.f), gfx::Size(50, 50),
+ true, false);
+
+ RenderSurfaceLayerList render_surface_layer_list;
+ // Now set the root render surface an empty clip.
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ root.get(), gfx::Size(), &render_surface_layer_list);
+
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+ ASSERT_TRUE(root->render_surface());
+ EXPECT_FALSE(root->is_clipped());
+
+ gfx::Rect empty;
+ EXPECT_EQ(empty, root->render_surface()->clip_rect());
+ EXPECT_TRUE(root->render_surface()->is_clipped());
+
+ // Visible content rect calculation will check if the target surface is
+ // clipped or not. An empty clip rect does not indicate the render surface
+ // is unclipped.
+ EXPECT_EQ(empty, child1->visible_content_rect());
+ EXPECT_EQ(empty, child2->visible_content_rect());
+ EXPECT_EQ(empty, child3->visible_content_rect());
+}
+
+TEST_F(LayerTreeHostCommonTest,
DrawableAndVisibleContentRectsForLayersWithUninvertibleTransform) {
scoped_refptr<Layer> root = Layer::Create();
scoped_refptr<LayerWithForcedDrawsContent> child =
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index e49dcfe..10b0685 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -151,22 +151,6 @@
max_transfer_buffer_usage_bytes);
}
-unsigned GetMapImageTextureTarget(
- const ContextProvider::Capabilities& context_capabilities) {
-// TODO(reveman): This should be a setting passed to the compositor instead
-// of hard-coded here. The target that need to be used depends on our choice
-// of GpuMemoryBuffer type. Note: SURFACE_TEXTURE needs EXTERNAL_OES,
-// IO_SURFACE needs RECTANGLE_ARB. crbug.com/431059
-#if defined(OS_ANDROID)
- if (context_capabilities.gpu.egl_image_external)
- return GL_TEXTURE_EXTERNAL_OES;
-#endif
- if (context_capabilities.gpu.texture_rectangle)
- return GL_TEXTURE_RECTANGLE_ARB;
-
- return GL_TEXTURE_2D;
-}
-
size_t GetMaxStagingResourceCount() {
// Upper bound for number of staging resource to allow.
return 32;
@@ -2005,9 +1989,6 @@
DCHECK(task_runner);
ContextProvider* context_provider = output_surface_->context_provider();
- bool should_use_zero_copy_rasterizer =
- settings_.use_zero_copy || IsSynchronousSingleThreaded();
-
if (!context_provider) {
*resource_pool =
ResourcePool::Create(resource_provider_.get(),
@@ -2018,7 +1999,10 @@
BitmapRasterWorkerPool::Create(task_runner,
RasterWorkerPool::GetTaskGraphRunner(),
resource_provider_.get());
- } else if (use_gpu_rasterization_) {
+ return;
+ }
+
+ if (use_gpu_rasterization_) {
*resource_pool =
ResourcePool::Create(resource_provider_.get(),
GL_TEXTURE_2D,
@@ -2029,53 +2013,65 @@
context_provider,
resource_provider_.get(),
settings_.use_distance_field_text);
- } else if (should_use_zero_copy_rasterizer && CanUseZeroCopyRasterizer()) {
- *resource_pool = ResourcePool::Create(
- resource_provider_.get(),
- GetMapImageTextureTarget(context_provider->ContextCapabilities()),
- resource_provider_->best_texture_format());
+ return;
+ }
- TaskGraphRunner* task_graph_runner;
- if (IsSynchronousSingleThreaded()) {
- DCHECK(!single_thread_synchronous_task_graph_runner_);
- single_thread_synchronous_task_graph_runner_.reset(new TaskGraphRunner);
- task_graph_runner = single_thread_synchronous_task_graph_runner_.get();
- } else {
- task_graph_runner = RasterWorkerPool::GetTaskGraphRunner();
+ if (GetRendererCapabilities().using_image) {
+ unsigned image_target = GL_TEXTURE_2D;
+#if defined(OS_MACOSX)
+ // GL_TEXTURE_RECTANGLE_ARB target is required by IOSurface backed images.
+ DCHECK(context_provider->ContextCapabilities().gpu.texture_rectangle);
+ image_target = GL_TEXTURE_RECTANGLE_ARB;
+#endif
+ if (settings_.use_image_external) {
+ DCHECK(context_provider->ContextCapabilities().gpu.egl_image_external);
+ image_target = GL_TEXTURE_EXTERNAL_OES;
}
- *raster_worker_pool = ZeroCopyRasterWorkerPool::Create(
- task_runner, task_graph_runner, resource_provider_.get());
- } else if (settings_.use_one_copy && CanUseOneCopyRasterizer()) {
- // We need to create a staging resource pool when using copy rasterizer.
- *staging_resource_pool = ResourcePool::Create(
- resource_provider_.get(),
- GetMapImageTextureTarget(context_provider->ContextCapabilities()),
- resource_provider_->best_texture_format());
- *resource_pool =
- ResourcePool::Create(resource_provider_.get(),
- GL_TEXTURE_2D,
- resource_provider_->best_texture_format());
+ if (settings_.use_zero_copy || IsSynchronousSingleThreaded()) {
+ *resource_pool =
+ ResourcePool::Create(resource_provider_.get(), image_target,
+ resource_provider_->best_texture_format());
- *raster_worker_pool =
- OneCopyRasterWorkerPool::Create(task_runner,
- RasterWorkerPool::GetTaskGraphRunner(),
- context_provider,
- resource_provider_.get(),
- staging_resource_pool_.get());
- } else {
- *resource_pool = ResourcePool::Create(
- resource_provider_.get(),
- GL_TEXTURE_2D,
- resource_provider_->memory_efficient_texture_format());
+ TaskGraphRunner* task_graph_runner;
+ if (IsSynchronousSingleThreaded()) {
+ DCHECK(!single_thread_synchronous_task_graph_runner_);
+ single_thread_synchronous_task_graph_runner_.reset(new TaskGraphRunner);
+ task_graph_runner = single_thread_synchronous_task_graph_runner_.get();
+ } else {
+ task_graph_runner = RasterWorkerPool::GetTaskGraphRunner();
+ }
- *raster_worker_pool = PixelBufferRasterWorkerPool::Create(
- task_runner, RasterWorkerPool::GetTaskGraphRunner(), context_provider,
- resource_provider_.get(),
- GetMaxTransferBufferUsageBytes(
- context_provider->ContextCapabilities(),
- settings_.renderer_settings.refresh_rate));
+ *raster_worker_pool = ZeroCopyRasterWorkerPool::Create(
+ task_runner, task_graph_runner, resource_provider_.get());
+ return;
+ }
+
+ if (settings_.use_one_copy) {
+ // We need to create a staging resource pool when using copy rasterizer.
+ *staging_resource_pool =
+ ResourcePool::Create(resource_provider_.get(), image_target,
+ resource_provider_->best_texture_format());
+ *resource_pool =
+ ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D,
+ resource_provider_->best_texture_format());
+
+ *raster_worker_pool = OneCopyRasterWorkerPool::Create(
+ task_runner, RasterWorkerPool::GetTaskGraphRunner(), context_provider,
+ resource_provider_.get(), staging_resource_pool_.get());
+ return;
+ }
}
+
+ *resource_pool = ResourcePool::Create(
+ resource_provider_.get(), GL_TEXTURE_2D,
+ resource_provider_->memory_efficient_texture_format());
+
+ *raster_worker_pool = PixelBufferRasterWorkerPool::Create(
+ task_runner, RasterWorkerPool::GetTaskGraphRunner(), context_provider,
+ resource_provider_.get(),
+ GetMaxTransferBufferUsageBytes(context_provider->ContextCapabilities(),
+ settings_.renderer_settings.refresh_rate));
}
void LayerTreeHostImpl::DestroyTileManager() {
@@ -2096,14 +2092,6 @@
return !proxy_->HasImplThread() && !settings_.single_thread_proxy_scheduler;
}
-bool LayerTreeHostImpl::CanUseZeroCopyRasterizer() const {
- return GetRendererCapabilities().using_image;
-}
-
-bool LayerTreeHostImpl::CanUseOneCopyRasterizer() const {
- return GetRendererCapabilities().using_image;
-}
-
void LayerTreeHostImpl::EnforceZeroBudget(bool zero_budget) {
SetManagedMemoryPolicy(cached_managed_memory_policy_, zero_budget);
}
@@ -2563,10 +2551,14 @@
return actual_viewport_end_point - viewport_point;
}
-static gfx::Vector2dF ScrollLayerWithLocalDelta(LayerImpl* layer_impl,
- const gfx::Vector2dF& local_delta) {
+static gfx::Vector2dF ScrollLayerWithLocalDelta(
+ LayerImpl* layer_impl,
+ const gfx::Vector2dF& local_delta,
+ float page_scale_factor) {
gfx::Vector2dF previous_delta(layer_impl->ScrollDelta());
- layer_impl->ScrollBy(local_delta);
+ gfx::Vector2dF delta = local_delta;
+ delta.Scale(1.f / page_scale_factor);
+ layer_impl->ScrollBy(delta);
return layer_impl->ScrollDelta() - previous_delta;
}
@@ -2644,7 +2636,8 @@
// Gesture events need to be transformed from viewport coordinates to local
// layer coordinates so that the scrolling contents exactly follow the
// user's finger. In contrast, wheel events represent a fixed amount of
- // scrolling so we can just apply them directly.
+ // scrolling so we can just apply them directly, but the page scale factor
+ // is applied to the scroll delta.
if (!wheel_scrolling_) {
float scale_from_viewport_to_screen_space = device_scale_factor_;
applied_delta =
@@ -2652,7 +2645,8 @@
scale_from_viewport_to_screen_space,
viewport_point, pending_delta);
} else {
- applied_delta = ScrollLayerWithLocalDelta(layer_impl, pending_delta);
+ applied_delta = ScrollLayerWithLocalDelta(
+ layer_impl, pending_delta, active_tree_->total_page_scale_factor());
}
const float kEpsilon = 0.1f;
@@ -2774,7 +2768,8 @@
gfx::Vector2dF delta = gfx::Vector2dF(0.f, page);
- gfx::Vector2dF applied_delta = ScrollLayerWithLocalDelta(layer_impl, delta);
+ gfx::Vector2dF applied_delta =
+ ScrollLayerWithLocalDelta(layer_impl, delta, 1.f);
if (!applied_delta.IsZero()) {
client_->SetNeedsCommitOnImplThread();
@@ -3251,9 +3246,9 @@
// task), fall back to physical time. This should still be monotonic.
if (current_begin_frame_args_.IsValid())
return current_begin_frame_args_;
- return BeginFrameArgs::Create(gfx::FrameTime::Now(), base::TimeTicks(),
- BeginFrameArgs::DefaultInterval(),
- BeginFrameArgs::NORMAL);
+ return BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, gfx::FrameTime::Now(), base::TimeTicks(),
+ BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
}
scoped_refptr<base::debug::ConvertableToTraceFormat>
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index d1b29ca..900e658 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -481,8 +481,6 @@
// Only valid for synchronous (non-scheduled) single-threaded case.
void SynchronouslyInitializeAllTiles();
- bool CanUseZeroCopyRasterizer() const;
- bool CanUseOneCopyRasterizer() const;
virtual void CreateResourceAndRasterWorkerPool(
scoped_ptr<RasterWorkerPool>* raster_worker_pool,
scoped_ptr<ResourcePool>* resource_pool,
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 7151689..4e070e2 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -945,7 +945,7 @@
}
// Scrolling after a pinch gesture should always be in local space. The
- // scroll deltas do not have the page scale factor applied.
+ // scroll deltas have the page scale factor applied.
{
host_impl_->active_tree()->SetPageScaleFactorAndLimits(
page_scale_factor, min_page_scale, max_page_scale);
@@ -968,9 +968,8 @@
scoped_ptr<ScrollAndScaleSet> scroll_info =
host_impl_->ProcessScrollDeltas();
- ExpectContains(*scroll_info.get(),
- scroll_layer->id(),
- scroll_delta);
+ ExpectContains(*scroll_info.get(), scroll_layer->id(),
+ gfx::Vector2d(0, scroll_delta.y() / page_scale_delta));
}
}
@@ -1395,7 +1394,8 @@
0) {}
BeginFrameArgs CurrentBeginFrameArgs() const override {
- return CreateBeginFrameArgsForTesting(fake_current_physical_time_);
+ return CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE,
+ fake_current_physical_time_);
}
void SetCurrentPhysicalTimeTicksForTest(base::TimeTicks fake_now) {
@@ -3596,7 +3596,7 @@
host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta);
host_impl_->ScrollEnd();
- // The scale should not have been applied to the scroll delta.
+ // It should apply the scale factor to the scroll delta for the wheel event.
scroll_info = host_impl_->ProcessScrollDeltas();
ExpectContains(*scroll_info.get(),
scroll_layer->id(),
@@ -7800,6 +7800,41 @@
EXPECT_EQ(1u, raw_replica_mask_layer->did_become_active_call_count());
}
+TEST_F(LayerTreeHostImplTest, WheelScrollWithPageScaleFactorOnInnerLayer) {
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+ DrawFrame();
+
+ EXPECT_EQ(scroll_layer, host_impl_->InnerViewportScrollLayer());
+
+ float min_page_scale = 1.f, max_page_scale = 4.f;
+ float page_scale_factor = 1.f;
+
+ // The scroll deltas should have the page scale factor applied.
+ {
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(
+ page_scale_factor, min_page_scale, max_page_scale);
+ host_impl_->active_tree()->SetPageScaleDelta(1.f);
+ scroll_layer->SetScrollDelta(gfx::Vector2d());
+
+ float page_scale_delta = 2.f;
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->PinchGestureBegin();
+ host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
+ host_impl_->PinchGestureEnd();
+ host_impl_->ScrollEnd();
+
+ gfx::Vector2dF scroll_delta(0, 5);
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->TotalScrollOffset());
+
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ host_impl_->ScrollEnd();
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 2.5), scroll_layer->TotalScrollOffset());
+ }
+}
+
class LayerTreeHostImplCountingLostSurfaces : public LayerTreeHostImplTest {
public:
LayerTreeHostImplCountingLostSurfaces() : num_lost_surfaces_(0) {}
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc
index c494914..1235e15 100644
--- a/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -47,6 +47,13 @@
}
}
+ scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) override {
+ NOTIMPLEMENTED();
+ return DisplayItemList::Create();
+ }
+
private:
gfx::Size bounds_;
};
diff --git a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc b/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
index e7dd149..a5ccb8b 100644
--- a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
+++ b/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
@@ -80,6 +80,13 @@
paint);
}
+ scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) override {
+ NOTIMPLEMENTED();
+ return DisplayItemList::Create();
+ }
+
private:
gfx::Rect layer_rect_;
};
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index f589c84..51c5d7e 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1112,6 +1112,12 @@
if (test_layer_)
test_layer_->SetOpacity(0.f);
}
+ scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) override {
+ NOTIMPLEMENTED();
+ return DisplayItemList::Create();
+ }
bool FillsBoundsCompletely() const override { return false; }
private:
@@ -2321,6 +2327,13 @@
++paint_count_;
}
+ scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) override {
+ NOTIMPLEMENTED();
+ return DisplayItemList::Create();
+ }
+
bool FillsBoundsCompletely() const override { return false; }
private:
@@ -2591,6 +2604,13 @@
layer_->SetBounds(gfx::Size(2, 2));
}
+ scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+ const gfx::Rect& clip,
+ GraphicsContextStatus gc_status) override {
+ NOTIMPLEMENTED();
+ return DisplayItemList::Create();
+ }
+
bool FillsBoundsCompletely() const override { return false; }
private:
@@ -5653,6 +5673,9 @@
TestWebGraphicsContext3D::Create();
context3d->set_support_image(true);
context3d->set_support_sync_query(true);
+#if defined(OS_MACOSX)
+ context3d->set_support_texture_rectangle(true);
+#endif
if (delegating_renderer())
return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
@@ -5840,4 +5863,59 @@
MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles);
+class LayerTreeHostTestOneActivatePerManageTiles : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestOneActivatePerManageTiles()
+ : notify_ready_to_activate_count_(0u), scheduled_manage_tiles_count_(0) {}
+
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+ scoped_refptr<FakePictureLayer> root_layer =
+ FakePictureLayer::Create(&client_);
+ root_layer->SetBounds(gfx::Size(1500, 1500));
+ root_layer->SetIsDrawable(true);
+
+ layer_tree_host()->SetRootLayer(root_layer);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void BeginTest() override {
+ layer_tree_host()->SetViewportSize(gfx::Size(16, 16));
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
+ bool success) override {
+ ASSERT_TRUE(success);
+ host_impl->tile_manager()->SetScheduledRasterTaskLimitForTesting(1);
+ }
+
+ void NotifyReadyToActivateOnThread(LayerTreeHostImpl* impl) override {
+ ++notify_ready_to_activate_count_;
+ EndTestAfterDelayMs(100);
+ }
+
+ void ScheduledActionManageTiles() override {
+ ++scheduled_manage_tiles_count_;
+ }
+
+ void AfterTest() override {
+ // Expect at most a notification for each scheduled manage tiles, plus one
+ // for the initial commit (which doesn't go through scheduled actions).
+ // The reason this is not an equality is because depending on timing, we
+ // might get a manage tiles but not yet get a notification that we're
+ // ready to activate. The intent of a test is to ensure that we don't
+ // get more than one notification per manage tiles, so this is OK.
+ EXPECT_LE(notify_ready_to_activate_count_,
+ 1u + scheduled_manage_tiles_count_);
+ }
+
+ protected:
+ FakeContentLayerClient client_;
+ size_t notify_ready_to_activate_count_;
+ size_t scheduled_manage_tiles_count_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestOneActivatePerManageTiles);
+
} // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index 8318192..f6bc4d9 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -106,13 +106,12 @@
LayerTreeHostAnimationTestSetNeedsAnimateInsideAnimationCallback);
// Add a layer animation and confirm that
-// LayerTreeHostImpl::updateAnimationState does get called and continues to
-// get called.
+// LayerTreeHostImpl::UpdateAnimationState does get called.
class LayerTreeHostAnimationTestAddAnimation
: public LayerTreeHostAnimationTest {
public:
LayerTreeHostAnimationTestAddAnimation()
- : num_begin_frames_(0), received_animation_started_notification_(false) {}
+ : update_animation_state_was_called_(false) {}
void BeginTest() override {
PostAddInstantAnimationToMainThread(layer_tree_host()->root_layer());
@@ -120,53 +119,28 @@
void UpdateAnimationState(LayerTreeHostImpl* host_impl,
bool has_unfinished_animation) override {
- if (!num_begin_frames_) {
- // The animation had zero duration so LayerTreeHostImpl should no
- // longer need to animate its layers.
- EXPECT_FALSE(has_unfinished_animation);
- num_begin_frames_++;
- return;
- }
-
- if (received_animation_started_notification_) {
- EXPECT_LT(base::TimeTicks(), start_time_);
-
- LayerAnimationController* controller_impl =
- host_impl->active_tree()->root_layer()->layer_animation_controller();
- Animation* animation_impl =
- controller_impl->GetAnimation(Animation::Opacity);
- if (animation_impl)
- controller_impl->RemoveAnimation(animation_impl->id());
-
- EndTest();
- }
+ EXPECT_FALSE(has_unfinished_animation);
+ update_animation_state_was_called_ = true;
}
void NotifyAnimationStarted(base::TimeTicks monotonic_time,
Animation::TargetProperty target_property,
int group) override {
- received_animation_started_notification_ = true;
- start_time_ = monotonic_time;
- if (num_begin_frames_) {
- EXPECT_LT(base::TimeTicks(), start_time_);
+ EXPECT_LT(base::TimeTicks(), monotonic_time);
- LayerAnimationController* controller =
- layer_tree_host()->root_layer()->layer_animation_controller();
- Animation* animation =
- controller->GetAnimation(Animation::Opacity);
- if (animation)
- controller->RemoveAnimation(animation->id());
+ LayerAnimationController* controller =
+ layer_tree_host()->root_layer()->layer_animation_controller();
+ Animation* animation = controller->GetAnimation(Animation::Opacity);
+ if (animation)
+ controller->RemoveAnimation(animation->id());
- EndTest();
- }
+ EndTest();
}
- void AfterTest() override {}
+ void AfterTest() override { EXPECT_TRUE(update_animation_state_was_called_); }
private:
- int num_begin_frames_;
- bool received_animation_started_notification_;
- base::TimeTicks start_time_;
+ bool update_animation_state_was_called_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAddAnimation);
@@ -531,9 +505,7 @@
class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes
: public LayerTreeHostAnimationTest {
public:
- LayerTreeHostAnimationTestSynchronizeAnimationStartTimes()
- : main_start_time_(-1.0),
- impl_start_time_(-1.0) {}
+ LayerTreeHostAnimationTestSynchronizeAnimationStartTimes() {}
void SetupTree() override {
LayerTreeHostAnimationTest::SetupTree();
@@ -553,12 +525,9 @@
layer_animation_controller();
Animation* animation =
controller->GetAnimation(Animation::Opacity);
- main_start_time_ =
- (animation->start_time() - base::TimeTicks()).InSecondsF();
+ main_start_time_ = animation->start_time();
controller->RemoveAnimation(animation->id());
-
- if (impl_start_time_ > 0.0)
- EndTest();
+ EndTest();
}
void UpdateAnimationState(LayerTreeHostImpl* impl_host,
@@ -571,21 +540,17 @@
if (!animation)
return;
- impl_start_time_ =
- (animation->start_time() - base::TimeTicks()).InSecondsF();
- controller->RemoveAnimation(animation->id());
-
- if (main_start_time_ > 0.0)
- EndTest();
+ impl_start_time_ = animation->start_time();
}
void AfterTest() override {
- EXPECT_FLOAT_EQ(impl_start_time_, main_start_time_);
+ EXPECT_EQ(impl_start_time_, main_start_time_);
+ EXPECT_LT(base::TimeTicks(), impl_start_time_);
}
private:
- double main_start_time_;
- double impl_start_time_;
+ base::TimeTicks main_start_time_;
+ base::TimeTicks impl_start_time_;
FakeContentLayerClient client_;
scoped_refptr<FakeContentLayer> content_;
};
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index e792427..0771eb8 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -61,10 +61,13 @@
strict_layer_property_change_checking(false),
use_one_copy(false),
use_zero_copy(false),
+ use_image_external(false),
ignore_root_layer_flings(false),
scheduled_raster_task_limit(32),
use_occlusion_for_tile_prioritization(false),
- record_full_layer(false) {
+ record_full_layer(false),
+ use_display_lists(false),
+ main_thread_should_always_be_low_latency(false) {
}
LayerTreeSettings::~LayerTreeSettings() {}
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index ebbe7f7..438344b 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -73,10 +73,13 @@
bool strict_layer_property_change_checking;
bool use_one_copy;
bool use_zero_copy;
+ bool use_image_external;
bool ignore_root_layer_flings;
size_t scheduled_raster_task_limit;
bool use_occlusion_for_tile_prioritization;
bool record_full_layer;
+ bool use_display_lists;
+ bool main_thread_should_always_be_low_latency;
LayerTreeDebugState initial_debug_state;
};
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 5a40d7e..9a13457 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -430,9 +430,8 @@
// equivalent of blocking commit until activation and also running
// all tasks posted during commit/activation before CommitComplete.
MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&SingleThreadProxy::CommitComplete,
- weak_factory_.GetWeakPtr()));
+ FROM_HERE, base::Bind(&SingleThreadProxy::CommitComplete,
+ weak_factory_.GetWeakPtr()));
}
timing_history_.DidActivateSyncTree();
@@ -493,8 +492,8 @@
{
BeginFrameArgs begin_frame_args(BeginFrameArgs::Create(
- frame_begin_time, base::TimeTicks(), BeginFrameArgs::DefaultInterval(),
- BeginFrameArgs::SYNCHRONOUS));
+ BEGINFRAME_FROM_HERE, frame_begin_time, base::TimeTicks(),
+ BeginFrameArgs::DefaultInterval(), BeginFrameArgs::SYNCHRONOUS));
DoBeginMainFrame(begin_frame_args);
DoCommit();