diff options
author | Zeno Albisser <zeno.albisser@theqtcompany.com> | 2014-12-05 15:04:29 +0100 |
---|---|---|
committer | Andras Becsi <andras.becsi@theqtcompany.com> | 2014-12-09 10:49:28 +0100 |
commit | af6588f8d723931a298c995fa97259bb7f7deb55 (patch) | |
tree | 060ca707847ba1735f01af2372e0d5e494dc0366 /chromium/cc/resources | |
parent | 2fff84d821cc7b1c785f6404e0f8091333283e74 (diff) | |
download | qtwebengine-chromium-af6588f8d723931a298c995fa97259bb7f7deb55.tar.gz |
BASELINE: Update chromium to 40.0.2214.28 and ninja to 1.5.3.
Change-Id: I759465284fd64d59ad120219cbe257f7402c4181
Reviewed-by: Andras Becsi <andras.becsi@theqtcompany.com>
Diffstat (limited to 'chromium/cc/resources')
127 files changed, 9989 insertions, 7544 deletions
diff --git a/chromium/cc/resources/bitmap_content_layer_updater.cc b/chromium/cc/resources/bitmap_content_layer_updater.cc index fff62cf0aca..63ba336a152 100644 --- a/chromium/cc/resources/bitmap_content_layer_updater.cc +++ b/chromium/cc/resources/bitmap_content_layer_updater.cc @@ -50,41 +50,38 @@ BitmapContentLayerUpdater::~BitmapContentLayerUpdater() {} scoped_ptr<LayerUpdater::Resource> BitmapContentLayerUpdater::CreateResource( PrioritizedResourceManager* manager) { - return scoped_ptr<LayerUpdater::Resource>( + return make_scoped_ptr( new Resource(this, PrioritizedResource::Create(manager))); } -void BitmapContentLayerUpdater::PrepareToUpdate( - const gfx::Rect& content_rect, - const gfx::Size& tile_size, - float contents_width_scale, - float contents_height_scale, - gfx::Rect* resulting_opaque_rect) { - if (canvas_size_ != content_rect.size()) { +void BitmapContentLayerUpdater::PrepareToUpdate(const gfx::Size& content_size, + const gfx::Rect& paint_rect, + const gfx::Size& tile_size, + float contents_width_scale, + float contents_height_scale) { + if (canvas_size_ != paint_rect.size()) { devtools_instrumentation::ScopedLayerTask paint_setup( devtools_instrumentation::kPaintSetup, layer_id_); - canvas_size_ = content_rect.size(); - bool alloc = bitmap_backing_.allocN32Pixels( + canvas_size_ = paint_rect.size(); + bitmap_backing_.allocN32Pixels( canvas_size_.width(), canvas_size_.height(), layer_is_opaque_); // TODO(danak): Remove when skia does the check for us: crbug.com/360384 - CHECK(alloc); canvas_ = skia::AdoptRef(new SkCanvas(bitmap_backing_)); - DCHECK_EQ(content_rect.width(), canvas_->getBaseLayerSize().width()); - DCHECK_EQ(content_rect.height(), canvas_->getBaseLayerSize().height()); + DCHECK_EQ(paint_rect.width(), canvas_->getBaseLayerSize().width()); + DCHECK_EQ(paint_rect.height(), canvas_->getBaseLayerSize().height()); } base::TimeTicks start_time = rendering_stats_instrumentation_->StartRecording(); PaintContents(canvas_.get(), - content_rect, + content_size, + paint_rect, contents_width_scale, - contents_height_scale, - resulting_opaque_rect); + contents_height_scale); base::TimeDelta duration = rendering_stats_instrumentation_->EndRecording(start_time); rendering_stats_instrumentation_->AddPaint( - duration, - content_rect.width() * content_rect.height()); + duration, paint_rect.width() * paint_rect.height()); } void BitmapContentLayerUpdater::UpdateTexture(ResourceUpdateQueue* queue, @@ -93,11 +90,8 @@ void BitmapContentLayerUpdater::UpdateTexture(ResourceUpdateQueue* queue, const gfx::Vector2d& dest_offset, bool partial_update) { CHECK(canvas_); - ResourceUpdate upload = ResourceUpdate::Create(texture, - &bitmap_backing_, - content_rect(), - source_rect, - dest_offset); + ResourceUpdate upload = ResourceUpdate::Create( + texture, &bitmap_backing_, paint_rect(), source_rect, dest_offset); if (partial_update) queue->AppendPartialUpload(upload); else diff --git a/chromium/cc/resources/bitmap_content_layer_updater.h b/chromium/cc/resources/bitmap_content_layer_updater.h index 781fc0baa73..5ddc35f48a7 100644 --- a/chromium/cc/resources/bitmap_content_layer_updater.h +++ b/chromium/cc/resources/bitmap_content_layer_updater.h @@ -27,12 +27,12 @@ class CC_EXPORT BitmapContentLayerUpdater : public ContentLayerUpdater { public: Resource(BitmapContentLayerUpdater* updater, scoped_ptr<PrioritizedResource> resource); - virtual ~Resource(); + ~Resource() override; - virtual void Update(ResourceUpdateQueue* queue, - const gfx::Rect& source_rect, - const gfx::Vector2d& dest_offset, - bool partial_update) OVERRIDE; + void Update(ResourceUpdateQueue* queue, + const gfx::Rect& source_rect, + const gfx::Vector2d& dest_offset, + bool partial_update) override; private: BitmapContentLayerUpdater* updater_; @@ -45,27 +45,27 @@ class CC_EXPORT BitmapContentLayerUpdater : public ContentLayerUpdater { RenderingStatsInstrumentation* stats_instrumenation, int layer_id); - virtual scoped_ptr<LayerUpdater::Resource> CreateResource( - PrioritizedResourceManager* manager) OVERRIDE; - virtual void PrepareToUpdate(const gfx::Rect& content_rect, - const gfx::Size& tile_size, - float contents_width_scale, - float contents_height_scale, - gfx::Rect* resulting_opaque_rect) OVERRIDE; + scoped_ptr<LayerUpdater::Resource> CreateResource( + PrioritizedResourceManager* manager) override; + void PrepareToUpdate(const gfx::Size& content_size, + const gfx::Rect& paint_rect, + const gfx::Size& tile_size, + float contents_width_scale, + float contents_height_scale) override; void UpdateTexture(ResourceUpdateQueue* queue, PrioritizedResource* resource, const gfx::Rect& source_rect, const gfx::Vector2d& dest_offset, bool partial_update); - virtual void SetOpaque(bool opaque) OVERRIDE; - virtual void ReduceMemoryUsage() OVERRIDE; + void SetOpaque(bool opaque) override; + void ReduceMemoryUsage() override; protected: BitmapContentLayerUpdater( scoped_ptr<LayerPainter> painter, RenderingStatsInstrumentation* stats_instrumenation, int layer_id); - virtual ~BitmapContentLayerUpdater(); + ~BitmapContentLayerUpdater() override; SkBitmap bitmap_backing_; skia::RefPtr<SkCanvas> canvas_; diff --git a/chromium/cc/resources/bitmap_raster_worker_pool.cc b/chromium/cc/resources/bitmap_raster_worker_pool.cc new file mode 100644 index 00000000000..3b3739a3ccc --- /dev/null +++ b/chromium/cc/resources/bitmap_raster_worker_pool.cc @@ -0,0 +1,203 @@ +// 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/bitmap_raster_worker_pool.h" + +#include <algorithm> + +#include "base/debug/trace_event.h" +#include "base/debug/trace_event_argument.h" +#include "base/strings/stringprintf.h" +#include "cc/debug/traced_value.h" +#include "cc/resources/raster_buffer.h" +#include "cc/resources/raster_source.h" +#include "cc/resources/resource.h" + +namespace cc { +namespace { + +class RasterBufferImpl : public RasterBuffer { + public: + RasterBufferImpl(ResourceProvider* resource_provider, + const Resource* resource) + : lock_(resource_provider, resource->id()) {} + + // Overridden from RasterBuffer: + void Playback(const RasterSource* raster_source, + const gfx::Rect& rect, + float scale) override { + raster_source->PlaybackToCanvas(lock_.sk_canvas(), rect, scale); + } + + private: + ResourceProvider::ScopedWriteLockSoftware lock_; + + DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); +}; + +} // namespace + +// static +scoped_ptr<RasterWorkerPool> BitmapRasterWorkerPool::Create( + base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ResourceProvider* resource_provider) { + return make_scoped_ptr<RasterWorkerPool>(new BitmapRasterWorkerPool( + task_runner, task_graph_runner, resource_provider)); +} + +BitmapRasterWorkerPool::BitmapRasterWorkerPool( + base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ResourceProvider* resource_provider) + : task_runner_(task_runner), + task_graph_runner_(task_graph_runner), + namespace_token_(task_graph_runner->GetNamespaceToken()), + resource_provider_(resource_provider), + raster_finished_weak_ptr_factory_(this) { +} + +BitmapRasterWorkerPool::~BitmapRasterWorkerPool() { +} + +Rasterizer* BitmapRasterWorkerPool::AsRasterizer() { + return this; +} + +void BitmapRasterWorkerPool::SetClient(RasterizerClient* client) { + client_ = client; +} + +void BitmapRasterWorkerPool::Shutdown() { + TRACE_EVENT0("cc", "BitmapRasterWorkerPool::Shutdown"); + + TaskGraph empty; + task_graph_runner_->ScheduleTasks(namespace_token_, &empty); + task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); +} + +void BitmapRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { + TRACE_EVENT0("cc", "BitmapRasterWorkerPool::ScheduleTasks"); + + if (raster_pending_.none()) + TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); + + // Mark all task sets as pending. + raster_pending_.set(); + + unsigned priority = kRasterTaskPriorityBase; + + graph_.Reset(); + + // Cancel existing OnRasterFinished callbacks. + raster_finished_weak_ptr_factory_.InvalidateWeakPtrs(); + + scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets]; + + size_t task_count[kNumberOfTaskSets] = {0}; + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + new_raster_finished_tasks[task_set] = CreateRasterFinishedTask( + task_runner_.get(), + base::Bind(&BitmapRasterWorkerPool::OnRasterFinished, + raster_finished_weak_ptr_factory_.GetWeakPtr(), + task_set)); + } + + for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); + it != queue->items.end(); + ++it) { + const RasterTaskQueue::Item& item = *it; + RasterTask* task = item.task; + DCHECK(!task->HasCompleted()); + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + if (!item.task_sets[task_set]) + continue; + + ++task_count[task_set]; + + graph_.edges.push_back( + TaskGraph::Edge(task, new_raster_finished_tasks[task_set].get())); + } + + InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); + } + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + InsertNodeForTask(&graph_, + new_raster_finished_tasks[task_set].get(), + kRasterFinishedTaskPriority, + task_count[task_set]); + } + + ScheduleTasksOnOriginThread(this, &graph_); + task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); + + std::copy(new_raster_finished_tasks, + new_raster_finished_tasks + kNumberOfTaskSets, + raster_finished_tasks_); + + TRACE_EVENT_ASYNC_STEP_INTO1( + "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue()); +} + +void BitmapRasterWorkerPool::CheckForCompletedTasks() { + TRACE_EVENT0("cc", "BitmapRasterWorkerPool::CheckForCompletedTasks"); + + task_graph_runner_->CollectCompletedTasks(namespace_token_, + &completed_tasks_); + for (Task::Vector::const_iterator it = completed_tasks_.begin(); + it != completed_tasks_.end(); + ++it) { + RasterizerTask* task = static_cast<RasterizerTask*>(it->get()); + + task->WillComplete(); + task->CompleteOnOriginThread(this); + task->DidComplete(); + + task->RunReplyOnOriginThread(); + } + completed_tasks_.clear(); +} + +scoped_ptr<RasterBuffer> BitmapRasterWorkerPool::AcquireBufferForRaster( + const Resource* resource) { + return make_scoped_ptr<RasterBuffer>( + new RasterBufferImpl(resource_provider_, resource)); +} + +void BitmapRasterWorkerPool::ReleaseBufferForRaster( + scoped_ptr<RasterBuffer> buffer) { + // Nothing to do here. RasterBufferImpl destructor cleans up after itself. +} + +void BitmapRasterWorkerPool::OnRasterFinished(TaskSet task_set) { + TRACE_EVENT1( + "cc", "BitmapRasterWorkerPool::OnRasterFinished", "task_set", task_set); + + DCHECK(raster_pending_[task_set]); + raster_pending_[task_set] = false; + if (raster_pending_.any()) { + TRACE_EVENT_ASYNC_STEP_INTO1( + "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue()); + } else { + TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); + } + client_->DidFinishRunningTasks(task_set); +} + +scoped_refptr<base::debug::ConvertableToTraceFormat> +BitmapRasterWorkerPool::StateAsValue() const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); + + state->BeginArray("tasks_pending"); + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) + state->AppendBoolean(raster_pending_[task_set]); + state->EndArray(); + return state; +} + +} // namespace cc diff --git a/chromium/cc/resources/bitmap_raster_worker_pool.h b/chromium/cc/resources/bitmap_raster_worker_pool.h new file mode 100644 index 00000000000..624318b5e74 --- /dev/null +++ b/chromium/cc/resources/bitmap_raster_worker_pool.h @@ -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. + +#ifndef CC_RESOURCES_BITMAP_RASTER_WORKER_POOL_H_ +#define CC_RESOURCES_BITMAP_RASTER_WORKER_POOL_H_ + +#include "base/memory/weak_ptr.h" +#include "base/values.h" +#include "cc/resources/raster_worker_pool.h" +#include "cc/resources/rasterizer.h" + +namespace base { +namespace debug { +class ConvertableToTraceFormat; +} +} + +namespace cc { +class ResourceProvider; + +class CC_EXPORT BitmapRasterWorkerPool : public RasterWorkerPool, + public Rasterizer, + public RasterizerTaskClient { + public: + ~BitmapRasterWorkerPool() override; + + static scoped_ptr<RasterWorkerPool> Create( + base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ResourceProvider* resource_provider); + + // Overridden from RasterWorkerPool: + Rasterizer* AsRasterizer() override; + + // Overridden from Rasterizer: + void SetClient(RasterizerClient* client) override; + void Shutdown() override; + void ScheduleTasks(RasterTaskQueue* queue) override; + void CheckForCompletedTasks() override; + + // Overridden from RasterizerTaskClient: + scoped_ptr<RasterBuffer> AcquireBufferForRaster( + const Resource* resource) override; + void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override; + + protected: + BitmapRasterWorkerPool(base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ResourceProvider* resource_provider); + + private: + void OnRasterFinished(TaskSet task_set); + scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const; + + scoped_refptr<base::SequencedTaskRunner> task_runner_; + TaskGraphRunner* task_graph_runner_; + const NamespaceToken namespace_token_; + RasterizerClient* client_; + ResourceProvider* resource_provider_; + + TaskSetCollection raster_pending_; + + scoped_refptr<RasterizerTask> raster_finished_tasks_[kNumberOfTaskSets]; + + // Task graph used when scheduling tasks and vector used to gather + // completed tasks. + TaskGraph graph_; + Task::Vector completed_tasks_; + + base::WeakPtrFactory<BitmapRasterWorkerPool> + raster_finished_weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BitmapRasterWorkerPool); +}; + +} // namespace cc + +#endif // CC_RESOURCES_BITMAP_RASTER_WORKER_POOL_H_ diff --git a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc index 21fdbbb72bc..5b8e5e43f2e 100644 --- a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc +++ b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc @@ -26,7 +26,7 @@ void BitmapSkPictureContentLayerUpdater::Resource::Update( SkAlphaType at = updater_->layer_is_opaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType; bitmap_.allocPixels(SkImageInfo::Make( - source_rect.width(), source_rect.height(), kPMColor_SkColorType, at)); + source_rect.width(), source_rect.height(), kN32_SkColorType, at)); SkCanvas canvas(bitmap_); updater_->PaintContentsRect(&canvas, source_rect); @@ -62,7 +62,7 @@ BitmapSkPictureContentLayerUpdater::~BitmapSkPictureContentLayerUpdater() {} scoped_ptr<LayerUpdater::Resource> BitmapSkPictureContentLayerUpdater::CreateResource( PrioritizedResourceManager* manager) { - return scoped_ptr<LayerUpdater::Resource>( + return make_scoped_ptr( new Resource(this, PrioritizedResource::Create(manager))); } @@ -72,16 +72,9 @@ void BitmapSkPictureContentLayerUpdater::PaintContentsRect( if (!canvas) return; // Translate the origin of content_rect to that of source_rect. - canvas->translate(content_rect().x() - source_rect.x(), - content_rect().y() - source_rect.y()); - base::TimeTicks start_time = - rendering_stats_instrumentation_->StartRecording(); + canvas->translate(paint_rect().x() - source_rect.x(), + paint_rect().y() - source_rect.y()); DrawPicture(canvas); - base::TimeDelta duration = - rendering_stats_instrumentation_->EndRecording(start_time); - rendering_stats_instrumentation_->AddRaster( - duration, - source_rect.width() * source_rect.height()); } } // namespace cc diff --git a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.h b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.h index e20e3c35c5e..ba22b2e5908 100644 --- a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.h +++ b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.h @@ -20,10 +20,10 @@ class BitmapSkPictureContentLayerUpdater : public SkPictureContentLayerUpdater { Resource(BitmapSkPictureContentLayerUpdater* updater, scoped_ptr<PrioritizedResource> texture); - virtual void Update(ResourceUpdateQueue* queue, - const gfx::Rect& source_rect, - const gfx::Vector2d& dest_offset, - bool partial_update) OVERRIDE; + void Update(ResourceUpdateQueue* queue, + const gfx::Rect& source_rect, + const gfx::Vector2d& dest_offset, + bool partial_update) override; private: SkBitmap bitmap_; @@ -37,8 +37,8 @@ class BitmapSkPictureContentLayerUpdater : public SkPictureContentLayerUpdater { RenderingStatsInstrumentation* stats_instrumentation, int layer_id); - virtual scoped_ptr<LayerUpdater::Resource> CreateResource( - PrioritizedResourceManager* manager) OVERRIDE; + scoped_ptr<LayerUpdater::Resource> CreateResource( + PrioritizedResourceManager* manager) override; void PaintContentsRect(SkCanvas* canvas, const gfx::Rect& source_rect); @@ -47,7 +47,7 @@ class BitmapSkPictureContentLayerUpdater : public SkPictureContentLayerUpdater { scoped_ptr<LayerPainter> painter, RenderingStatsInstrumentation* stats_instrumentation, int layer_id); - virtual ~BitmapSkPictureContentLayerUpdater(); + ~BitmapSkPictureContentLayerUpdater() override; DISALLOW_COPY_AND_ASSIGN(BitmapSkPictureContentLayerUpdater); }; diff --git a/chromium/cc/resources/content_layer_updater.cc b/chromium/cc/resources/content_layer_updater.cc index 249a6e92cd8..971362fb8b8 100644 --- a/chromium/cc/resources/content_layer_updater.cc +++ b/chromium/cc/resources/content_layer_updater.cc @@ -5,15 +5,14 @@ #include "cc/resources/content_layer_updater.h" #include "base/debug/trace_event.h" -#include "base/time/time.h" #include "cc/debug/rendering_stats_instrumentation.h" #include "cc/resources/layer_painter.h" #include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkScalar.h" -#include "ui/gfx/rect_conversions.h" -#include "ui/gfx/rect_f.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/skia_util.h" namespace cc { @@ -25,7 +24,9 @@ ContentLayerUpdater::ContentLayerUpdater( layer_id_(layer_id), layer_is_opaque_(false), layer_fills_bounds_completely_(false), - painter_(painter.Pass()) {} + painter_(painter.Pass()), + background_color_(SK_ColorTRANSPARENT) { +} ContentLayerUpdater::~ContentLayerUpdater() {} @@ -35,28 +36,62 @@ void ContentLayerUpdater::set_rendering_stats_instrumentation( } void ContentLayerUpdater::PaintContents(SkCanvas* canvas, - const gfx::Rect& content_rect, + const gfx::Size& layer_content_size, + const gfx::Rect& paint_rect, float contents_width_scale, - float contents_height_scale, - gfx::Rect* resulting_opaque_rect) { + float contents_height_scale) { TRACE_EVENT0("cc", "ContentLayerUpdater::PaintContents"); if (!canvas) return; canvas->save(); - canvas->translate(SkFloatToScalar(-content_rect.x()), - SkFloatToScalar(-content_rect.y())); - - // The |canvas| backing should be sized to hold the |content_rect|. - DCHECK_EQ(content_rect.width(), canvas->getBaseLayerSize().width()); - DCHECK_EQ(content_rect.height(), canvas->getBaseLayerSize().height()); + canvas->translate(SkIntToScalar(-paint_rect.x()), + SkIntToScalar(-paint_rect.y())); + + // The |canvas| backing should be sized to hold the |paint_rect|. + DCHECK_EQ(paint_rect.width(), canvas->getBaseLayerSize().width()); + DCHECK_EQ(paint_rect.height(), canvas->getBaseLayerSize().height()); + + const bool is_scaled = + contents_width_scale != 1.f || contents_height_scale != 1.f; + + if (is_scaled && (layer_is_opaque_ || layer_fills_bounds_completely_)) { + // 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 paint won't cover it). + // + // 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. + const gfx::Rect layer_content_rect = gfx::Rect(layer_content_size); + gfx::Rect deflated_layer_content_rect = layer_content_rect; + deflated_layer_content_rect.Inset(0, 0, 1, 1); + + if (!layer_content_rect.Contains(deflated_layer_content_rect)) { + // Drawing at most 1 x 1 x (canvas width + canvas height) texels is 2-3X + // faster than clearing, so special case this. + DCHECK_LE(paint_rect.right(), layer_content_rect.right()); + DCHECK_LE(paint_rect.bottom(), layer_content_rect.bottom()); + canvas->save(); + canvas->clipRect(gfx::RectToSkRect(layer_content_rect), + SkRegion::kReplace_Op); + canvas->clipRect(gfx::RectToSkRect(deflated_layer_content_rect), + SkRegion::kDifference_Op); + canvas->drawColor(background_color_, SkXfermode::kSrc_Mode); + canvas->restore(); + } + } - gfx::Rect layer_rect = content_rect; - if (contents_width_scale != 1.f || contents_height_scale != 1.f) { + gfx::Rect layer_rect; + if (is_scaled) { canvas->scale(SkFloatToScalar(contents_width_scale), SkFloatToScalar(contents_height_scale)); + // NOTE: this may go beyond the bounds of the layer, but that shouldn't + // cause problems (anything beyond the layer is clipped out). layer_rect = gfx::ScaleToEnclosingRect( - content_rect, 1.f / contents_width_scale, 1.f / contents_height_scale); + paint_rect, 1.f / contents_width_scale, 1.f / contents_height_scale); + } else { + layer_rect = paint_rect; } SkRect layer_sk_rect = SkRect::MakeXYWH( @@ -71,15 +106,10 @@ void ContentLayerUpdater::PaintContents(SkCanvas* canvas, canvas->drawColor(SK_ColorTRANSPARENT, SkXfermode::kSrc_Mode); } - gfx::RectF opaque_layer_rect; - painter_->Paint(canvas, layer_rect, &opaque_layer_rect); + painter_->Paint(canvas, layer_rect); canvas->restore(); - gfx::Rect opaque_content_rect = gfx::ToEnclosedRect(gfx::ScaleRect( - opaque_layer_rect, contents_width_scale, contents_height_scale)); - *resulting_opaque_rect = opaque_content_rect; - - content_rect_ = content_rect; + paint_rect_ = paint_rect; } void ContentLayerUpdater::SetOpaque(bool opaque) { @@ -90,4 +120,8 @@ void ContentLayerUpdater::SetFillsBoundsCompletely(bool fills_bounds) { layer_fills_bounds_completely_ = fills_bounds; } +void ContentLayerUpdater::SetBackgroundColor(SkColor background_color) { + background_color_ = background_color; +} + } // namespace cc diff --git a/chromium/cc/resources/content_layer_updater.h b/chromium/cc/resources/content_layer_updater.h index 7dfcb6a794f..4ba18ba9e40 100644 --- a/chromium/cc/resources/content_layer_updater.h +++ b/chromium/cc/resources/content_layer_updater.h @@ -7,7 +7,7 @@ #include "cc/base/cc_export.h" #include "cc/resources/layer_updater.h" -#include "ui/gfx/rect.h" +#include "ui/gfx/geometry/rect.h" class SkCanvas; @@ -22,27 +22,33 @@ class RenderingStatsInstrumentation; class CC_EXPORT ContentLayerUpdater : public LayerUpdater { public: void set_rendering_stats_instrumentation(RenderingStatsInstrumentation* rsi); - virtual void SetOpaque(bool opaque) OVERRIDE; - virtual void SetFillsBoundsCompletely(bool fills_bounds) OVERRIDE; + void SetOpaque(bool opaque) override; + void SetFillsBoundsCompletely(bool fills_bounds) override; + void SetBackgroundColor(SkColor background_color) override; protected: ContentLayerUpdater(scoped_ptr<LayerPainter> painter, RenderingStatsInstrumentation* stats_instrumentation, int layer_id); - virtual ~ContentLayerUpdater(); + ~ContentLayerUpdater() override; + // Paints the contents. |content_size| size of the underlying layer in + // layer's content space. |paint_rect| bounds to paint in content space of the + // layer. Both |content_size| and |paint_rect| are in pixels. void PaintContents(SkCanvas* canvas, - const gfx::Rect& content_rect, + const gfx::Size& layer_content_size, + const gfx::Rect& paint_rect, float contents_width_scale, - float contents_height_scale, - gfx::Rect* resulting_opaque_rect); - gfx::Rect content_rect() const { return content_rect_; } + float contents_height_scale); + gfx::Rect paint_rect() const { return paint_rect_; } bool layer_is_opaque() const { return layer_is_opaque_; } bool layer_fills_bounds_completely() const { return layer_fills_bounds_completely_; } + SkColor background_color() const { return background_color_; } + RenderingStatsInstrumentation* rendering_stats_instrumentation_; int layer_id_; @@ -52,8 +58,9 @@ class CC_EXPORT ContentLayerUpdater : public LayerUpdater { bool layer_fills_bounds_completely_; private: - gfx::Rect content_rect_; + gfx::Rect paint_rect_; scoped_ptr<LayerPainter> painter_; + SkColor background_color_; DISALLOW_COPY_AND_ASSIGN(ContentLayerUpdater); }; diff --git a/chromium/cc/resources/direct_raster_worker_pool.cc b/chromium/cc/resources/direct_raster_worker_pool.cc deleted file mode 100644 index 4bd0c55c739..00000000000 --- a/chromium/cc/resources/direct_raster_worker_pool.cc +++ /dev/null @@ -1,215 +0,0 @@ -// 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/direct_raster_worker_pool.h" - -#include "base/debug/trace_event.h" -#include "cc/output/context_provider.h" -#include "cc/resources/resource.h" -#include "cc/resources/resource_provider.h" -#include "gpu/command_buffer/client/gles2_interface.h" -#include "third_party/skia/include/gpu/GrContext.h" - -namespace cc { - -// static -scoped_ptr<RasterWorkerPool> DirectRasterWorkerPool::Create( - base::SequencedTaskRunner* task_runner, - ResourceProvider* resource_provider, - ContextProvider* context_provider) { - return make_scoped_ptr<RasterWorkerPool>(new DirectRasterWorkerPool( - task_runner, resource_provider, context_provider)); -} - -DirectRasterWorkerPool::DirectRasterWorkerPool( - base::SequencedTaskRunner* task_runner, - ResourceProvider* resource_provider, - ContextProvider* context_provider) - : task_runner_(task_runner), - task_graph_runner_(new TaskGraphRunner), - namespace_token_(task_graph_runner_->GetNamespaceToken()), - resource_provider_(resource_provider), - context_provider_(context_provider), - run_tasks_on_origin_thread_pending_(false), - raster_tasks_pending_(false), - raster_tasks_required_for_activation_pending_(false), - raster_finished_weak_ptr_factory_(this), - weak_ptr_factory_(this) {} - -DirectRasterWorkerPool::~DirectRasterWorkerPool() { - DCHECK_EQ(0u, completed_tasks_.size()); -} - -Rasterizer* DirectRasterWorkerPool::AsRasterizer() { return this; } - -void DirectRasterWorkerPool::SetClient(RasterizerClient* client) { - client_ = client; -} - -void DirectRasterWorkerPool::Shutdown() { - TRACE_EVENT0("cc", "DirectRasterWorkerPool::Shutdown"); - - TaskGraph empty; - task_graph_runner_->ScheduleTasks(namespace_token_, &empty); - task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); -} - -void DirectRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { - TRACE_EVENT0("cc", "DirectRasterWorkerPool::ScheduleTasks"); - - DCHECK_EQ(queue->required_for_activation_count, - static_cast<size_t>( - std::count_if(queue->items.begin(), - queue->items.end(), - RasterTaskQueue::Item::IsRequiredForActivation))); - - raster_tasks_pending_ = true; - raster_tasks_required_for_activation_pending_ = true; - - unsigned priority = kRasterTaskPriorityBase; - - graph_.Reset(); - - // Cancel existing OnRasterFinished callbacks. - raster_finished_weak_ptr_factory_.InvalidateWeakPtrs(); - - scoped_refptr<RasterizerTask> - new_raster_required_for_activation_finished_task( - CreateRasterRequiredForActivationFinishedTask( - queue->required_for_activation_count, - task_runner_.get(), - base::Bind(&DirectRasterWorkerPool:: - OnRasterRequiredForActivationFinished, - raster_finished_weak_ptr_factory_.GetWeakPtr()))); - scoped_refptr<RasterizerTask> new_raster_finished_task( - CreateRasterFinishedTask( - task_runner_.get(), - base::Bind(&DirectRasterWorkerPool::OnRasterFinished, - raster_finished_weak_ptr_factory_.GetWeakPtr()))); - - for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); - it != queue->items.end(); - ++it) { - const RasterTaskQueue::Item& item = *it; - RasterTask* task = item.task; - DCHECK(!task->HasCompleted()); - - if (item.required_for_activation) { - graph_.edges.push_back(TaskGraph::Edge( - task, new_raster_required_for_activation_finished_task.get())); - } - - InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); - - graph_.edges.push_back( - TaskGraph::Edge(task, new_raster_finished_task.get())); - } - - InsertNodeForTask(&graph_, - new_raster_required_for_activation_finished_task.get(), - kRasterRequiredForActivationFinishedTaskPriority, - queue->required_for_activation_count); - InsertNodeForTask(&graph_, - new_raster_finished_task.get(), - kRasterFinishedTaskPriority, - queue->items.size()); - - ScheduleTasksOnOriginThread(this, &graph_); - task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); - - ScheduleRunTasksOnOriginThread(); - - raster_finished_task_ = new_raster_finished_task; - raster_required_for_activation_finished_task_ = - new_raster_required_for_activation_finished_task; -} - -void DirectRasterWorkerPool::CheckForCompletedTasks() { - TRACE_EVENT0("cc", "DirectRasterWorkerPool::CheckForCompletedTasks"); - - task_graph_runner_->CollectCompletedTasks(namespace_token_, - &completed_tasks_); - for (Task::Vector::const_iterator it = completed_tasks_.begin(); - it != completed_tasks_.end(); - ++it) { - RasterizerTask* task = static_cast<RasterizerTask*>(it->get()); - - task->WillComplete(); - task->CompleteOnOriginThread(this); - task->DidComplete(); - - task->RunReplyOnOriginThread(); - } - completed_tasks_.clear(); -} - -SkCanvas* DirectRasterWorkerPool::AcquireCanvasForRaster(RasterTask* task) { - return resource_provider_->MapDirectRasterBuffer(task->resource()->id()); -} - -void DirectRasterWorkerPool::ReleaseCanvasForRaster(RasterTask* task) { - resource_provider_->UnmapDirectRasterBuffer(task->resource()->id()); -} - -void DirectRasterWorkerPool::OnRasterFinished() { - TRACE_EVENT0("cc", "DirectRasterWorkerPool::OnRasterFinished"); - - DCHECK(raster_tasks_pending_); - raster_tasks_pending_ = false; - client_->DidFinishRunningTasks(); -} - -void DirectRasterWorkerPool::OnRasterRequiredForActivationFinished() { - TRACE_EVENT0("cc", - "DirectRasterWorkerPool::OnRasterRequiredForActivationFinished"); - - DCHECK(raster_tasks_required_for_activation_pending_); - raster_tasks_required_for_activation_pending_ = false; - client_->DidFinishRunningTasksRequiredForActivation(); -} - -void DirectRasterWorkerPool::ScheduleRunTasksOnOriginThread() { - if (run_tasks_on_origin_thread_pending_) - return; - - task_runner_->PostTask( - FROM_HERE, - base::Bind(&DirectRasterWorkerPool::RunTasksOnOriginThread, - weak_ptr_factory_.GetWeakPtr())); - run_tasks_on_origin_thread_pending_ = true; -} - -void DirectRasterWorkerPool::RunTasksOnOriginThread() { - TRACE_EVENT0("cc", "DirectRasterWorkerPool::RunTasksOnOriginThread"); - - DCHECK(run_tasks_on_origin_thread_pending_); - run_tasks_on_origin_thread_pending_ = false; - - if (context_provider_) { - DCHECK(context_provider_->ContextGL()); - // TODO(alokp): Use a trace macro to push/pop markers. - // Using push/pop functions directly incurs cost to evaluate function - // arguments even when tracing is disabled. - context_provider_->ContextGL()->PushGroupMarkerEXT( - 0, "DirectRasterWorkerPool::RunTasksOnOriginThread"); - - GrContext* gr_context = context_provider_->GrContext(); - // TODO(alokp): Implement TestContextProvider::GrContext(). - if (gr_context) - gr_context->resetContext(); - } - - task_graph_runner_->RunUntilIdle(); - - if (context_provider_) { - GrContext* gr_context = context_provider_->GrContext(); - // TODO(alokp): Implement TestContextProvider::GrContext(). - if (gr_context) - gr_context->flush(); - - context_provider_->ContextGL()->PopGroupMarkerEXT(); - } -} - -} // namespace cc diff --git a/chromium/cc/resources/direct_raster_worker_pool.h b/chromium/cc/resources/direct_raster_worker_pool.h deleted file mode 100644 index 8194b4f2d6c..00000000000 --- a/chromium/cc/resources/direct_raster_worker_pool.h +++ /dev/null @@ -1,81 +0,0 @@ -// 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_DIRECT_RASTER_WORKER_POOL_H_ -#define CC_RESOURCES_DIRECT_RASTER_WORKER_POOL_H_ - -#include "base/memory/weak_ptr.h" -#include "cc/resources/raster_worker_pool.h" -#include "cc/resources/rasterizer.h" - -namespace cc { -class ContextProvider; -class ResourceProvider; - -class CC_EXPORT DirectRasterWorkerPool : public RasterWorkerPool, - public Rasterizer, - public RasterizerTaskClient { - public: - virtual ~DirectRasterWorkerPool(); - - static scoped_ptr<RasterWorkerPool> Create( - base::SequencedTaskRunner* task_runner, - ResourceProvider* resource_provider, - ContextProvider* context_provider); - - // Overridden from RasterWorkerPool: - virtual Rasterizer* AsRasterizer() OVERRIDE; - - // Overridden from Rasterizer: - virtual void SetClient(RasterizerClient* client) OVERRIDE; - virtual void Shutdown() OVERRIDE; - virtual void ScheduleTasks(RasterTaskQueue* queue) OVERRIDE; - virtual void CheckForCompletedTasks() OVERRIDE; - - // Overridden from RasterizerTaskClient: - virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) OVERRIDE; - virtual void ReleaseCanvasForRaster(RasterTask* task) OVERRIDE; - - private: - DirectRasterWorkerPool(base::SequencedTaskRunner* task_runner, - ResourceProvider* resource_provider, - ContextProvider* context_provider); - - void OnRasterFinished(); - void OnRasterRequiredForActivationFinished(); - void ScheduleRunTasksOnOriginThread(); - void RunTasksOnOriginThread(); - void RunTaskOnOriginThread(RasterizerTask* task); - - scoped_refptr<base::SequencedTaskRunner> task_runner_; - scoped_ptr<TaskGraphRunner> task_graph_runner_; - const NamespaceToken namespace_token_; - RasterizerClient* client_; - ResourceProvider* resource_provider_; - ContextProvider* context_provider_; - - bool run_tasks_on_origin_thread_pending_; - - bool raster_tasks_pending_; - bool raster_tasks_required_for_activation_pending_; - - base::WeakPtrFactory<DirectRasterWorkerPool> - raster_finished_weak_ptr_factory_; - - scoped_refptr<RasterizerTask> raster_finished_task_; - scoped_refptr<RasterizerTask> raster_required_for_activation_finished_task_; - - // Task graph used when scheduling tasks and vector used to gather - // completed tasks. - TaskGraph graph_; - Task::Vector completed_tasks_; - - base::WeakPtrFactory<DirectRasterWorkerPool> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(DirectRasterWorkerPool); -}; - -} // namespace cc - -#endif // CC_RESOURCES_DIRECT_RASTER_WORKER_POOL_H_ diff --git a/chromium/cc/resources/eviction_tile_priority_queue.cc b/chromium/cc/resources/eviction_tile_priority_queue.cc new file mode 100644 index 00000000000..9f05e816764 --- /dev/null +++ b/chromium/cc/resources/eviction_tile_priority_queue.cc @@ -0,0 +1,221 @@ +// 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/eviction_tile_priority_queue.h" + +namespace cc { + +namespace { + +class EvictionOrderComparator { + public: + explicit EvictionOrderComparator(TreePriority tree_priority) + : tree_priority_(tree_priority) {} + + bool operator()( + const EvictionTilePriorityQueue::PairedPictureLayerQueue* a, + const EvictionTilePriorityQueue::PairedPictureLayerQueue* 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. + if (a->IsEmpty() || b->IsEmpty()) + 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; + + WhichTree b_tree = b->NextTileIteratorTree(tree_priority_); + const PictureLayerImpl::LayerEvictionTileIterator* b_iterator = + b_tree == ACTIVE_TREE ? &b->active_iterator : &b->pending_iterator; + + const Tile* a_tile = **a_iterator; + const Tile* b_tile = **b_iterator; + + const TilePriority& a_priority = + a_tile->priority_for_tree_priority(tree_priority_); + const TilePriority& b_priority = + b_tile->priority_for_tree_priority(tree_priority_); + bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY; + + // If the priority bin differs, b is lower priority if it has the higher + // priority bin. + if (a_priority.priority_bin != b_priority.priority_bin) + return b_priority.priority_bin > a_priority.priority_bin; + + // Otherwise if the resolution differs, then the order will be determined by + // whether we prioritize low res or not. + // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile + // class but instead produced by the iterators. + if (b_priority.resolution != a_priority.resolution) { + // Non ideal resolution should be sorted higher than other resolutions. + if (a_priority.resolution == NON_IDEAL_RESOLUTION) + return false; + + if (b_priority.resolution == NON_IDEAL_RESOLUTION) + return true; + + if (prioritize_low_res) + return a_priority.resolution == LOW_RESOLUTION; + return a_priority.resolution == HIGH_RESOLUTION; + } + + // Otherwise if the occlusion differs, b is lower priority if it is + // occluded. + bool a_is_occluded = a_tile->is_occluded_for_tree_priority(tree_priority_); + bool b_is_occluded = b_tile->is_occluded_for_tree_priority(tree_priority_); + if (a_is_occluded != b_is_occluded) + return b_is_occluded; + + // b is lower priorty if it is farther from visible. + return b_priority.distance_to_visible > a_priority.distance_to_visible; + } + + private: + TreePriority tree_priority_; +}; + +} // namespace + +EvictionTilePriorityQueue::EvictionTilePriorityQueue() { +} + +EvictionTilePriorityQueue::~EvictionTilePriorityQueue() { +} + +void EvictionTilePriorityQueue::Build( + const std::vector<PictureLayerImpl::Pair>& paired_layers, + TreePriority tree_priority) { + tree_priority_ = tree_priority; + + for (std::vector<PictureLayerImpl::Pair>::const_iterator it = + paired_layers.begin(); + it != paired_layers.end(); + ++it) { + paired_queues_.push_back( + make_scoped_ptr(new PairedPictureLayerQueue(*it, tree_priority_))); + } + + paired_queues_.make_heap(EvictionOrderComparator(tree_priority_)); +} + +void EvictionTilePriorityQueue::Reset() { + paired_queues_.clear(); +} + +bool EvictionTilePriorityQueue::IsEmpty() const { + return paired_queues_.empty() || paired_queues_.front()->IsEmpty(); +} + +Tile* EvictionTilePriorityQueue::Top() { + DCHECK(!IsEmpty()); + return paired_queues_.front()->Top(tree_priority_); +} + +void EvictionTilePriorityQueue::Pop() { + DCHECK(!IsEmpty()); + + paired_queues_.pop_heap(EvictionOrderComparator(tree_priority_)); + PairedPictureLayerQueue* paired_queue = paired_queues_.back(); + paired_queue->Pop(tree_priority_); + paired_queues_.push_heap(EvictionOrderComparator(tree_priority_)); +} + +EvictionTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue() { +} + +EvictionTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue( + 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()) { +} + +EvictionTilePriorityQueue::PairedPictureLayerQueue::~PairedPictureLayerQueue() { +} + +bool EvictionTilePriorityQueue::PairedPictureLayerQueue::IsEmpty() const { + return !active_iterator && !pending_iterator; +} + +Tile* EvictionTilePriorityQueue::PairedPictureLayerQueue::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); + + Tile* tile = **next_iterator; + DCHECK(std::find(returned_shared_tiles.begin(), + returned_shared_tiles.end(), + tile) == returned_shared_tiles.end()); + return tile; +} + +void EvictionTilePriorityQueue::PairedPictureLayerQueue::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); + + if (IsEmpty()) + return; + + next_tree = NextTileIteratorTree(tree_priority); + next_iterator = + next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator; + while (std::find(returned_shared_tiles.begin(), + returned_shared_tiles.end(), + **next_iterator) != returned_shared_tiles.end()) { + ++(*next_iterator); + if (IsEmpty()) + break; + next_tree = NextTileIteratorTree(tree_priority); + next_iterator = + next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator; + } +} + +WhichTree +EvictionTilePriorityQueue::PairedPictureLayerQueue::NextTileIteratorTree( + TreePriority tree_priority) const { + DCHECK(!IsEmpty()); + + // If we only have one iterator with tiles, return it. + if (!active_iterator) + return PENDING_TREE; + if (!pending_iterator) + return ACTIVE_TREE; + + const Tile* active_tile = *active_iterator; + const Tile* pending_tile = *pending_iterator; + if (active_tile == pending_tile) + return ACTIVE_TREE; + + const TilePriority& active_priority = + active_tile->priority_for_tree_priority(tree_priority); + const TilePriority& pending_priority = + pending_tile->priority_for_tree_priority(tree_priority); + + if (pending_priority.IsHigherPriorityThan(active_priority)) + return ACTIVE_TREE; + return PENDING_TREE; +} + +} // namespace cc diff --git a/chromium/cc/resources/eviction_tile_priority_queue.h b/chromium/cc/resources/eviction_tile_priority_queue.h new file mode 100644 index 00000000000..e91f0d2a682 --- /dev/null +++ b/chromium/cc/resources/eviction_tile_priority_queue.h @@ -0,0 +1,61 @@ +// 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_EVICTION_TILE_PRIORITY_QUEUE_H_ +#define CC_RESOURCES_EVICTION_TILE_PRIORITY_QUEUE_H_ + +#include <utility> +#include <vector> + +#include "cc/base/cc_export.h" +#include "cc/layers/picture_layer_impl.h" +#include "cc/resources/tile_priority.h" + +namespace cc { + +class CC_EXPORT EvictionTilePriorityQueue { + public: + struct PairedPictureLayerQueue { + PairedPictureLayerQueue(); + PairedPictureLayerQueue(const PictureLayerImpl::Pair& layer_pair, + TreePriority tree_priority); + ~PairedPictureLayerQueue(); + + bool IsEmpty() const; + Tile* Top(TreePriority tree_priority); + void Pop(TreePriority tree_priority); + + WhichTree NextTileIteratorTree(TreePriority tree_priority) const; + + PictureLayerImpl::LayerEvictionTileIterator active_iterator; + PictureLayerImpl::LayerEvictionTileIterator pending_iterator; + + // TODO(vmpstr): Investigate removing this. + std::vector<Tile*> returned_shared_tiles; + }; + + EvictionTilePriorityQueue(); + ~EvictionTilePriorityQueue(); + + void Build(const std::vector<PictureLayerImpl::Pair>& paired_layers, + TreePriority tree_priority); + void Reset(); + + bool IsEmpty() const; + Tile* Top(); + void Pop(); + + 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_; + TreePriority tree_priority_; + + DISALLOW_COPY_AND_ASSIGN(EvictionTilePriorityQueue); +}; + +} // namespace cc + +#endif // CC_RESOURCES_EVICTION_TILE_PRIORITY_QUEUE_H_ diff --git a/chromium/cc/resources/gpu_raster_worker_pool.cc b/chromium/cc/resources/gpu_raster_worker_pool.cc new file mode 100644 index 00000000000..04724f120f0 --- /dev/null +++ b/chromium/cc/resources/gpu_raster_worker_pool.cc @@ -0,0 +1,252 @@ +// 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/gpu_raster_worker_pool.h" + +#include <algorithm> + +#include "base/debug/trace_event.h" +#include "cc/output/context_provider.h" +#include "cc/resources/raster_buffer.h" +#include "cc/resources/raster_source.h" +#include "cc/resources/resource.h" +#include "cc/resources/resource_provider.h" +#include "cc/resources/scoped_gpu_raster.h" +#include "gpu/command_buffer/client/gles2_interface.h" +#include "third_party/skia/include/core/SkMultiPictureDraw.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/gpu/GrContext.h" + +namespace cc { +namespace { + +class RasterBufferImpl : public RasterBuffer { + public: + RasterBufferImpl(ResourceProvider* resource_provider, + const Resource* resource, + SkMultiPictureDraw* multi_picture_draw, + bool use_distance_field_text) + : lock_(resource_provider, resource->id()), + resource_(resource), + multi_picture_draw_(multi_picture_draw), + use_distance_field_text_(use_distance_field_text) {} + + // Overridden from RasterBuffer: + void Playback(const RasterSource* raster_source, + const gfx::Rect& rect, + float scale) override { + // Turn on distance fields for layers that have ever animated. + bool use_distance_field_text = + use_distance_field_text_ || + raster_source->SuitableForDistanceFieldText(); + SkSurface* sk_surface = lock_.GetSkSurface(use_distance_field_text); + + if (!sk_surface) + return; + + SkPictureRecorder recorder; + gfx::Size size = resource_->size(); + skia::RefPtr<SkCanvas> canvas = + skia::SharePtr(recorder.beginRecording(size.width(), size.height())); + + canvas->save(); + raster_source->PlaybackToCanvas(canvas.get(), rect, scale); + canvas->restore(); + + // Add the canvas and recorded picture to |multi_picture_draw_|. + skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording()); + multi_picture_draw_->add(sk_surface->getCanvas(), picture.get()); + } + + private: + ResourceProvider::ScopedWriteLockGr lock_; + const Resource* resource_; + SkMultiPictureDraw* multi_picture_draw_; + bool use_distance_field_text_; + + DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); +}; + +} // namespace + +// static +scoped_ptr<RasterWorkerPool> GpuRasterWorkerPool::Create( + base::SequencedTaskRunner* task_runner, + ContextProvider* context_provider, + ResourceProvider* resource_provider, + bool use_distance_field_text) { + return make_scoped_ptr<RasterWorkerPool>( + new GpuRasterWorkerPool(task_runner, + context_provider, + resource_provider, + use_distance_field_text)); +} + +GpuRasterWorkerPool::GpuRasterWorkerPool(base::SequencedTaskRunner* task_runner, + ContextProvider* context_provider, + ResourceProvider* resource_provider, + bool use_distance_field_text) + : task_runner_(task_runner), + task_graph_runner_(new TaskGraphRunner), + namespace_token_(task_graph_runner_->GetNamespaceToken()), + context_provider_(context_provider), + resource_provider_(resource_provider), + run_tasks_on_origin_thread_pending_(false), + use_distance_field_text_(use_distance_field_text), + raster_finished_weak_ptr_factory_(this), + weak_ptr_factory_(this) { + DCHECK(context_provider_); +} + +GpuRasterWorkerPool::~GpuRasterWorkerPool() { + DCHECK_EQ(0u, completed_tasks_.size()); +} + +Rasterizer* GpuRasterWorkerPool::AsRasterizer() { + return this; +} + +void GpuRasterWorkerPool::SetClient(RasterizerClient* client) { + client_ = client; +} + +void GpuRasterWorkerPool::Shutdown() { + TRACE_EVENT0("cc", "GpuRasterWorkerPool::Shutdown"); + + TaskGraph empty; + task_graph_runner_->ScheduleTasks(namespace_token_, &empty); + task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); +} + +void GpuRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { + TRACE_EVENT0("cc", "GpuRasterWorkerPool::ScheduleTasks"); + + // Mark all task sets as pending. + raster_pending_.set(); + + unsigned priority = kRasterTaskPriorityBase; + + graph_.Reset(); + + // Cancel existing OnRasterFinished callbacks. + raster_finished_weak_ptr_factory_.InvalidateWeakPtrs(); + + scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets]; + + size_t task_count[kNumberOfTaskSets] = {0}; + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + new_raster_finished_tasks[task_set] = CreateRasterFinishedTask( + task_runner_.get(), + base::Bind(&GpuRasterWorkerPool::OnRasterFinished, + raster_finished_weak_ptr_factory_.GetWeakPtr(), + task_set)); + } + + for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); + it != queue->items.end(); + ++it) { + const RasterTaskQueue::Item& item = *it; + RasterTask* task = item.task; + DCHECK(!task->HasCompleted()); + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + if (!item.task_sets[task_set]) + continue; + + ++task_count[task_set]; + + graph_.edges.push_back( + TaskGraph::Edge(task, new_raster_finished_tasks[task_set].get())); + } + + InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); + } + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + InsertNodeForTask(&graph_, + new_raster_finished_tasks[task_set].get(), + kRasterFinishedTaskPriority, + task_count[task_set]); + } + + ScheduleTasksOnOriginThread(this, &graph_); + task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); + + ScheduleRunTasksOnOriginThread(); + + std::copy(new_raster_finished_tasks, + new_raster_finished_tasks + kNumberOfTaskSets, + raster_finished_tasks_); +} + +void GpuRasterWorkerPool::CheckForCompletedTasks() { + TRACE_EVENT0("cc", "GpuRasterWorkerPool::CheckForCompletedTasks"); + + task_graph_runner_->CollectCompletedTasks(namespace_token_, + &completed_tasks_); + for (Task::Vector::const_iterator it = completed_tasks_.begin(); + it != completed_tasks_.end(); + ++it) { + RasterizerTask* task = static_cast<RasterizerTask*>(it->get()); + + task->WillComplete(); + task->CompleteOnOriginThread(this); + task->DidComplete(); + + task->RunReplyOnOriginThread(); + } + completed_tasks_.clear(); +} + +scoped_ptr<RasterBuffer> GpuRasterWorkerPool::AcquireBufferForRaster( + const Resource* resource) { + return make_scoped_ptr<RasterBuffer>( + new RasterBufferImpl(resource_provider_, + resource, + &multi_picture_draw_, + use_distance_field_text_)); +} + +void GpuRasterWorkerPool::ReleaseBufferForRaster( + scoped_ptr<RasterBuffer> buffer) { + // Nothing to do here. RasterBufferImpl destructor cleans up after itself. +} + +void GpuRasterWorkerPool::OnRasterFinished(TaskSet task_set) { + TRACE_EVENT1( + "cc", "GpuRasterWorkerPool::OnRasterFinished", "task_set", task_set); + + DCHECK(raster_pending_[task_set]); + raster_pending_[task_set] = false; + client_->DidFinishRunningTasks(task_set); +} + +void GpuRasterWorkerPool::ScheduleRunTasksOnOriginThread() { + if (run_tasks_on_origin_thread_pending_) + return; + + task_runner_->PostTask( + FROM_HERE, + base::Bind(&GpuRasterWorkerPool::RunTasksOnOriginThread, + weak_ptr_factory_.GetWeakPtr())); + run_tasks_on_origin_thread_pending_ = true; +} + +void GpuRasterWorkerPool::RunTasksOnOriginThread() { + TRACE_EVENT0("cc", "GpuRasterWorkerPool::RunTasksOnOriginThread"); + + DCHECK(run_tasks_on_origin_thread_pending_); + run_tasks_on_origin_thread_pending_ = false; + + ScopedGpuRaster gpu_raster(context_provider_); + task_graph_runner_->RunUntilIdle(); + + // Draw each all of the pictures that were collected. This will also clear + // the pictures and canvases added to |multi_picture_draw_| + multi_picture_draw_.draw(); +} + +} // namespace cc diff --git a/chromium/cc/resources/gpu_raster_worker_pool.h b/chromium/cc/resources/gpu_raster_worker_pool.h new file mode 100644 index 00000000000..c5ff13f1361 --- /dev/null +++ b/chromium/cc/resources/gpu_raster_worker_pool.h @@ -0,0 +1,83 @@ +// 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_GPU_RASTER_WORKER_POOL_H_ +#define CC_RESOURCES_GPU_RASTER_WORKER_POOL_H_ + +#include "base/memory/weak_ptr.h" +#include "cc/resources/raster_worker_pool.h" +#include "cc/resources/rasterizer.h" +#include "third_party/skia/include/core/SkMultiPictureDraw.h" + +namespace cc { +class ContextProvider; +class ResourceProvider; + +class CC_EXPORT GpuRasterWorkerPool : public RasterWorkerPool, + public Rasterizer, + public RasterizerTaskClient { + public: + ~GpuRasterWorkerPool() override; + + static scoped_ptr<RasterWorkerPool> Create( + base::SequencedTaskRunner* task_runner, + ContextProvider* context_provider, + ResourceProvider* resource_provider, + bool use_distance_field_text); + + // Overridden from RasterWorkerPool: + Rasterizer* AsRasterizer() override; + + // Overridden from Rasterizer: + void SetClient(RasterizerClient* client) override; + void Shutdown() override; + void ScheduleTasks(RasterTaskQueue* queue) override; + void CheckForCompletedTasks() override; + + // Overridden from RasterizerTaskClient: + scoped_ptr<RasterBuffer> AcquireBufferForRaster( + const Resource* resource) override; + void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override; + + private: + GpuRasterWorkerPool(base::SequencedTaskRunner* task_runner, + ContextProvider* context_provider, + ResourceProvider* resource_provider, + bool use_distance_field_text); + + void OnRasterFinished(TaskSet task_set); + void ScheduleRunTasksOnOriginThread(); + void RunTasksOnOriginThread(); + void RunTaskOnOriginThread(RasterizerTask* task); + + scoped_refptr<base::SequencedTaskRunner> task_runner_; + scoped_ptr<TaskGraphRunner> task_graph_runner_; + const NamespaceToken namespace_token_; + RasterizerClient* client_; + ContextProvider* context_provider_; + ResourceProvider* resource_provider_; + SkMultiPictureDraw multi_picture_draw_; + + bool run_tasks_on_origin_thread_pending_; + bool use_distance_field_text_; + + TaskSetCollection raster_pending_; + + scoped_refptr<RasterizerTask> raster_finished_tasks_[kNumberOfTaskSets]; + + // Task graph used when scheduling tasks and vector used to gather + // completed tasks. + TaskGraph graph_; + Task::Vector completed_tasks_; + + base::WeakPtrFactory<GpuRasterWorkerPool> raster_finished_weak_ptr_factory_; + + base::WeakPtrFactory<GpuRasterWorkerPool> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(GpuRasterWorkerPool); +}; + +} // namespace cc + +#endif // CC_RESOURCES_GPU_RASTER_WORKER_POOL_H_ diff --git a/chromium/cc/resources/image_copy_raster_worker_pool.cc b/chromium/cc/resources/image_copy_raster_worker_pool.cc deleted file mode 100644 index 0d4f7441e52..00000000000 --- a/chromium/cc/resources/image_copy_raster_worker_pool.cc +++ /dev/null @@ -1,260 +0,0 @@ -// 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/image_copy_raster_worker_pool.h" - -#include <algorithm> - -#include "base/debug/trace_event.h" -#include "cc/debug/traced_value.h" -#include "cc/resources/resource_pool.h" -#include "cc/resources/scoped_resource.h" - -namespace cc { - -// static -scoped_ptr<RasterWorkerPool> ImageCopyRasterWorkerPool::Create( - base::SequencedTaskRunner* task_runner, - TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider, - ResourcePool* resource_pool) { - return make_scoped_ptr<RasterWorkerPool>(new ImageCopyRasterWorkerPool( - task_runner, task_graph_runner, resource_provider, resource_pool)); -} - -ImageCopyRasterWorkerPool::ImageCopyRasterWorkerPool( - base::SequencedTaskRunner* task_runner, - TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider, - ResourcePool* resource_pool) - : task_runner_(task_runner), - task_graph_runner_(task_graph_runner), - namespace_token_(task_graph_runner->GetNamespaceToken()), - resource_provider_(resource_provider), - resource_pool_(resource_pool), - has_performed_copy_since_last_flush_(false), - raster_tasks_pending_(false), - raster_tasks_required_for_activation_pending_(false), - raster_finished_weak_ptr_factory_(this) {} - -ImageCopyRasterWorkerPool::~ImageCopyRasterWorkerPool() { - DCHECK_EQ(0u, raster_task_states_.size()); -} - -Rasterizer* ImageCopyRasterWorkerPool::AsRasterizer() { return this; } - -void ImageCopyRasterWorkerPool::SetClient(RasterizerClient* client) { - client_ = client; -} - -void ImageCopyRasterWorkerPool::Shutdown() { - TRACE_EVENT0("cc", "ImageCopyRasterWorkerPool::Shutdown"); - - TaskGraph empty; - task_graph_runner_->ScheduleTasks(namespace_token_, &empty); - task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); -} - -void ImageCopyRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { - TRACE_EVENT0("cc", "ImageCopyRasterWorkerPool::ScheduleTasks"); - - DCHECK_EQ(queue->required_for_activation_count, - static_cast<size_t>( - std::count_if(queue->items.begin(), - queue->items.end(), - RasterTaskQueue::Item::IsRequiredForActivation))); - - if (!raster_tasks_pending_) - TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); - - raster_tasks_pending_ = true; - raster_tasks_required_for_activation_pending_ = true; - - unsigned priority = kRasterTaskPriorityBase; - - graph_.Reset(); - - // Cancel existing OnRasterFinished callbacks. - raster_finished_weak_ptr_factory_.InvalidateWeakPtrs(); - - scoped_refptr<RasterizerTask> - new_raster_required_for_activation_finished_task( - CreateRasterRequiredForActivationFinishedTask( - queue->required_for_activation_count, - task_runner_.get(), - base::Bind(&ImageCopyRasterWorkerPool:: - OnRasterRequiredForActivationFinished, - raster_finished_weak_ptr_factory_.GetWeakPtr()))); - scoped_refptr<RasterizerTask> new_raster_finished_task( - CreateRasterFinishedTask( - task_runner_.get(), - base::Bind(&ImageCopyRasterWorkerPool::OnRasterFinished, - raster_finished_weak_ptr_factory_.GetWeakPtr()))); - - resource_pool_->CheckBusyResources(); - - for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); - it != queue->items.end(); - ++it) { - const RasterTaskQueue::Item& item = *it; - RasterTask* task = item.task; - DCHECK(!task->HasCompleted()); - - if (item.required_for_activation) { - graph_.edges.push_back(TaskGraph::Edge( - task, new_raster_required_for_activation_finished_task.get())); - } - - InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); - - graph_.edges.push_back( - TaskGraph::Edge(task, new_raster_finished_task.get())); - } - - InsertNodeForTask(&graph_, - new_raster_required_for_activation_finished_task.get(), - kRasterRequiredForActivationFinishedTaskPriority, - queue->required_for_activation_count); - InsertNodeForTask(&graph_, - new_raster_finished_task.get(), - kRasterFinishedTaskPriority, - queue->items.size()); - - ScheduleTasksOnOriginThread(this, &graph_); - task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); - - raster_finished_task_ = new_raster_finished_task; - raster_required_for_activation_finished_task_ = - new_raster_required_for_activation_finished_task; - - resource_pool_->ReduceResourceUsage(); - - TRACE_EVENT_ASYNC_STEP_INTO1( - "cc", - "ScheduledTasks", - this, - "rasterizing", - "state", - TracedValue::FromValue(StateAsValue().release())); -} - -void ImageCopyRasterWorkerPool::CheckForCompletedTasks() { - TRACE_EVENT0("cc", "ImageCopyRasterWorkerPool::CheckForCompletedTasks"); - - task_graph_runner_->CollectCompletedTasks(namespace_token_, - &completed_tasks_); - for (Task::Vector::const_iterator it = completed_tasks_.begin(); - it != completed_tasks_.end(); - ++it) { - RasterizerTask* task = static_cast<RasterizerTask*>(it->get()); - - task->WillComplete(); - task->CompleteOnOriginThread(this); - task->DidComplete(); - - task->RunReplyOnOriginThread(); - } - completed_tasks_.clear(); - - FlushCopies(); -} - -SkCanvas* ImageCopyRasterWorkerPool::AcquireCanvasForRaster(RasterTask* task) { - DCHECK_EQ(task->resource()->format(), resource_pool_->resource_format()); - scoped_ptr<ScopedResource> resource( - resource_pool_->AcquireResource(task->resource()->size())); - SkCanvas* canvas = resource_provider_->MapImageRasterBuffer(resource->id()); - DCHECK(std::find_if(raster_task_states_.begin(), - raster_task_states_.end(), - RasterTaskState::TaskComparator(task)) == - raster_task_states_.end()); - raster_task_states_.push_back(RasterTaskState(task, resource.release())); - return canvas; -} - -void ImageCopyRasterWorkerPool::ReleaseCanvasForRaster(RasterTask* task) { - RasterTaskState::Vector::iterator it = - std::find_if(raster_task_states_.begin(), - raster_task_states_.end(), - RasterTaskState::TaskComparator(task)); - DCHECK(it != raster_task_states_.end()); - scoped_ptr<ScopedResource> resource(it->resource); - std::swap(*it, raster_task_states_.back()); - raster_task_states_.pop_back(); - - bool content_has_changed = - resource_provider_->UnmapImageRasterBuffer(resource->id()); - - // |content_has_changed| can be false as result of task being canceled or - // task implementation deciding not to modify bitmap (ie. analysis of raster - // commands detected content as a solid color). - if (content_has_changed) { - resource_provider_->CopyResource(resource->id(), task->resource()->id()); - has_performed_copy_since_last_flush_ = true; - } - - resource_pool_->ReleaseResource(resource.Pass()); -} - -void ImageCopyRasterWorkerPool::OnRasterFinished() { - TRACE_EVENT0("cc", "ImageCopyRasterWorkerPool::OnRasterFinished"); - - DCHECK(raster_tasks_pending_); - raster_tasks_pending_ = false; - TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); - client_->DidFinishRunningTasks(); -} - -void ImageCopyRasterWorkerPool::OnRasterRequiredForActivationFinished() { - TRACE_EVENT0( - "cc", "ImageCopyRasterWorkerPool::OnRasterRequiredForActivationFinished"); - - DCHECK(raster_tasks_required_for_activation_pending_); - raster_tasks_required_for_activation_pending_ = false; - TRACE_EVENT_ASYNC_STEP_INTO1( - "cc", - "ScheduledTasks", - this, - "rasterizing", - "state", - TracedValue::FromValue(StateAsValue().release())); - client_->DidFinishRunningTasksRequiredForActivation(); -} - -void ImageCopyRasterWorkerPool::FlushCopies() { - if (!has_performed_copy_since_last_flush_) - return; - - resource_provider_->ShallowFlushIfSupported(); - has_performed_copy_since_last_flush_ = false; -} - -scoped_ptr<base::Value> ImageCopyRasterWorkerPool::StateAsValue() const { - scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); - - state->SetInteger("pending_count", raster_task_states_.size()); - state->SetBoolean("tasks_required_for_activation_pending", - raster_tasks_required_for_activation_pending_); - state->Set("staging_state", StagingStateAsValue().release()); - - return state.PassAs<base::Value>(); -} -scoped_ptr<base::Value> ImageCopyRasterWorkerPool::StagingStateAsValue() const { - scoped_ptr<base::DictionaryValue> staging_state(new base::DictionaryValue); - - staging_state->SetInteger("staging_resource_count", - resource_pool_->total_resource_count()); - staging_state->SetInteger("bytes_used_for_staging_resources", - resource_pool_->total_memory_usage_bytes()); - staging_state->SetInteger("pending_copy_count", - resource_pool_->total_resource_count() - - resource_pool_->acquired_resource_count()); - staging_state->SetInteger("bytes_pending_copy", - resource_pool_->total_memory_usage_bytes() - - resource_pool_->acquired_memory_usage_bytes()); - - return staging_state.PassAs<base::Value>(); -} - -} // namespace cc diff --git a/chromium/cc/resources/image_copy_raster_worker_pool.h b/chromium/cc/resources/image_copy_raster_worker_pool.h deleted file mode 100644 index cb243daca38..00000000000 --- a/chromium/cc/resources/image_copy_raster_worker_pool.h +++ /dev/null @@ -1,110 +0,0 @@ -// 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_IMAGE_COPY_RASTER_WORKER_POOL_H_ -#define CC_RESOURCES_IMAGE_COPY_RASTER_WORKER_POOL_H_ - -#include <vector> - -#include "base/memory/weak_ptr.h" -#include "base/values.h" -#include "cc/resources/raster_worker_pool.h" -#include "cc/resources/rasterizer.h" - -namespace cc { -class ResourcePool; -class ResourceProvider; -class ScopedResource; - -class CC_EXPORT ImageCopyRasterWorkerPool : public RasterWorkerPool, - public Rasterizer, - public RasterizerTaskClient { - public: - virtual ~ImageCopyRasterWorkerPool(); - - static scoped_ptr<RasterWorkerPool> Create( - base::SequencedTaskRunner* task_runner, - TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider, - ResourcePool* resource_pool); - - // Overridden from RasterWorkerPool: - virtual Rasterizer* AsRasterizer() OVERRIDE; - - // Overridden from Rasterizer: - virtual void SetClient(RasterizerClient* client) OVERRIDE; - virtual void Shutdown() OVERRIDE; - virtual void ScheduleTasks(RasterTaskQueue* queue) OVERRIDE; - virtual void CheckForCompletedTasks() OVERRIDE; - - // Overridden from RasterizerTaskClient: - virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) OVERRIDE; - virtual void ReleaseCanvasForRaster(RasterTask* task) OVERRIDE; - - protected: - ImageCopyRasterWorkerPool(base::SequencedTaskRunner* task_runner, - TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider, - ResourcePool* resource_pool); - - private: - struct RasterTaskState { - class TaskComparator { - public: - explicit TaskComparator(const RasterTask* task) : task_(task) {} - - bool operator()(const RasterTaskState& state) const { - return state.task == task_; - } - - private: - const RasterTask* task_; - }; - - typedef std::vector<RasterTaskState> Vector; - - RasterTaskState(const RasterTask* task, ScopedResource* resource) - : task(task), resource(resource) {} - - const RasterTask* task; - ScopedResource* resource; - }; - - void OnRasterFinished(); - void OnRasterRequiredForActivationFinished(); - void FlushCopies(); - scoped_ptr<base::Value> StateAsValue() const; - scoped_ptr<base::Value> StagingStateAsValue() const; - - scoped_refptr<base::SequencedTaskRunner> task_runner_; - TaskGraphRunner* task_graph_runner_; - const NamespaceToken namespace_token_; - RasterizerClient* client_; - ResourceProvider* resource_provider_; - ResourcePool* resource_pool_; - - RasterTaskState::Vector raster_task_states_; - - bool has_performed_copy_since_last_flush_; - - bool raster_tasks_pending_; - bool raster_tasks_required_for_activation_pending_; - - base::WeakPtrFactory<ImageCopyRasterWorkerPool> - raster_finished_weak_ptr_factory_; - - scoped_refptr<RasterizerTask> raster_finished_task_; - scoped_refptr<RasterizerTask> raster_required_for_activation_finished_task_; - - // Task graph used when scheduling tasks and vector used to gather - // completed tasks. - TaskGraph graph_; - Task::Vector completed_tasks_; - - DISALLOW_COPY_AND_ASSIGN(ImageCopyRasterWorkerPool); -}; - -} // namespace cc - -#endif // CC_RESOURCES_IMAGE_COPY_RASTER_WORKER_POOL_H_ diff --git a/chromium/cc/resources/image_layer_updater.cc b/chromium/cc/resources/image_layer_updater.cc index d5d62ed5e97..0538d96ea36 100644 --- a/chromium/cc/resources/image_layer_updater.cc +++ b/chromium/cc/resources/image_layer_updater.cc @@ -29,7 +29,7 @@ scoped_refptr<ImageLayerUpdater> ImageLayerUpdater::Create() { scoped_ptr<LayerUpdater::Resource> ImageLayerUpdater::CreateResource( PrioritizedResourceManager* manager) { - return scoped_ptr<LayerUpdater::Resource>( + return make_scoped_ptr( new Resource(this, PrioritizedResource::Create(manager))); } diff --git a/chromium/cc/resources/image_layer_updater.h b/chromium/cc/resources/image_layer_updater.h index b2235b18031..81225ba7b5e 100644 --- a/chromium/cc/resources/image_layer_updater.h +++ b/chromium/cc/resources/image_layer_updater.h @@ -19,12 +19,12 @@ class CC_EXPORT ImageLayerUpdater : public LayerUpdater { public: Resource(ImageLayerUpdater* updater, scoped_ptr<PrioritizedResource> texture); - virtual ~Resource(); + ~Resource() override; - virtual void Update(ResourceUpdateQueue* queue, - const gfx::Rect& source_rect, - const gfx::Vector2d& dest_offset, - bool partial_update) OVERRIDE; + void Update(ResourceUpdateQueue* queue, + const gfx::Rect& source_rect, + const gfx::Vector2d& dest_offset, + bool partial_update) override; private: ImageLayerUpdater* updater_; @@ -34,8 +34,8 @@ class CC_EXPORT ImageLayerUpdater : public LayerUpdater { static scoped_refptr<ImageLayerUpdater> Create(); - virtual scoped_ptr<LayerUpdater::Resource> CreateResource( - PrioritizedResourceManager*) OVERRIDE; + scoped_ptr<LayerUpdater::Resource> CreateResource( + PrioritizedResourceManager*) override; void UpdateTexture(ResourceUpdateQueue* queue, PrioritizedResource* texture, @@ -48,7 +48,7 @@ class CC_EXPORT ImageLayerUpdater : public LayerUpdater { private: ImageLayerUpdater() {} - virtual ~ImageLayerUpdater() {} + ~ImageLayerUpdater() override {} SkBitmap bitmap_; diff --git a/chromium/cc/resources/image_raster_worker_pool.cc b/chromium/cc/resources/image_raster_worker_pool.cc deleted file mode 100644 index 007c1ed83f3..00000000000 --- a/chromium/cc/resources/image_raster_worker_pool.cc +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/resources/image_raster_worker_pool.h" - -#include "base/debug/trace_event.h" -#include "cc/debug/traced_value.h" -#include "cc/resources/resource.h" - -namespace cc { - -// static -scoped_ptr<RasterWorkerPool> ImageRasterWorkerPool::Create( - base::SequencedTaskRunner* task_runner, - TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider) { - return make_scoped_ptr<RasterWorkerPool>(new ImageRasterWorkerPool( - task_runner, task_graph_runner, resource_provider)); -} - -ImageRasterWorkerPool::ImageRasterWorkerPool( - base::SequencedTaskRunner* task_runner, - TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider) - : task_runner_(task_runner), - task_graph_runner_(task_graph_runner), - namespace_token_(task_graph_runner->GetNamespaceToken()), - resource_provider_(resource_provider), - raster_tasks_pending_(false), - raster_tasks_required_for_activation_pending_(false), - raster_finished_weak_ptr_factory_(this) {} - -ImageRasterWorkerPool::~ImageRasterWorkerPool() {} - -Rasterizer* ImageRasterWorkerPool::AsRasterizer() { return this; } - -void ImageRasterWorkerPool::SetClient(RasterizerClient* client) { - client_ = client; -} - -void ImageRasterWorkerPool::Shutdown() { - TRACE_EVENT0("cc", "ImageRasterWorkerPool::Shutdown"); - - TaskGraph empty; - task_graph_runner_->ScheduleTasks(namespace_token_, &empty); - task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); -} - -void ImageRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { - TRACE_EVENT0("cc", "ImageRasterWorkerPool::ScheduleTasks"); - - DCHECK_EQ(queue->required_for_activation_count, - static_cast<size_t>( - std::count_if(queue->items.begin(), - queue->items.end(), - RasterTaskQueue::Item::IsRequiredForActivation))); - - if (!raster_tasks_pending_) - TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); - - raster_tasks_pending_ = true; - raster_tasks_required_for_activation_pending_ = true; - - unsigned priority = kRasterTaskPriorityBase; - - graph_.Reset(); - - // Cancel existing OnRasterFinished callbacks. - raster_finished_weak_ptr_factory_.InvalidateWeakPtrs(); - - scoped_refptr<RasterizerTask> - new_raster_required_for_activation_finished_task( - CreateRasterRequiredForActivationFinishedTask( - queue->required_for_activation_count, - task_runner_.get(), - base::Bind( - &ImageRasterWorkerPool::OnRasterRequiredForActivationFinished, - raster_finished_weak_ptr_factory_.GetWeakPtr()))); - scoped_refptr<RasterizerTask> new_raster_finished_task( - CreateRasterFinishedTask( - task_runner_.get(), - base::Bind(&ImageRasterWorkerPool::OnRasterFinished, - raster_finished_weak_ptr_factory_.GetWeakPtr()))); - - for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); - it != queue->items.end(); - ++it) { - const RasterTaskQueue::Item& item = *it; - RasterTask* task = item.task; - DCHECK(!task->HasCompleted()); - - if (item.required_for_activation) { - graph_.edges.push_back(TaskGraph::Edge( - task, new_raster_required_for_activation_finished_task.get())); - } - - InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); - - graph_.edges.push_back( - TaskGraph::Edge(task, new_raster_finished_task.get())); - } - - InsertNodeForTask(&graph_, - new_raster_required_for_activation_finished_task.get(), - kRasterRequiredForActivationFinishedTaskPriority, - queue->required_for_activation_count); - InsertNodeForTask(&graph_, - new_raster_finished_task.get(), - kRasterFinishedTaskPriority, - queue->items.size()); - - ScheduleTasksOnOriginThread(this, &graph_); - task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); - - raster_finished_task_ = new_raster_finished_task; - raster_required_for_activation_finished_task_ = - new_raster_required_for_activation_finished_task; - - TRACE_EVENT_ASYNC_STEP_INTO1( - "cc", - "ScheduledTasks", - this, - "rasterizing", - "state", - TracedValue::FromValue(StateAsValue().release())); -} - -void ImageRasterWorkerPool::CheckForCompletedTasks() { - TRACE_EVENT0("cc", "ImageRasterWorkerPool::CheckForCompletedTasks"); - - task_graph_runner_->CollectCompletedTasks(namespace_token_, - &completed_tasks_); - for (Task::Vector::const_iterator it = completed_tasks_.begin(); - it != completed_tasks_.end(); - ++it) { - RasterizerTask* task = static_cast<RasterizerTask*>(it->get()); - - task->WillComplete(); - task->CompleteOnOriginThread(this); - task->DidComplete(); - - task->RunReplyOnOriginThread(); - } - completed_tasks_.clear(); -} - -SkCanvas* ImageRasterWorkerPool::AcquireCanvasForRaster(RasterTask* task) { - return resource_provider_->MapImageRasterBuffer(task->resource()->id()); -} - -void ImageRasterWorkerPool::ReleaseCanvasForRaster(RasterTask* task) { - resource_provider_->UnmapImageRasterBuffer(task->resource()->id()); - - // Map/UnmapImageRasterBuffer provides direct access to the memory used by the - // GPU. Read lock fences are required to ensure that we're not trying to map a - // resource that is currently in-use by the GPU. - resource_provider_->EnableReadLockFences(task->resource()->id(), true); -} - -void ImageRasterWorkerPool::OnRasterFinished() { - TRACE_EVENT0("cc", "ImageRasterWorkerPool::OnRasterFinished"); - - DCHECK(raster_tasks_pending_); - raster_tasks_pending_ = false; - TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); - client_->DidFinishRunningTasks(); -} - -void ImageRasterWorkerPool::OnRasterRequiredForActivationFinished() { - TRACE_EVENT0("cc", - "ImageRasterWorkerPool::OnRasterRequiredForActivationFinished"); - - DCHECK(raster_tasks_required_for_activation_pending_); - raster_tasks_required_for_activation_pending_ = false; - TRACE_EVENT_ASYNC_STEP_INTO1( - "cc", - "ScheduledTasks", - this, - "rasterizing", - "state", - TracedValue::FromValue(StateAsValue().release())); - client_->DidFinishRunningTasksRequiredForActivation(); -} - -scoped_ptr<base::Value> ImageRasterWorkerPool::StateAsValue() const { - scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); - - state->SetBoolean("tasks_required_for_activation_pending", - raster_tasks_required_for_activation_pending_); - return state.PassAs<base::Value>(); -} - -} // namespace cc diff --git a/chromium/cc/resources/image_raster_worker_pool.h b/chromium/cc/resources/image_raster_worker_pool.h deleted file mode 100644 index 2e11a220f41..00000000000 --- a/chromium/cc/resources/image_raster_worker_pool.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CC_RESOURCES_IMAGE_RASTER_WORKER_POOL_H_ -#define CC_RESOURCES_IMAGE_RASTER_WORKER_POOL_H_ - -#include "base/memory/weak_ptr.h" -#include "base/values.h" -#include "cc/resources/raster_worker_pool.h" -#include "cc/resources/rasterizer.h" - -namespace cc { -class ResourceProvider; - -class CC_EXPORT ImageRasterWorkerPool : public RasterWorkerPool, - public Rasterizer, - public RasterizerTaskClient { - public: - virtual ~ImageRasterWorkerPool(); - - static scoped_ptr<RasterWorkerPool> Create( - base::SequencedTaskRunner* task_runner, - TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider); - - // Overridden from RasterWorkerPool: - virtual Rasterizer* AsRasterizer() OVERRIDE; - - // Overridden from Rasterizer: - virtual void SetClient(RasterizerClient* client) OVERRIDE; - virtual void Shutdown() OVERRIDE; - virtual void ScheduleTasks(RasterTaskQueue* queue) OVERRIDE; - virtual void CheckForCompletedTasks() OVERRIDE; - - // Overridden from RasterizerTaskClient: - virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) OVERRIDE; - virtual void ReleaseCanvasForRaster(RasterTask* task) OVERRIDE; - - protected: - ImageRasterWorkerPool(base::SequencedTaskRunner* task_runner, - TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider); - - private: - void OnRasterFinished(); - void OnRasterRequiredForActivationFinished(); - scoped_ptr<base::Value> StateAsValue() const; - - scoped_refptr<base::SequencedTaskRunner> task_runner_; - TaskGraphRunner* task_graph_runner_; - const NamespaceToken namespace_token_; - RasterizerClient* client_; - ResourceProvider* resource_provider_; - - bool raster_tasks_pending_; - bool raster_tasks_required_for_activation_pending_; - - base::WeakPtrFactory<ImageRasterWorkerPool> raster_finished_weak_ptr_factory_; - - scoped_refptr<RasterizerTask> raster_finished_task_; - scoped_refptr<RasterizerTask> raster_required_for_activation_finished_task_; - - // Task graph used when scheduling tasks and vector used to gather - // completed tasks. - TaskGraph graph_; - Task::Vector completed_tasks_; - - DISALLOW_COPY_AND_ASSIGN(ImageRasterWorkerPool); -}; - -} // namespace cc - -#endif // CC_RESOURCES_IMAGE_RASTER_WORKER_POOL_H_ diff --git a/chromium/cc/resources/layer_painter.h b/chromium/cc/resources/layer_painter.h index 4cb2527c42f..54dc434671d 100644 --- a/chromium/cc/resources/layer_painter.h +++ b/chromium/cc/resources/layer_painter.h @@ -19,9 +19,7 @@ namespace cc { class CC_EXPORT LayerPainter { public: virtual ~LayerPainter() {} - virtual void Paint(SkCanvas* canvas, - const gfx::Rect& content_rect, - gfx::RectF* opaque) = 0; + virtual void Paint(SkCanvas* canvas, const gfx::Rect& content_rect) = 0; }; } // namespace cc diff --git a/chromium/cc/resources/layer_quad.cc b/chromium/cc/resources/layer_quad.cc index fdd68662e35..38ec7b32b01 100644 --- a/chromium/cc/resources/layer_quad.cc +++ b/chromium/cc/resources/layer_quad.cc @@ -5,7 +5,7 @@ #include "cc/resources/layer_quad.h" #include "base/logging.h" -#include "ui/gfx/quad_f.h" +#include "ui/gfx/geometry/quad_f.h" namespace cc { diff --git a/chromium/cc/resources/layer_quad.h b/chromium/cc/resources/layer_quad.h index 1d711931b20..ed1db101a97 100644 --- a/chromium/cc/resources/layer_quad.h +++ b/chromium/cc/resources/layer_quad.h @@ -8,7 +8,7 @@ #include "base/basictypes.h" #include "cc/base/cc_export.h" -#include "ui/gfx/point_f.h" +#include "ui/gfx/geometry/point_f.h" namespace gfx { class QuadF; diff --git a/chromium/cc/resources/layer_quad_unittest.cc b/chromium/cc/resources/layer_quad_unittest.cc index 8d3909cb586..3560b8d379e 100644 --- a/chromium/cc/resources/layer_quad_unittest.cc +++ b/chromium/cc/resources/layer_quad_unittest.cc @@ -5,7 +5,7 @@ #include "cc/resources/layer_quad.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/quad_f.h" +#include "ui/gfx/geometry/quad_f.h" namespace cc { namespace { diff --git a/chromium/cc/resources/layer_tiling_data.cc b/chromium/cc/resources/layer_tiling_data.cc index b8d80bc3760..63b003628c3 100644 --- a/chromium/cc/resources/layer_tiling_data.cc +++ b/chromium/cc/resources/layer_tiling_data.cc @@ -7,6 +7,8 @@ #include <vector> #include "base/logging.h" +#include "cc/base/region.h" +#include "cc/base/simple_enclosed_region.h" namespace cc { @@ -17,7 +19,7 @@ scoped_ptr<LayerTilingData> LayerTilingData::Create(const gfx::Size& tile_size, LayerTilingData::LayerTilingData(const gfx::Size& tile_size, BorderTexelOption border) - : tiling_data_(tile_size, gfx::Rect(), border == HAS_BORDER_TEXELS) { + : tiling_data_(tile_size, gfx::Size(), border == HAS_BORDER_TEXELS) { SetTileSize(tile_size); } @@ -90,31 +92,9 @@ gfx::Rect LayerTilingData::TileRect(const Tile* tile) const { return tile_rect; } -Region LayerTilingData::OpaqueRegionInContentRect( - const gfx::Rect& content_rect) const { - if (content_rect.IsEmpty()) - return Region(); - - Region opaque_region; - int left, top, right, bottom; - ContentRectToTileIndices(content_rect, &left, &top, &right, &bottom); - for (int j = top; j <= bottom; ++j) { - for (int i = left; i <= right; ++i) { - Tile* tile = TileAt(i, j); - if (!tile) - continue; - - gfx::Rect tile_opaque_rect = - gfx::IntersectRects(content_rect, tile->opaque_rect()); - opaque_region.Union(tile_opaque_rect); - } - } - return opaque_region; -} - -void LayerTilingData::SetTilingRect(const gfx::Rect& tiling_rect) { - tiling_data_.SetTilingRect(tiling_rect); - if (tiling_rect.IsEmpty()) { +void LayerTilingData::SetTilingSize(const gfx::Size& tiling_size) { + tiling_data_.SetTilingSize(tiling_size); + if (tiling_size.IsEmpty()) { tiles_.clear(); return; } @@ -122,7 +102,8 @@ void LayerTilingData::SetTilingRect(const gfx::Rect& tiling_rect) { // Any tiles completely outside our new bounds are invalid and should be // dropped. int left, top, right, bottom; - ContentRectToTileIndices(tiling_rect, &left, &top, &right, &bottom); + ContentRectToTileIndices( + gfx::Rect(tiling_size), &left, &top, &right, &bottom); std::vector<TileMapKey> invalid_tile_keys; for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { if (it->first.first > right || it->first.second > bottom) diff --git a/chromium/cc/resources/layer_tiling_data.h b/chromium/cc/resources/layer_tiling_data.h index b145e38ffab..51681184bbd 100644 --- a/chromium/cc/resources/layer_tiling_data.h +++ b/chromium/cc/resources/layer_tiling_data.h @@ -12,9 +12,9 @@ #include "base/containers/scoped_ptr_hash_map.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" -#include "cc/base/region.h" +#include "cc/base/simple_enclosed_region.h" #include "cc/base/tiling_data.h" -#include "ui/gfx/rect.h" +#include "ui/gfx/geometry/rect.h" namespace cc { @@ -63,14 +63,9 @@ class CC_EXPORT LayerTilingData { j_ = j; } - gfx::Rect opaque_rect() const { return opaque_rect_; } - void set_opaque_rect(const gfx::Rect& opaque_rect) { - opaque_rect_ = opaque_rect; - } private: int i_; int j_; - gfx::Rect opaque_rect_; DISALLOW_COPY_AND_ASSIGN(Tile); }; typedef std::pair<int, int> TileMapKey; @@ -81,8 +76,8 @@ class CC_EXPORT LayerTilingData { Tile* TileAt(int i, int j) const; const TileMap& tiles() const { return tiles_; } - void SetTilingRect(const gfx::Rect& tiling_rect); - gfx::Rect tiling_rect() const { return tiling_data_.tiling_rect(); } + void SetTilingSize(const gfx::Size& tiling_size); + gfx::Size tiling_size() const { return tiling_data_.tiling_size(); } void ContentRectToTileIndices(const gfx::Rect& rect, int* left, @@ -91,8 +86,6 @@ class CC_EXPORT LayerTilingData { int* bottom) const; gfx::Rect TileRect(const Tile* tile) const; - Region OpaqueRegionInContentRect(const gfx::Rect& rect) const; - void reset() { tiles_.clear(); } protected: diff --git a/chromium/cc/resources/layer_updater.h b/chromium/cc/resources/layer_updater.h index 47f44106e40..a5eb0a11da7 100644 --- a/chromium/cc/resources/layer_updater.h +++ b/chromium/cc/resources/layer_updater.h @@ -8,8 +8,9 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/vector2d.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" namespace cc { @@ -46,14 +47,11 @@ class CC_EXPORT LayerUpdater : public base::RefCounted<LayerUpdater> { virtual scoped_ptr<Resource> CreateResource( PrioritizedResourceManager* manager) = 0; - // The |resulting_opaque_rect| gives back a region of the layer that was - // painted opaque. If the layer is marked opaque in the updater, then this - // region should be ignored in preference for the entire layer's area. - virtual void PrepareToUpdate(const gfx::Rect& content_rect, + virtual void PrepareToUpdate(const gfx::Size& content_size, + const gfx::Rect& paint_rect, const gfx::Size& tile_size, float contents_width_scale, - float contents_height_scale, - gfx::Rect* resulting_opaque_rect) {} + float contents_height_scale) {} virtual void ReduceMemoryUsage() {} // Set true by the layer when it is known that the entire output is going to @@ -62,6 +60,7 @@ class CC_EXPORT LayerUpdater : public base::RefCounted<LayerUpdater> { // Set true by the layer when it is known that the entire output bounds will // be rasterized. virtual void SetFillsBoundsCompletely(bool fills_bounds) {} + virtual void SetBackgroundColor(SkColor background_color) {} protected: virtual ~LayerUpdater() {} diff --git a/chromium/cc/resources/managed_tile_state.cc b/chromium/cc/resources/managed_tile_state.cc index 037432764bd..2841711dd81 100644 --- a/chromium/cc/resources/managed_tile_state.cc +++ b/chromium/cc/resources/managed_tile_state.cc @@ -5,61 +5,57 @@ #include "cc/resources/managed_tile_state.h" #include <limits> +#include <string> +#include "base/debug/trace_event_argument.h" #include "cc/base/math_util.h" namespace cc { -scoped_ptr<base::Value> ManagedTileBinAsValue(ManagedTileBin bin) { +std::string ManagedTileBinToString(ManagedTileBin bin) { switch (bin) { case NOW_AND_READY_TO_DRAW_BIN: - return scoped_ptr<base::Value>( - new base::StringValue("NOW_AND_READY_TO_DRAW_BIN")); + return "NOW_AND_READY_TO_DRAW_BIN"; case NOW_BIN: - return scoped_ptr<base::Value>(new base::StringValue("NOW_BIN")); + return "NOW_BIN"; case SOON_BIN: - return scoped_ptr<base::Value>( - new base::StringValue("SOON_BIN")); + return "SOON_BIN"; case EVENTUALLY_AND_ACTIVE_BIN: - return scoped_ptr<base::Value>( - new base::StringValue("EVENTUALLY_AND_ACTIVE_BIN")); + return "EVENTUALLY_AND_ACTIVE_BIN"; case EVENTUALLY_BIN: - return scoped_ptr<base::Value>( - new base::StringValue("EVENTUALLY_BIN")); + return "EVENTUALLY_BIN"; case AT_LAST_AND_ACTIVE_BIN: - return scoped_ptr<base::Value>( - new base::StringValue("AT_LAST_AND_ACTIVE_BIN")); + return "AT_LAST_AND_ACTIVE_BIN"; case AT_LAST_BIN: - return scoped_ptr<base::Value>( - new base::StringValue("AT_LAST_BIN")); + return "AT_LAST_BIN"; case NEVER_BIN: - return scoped_ptr<base::Value>( - new base::StringValue("NEVER_BIN")); + return "NEVER_BIN"; case NUM_BINS: NOTREACHED(); - return scoped_ptr<base::Value>( - new base::StringValue("Invalid Bin (NUM_BINS)")); + return "Invalid Bin (NUM_BINS)"; } - return scoped_ptr<base::Value>( - new base::StringValue("Invalid Bin (UNKNOWN)")); + return "Invalid Bin (UNKNOWN)"; } ManagedTileState::ManagedTileState() - : raster_mode(LOW_QUALITY_RASTER_MODE), - bin(NEVER_BIN), + : bin(NEVER_BIN), resolution(NON_IDEAL_RESOLUTION), required_for_activation(false), priority_bin(TilePriority::EVENTUALLY), distance_to_visible(std::numeric_limits<float>::infinity()), visible_and_ready_to_draw(false), - scheduled_priority(0) {} + scheduled_priority(0) { +} -ManagedTileState::TileVersion::TileVersion() : mode_(RESOURCE_MODE) { +ManagedTileState::DrawInfo::DrawInfo() + : mode_(RESOURCE_MODE), solid_color_(SK_ColorWHITE) { } -ManagedTileState::TileVersion::~TileVersion() { DCHECK(!resource_); } +ManagedTileState::DrawInfo::~DrawInfo() { + DCHECK(!resource_); +} -bool ManagedTileState::TileVersion::IsReadyToDraw() const { +bool ManagedTileState::DrawInfo::IsReadyToDraw() const { switch (mode_) { case RESOURCE_MODE: return !!resource_; @@ -71,42 +67,28 @@ bool ManagedTileState::TileVersion::IsReadyToDraw() const { return false; } -size_t ManagedTileState::TileVersion::GPUMemoryUsageInBytes() const { - if (!resource_) - return 0; - return resource_->bytes(); -} - ManagedTileState::~ManagedTileState() {} -scoped_ptr<base::Value> ManagedTileState::AsValue() const { - bool has_resource = false; - bool has_active_task = false; - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { - has_resource |= (tile_versions[mode].resource_.get() != 0); - has_active_task |= (tile_versions[mode].raster_task_.get() != 0); - } +void ManagedTileState::AsValueInto(base::debug::TracedValue* state) const { + bool has_resource = (draw_info.resource_.get() != 0); + bool has_active_task = (raster_task.get() != 0); bool is_using_gpu_memory = has_resource || has_active_task; - scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); state->SetBoolean("has_resource", has_resource); state->SetBoolean("is_using_gpu_memory", is_using_gpu_memory); - state->Set("bin", ManagedTileBinAsValue(bin).release()); - state->Set("resolution", TileResolutionAsValue(resolution).release()); - state->Set("priority_bin", TilePriorityBinAsValue(priority_bin).release()); - state->Set("distance_to_visible", - MathUtil::AsValueSafely(distance_to_visible).release()); + 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", - tile_versions[raster_mode].mode_ == TileVersion::SOLID_COLOR_MODE); - state->SetBoolean( - "is_transparent", - tile_versions[raster_mode].mode_ == TileVersion::SOLID_COLOR_MODE && - !SkColorGetA(tile_versions[raster_mode].solid_color_)); + state->SetBoolean("is_solid_color", + draw_info.mode_ == DrawInfo::SOLID_COLOR_MODE); + state->SetBoolean("is_transparent", + draw_info.mode_ == DrawInfo::SOLID_COLOR_MODE && + !SkColorGetA(draw_info.solid_color_)); state->SetInteger("scheduled_priority", scheduled_priority); - return state.PassAs<base::Value>(); } } // namespace cc diff --git a/chromium/cc/resources/managed_tile_state.h b/chromium/cc/resources/managed_tile_state.h index 7224dd64b41..58b77c60fc3 100644 --- a/chromium/cc/resources/managed_tile_state.h +++ b/chromium/cc/resources/managed_tile_state.h @@ -7,7 +7,6 @@ #include "base/memory/scoped_ptr.h" #include "cc/resources/platform_color.h" -#include "cc/resources/raster_mode.h" #include "cc/resources/rasterizer.h" #include "cc/resources/resource_pool.h" #include "cc/resources/resource_provider.h" @@ -38,12 +37,13 @@ scoped_ptr<base::Value> ManagedTileBinAsValue(ManagedTileBin bin); // managed by the TileManager. class CC_EXPORT ManagedTileState { public: - class CC_EXPORT TileVersion { + // This class holds all the state relevant to drawing a tile. + class CC_EXPORT DrawInfo { public: enum Mode { RESOURCE_MODE, SOLID_COLOR_MODE, PICTURE_PILE_MODE }; - TileVersion(); - ~TileVersion(); + DrawInfo(); + ~DrawInfo(); Mode mode() const { return mode_; } @@ -73,8 +73,6 @@ class CC_EXPORT ManagedTileState { inline bool has_resource() const { return !!resource_; } - size_t GPUMemoryUsageInBytes() const; - void SetSolidColorForTesting(SkColor color) { set_solid_color(color); } void SetResourceForTesting(scoped_ptr<ScopedResource> resource) { resource_ = resource.Pass(); @@ -98,17 +96,16 @@ class CC_EXPORT ManagedTileState { Mode mode_; SkColor solid_color_; scoped_ptr<ScopedResource> resource_; - scoped_refptr<RasterTask> raster_task_; }; ManagedTileState(); ~ManagedTileState(); - scoped_ptr<base::Value> AsValue() const; + void AsValueInto(base::debug::TracedValue* dict) const; // Persisted state: valid all the time. - TileVersion tile_versions[NUM_RASTER_MODES]; - RasterMode raster_mode; + DrawInfo draw_info; + scoped_refptr<RasterTask> raster_task; ManagedTileBin bin; diff --git a/chromium/cc/resources/memory_history.cc b/chromium/cc/resources/memory_history.cc index a2f8b6ee113..4dc49c881a6 100644 --- a/chromium/cc/resources/memory_history.cc +++ b/chromium/cc/resources/memory_history.cc @@ -24,7 +24,7 @@ void MemoryHistory::GetMinAndMax(size_t* min, size_t* max) const { *max = 0; for (RingBufferType::Iterator it = ring_buffer_.Begin(); it; ++it) { - size_t bytes_total = it->bytes_total(); + size_t bytes_total = it->total_bytes_used; if (bytes_total < *min) *min = bytes_total; diff --git a/chromium/cc/resources/memory_history.h b/chromium/cc/resources/memory_history.h index daca10f35a0..570a3d0ca43 100644 --- a/chromium/cc/resources/memory_history.h +++ b/chromium/cc/resources/memory_history.h @@ -22,17 +22,12 @@ class MemoryHistory { struct Entry { Entry() : total_budget_in_bytes(0), - bytes_allocated(0), - bytes_unreleasable(0), - bytes_over(0) {} + total_bytes_used(0), + had_enough_memory(false) {} size_t total_budget_in_bytes; - size_t bytes_allocated; - size_t bytes_unreleasable; - size_t bytes_over; - size_t bytes_total() const { - return bytes_allocated + bytes_unreleasable + bytes_over; - } + size_t total_bytes_used; + bool had_enough_memory; }; void SaveEntry(const Entry& entry); diff --git a/chromium/cc/resources/one_copy_raster_worker_pool.cc b/chromium/cc/resources/one_copy_raster_worker_pool.cc new file mode 100644 index 00000000000..a8b838e8390 --- /dev/null +++ b/chromium/cc/resources/one_copy_raster_worker_pool.cc @@ -0,0 +1,506 @@ +// 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/one_copy_raster_worker_pool.h" + +#include <algorithm> +#include <limits> + +#include "base/debug/trace_event.h" +#include "base/debug/trace_event_argument.h" +#include "base/strings/stringprintf.h" +#include "cc/debug/traced_value.h" +#include "cc/resources/raster_buffer.h" +#include "cc/resources/resource_pool.h" +#include "cc/resources/scoped_resource.h" +#include "gpu/command_buffer/client/gles2_interface.h" +#include "ui/gfx/gpu_memory_buffer.h" + +namespace cc { +namespace { + +class RasterBufferImpl : public RasterBuffer { + public: + RasterBufferImpl(OneCopyRasterWorkerPool* worker_pool, + ResourceProvider* resource_provider, + ResourcePool* resource_pool, + const Resource* resource) + : worker_pool_(worker_pool), + resource_provider_(resource_provider), + resource_pool_(resource_pool), + resource_(resource), + raster_resource_(resource_pool->AcquireResource(resource->size())), + lock_(new ResourceProvider::ScopedWriteLockGpuMemoryBuffer( + resource_provider_, + raster_resource_->id())), + sequence_(0) {} + + ~RasterBufferImpl() override { + // Release write lock in case a copy was never scheduled. + lock_.reset(); + + // Make sure any scheduled copy operations are issued before we release the + // raster resource. + if (sequence_) + worker_pool_->AdvanceLastIssuedCopyTo(sequence_); + + // Return raster resource to pool so it can be used by another RasterBuffer + // instance. + if (raster_resource_) + resource_pool_->ReleaseResource(raster_resource_.Pass()); + } + + // Overridden from RasterBuffer: + void Playback(const RasterSource* raster_source, + const gfx::Rect& rect, + float scale) override { + sequence_ = worker_pool_->PlaybackAndScheduleCopyOnWorkerThread( + lock_.Pass(), raster_resource_.Pass(), resource_, raster_source, rect, + scale); + } + + private: + OneCopyRasterWorkerPool* worker_pool_; + ResourceProvider* resource_provider_; + ResourcePool* resource_pool_; + const Resource* resource_; + scoped_ptr<ScopedResource> raster_resource_; + scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> lock_; + CopySequenceNumber sequence_; + + DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); +}; + +// Flush interval when performing copy operations. +const int kCopyFlushPeriod = 4; + +// Number of in-flight copy operations to allow. +const int kMaxCopyOperations = 16; + +// Delay been checking for copy operations to complete. +const int kCheckForCompletedCopyOperationsTickRateMs = 1; + +// Number of failed attempts to allow before we perform a check that will +// wait for copy operations to complete if needed. +const int kFailedAttemptsBeforeWaitIfNeeded = 256; + +} // namespace + +OneCopyRasterWorkerPool::CopyOperation::CopyOperation( + scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> write_lock, + scoped_ptr<ScopedResource> src, + const Resource* dst) + : write_lock(write_lock.Pass()), src(src.Pass()), dst(dst) { +} + +OneCopyRasterWorkerPool::CopyOperation::~CopyOperation() { +} + +// static +scoped_ptr<RasterWorkerPool> OneCopyRasterWorkerPool::Create( + base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ContextProvider* context_provider, + ResourceProvider* resource_provider, + ResourcePool* resource_pool) { + return make_scoped_ptr<RasterWorkerPool>( + new OneCopyRasterWorkerPool(task_runner, + task_graph_runner, + context_provider, + resource_provider, + resource_pool)); +} + +OneCopyRasterWorkerPool::OneCopyRasterWorkerPool( + base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ContextProvider* context_provider, + ResourceProvider* resource_provider, + ResourcePool* resource_pool) + : task_runner_(task_runner), + task_graph_runner_(task_graph_runner), + namespace_token_(task_graph_runner->GetNamespaceToken()), + context_provider_(context_provider), + resource_provider_(resource_provider), + resource_pool_(resource_pool), + last_issued_copy_operation_(0), + last_flushed_copy_operation_(0), + lock_(), + copy_operation_count_cv_(&lock_), + scheduled_copy_operation_count_(0), + issued_copy_operation_count_(0), + next_copy_operation_sequence_(1), + check_for_completed_copy_operations_pending_(false), + shutdown_(false), + weak_ptr_factory_(this), + raster_finished_weak_ptr_factory_(this) { + DCHECK(context_provider_); +} + +OneCopyRasterWorkerPool::~OneCopyRasterWorkerPool() { + DCHECK_EQ(scheduled_copy_operation_count_, 0u); +} + +Rasterizer* OneCopyRasterWorkerPool::AsRasterizer() { + return this; +} + +void OneCopyRasterWorkerPool::SetClient(RasterizerClient* client) { + client_ = client; +} + +void OneCopyRasterWorkerPool::Shutdown() { + TRACE_EVENT0("cc", "OneCopyRasterWorkerPool::Shutdown"); + + { + base::AutoLock lock(lock_); + + shutdown_ = true; + copy_operation_count_cv_.Signal(); + } + + TaskGraph empty; + task_graph_runner_->ScheduleTasks(namespace_token_, &empty); + task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); +} + +void OneCopyRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { + TRACE_EVENT0("cc", "OneCopyRasterWorkerPool::ScheduleTasks"); + + if (raster_pending_.none()) + TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); + + // Mark all task sets as pending. + raster_pending_.set(); + + unsigned priority = kRasterTaskPriorityBase; + + graph_.Reset(); + + // Cancel existing OnRasterFinished callbacks. + raster_finished_weak_ptr_factory_.InvalidateWeakPtrs(); + + scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets]; + + size_t task_count[kNumberOfTaskSets] = {0}; + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + new_raster_finished_tasks[task_set] = CreateRasterFinishedTask( + task_runner_.get(), + base::Bind(&OneCopyRasterWorkerPool::OnRasterFinished, + raster_finished_weak_ptr_factory_.GetWeakPtr(), + task_set)); + } + + resource_pool_->CheckBusyResources(false); + + for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); + it != queue->items.end(); + ++it) { + const RasterTaskQueue::Item& item = *it; + RasterTask* task = item.task; + DCHECK(!task->HasCompleted()); + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + if (!item.task_sets[task_set]) + continue; + + ++task_count[task_set]; + + graph_.edges.push_back( + TaskGraph::Edge(task, new_raster_finished_tasks[task_set].get())); + } + + InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); + } + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + InsertNodeForTask(&graph_, + new_raster_finished_tasks[task_set].get(), + kRasterFinishedTaskPriority, + task_count[task_set]); + } + + ScheduleTasksOnOriginThread(this, &graph_); + task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); + + std::copy(new_raster_finished_tasks, + new_raster_finished_tasks + kNumberOfTaskSets, + raster_finished_tasks_); + + resource_pool_->ReduceResourceUsage(); + + TRACE_EVENT_ASYNC_STEP_INTO1( + "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue()); +} + +void OneCopyRasterWorkerPool::CheckForCompletedTasks() { + TRACE_EVENT0("cc", "OneCopyRasterWorkerPool::CheckForCompletedTasks"); + + task_graph_runner_->CollectCompletedTasks(namespace_token_, + &completed_tasks_); + + for (Task::Vector::const_iterator it = completed_tasks_.begin(); + it != completed_tasks_.end(); + ++it) { + RasterizerTask* task = static_cast<RasterizerTask*>(it->get()); + + task->WillComplete(); + task->CompleteOnOriginThread(this); + task->DidComplete(); + + task->RunReplyOnOriginThread(); + } + completed_tasks_.clear(); +} + +scoped_ptr<RasterBuffer> OneCopyRasterWorkerPool::AcquireBufferForRaster( + const Resource* resource) { + DCHECK_EQ(resource->format(), resource_pool_->resource_format()); + return make_scoped_ptr<RasterBuffer>( + new RasterBufferImpl(this, resource_provider_, resource_pool_, resource)); +} + +void OneCopyRasterWorkerPool::ReleaseBufferForRaster( + scoped_ptr<RasterBuffer> buffer) { + // Nothing to do here. RasterBufferImpl destructor cleans up after itself. +} + +CopySequenceNumber +OneCopyRasterWorkerPool::PlaybackAndScheduleCopyOnWorkerThread( + scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> write_lock, + scoped_ptr<ScopedResource> src, + const Resource* dst, + const RasterSource* raster_source, + const gfx::Rect& rect, + float scale) { + base::AutoLock lock(lock_); + + int failed_attempts = 0; + while ((scheduled_copy_operation_count_ + issued_copy_operation_count_) >= + kMaxCopyOperations) { + // Ignore limit when shutdown is set. + if (shutdown_) + break; + + ++failed_attempts; + + // Schedule a check that will also wait for operations to complete + // after too many failed attempts. + bool wait_if_needed = failed_attempts > kFailedAttemptsBeforeWaitIfNeeded; + + // Schedule a check for completed copy operations if too many operations + // are currently in-flight. + ScheduleCheckForCompletedCopyOperationsWithLockAcquired(wait_if_needed); + + { + TRACE_EVENT0("cc", "WaitingForCopyOperationsToComplete"); + + // Wait for in-flight copy operations to drop below limit. + copy_operation_count_cv_.Wait(); + } + } + + // Increment |scheduled_copy_operation_count_| before releasing |lock_|. + ++scheduled_copy_operation_count_; + + // There may be more work available, so wake up another worker thread. + copy_operation_count_cv_.Signal(); + + { + base::AutoUnlock unlock(lock_); + + gfx::GpuMemoryBuffer* gpu_memory_buffer = write_lock->GetGpuMemoryBuffer(); + if (gpu_memory_buffer) { + RasterWorkerPool::PlaybackToMemory(gpu_memory_buffer->Map(), + src->format(), + src->size(), + gpu_memory_buffer->GetStride(), + raster_source, + rect, + scale); + gpu_memory_buffer->Unmap(); + } + } + + pending_copy_operations_.push_back( + make_scoped_ptr(new CopyOperation(write_lock.Pass(), src.Pass(), dst))); + + // Acquire a sequence number for this copy operation. + CopySequenceNumber sequence = next_copy_operation_sequence_++; + + // Post task that will advance last flushed copy operation to |sequence| + // if we have reached the flush period. + if ((sequence % kCopyFlushPeriod) == 0) { + task_runner_->PostTask( + FROM_HERE, + base::Bind(&OneCopyRasterWorkerPool::AdvanceLastFlushedCopyTo, + weak_ptr_factory_.GetWeakPtr(), + sequence)); + } + + return sequence; +} + +void OneCopyRasterWorkerPool::AdvanceLastIssuedCopyTo( + CopySequenceNumber sequence) { + if (last_issued_copy_operation_ >= sequence) + return; + + IssueCopyOperations(sequence - last_issued_copy_operation_); + last_issued_copy_operation_ = sequence; +} + +void OneCopyRasterWorkerPool::AdvanceLastFlushedCopyTo( + CopySequenceNumber sequence) { + if (last_flushed_copy_operation_ >= sequence) + return; + + AdvanceLastIssuedCopyTo(sequence); + + // Flush all issued copy operations. + context_provider_->ContextGL()->ShallowFlushCHROMIUM(); + last_flushed_copy_operation_ = last_issued_copy_operation_; +} + +void OneCopyRasterWorkerPool::OnRasterFinished(TaskSet task_set) { + TRACE_EVENT1( + "cc", "OneCopyRasterWorkerPool::OnRasterFinished", "task_set", task_set); + + DCHECK(raster_pending_[task_set]); + raster_pending_[task_set] = false; + if (raster_pending_.any()) { + TRACE_EVENT_ASYNC_STEP_INTO1( + "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue()); + } else { + TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); + } + client_->DidFinishRunningTasks(task_set); +} + +void OneCopyRasterWorkerPool::IssueCopyOperations(int64 count) { + TRACE_EVENT1( + "cc", "OneCopyRasterWorkerPool::IssueCopyOperations", "count", count); + + CopyOperation::Deque copy_operations; + + { + base::AutoLock lock(lock_); + + for (int64 i = 0; i < count; ++i) { + DCHECK(!pending_copy_operations_.empty()); + copy_operations.push_back(pending_copy_operations_.take_front()); + } + + // Decrement |scheduled_copy_operation_count_| and increment + // |issued_copy_operation_count_| to reflect the transition of copy + // operations from "pending" to "issued" state. + DCHECK_GE(scheduled_copy_operation_count_, copy_operations.size()); + scheduled_copy_operation_count_ -= copy_operations.size(); + issued_copy_operation_count_ += copy_operations.size(); + } + + while (!copy_operations.empty()) { + scoped_ptr<CopyOperation> copy_operation = copy_operations.take_front(); + + // Remove the write lock. + copy_operation->write_lock.reset(); + + // Copy contents of source resource to destination resource. + resource_provider_->CopyResource(copy_operation->src->id(), + copy_operation->dst->id()); + + // Return source resource to pool where it can be reused once copy + // operation has completed and resource is no longer busy. + resource_pool_->ReleaseResource(copy_operation->src.Pass()); + } +} + +void OneCopyRasterWorkerPool:: + ScheduleCheckForCompletedCopyOperationsWithLockAcquired( + bool wait_if_needed) { + lock_.AssertAcquired(); + + if (check_for_completed_copy_operations_pending_) + return; + + base::TimeTicks now = base::TimeTicks::Now(); + + // Schedule a check for completed copy operations as soon as possible but + // don't allow two consecutive checks to be scheduled to run less than the + // tick rate apart. + base::TimeTicks next_check_for_completed_copy_operations_time = + std::max(last_check_for_completed_copy_operations_time_ + + base::TimeDelta::FromMilliseconds( + kCheckForCompletedCopyOperationsTickRateMs), + now); + + task_runner_->PostDelayedTask( + FROM_HERE, + base::Bind(&OneCopyRasterWorkerPool::CheckForCompletedCopyOperations, + weak_ptr_factory_.GetWeakPtr(), + wait_if_needed), + next_check_for_completed_copy_operations_time - now); + + last_check_for_completed_copy_operations_time_ = + next_check_for_completed_copy_operations_time; + check_for_completed_copy_operations_pending_ = true; +} + +void OneCopyRasterWorkerPool::CheckForCompletedCopyOperations( + bool wait_if_needed) { + TRACE_EVENT1("cc", + "OneCopyRasterWorkerPool::CheckForCompletedCopyOperations", + "wait_if_needed", + wait_if_needed); + + resource_pool_->CheckBusyResources(wait_if_needed); + + { + base::AutoLock lock(lock_); + + DCHECK(check_for_completed_copy_operations_pending_); + check_for_completed_copy_operations_pending_ = false; + + // The number of busy resources in the pool reflects the number of issued + // copy operations that have not yet completed. + issued_copy_operation_count_ = resource_pool_->busy_resource_count(); + + // There may be work blocked on too many in-flight copy operations, so wake + // up a worker thread. + copy_operation_count_cv_.Signal(); + } +} + +scoped_refptr<base::debug::ConvertableToTraceFormat> +OneCopyRasterWorkerPool::StateAsValue() const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); + + state->BeginArray("tasks_pending"); + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) + state->AppendBoolean(raster_pending_[task_set]); + state->EndArray(); + state->BeginDictionary("staging_state"); + StagingStateAsValueInto(state.get()); + state->EndDictionary(); + + return state; +} + +void OneCopyRasterWorkerPool::StagingStateAsValueInto( + base::debug::TracedValue* staging_state) const { + staging_state->SetInteger("staging_resource_count", + resource_pool_->total_resource_count()); + staging_state->SetInteger("bytes_used_for_staging_resources", + resource_pool_->total_memory_usage_bytes()); + staging_state->SetInteger("pending_copy_count", + resource_pool_->total_resource_count() - + resource_pool_->acquired_resource_count()); + staging_state->SetInteger("bytes_pending_copy", + resource_pool_->total_memory_usage_bytes() - + resource_pool_->acquired_memory_usage_bytes()); +} + +} // namespace cc diff --git a/chromium/cc/resources/one_copy_raster_worker_pool.h b/chromium/cc/resources/one_copy_raster_worker_pool.h new file mode 100644 index 00000000000..b209da274bf --- /dev/null +++ b/chromium/cc/resources/one_copy_raster_worker_pool.h @@ -0,0 +1,141 @@ +// 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_ONE_COPY_RASTER_WORKER_POOL_H_ +#define CC_RESOURCES_ONE_COPY_RASTER_WORKER_POOL_H_ + +#include "base/memory/weak_ptr.h" +#include "base/synchronization/lock.h" +#include "base/values.h" +#include "cc/base/scoped_ptr_deque.h" +#include "cc/output/context_provider.h" +#include "cc/resources/raster_worker_pool.h" +#include "cc/resources/rasterizer.h" +#include "cc/resources/resource_provider.h" + +namespace base { +namespace debug { +class ConvertableToTraceFormat; +class TracedValue; +} +} + +namespace cc { +class ResourcePool; +class ScopedResource; + +typedef int64 CopySequenceNumber; + +class CC_EXPORT OneCopyRasterWorkerPool : public RasterWorkerPool, + public Rasterizer, + public RasterizerTaskClient { + public: + ~OneCopyRasterWorkerPool() override; + + static scoped_ptr<RasterWorkerPool> Create( + base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ContextProvider* context_provider, + ResourceProvider* resource_provider, + ResourcePool* resource_pool); + + // Overridden from RasterWorkerPool: + Rasterizer* AsRasterizer() override; + + // Overridden from Rasterizer: + void SetClient(RasterizerClient* client) override; + void Shutdown() override; + void ScheduleTasks(RasterTaskQueue* queue) override; + void CheckForCompletedTasks() override; + + // Overridden from RasterizerTaskClient: + scoped_ptr<RasterBuffer> AcquireBufferForRaster( + const Resource* resource) override; + void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override; + + // Playback raster source and schedule copy of |src| resource to |dst| + // resource. Returns a non-zero sequence number for this copy operation. + CopySequenceNumber PlaybackAndScheduleCopyOnWorkerThread( + scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> write_lock, + scoped_ptr<ScopedResource> src, + const Resource* dst, + const RasterSource* raster_source, + const gfx::Rect& rect, + float scale); + + // Issues copy operations until |sequence| has been processed. This will + // return immediately if |sequence| has already been processed. + void AdvanceLastIssuedCopyTo(CopySequenceNumber sequence); + + protected: + OneCopyRasterWorkerPool(base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ContextProvider* context_provider, + ResourceProvider* resource_provider, + ResourcePool* resource_pool); + + private: + struct CopyOperation { + typedef ScopedPtrDeque<CopyOperation> Deque; + + CopyOperation( + scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> write_lock, + scoped_ptr<ScopedResource> src, + const Resource* dst); + ~CopyOperation(); + + scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> write_lock; + scoped_ptr<ScopedResource> src; + const Resource* dst; + }; + + void OnRasterFinished(TaskSet task_set); + void AdvanceLastFlushedCopyTo(CopySequenceNumber sequence); + void IssueCopyOperations(int64 count); + void ScheduleCheckForCompletedCopyOperationsWithLockAcquired( + bool wait_if_needed); + void CheckForCompletedCopyOperations(bool wait_if_needed); + scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const; + void StagingStateAsValueInto(base::debug::TracedValue* staging_state) const; + + scoped_refptr<base::SequencedTaskRunner> task_runner_; + TaskGraphRunner* task_graph_runner_; + const NamespaceToken namespace_token_; + RasterizerClient* client_; + ContextProvider* context_provider_; + ResourceProvider* resource_provider_; + ResourcePool* resource_pool_; + TaskSetCollection raster_pending_; + scoped_refptr<RasterizerTask> raster_finished_tasks_[kNumberOfTaskSets]; + CopySequenceNumber last_issued_copy_operation_; + CopySequenceNumber last_flushed_copy_operation_; + + // Task graph used when scheduling tasks and vector used to gather + // completed tasks. + TaskGraph graph_; + Task::Vector completed_tasks_; + + base::Lock lock_; + // |lock_| must be acquired when accessing the following members. + base::ConditionVariable copy_operation_count_cv_; + size_t scheduled_copy_operation_count_; + size_t issued_copy_operation_count_; + CopyOperation::Deque pending_copy_operations_; + CopySequenceNumber next_copy_operation_sequence_; + bool check_for_completed_copy_operations_pending_; + base::TimeTicks last_check_for_completed_copy_operations_time_; + bool shutdown_; + + base::WeakPtrFactory<OneCopyRasterWorkerPool> weak_ptr_factory_; + // "raster finished" tasks need their own factory as they need to be + // canceled when ScheduleTasks() is called. + base::WeakPtrFactory<OneCopyRasterWorkerPool> + raster_finished_weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(OneCopyRasterWorkerPool); +}; + +} // namespace cc + +#endif // CC_RESOURCES_ONE_COPY_RASTER_WORKER_POOL_H_ diff --git a/chromium/cc/resources/picture.cc b/chromium/cc/resources/picture.cc index a19fd33f3a0..c35da96848e 100644 --- a/chromium/cc/resources/picture.cc +++ b/chromium/cc/resources/picture.cc @@ -10,6 +10,7 @@ #include "base/base64.h" #include "base/debug/trace_event.h" +#include "base/debug/trace_event_argument.h" #include "base/values.h" #include "cc/base/math_util.h" #include "cc/base/util.h" @@ -17,17 +18,16 @@ #include "cc/debug/traced_value.h" #include "cc/layers/content_layer_client.h" #include "skia/ext/pixel_ref_utils.h" +#include "third_party/skia/include/core/SkBBHFactory.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkData.h" -#include "third_party/skia/include/core/SkDrawFilter.h" #include "third_party/skia/include/core/SkPaint.h" #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/rect_conversions.h" +#include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/skia_util.h" namespace cc { @@ -88,14 +88,12 @@ scoped_refptr<Picture> Picture::Create( ContentLayerClient* client, const SkTileGridFactory::TileGridInfo& tile_grid_info, bool gather_pixel_refs, - int num_raster_threads, RecordingMode recording_mode) { scoped_refptr<Picture> picture = make_scoped_refptr(new Picture(layer_rect)); picture->Record(client, tile_grid_info, recording_mode); if (gather_pixel_refs) picture->GatherPixelRefs(tile_grid_info); - picture->CloneForDrawing(num_raster_threads); return picture; } @@ -123,9 +121,7 @@ scoped_refptr<Picture> Picture::CreateFromSkpValue(const base::Value* value) { return NULL; gfx::Rect layer_rect(skpicture->width(), skpicture->height()); - gfx::Rect opaque_rect(skpicture->width(), skpicture->height()); - - return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect)); + return make_scoped_refptr(new Picture(skpicture, layer_rect)); } scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) { @@ -150,37 +146,24 @@ scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) { if (!MathUtil::FromValue(layer_rect_value, &layer_rect)) return NULL; - const base::Value* opaque_rect_value = NULL; - if (!value->Get("params.opaque_rect", &opaque_rect_value)) - return NULL; - - gfx::Rect opaque_rect; - if (!MathUtil::FromValue(opaque_rect_value, &opaque_rect)) - return NULL; - // Read the picture. This creates an empty picture on failure. SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap); if (skpicture == NULL) return NULL; - return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect)); + return make_scoped_refptr(new Picture(skpicture, layer_rect)); } -Picture::Picture(SkPicture* picture, - const gfx::Rect& layer_rect, - const gfx::Rect& opaque_rect) : - layer_rect_(layer_rect), - opaque_rect_(opaque_rect), - picture_(skia::AdoptRef(picture)), - cell_size_(layer_rect.size()) { +Picture::Picture(SkPicture* picture, const gfx::Rect& layer_rect) + : layer_rect_(layer_rect), + picture_(skia::AdoptRef(picture)), + cell_size_(layer_rect.size()) { } Picture::Picture(const skia::RefPtr<SkPicture>& picture, const gfx::Rect& layer_rect, - const gfx::Rect& opaque_rect, const PixelRefMap& pixel_refs) : layer_rect_(layer_rect), - opaque_rect_(opaque_rect), picture_(picture), pixel_refs_(pixel_refs), cell_size_(layer_rect.size()) { @@ -191,18 +174,6 @@ Picture::~Picture() { TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this); } -Picture* Picture::GetCloneForDrawingOnThread(unsigned thread_index) { - // We don't need clones to draw from multiple threads with SkRecord. - if (playback_) { - return this; - } - - // SkPicture is not thread-safe to rasterize with, this returns a clone - // to rasterize with on a specific thread. - CHECK_GE(clones_.size(), thread_index); - return thread_index == clones_.size() ? this : clones_[thread_index].get(); -} - bool Picture::IsSuitableForGpuRasterization() const { DCHECK(picture_); @@ -216,36 +187,14 @@ bool Picture::IsSuitableForGpuRasterization() const { return picture_->suitableForGpuRasterization(NULL); } -void Picture::CloneForDrawing(int num_threads) { - TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); - - // We don't need clones to draw from multiple threads with SkRecord. - if (playback_) { - return; - } - +int Picture::ApproximateOpCount() const { DCHECK(picture_); - DCHECK(clones_.empty()); - - // We can re-use this picture for one raster worker thread. - raster_thread_checker_.DetachFromThread(); - - if (num_threads > 1) { - scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads - 1]); - picture_->clone(&clones[0], num_threads - 1); - - for (int i = 0; i < num_threads - 1; i++) { - scoped_refptr<Picture> clone = make_scoped_refptr( - new Picture(skia::AdoptRef(new SkPicture(clones[i])), - layer_rect_, - opaque_rect_, - pixel_refs_)); - clones_.push_back(clone); + return picture_->approximateOpCount(); +} - clone->EmitTraceSnapshotAlias(this); - clone->raster_thread_checker_.DetachFromThread(); - } - } +bool Picture::HasText() const { + DCHECK(picture_); + return picture_->hasText(); } void Picture::Record(ContentLayerClient* painter, @@ -264,8 +213,6 @@ void Picture::Record(ContentLayerClient* painter, SkTileGridFactory factory(tile_grid_info); SkPictureRecorder recorder; - scoped_ptr<EXPERIMENTAL::SkRecording> recording; - skia::RefPtr<SkCanvas> canvas; canvas = skia::SharePtr(recorder.beginRecording( layer_rect_.width(), layer_rect_.height(), &factory)); @@ -288,11 +235,6 @@ void Picture::Record(ContentLayerClient* painter, canvas = skia::AdoptRef(SkCreateNullCanvas()); graphics_context_status = ContentLayerClient::GRAPHICS_CONTEXT_DISABLED; break; - case RECORD_WITH_SKRECORD: - recording.reset(new EXPERIMENTAL::SkRecording(layer_rect_.width(), - layer_rect_.height())); - canvas = skia::SharePtr(recording->canvas()); - break; default: NOTREACHED(); } @@ -307,23 +249,12 @@ void Picture::Record(ContentLayerClient* painter, layer_rect_.height()); canvas->clipRect(layer_skrect); - gfx::RectF opaque_layer_rect; - painter->PaintContents( - canvas.get(), layer_rect_, &opaque_layer_rect, graphics_context_status); + painter->PaintContents(canvas.get(), layer_rect_, graphics_context_status); canvas->restore(); picture_ = skia::AdoptRef(recorder.endRecording()); DCHECK(picture_); - if (recording) { - // SkRecording requires it's the only one holding onto canvas before we - // may call releasePlayback(). (This helps enforce thread-safety.) - canvas.clear(); - playback_.reset(recording->releasePlayback()); - } - - opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); - EmitTraceSnapshot(); } @@ -383,13 +314,10 @@ void Picture::GatherPixelRefs( max_pixel_cell_ = gfx::Point(max_x, max_y); } -int Picture::Raster( - SkCanvas* canvas, - SkDrawPictureCallback* callback, - const Region& negated_content_region, - float contents_scale) { - if (!playback_) - DCHECK(raster_thread_checker_.CalledOnValidThread()); +int Picture::Raster(SkCanvas* canvas, + SkDrawPictureCallback* callback, + const Region& negated_content_region, + float contents_scale) const { TRACE_EVENT_BEGIN1( "cc", "Picture::Raster", @@ -405,10 +333,14 @@ int Picture::Raster( canvas->scale(contents_scale, contents_scale); canvas->translate(layer_rect_.x(), layer_rect_.y()); - if (playback_) { - playback_->draw(canvas); - } else { + if (callback) { + // If we have a callback, we need to call |draw()|, |drawPicture()| doesn't + // take a callback. This is used by |AnalysisCanvas| to early out. picture_->draw(canvas, callback); + } else { + // Prefer to call |drawPicture()| on the canvas since it could place the + // entire picture on the canvas instead of parsing the skia operations. + canvas->drawPicture(picture_.get()); } SkIRect bounds; canvas->getClipDeviceBounds(&bounds); @@ -420,16 +352,9 @@ int Picture::Raster( } void Picture::Replay(SkCanvas* canvas) { - if (!playback_) - DCHECK(raster_thread_checker_.CalledOnValidThread()); TRACE_EVENT_BEGIN0("cc", "Picture::Replay"); DCHECK(picture_); - - if (playback_) { - playback_->draw(canvas); - } else { - picture_->draw(canvas); - } + picture_->draw(canvas); SkIRect bounds; canvas->getClipDeviceBounds(&bounds); TRACE_EVENT_END1("cc", "Picture::Replay", @@ -438,26 +363,11 @@ void Picture::Replay(SkCanvas* canvas) { scoped_ptr<base::Value> Picture::AsValue() const { SkDynamicMemoryWStream stream; - - if (playback_) { - // SkPlayback can't serialize itself, so re-record into an SkPicture. - SkPictureRecorder recorder; - skia::RefPtr<SkCanvas> canvas(skia::SharePtr(recorder.beginRecording( - layer_rect_.width(), - layer_rect_.height(), - NULL))); // Default (no) bounding-box hierarchy is fastest. - playback_->draw(canvas.get()); - skia::RefPtr<SkPicture> picture(skia::AdoptRef(recorder.endRecording())); - picture->serialize(&stream, &EncodeBitmap); - } else { - // Serialize the picture. - picture_->serialize(&stream, &EncodeBitmap); - } + picture_->serialize(&stream, &EncodeBitmap); // Encode the picture as base64. scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release()); - res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release()); size_t serialized_size = stream.bytesWritten(); scoped_ptr<char[]> serialized_picture(new char[serialized_size]); @@ -466,7 +376,7 @@ scoped_ptr<base::Value> Picture::AsValue() const { base::Base64Encode(std::string(serialized_picture.get(), serialized_size), &b64_picture); res->SetString("skp64", b64_picture); - return res.PassAs<base::Value>(); + return res.Pass(); } void Picture::EmitTraceSnapshot() const { @@ -589,18 +499,22 @@ Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() { scoped_refptr<base::debug::ConvertableToTraceFormat> Picture::AsTraceableRasterData(float scale) const { - scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue()); - raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release()); + scoped_refptr<base::debug::TracedValue> raster_data = + new base::debug::TracedValue(); + TracedValue::SetIDRef(this, raster_data.get(), "picture_id"); raster_data->SetDouble("scale", scale); - return TracedValue::FromValue(raster_data.release()); + return raster_data; } scoped_refptr<base::debug::ConvertableToTraceFormat> Picture::AsTraceableRecordData() const { - scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue()); - record_data->Set("picture_id", TracedValue::CreateIDRef(this).release()); - record_data->Set("layer_rect", MathUtil::AsValue(layer_rect_).release()); - return TracedValue::FromValue(record_data.release()); + scoped_refptr<base::debug::TracedValue> record_data = + new base::debug::TracedValue(); + TracedValue::SetIDRef(this, record_data.get(), "picture_id"); + record_data->BeginArray("layer_rect"); + MathUtil::AddToTracedValue(layer_rect_, record_data.get()); + record_data->EndArray(); + return record_data; } } // namespace cc diff --git a/chromium/cc/resources/picture.h b/chromium/cc/resources/picture.h index 78833d17e91..1677309a6e2 100644 --- a/chromium/cc/resources/picture.h +++ b/chromium/cc/resources/picture.h @@ -16,14 +16,12 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "base/threading/thread_checker.h" #include "cc/base/cc_export.h" #include "cc/base/region.h" #include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkBBHFactory.h" #include "third_party/skia/include/core/SkPicture.h" -#include "third_party/skia/include/record/SkRecording.h" -#include "ui/gfx/rect.h" +#include "ui/gfx/geometry/rect.h" class SkPixelRef; @@ -50,7 +48,6 @@ class CC_EXPORT Picture RECORD_NORMALLY, RECORD_WITH_SK_NULL_CANVAS, RECORD_WITH_PAINTING_DISABLED, - RECORD_WITH_SKRECORD, RECORDING_MODE_COUNT, // Must be the last entry. }; @@ -59,21 +56,19 @@ class CC_EXPORT Picture ContentLayerClient* client, const SkTileGridFactory::TileGridInfo& tile_grid_info, bool gather_pixels_refs, - int num_raster_threads, RecordingMode recording_mode); static scoped_refptr<Picture> CreateFromValue(const base::Value* value); static scoped_refptr<Picture> CreateFromSkpValue(const base::Value* value); gfx::Rect LayerRect() const { return layer_rect_; } - gfx::Rect OpaqueRect() const { return opaque_rect_; } - - // Get thread-safe clone for rasterizing with on a specific thread. - Picture* GetCloneForDrawingOnThread(unsigned thread_index); // Has Record() been called yet? bool HasRecording() const { return picture_.get() != NULL; } bool IsSuitableForGpuRasterization() const; + int ApproximateOpCount() const; + + bool HasText() const; // Apply this scale and raster the negated region into the canvas. // |negated_content_region| specifies the region to be clipped out of the @@ -82,7 +77,7 @@ class CC_EXPORT Picture int Raster(SkCanvas* canvas, SkDrawPictureCallback* callback, const Region& negated_content_region, - float contents_scale); + float contents_scale) const; // Draw the picture directly into the given canvas, without applying any // clip/scale/layer transformations. @@ -137,17 +132,11 @@ class CC_EXPORT Picture // ownership to this picture. Picture(const skia::RefPtr<SkPicture>&, const gfx::Rect& layer_rect, - const gfx::Rect& opaque_rect, const PixelRefMap& pixel_refs); // This constructor will call AdoptRef on the SkPicture. - Picture(SkPicture*, - const gfx::Rect& layer_rect, - const gfx::Rect& opaque_rect); + Picture(SkPicture*, const gfx::Rect& layer_rect); ~Picture(); - // Make thread-safe clones for rasterizing with. - void CloneForDrawing(int num_threads); - // Record a paint operation. To be able to safely use this SkPicture for // playback on a different thread this can only be called once. void Record(ContentLayerClient* client, @@ -158,12 +147,7 @@ class CC_EXPORT Picture void GatherPixelRefs(const SkTileGridFactory::TileGridInfo& tile_grid_info); gfx::Rect layer_rect_; - gfx::Rect opaque_rect_; skia::RefPtr<SkPicture> picture_; - scoped_ptr<const EXPERIMENTAL::SkPlayback> playback_; - - typedef std::vector<scoped_refptr<Picture> > PictureVector; - PictureVector clones_; PixelRefMap pixel_refs_; gfx::Point min_pixel_cell_; @@ -175,8 +159,6 @@ class CC_EXPORT Picture scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableRecordData() const; - base::ThreadChecker raster_thread_checker_; - friend class base::RefCountedThreadSafe<Picture>; friend class PixelRefIterator; DISALLOW_COPY_AND_ASSIGN(Picture); diff --git a/chromium/cc/resources/picture_layer_tiling.cc b/chromium/cc/resources/picture_layer_tiling.cc index 5a419516e63..d8885e7bc13 100644 --- a/chromium/cc/resources/picture_layer_tiling.cc +++ b/chromium/cc/resources/picture_layer_tiling.cc @@ -7,15 +7,18 @@ #include <algorithm> #include <cmath> #include <limits> +#include <set> #include "base/debug/trace_event.h" +#include "base/debug/trace_event_argument.h" +#include "base/logging.h" #include "cc/base/math_util.h" #include "cc/resources/tile.h" #include "cc/resources/tile_priority.h" -#include "ui/gfx/point_conversions.h" -#include "ui/gfx/rect_conversions.h" -#include "ui/gfx/safe_integer_conversions.h" -#include "ui/gfx/size_conversions.h" +#include "ui/gfx/geometry/point_conversions.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/safe_integer_conversions.h" +#include "ui/gfx/geometry/size_conversions.h" namespace cc { namespace { @@ -34,16 +37,23 @@ class TileEvictionOrder { const TilePriority& b_priority = b->priority_for_tree_priority(tree_priority_); - if (a_priority.priority_bin == b_priority.priority_bin && - a->required_for_activation() != b->required_for_activation()) { - return b->required_for_activation(); - } - return b_priority.IsHigherPriorityThan(a_priority); + DCHECK(a_priority.priority_bin == b_priority.priority_bin); + DCHECK(a->required_for_activation() == b->required_for_activation()); + + // Or if a is occluded and b is unoccluded. + bool a_is_occluded = a->is_occluded_for_tree_priority(tree_priority_); + bool b_is_occluded = b->is_occluded_for_tree_priority(tree_priority_); + if (a_is_occluded != b_is_occluded) + return a_is_occluded; + + // Or if a is farther away from visible. + return a_priority.distance_to_visible > b_priority.distance_to_visible; } private: TreePriority tree_priority_; }; + } // namespace scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( @@ -62,13 +72,23 @@ PictureLayerTiling::PictureLayerTiling(float contents_scale, layer_bounds_(layer_bounds), resolution_(NON_IDEAL_RESOLUTION), client_(client), - tiling_data_(gfx::Size(), gfx::Rect(), true), + tiling_data_(gfx::Size(), gfx::Size(), kBorderTexels), last_impl_frame_time_in_seconds_(0.0), + content_to_screen_scale_(0.f), + can_require_tiles_for_activation_(false), + has_visible_rect_tiles_(false), + has_skewport_rect_tiles_(false), + has_soon_border_rect_tiles_(false), + has_eventually_rect_tiles_(false), eviction_tiles_cache_valid_(false), eviction_cache_tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES) { gfx::Size content_bounds = gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)); gfx::Size tile_size = client_->CalculateTileSize(content_bounds); + if (tile_size.IsEmpty()) { + layer_bounds_ = gfx::Size(); + content_bounds = gfx::Size(); + } DCHECK(!gfx::ToFlooredSize( gfx::ScaleSize(layer_bounds, contents_scale)).IsEmpty()) << @@ -76,21 +96,19 @@ PictureLayerTiling::PictureLayerTiling(float contents_scale, " Layer bounds: " << layer_bounds.ToString() << " Contents scale: " << contents_scale; - tiling_data_.SetTilingRect(gfx::Rect(content_bounds)); + tiling_data_.SetTilingSize(content_bounds); tiling_data_.SetMaxTextureSize(tile_size); } PictureLayerTiling::~PictureLayerTiling() { + for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) + it->second->set_shared(false); } void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) { client_ = client; } -gfx::Rect PictureLayerTiling::TilingRect() const { - return tiling_data_.tiling_rect(); -} - Tile* PictureLayerTiling::CreateTile(int i, int j, const PictureLayerTiling* twin_tiling) { @@ -108,7 +126,12 @@ Tile* PictureLayerTiling::CreateTile(int i, if (Tile* candidate_tile = twin_tiling->TileAt(i, j)) { gfx::Rect rect = gfx::ScaleToEnclosingRect(paint_rect, 1.0f / contents_scale_); - if (!client_->GetInvalidation()->Intersects(rect)) { + const Region* invalidation = client_->GetPendingInvalidation(); + if (!invalidation || !invalidation->Intersects(rect)) { + DCHECK(!candidate_tile->is_shared()); + DCHECK_EQ(i, candidate_tile->tiling_i_index()); + DCHECK_EQ(j, candidate_tile->tiling_j_index()); + candidate_tile->set_shared(true); tiles_[key] = candidate_tile; return candidate_tile; } @@ -117,14 +140,19 @@ Tile* PictureLayerTiling::CreateTile(int i, // Create a new tile because our twin didn't have a valid one. scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect); - if (tile.get()) + if (tile.get()) { + DCHECK(!tile->is_shared()); + tile->set_tiling_index(i, j); tiles_[key] = tile; + } + eviction_tiles_cache_valid_ = false; return tile.get(); } void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() { - const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this); - bool include_borders = true; + const PictureLayerTiling* twin_tiling = + client_->GetPendingOrActiveTwinTiling(this); + bool include_borders = false; for (TilingData::Iterator iter( &tiling_data_, live_tiles_rect_, include_borders); iter; @@ -135,80 +163,152 @@ void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() { continue; CreateTile(key.first, key.second, twin_tiling); } + + VerifyLiveTilesRect(); } -void PictureLayerTiling::SetLayerBounds(const gfx::Size& layer_bounds) { - if (layer_bounds_ == layer_bounds) - return; +void PictureLayerTiling::UpdateTilesToCurrentPile( + const Region& layer_invalidation, + const gfx::Size& new_layer_bounds) { + DCHECK(!new_layer_bounds.IsEmpty()); - DCHECK(!layer_bounds.IsEmpty()); + gfx::Size tile_size = tiling_data_.max_texture_size(); - gfx::Size old_layer_bounds = layer_bounds_; - layer_bounds_ = layer_bounds; - gfx::Size content_bounds = - gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_)); + if (new_layer_bounds != layer_bounds_) { + gfx::Size content_bounds = + gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_)); + + tile_size = client_->CalculateTileSize(content_bounds); + if (tile_size.IsEmpty()) { + layer_bounds_ = gfx::Size(); + content_bounds = gfx::Size(); + } else { + layer_bounds_ = new_layer_bounds; + } + + // The SetLiveTilesRect() method would drop tiles outside the new bounds, + // but may do so incorrectly if resizing the tiling causes the number of + // tiles in the tiling_data_ to change. + gfx::Rect content_rect(content_bounds); + int before_left = tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.x()); + int before_top = tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.y()); + int before_right = + tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1); + int before_bottom = + tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1); + + // The live_tiles_rect_ is clamped to stay within the tiling size as we + // change it. + live_tiles_rect_.Intersect(content_rect); + tiling_data_.SetTilingSize(content_bounds); + + int after_right = -1; + int after_bottom = -1; + if (!live_tiles_rect_.IsEmpty()) { + after_right = + tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1); + after_bottom = + tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1); + } + + // There is no recycled twin since this is run on the pending tiling. + PictureLayerTiling* recycled_twin = NULL; + DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this)); + DCHECK_EQ(PENDING_TREE, client_->GetTree()); + + // Drop tiles outside the new layer bounds if the layer shrank. + for (int i = after_right + 1; i <= before_right; ++i) { + for (int j = before_top; j <= before_bottom; ++j) + RemoveTileAt(i, j, recycled_twin); + } + for (int i = before_left; i <= after_right; ++i) { + for (int j = after_bottom + 1; j <= before_bottom; ++j) + RemoveTileAt(i, j, recycled_twin); + } + + // If the layer grew, the live_tiles_rect_ is not changed, but a new row + // and/or column of tiles may now exist inside the same live_tiles_rect_. + const PictureLayerTiling* twin_tiling = + client_->GetPendingOrActiveTwinTiling(this); + if (after_right > before_right) { + DCHECK_EQ(after_right, before_right + 1); + for (int j = before_top; j <= after_bottom; ++j) + CreateTile(after_right, j, twin_tiling); + } + if (after_bottom > before_bottom) { + DCHECK_EQ(after_bottom, before_bottom + 1); + for (int i = before_left; i <= before_right; ++i) + CreateTile(i, after_bottom, twin_tiling); + } + } - gfx::Size tile_size = client_->CalculateTileSize(content_bounds); if (tile_size != tiling_data_.max_texture_size()) { - tiling_data_.SetTilingRect(gfx::Rect(content_bounds)); tiling_data_.SetMaxTextureSize(tile_size); + // When the tile size changes, the TilingData positions no longer work + // as valid keys to the TileMap, so just drop all tiles. Reset(); - return; + } else { + Invalidate(layer_invalidation); } - // Any tiles outside our new bounds are invalid and should be dropped. - gfx::Rect bounded_live_tiles_rect(live_tiles_rect_); - bounded_live_tiles_rect.Intersect(gfx::Rect(content_bounds)); - SetLiveTilesRect(bounded_live_tiles_rect); - tiling_data_.SetTilingRect(gfx::Rect(content_bounds)); - - // Create tiles for newly exposed areas. - Region layer_region((gfx::Rect(layer_bounds_))); - layer_region.Subtract(gfx::Rect(old_layer_bounds)); - Invalidate(layer_region); + RasterSource* raster_source = client_->GetRasterSource(); + for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) + it->second->set_raster_source(raster_source); + VerifyLiveTilesRect(); } void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_region) { - DoInvalidate(layer_region, false /* recreate_tiles */); + bool recreate_invalidated_tiles = false; + DoInvalidate(layer_region, recreate_invalidated_tiles); } void PictureLayerTiling::Invalidate(const Region& layer_region) { - DoInvalidate(layer_region, true /* recreate_tiles */); + bool recreate_invalidated_tiles = true; + DoInvalidate(layer_region, recreate_invalidated_tiles); } void PictureLayerTiling::DoInvalidate(const Region& layer_region, - bool recreate_tiles) { + bool recreate_invalidated_tiles) { std::vector<TileMapKey> new_tile_keys; - gfx::Rect expanded_live_tiles_rect( - tiling_data_.ExpandRectToTileBoundsWithBorders(live_tiles_rect_)); + gfx::Rect expanded_live_tiles_rect = + tiling_data_.ExpandRectIgnoringBordersToTileBounds(live_tiles_rect_); for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) { gfx::Rect layer_rect = iter.rect(); gfx::Rect content_rect = gfx::ScaleToEnclosingRect(layer_rect, contents_scale_); + // Consider tiles inside the live tiles rect even if only their border + // pixels intersect the invalidation. But don't consider tiles outside + // the live tiles rect with the same conditions, as they won't exist. + int border_pixels = tiling_data_.border_texels(); + content_rect.Inset(-border_pixels, -border_pixels); // Avoid needless work by not bothering to invalidate where there aren't // tiles. content_rect.Intersect(expanded_live_tiles_rect); if (content_rect.IsEmpty()) continue; - bool include_borders = true; + // Since the content_rect includes border pixels already, don't include + // borders when iterating to avoid double counting them. + bool include_borders = false; for (TilingData::Iterator iter( &tiling_data_, content_rect, include_borders); iter; ++iter) { - TileMapKey key(iter.index()); - TileMap::iterator find = tiles_.find(key); - if (find == tiles_.end()) - continue; - tiles_.erase(find); - if (recreate_tiles) - new_tile_keys.push_back(key); + // There is no recycled twin since this is run on the pending tiling. + PictureLayerTiling* recycled_twin = NULL; + DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this)); + DCHECK_EQ(PENDING_TREE, client_->GetTree()); + if (RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin)) + new_tile_keys.push_back(iter.index()); } } - if (recreate_tiles) { - const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this); - for (size_t i = 0; i < new_tile_keys.size(); ++i) + if (recreate_invalidated_tiles && !new_tile_keys.empty()) { + for (size_t i = 0; i < new_tile_keys.size(); ++i) { + // Don't try to share a tile with the twin layer, it's been invalidated so + // we have to make our own tile here. + const PictureLayerTiling* twin_tiling = NULL; CreateTile(new_tile_keys[i].first, new_tile_keys[i].second, twin_tiling); + } } } @@ -249,7 +349,7 @@ PictureLayerTiling::CoverageIterator::CoverageIterator( dest_to_content_scale_); // IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to // check for non-intersection first. - content_rect.Intersect(tiling_->TilingRect()); + content_rect.Intersect(gfx::Rect(tiling_->tiling_size())); if (content_rect.IsEmpty()) return; @@ -350,7 +450,7 @@ gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const { gfx::RectF texture_rect(current_geometry_rect_); texture_rect.Scale(dest_to_content_scale_, dest_to_content_scale_); - texture_rect.Intersect(tiling_->TilingRect()); + texture_rect.Intersect(gfx::Rect(tiling_->tiling_size())); if (texture_rect.IsEmpty()) return texture_rect; texture_rect.Offset(-tex_origin.OffsetFromOrigin()); @@ -362,9 +462,32 @@ gfx::Size PictureLayerTiling::CoverageIterator::texture_size() const { return tiling_->tiling_data_.max_texture_size(); } +bool PictureLayerTiling::RemoveTileAt(int i, + int j, + PictureLayerTiling* recycled_twin) { + TileMap::iterator found = tiles_.find(TileMapKey(i, j)); + if (found == tiles_.end()) + return false; + found->second->set_shared(false); + tiles_.erase(found); + eviction_tiles_cache_valid_ = false; + if (recycled_twin) { + // Recycled twin does not also have a recycled twin, so pass NULL. + recycled_twin->RemoveTileAt(i, j, NULL); + } + return true; +} + void PictureLayerTiling::Reset() { live_tiles_rect_ = gfx::Rect(); + PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this); + for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { + it->second->set_shared(false); + if (recycled_twin) + recycled_twin->RemoveTileAt(it->first.first, it->first.second, NULL); + } tiles_.clear(); + eviction_tiles_cache_valid_ = false; } gfx::Rect PictureLayerTiling::ComputeSkewport( @@ -415,156 +538,104 @@ gfx::Rect PictureLayerTiling::ComputeSkewport( return skewport; } -void PictureLayerTiling::UpdateTilePriorities( +void PictureLayerTiling::ComputeTilePriorityRects( WhichTree tree, - const gfx::Rect& visible_layer_rect, - float layer_contents_scale, - double current_frame_time_in_seconds) { - if (!NeedsUpdateForFrameAtTime(current_frame_time_in_seconds)) { + const gfx::Rect& viewport_in_layer_space, + float ideal_contents_scale, + double current_frame_time_in_seconds, + const Occlusion& occlusion_in_layer_space) { + if (!NeedsUpdateForFrameAtTimeAndViewport(current_frame_time_in_seconds, + viewport_in_layer_space)) { // This should never be zero for the purposes of has_ever_been_updated(). DCHECK_NE(current_frame_time_in_seconds, 0.0); return; } gfx::Rect visible_rect_in_content_space = - gfx::ScaleToEnclosingRect(visible_layer_rect, contents_scale_); + gfx::ScaleToEnclosingRect(viewport_in_layer_space, contents_scale_); - if (TilingRect().IsEmpty()) { + if (tiling_size().IsEmpty()) { last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds; + last_viewport_in_layer_space_ = viewport_in_layer_space; last_visible_rect_in_content_space_ = visible_rect_in_content_space; return; } + // Calculate the skewport. + gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds, + visible_rect_in_content_space); + DCHECK(skewport.Contains(visible_rect_in_content_space)); + + // Calculate the eventually/live tiles rect. size_t max_tiles_for_interest_area = client_->GetMaxTilesForInterestArea(); gfx::Size tile_size = tiling_data_.max_texture_size(); int64 eventually_rect_area = max_tiles_for_interest_area * tile_size.width() * tile_size.height(); - gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds, - visible_rect_in_content_space); - DCHECK(skewport.Contains(visible_rect_in_content_space)); - gfx::Rect eventually_rect = ExpandRectEquallyToAreaBoundedBy(visible_rect_in_content_space, eventually_rect_area, - TilingRect(), + gfx::Rect(tiling_size()), &expansion_cache_); - DCHECK(eventually_rect.IsEmpty() || TilingRect().Contains(eventually_rect)); + DCHECK(eventually_rect.IsEmpty() || + gfx::Rect(tiling_size()).Contains(eventually_rect)) + << "tiling_size: " << tiling_size().ToString() + << " eventually_rect: " << eventually_rect.ToString(); + + // Calculate the soon border rect. + content_to_screen_scale_ = ideal_contents_scale / contents_scale_; + gfx::Rect soon_border_rect = visible_rect_in_content_space; + float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale_; + soon_border_rect.Inset(-border, -border, -border, -border); + // Update the tiling state. SetLiveTilesRect(eventually_rect); last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds; + last_viewport_in_layer_space_ = viewport_in_layer_space; last_visible_rect_in_content_space_ = visible_rect_in_content_space; - current_visible_rect_in_content_space_ = visible_rect_in_content_space; - current_skewport_ = skewport; - current_eventually_rect_ = eventually_rect; eviction_tiles_cache_valid_ = false; - TilePriority now_priority(resolution_, TilePriority::NOW, 0); - float content_to_screen_scale = - 1.0f / (contents_scale_ * layer_contents_scale); - - // Assign now priority to all visible tiles. - bool include_borders = true; - for (TilingData::Iterator iter( - &tiling_data_, visible_rect_in_content_space, include_borders); - iter; - ++iter) { - TileMap::iterator find = tiles_.find(iter.index()); - if (find == tiles_.end()) - continue; - Tile* tile = find->second.get(); - - tile->SetPriority(tree, now_priority); - } - - // Assign soon priority to skewport tiles. - for (TilingData::DifferenceIterator iter( - &tiling_data_, skewport, visible_rect_in_content_space); - iter; - ++iter) { - TileMap::iterator find = tiles_.find(iter.index()); - if (find == tiles_.end()) - continue; - Tile* tile = find->second.get(); - - gfx::Rect tile_bounds = - tiling_data_.TileBounds(iter.index_x(), iter.index_y()); - - float distance_to_visible = - visible_rect_in_content_space.ManhattanInternalDistance(tile_bounds) * - content_to_screen_scale; - - TilePriority priority(resolution_, TilePriority::SOON, distance_to_visible); - tile->SetPriority(tree, priority); - } - - // Assign eventually priority to interest rect tiles. - for (TilingData::DifferenceIterator iter( - &tiling_data_, eventually_rect, skewport); - iter; - ++iter) { - TileMap::iterator find = tiles_.find(iter.index()); - if (find == tiles_.end()) - continue; - Tile* tile = find->second.get(); - - gfx::Rect tile_bounds = - tiling_data_.TileBounds(iter.index_x(), iter.index_y()); - - float distance_to_visible = - visible_rect_in_content_space.ManhattanInternalDistance(tile_bounds) * - content_to_screen_scale; - TilePriority priority( - resolution_, TilePriority::EVENTUALLY, distance_to_visible); - tile->SetPriority(tree, priority); - } + current_visible_rect_ = visible_rect_in_content_space; + current_skewport_rect_ = skewport; + current_soon_border_rect_ = soon_border_rect; + current_eventually_rect_ = eventually_rect; + current_occlusion_in_layer_space_ = occlusion_in_layer_space; - // Upgrade the priority on border tiles to be SOON. - current_soon_border_rect_ = visible_rect_in_content_space; - float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale; - current_soon_border_rect_.Inset(-border, -border, -border, -border); - for (TilingData::DifferenceIterator iter( - &tiling_data_, current_soon_border_rect_, skewport); - iter; - ++iter) { - TileMap::iterator find = tiles_.find(iter.index()); - if (find == tiles_.end()) - continue; - Tile* tile = find->second.get(); + // Update has_*_tiles state. + gfx::Rect tiling_rect(tiling_size()); - TilePriority priority(resolution_, - TilePriority::SOON, - tile->priority(tree).distance_to_visible); - tile->SetPriority(tree, priority); - } + has_visible_rect_tiles_ = tiling_rect.Intersects(current_visible_rect_); + has_skewport_rect_tiles_ = tiling_rect.Intersects(current_skewport_rect_); + has_soon_border_rect_tiles_ = + tiling_rect.Intersects(current_soon_border_rect_); + has_eventually_rect_tiles_ = tiling_rect.Intersects(current_eventually_rect_); } void PictureLayerTiling::SetLiveTilesRect( const gfx::Rect& new_live_tiles_rect) { DCHECK(new_live_tiles_rect.IsEmpty() || - TilingRect().Contains(new_live_tiles_rect)); + gfx::Rect(tiling_size()).Contains(new_live_tiles_rect)) + << "tiling_size: " << tiling_size().ToString() + << " new_live_tiles_rect: " << new_live_tiles_rect.ToString(); if (live_tiles_rect_ == new_live_tiles_rect) return; // Iterate to delete all tiles outside of our new live_tiles rect. + PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this); for (TilingData::DifferenceIterator iter(&tiling_data_, live_tiles_rect_, new_live_tiles_rect); iter; ++iter) { - TileMapKey key(iter.index()); - TileMap::iterator found = tiles_.find(key); - // If the tile was outside of the recorded region, it won't exist even - // though it was in the live rect. - if (found != tiles_.end()) - tiles_.erase(found); + RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin); } - const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this); + const PictureLayerTiling* twin_tiling = + client_->GetPendingOrActiveTwinTiling(this); // Iterate to allocate new tiles for all regions with newly exposed area. for (TilingData::DifferenceIterator iter(&tiling_data_, @@ -577,45 +648,172 @@ void PictureLayerTiling::SetLiveTilesRect( } live_tiles_rect_ = new_live_tiles_rect; + VerifyLiveTilesRect(); } -void PictureLayerTiling::DidBecomeRecycled() { - // DidBecomeActive below will set the active priority for tiles that are - // still in the tree. Calling this first on an active tiling that is becoming - // recycled takes care of tiles that are no longer in the active tree (eg. - // due to a pending invalidation). - for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { - it->second->SetPriority(ACTIVE_TREE, TilePriority()); +void PictureLayerTiling::VerifyLiveTilesRect() { +#if DCHECK_IS_ON + for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { + if (!it->second.get()) + continue; + DCHECK(it->first.first < tiling_data_.num_tiles_x()) + << this << " " << it->first.first << "," << it->first.second + << " num_tiles_x " << tiling_data_.num_tiles_x() << " live_tiles_rect " + << live_tiles_rect_.ToString(); + DCHECK(it->first.second < tiling_data_.num_tiles_y()) + << this << " " << it->first.first << "," << it->first.second + << " num_tiles_y " << tiling_data_.num_tiles_y() << " live_tiles_rect " + << live_tiles_rect_.ToString(); + DCHECK(tiling_data_.TileBounds(it->first.first, it->first.second) + .Intersects(live_tiles_rect_)) + << this << " " << it->first.first << "," << it->first.second + << " tile bounds " + << tiling_data_.TileBounds(it->first.first, it->first.second).ToString() + << " live_tiles_rect " << live_tiles_rect_.ToString(); } +#endif } -void PictureLayerTiling::DidBecomeActive() { - for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { - it->second->SetPriority(ACTIVE_TREE, it->second->priority(PENDING_TREE)); - it->second->SetPriority(PENDING_TREE, TilePriority()); +bool PictureLayerTiling::IsTileOccluded(const Tile* tile) const { + DCHECK(tile); + + if (!current_occlusion_in_layer_space_.HasOcclusion()) + return false; + + gfx::Rect tile_query_rect = + gfx::IntersectRects(tile->content_rect(), current_visible_rect_); - // Tile holds a ref onto a picture pile. If the tile never gets invalidated - // and recreated, then that picture pile ref could exist indefinitely. To - // prevent this, ask the client to update the pile to its own ref. This - // will cause PicturePileImpls and their clones to get deleted once the - // corresponding PictureLayerImpl and any in flight raster jobs go out of - // scope. - client_->UpdatePile(it->second.get()); + // Explicitly check if the tile is outside the viewport. If so, we need to + // return false, since occlusion for this tile is unknown. + // TODO(vmpstr): Since the current visible rect is really a viewport in + // layer space, we should probably clip tile query rect to tiling bounds + // or live tiles rect. + if (tile_query_rect.IsEmpty()) + return false; + + if (contents_scale_ != 1.f) { + tile_query_rect = + gfx::ScaleToEnclosingRect(tile_query_rect, 1.0f / contents_scale_); } + + return current_occlusion_in_layer_space_.IsOccluded(tile_query_rect); } -void PictureLayerTiling::UpdateTilesToCurrentPile() { - for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { - client_->UpdatePile(it->second.get()); +bool PictureLayerTiling::IsTileRequiredForActivation(const Tile* tile) const { + DCHECK_EQ(PENDING_TREE, client_->GetTree()); + + // Note that although this function will determine whether tile is required + // for activation assuming that it is in visible (ie in the viewport). That is + // to say, even if the tile is outside of the viewport, it will be treated as + // if it was inside (there are no explicit checks for this). Hence, this + // function is only called for visible tiles to ensure we don't block + // activation on tiles outside of the viewport. + + // If we are not allowed to mark tiles as required for activation, then don't + // do it. + if (!can_require_tiles_for_activation_) + return false; + + if (resolution_ != HIGH_RESOLUTION) + return false; + + if (IsTileOccluded(tile)) + return false; + + if (client_->RequiresHighResToDraw()) + return true; + + const PictureLayerTiling* twin_tiling = + client_->GetPendingOrActiveTwinTiling(this); + if (!twin_tiling) + return true; + + if (twin_tiling->layer_bounds() != layer_bounds()) + return true; + + if (twin_tiling->current_visible_rect_ != current_visible_rect_) + return true; + + Tile* twin_tile = + twin_tiling->TileAt(tile->tiling_i_index(), tile->tiling_j_index()); + // If twin tile is missing, it might not have a recording, so we don't need + // this tile to be required for activation. + if (!twin_tile) + return false; + + return true; +} + +void PictureLayerTiling::UpdateTileAndTwinPriority(Tile* tile) const { + UpdateTilePriority(tile); + + const PictureLayerTiling* twin_tiling = + client_->GetPendingOrActiveTwinTiling(this); + if (!tile->is_shared() || !twin_tiling) { + WhichTree tree = client_->GetTree(); + WhichTree twin_tree = tree == ACTIVE_TREE ? PENDING_TREE : ACTIVE_TREE; + tile->SetPriority(twin_tree, TilePriority()); + tile->set_is_occluded(twin_tree, false); + if (twin_tree == PENDING_TREE) + tile->set_required_for_activation(false); + return; + } + + twin_tiling->UpdateTilePriority(tile); +} + +void PictureLayerTiling::UpdateTilePriority(Tile* tile) const { + // TODO(vmpstr): This code should return the priority instead of setting it on + // the tile. This should be a part of the change to move tile priority from + // tiles into iterators. + WhichTree tree = client_->GetTree(); + + DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile); + gfx::Rect tile_bounds = + tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index()); + + if (current_visible_rect_.Intersects(tile_bounds)) { + tile->SetPriority(tree, TilePriority(resolution_, TilePriority::NOW, 0)); + if (tree == PENDING_TREE) + tile->set_required_for_activation(IsTileRequiredForActivation(tile)); + tile->set_is_occluded(tree, IsTileOccluded(tile)); + return; + } + + if (tree == PENDING_TREE) + tile->set_required_for_activation(false); + tile->set_is_occluded(tree, false); + + DCHECK_GT(content_to_screen_scale_, 0.f); + float distance_to_visible = + current_visible_rect_.ManhattanInternalDistance(tile_bounds) * + content_to_screen_scale_; + + if (current_soon_border_rect_.Intersects(tile_bounds) || + current_skewport_rect_.Intersects(tile_bounds)) { + tile->SetPriority( + tree, + TilePriority(resolution_, TilePriority::SOON, distance_to_visible)); + return; } + + tile->SetPriority( + tree, + TilePriority(resolution_, TilePriority::EVENTUALLY, distance_to_visible)); } -scoped_ptr<base::Value> PictureLayerTiling::AsValue() const { - scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); +void PictureLayerTiling::GetAllTilesForTracing( + std::set<const Tile*>* tiles) const { + for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) + tiles->insert(it->second.get()); +} + +void PictureLayerTiling::AsValueInto(base::debug::TracedValue* state) const { state->SetInteger("num_tiles", tiles_.size()); state->SetDouble("content_scale", contents_scale_); - state->Set("tiling_rect", MathUtil::AsValue(TilingRect()).release()); - return state.PassAs<base::Value>(); + state->BeginDictionary("tiling_size"); + MathUtil::AddToTracedValue(tiling_size(), state); + state->EndDictionary(); } size_t PictureLayerTiling::GPUMemoryUsageInBytes() const { @@ -652,9 +850,11 @@ int ComputeExpansionDelta(int num_x_edges, int num_y_edges, int64 c = static_cast<int64>(width) * height - target_area; // Compute the delta for our edges using the quadratic equation. - return a == 0 ? -c / b : - (-b + static_cast<int>( - std::sqrt(static_cast<int64>(b) * b - 4.0 * a * c))) / (2 * a); + int delta = + (a == 0) ? -c / b : (-b + static_cast<int>(std::sqrt( + static_cast<int64>(b) * b - 4.0 * a * c))) / + (2 * a); + return std::max(0, delta); } } // namespace @@ -782,44 +982,100 @@ void PictureLayerTiling::UpdateEvictionCacheIfNeeded( eviction_cache_tree_priority_ == tree_priority) return; - eviction_tiles_cache_.clear(); - eviction_tiles_cache_.reserve(tiles_.size()); + eviction_tiles_now_.clear(); + eviction_tiles_now_and_required_for_activation_.clear(); + eviction_tiles_soon_.clear(); + eviction_tiles_soon_and_required_for_activation_.clear(); + eviction_tiles_eventually_.clear(); + eviction_tiles_eventually_and_required_for_activation_.clear(); + for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { - // TODO(vmpstr): This should update the priority if UpdateTilePriorities - // changes not to do this. - eviction_tiles_cache_.push_back(it->second); + Tile* tile = it->second.get(); + UpdateTileAndTwinPriority(tile); + const TilePriority& priority = + tile->priority_for_tree_priority(tree_priority); + switch (priority.priority_bin) { + case TilePriority::EVENTUALLY: + if (tile->required_for_activation()) + eviction_tiles_eventually_and_required_for_activation_.push_back( + tile); + else + eviction_tiles_eventually_.push_back(tile); + break; + case TilePriority::SOON: + if (tile->required_for_activation()) + eviction_tiles_soon_and_required_for_activation_.push_back(tile); + else + eviction_tiles_soon_.push_back(tile); + break; + case TilePriority::NOW: + if (tile->required_for_activation()) + eviction_tiles_now_and_required_for_activation_.push_back(tile); + else + eviction_tiles_now_.push_back(tile); + break; + } } - std::sort(eviction_tiles_cache_.begin(), - eviction_tiles_cache_.end(), - TileEvictionOrder(tree_priority)); + // TODO(vmpstr): Do this lazily. One option is to have a "sorted" flag that + // can be updated for each of the queues. + TileEvictionOrder sort_order(tree_priority); + std::sort(eviction_tiles_now_.begin(), eviction_tiles_now_.end(), sort_order); + std::sort(eviction_tiles_now_and_required_for_activation_.begin(), + eviction_tiles_now_and_required_for_activation_.end(), + sort_order); + std::sort( + eviction_tiles_soon_.begin(), eviction_tiles_soon_.end(), sort_order); + std::sort(eviction_tiles_soon_and_required_for_activation_.begin(), + eviction_tiles_soon_and_required_for_activation_.end(), + sort_order); + std::sort(eviction_tiles_eventually_.begin(), + eviction_tiles_eventually_.end(), + sort_order); + std::sort(eviction_tiles_eventually_and_required_for_activation_.begin(), + eviction_tiles_eventually_and_required_for_activation_.end(), + sort_order); + eviction_tiles_cache_valid_ = true; eviction_cache_tree_priority_ = tree_priority; } +const std::vector<Tile*>* PictureLayerTiling::GetEvictionTiles( + TreePriority tree_priority, + EvictionCategory category) { + UpdateEvictionCacheIfNeeded(tree_priority); + switch (category) { + case EVENTUALLY: + return &eviction_tiles_eventually_; + case EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION: + return &eviction_tiles_eventually_and_required_for_activation_; + case SOON: + return &eviction_tiles_soon_; + case SOON_AND_REQUIRED_FOR_ACTIVATION: + return &eviction_tiles_soon_and_required_for_activation_; + case NOW: + return &eviction_tiles_now_; + case NOW_AND_REQUIRED_FOR_ACTIVATION: + return &eviction_tiles_now_and_required_for_activation_; + } + NOTREACHED(); + return &eviction_tiles_eventually_; +} + PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator() : tiling_(NULL), current_tile_(NULL) {} PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator( - PictureLayerTiling* tiling, - WhichTree tree) - : tiling_(tiling), - type_(TilePriority::NOW), - visible_rect_in_content_space_( - tiling_->current_visible_rect_in_content_space_), - skewport_in_content_space_(tiling_->current_skewport_), - eventually_rect_in_content_space_(tiling_->current_eventually_rect_), - soon_border_rect_in_content_space_(tiling_->current_soon_border_rect_), - tree_(tree), - current_tile_(NULL), - visible_iterator_(&tiling->tiling_data_, - visible_rect_in_content_space_, - true /* include_borders */), - spiral_iterator_(&tiling->tiling_data_, - skewport_in_content_space_, - visible_rect_in_content_space_, - visible_rect_in_content_space_), - skewport_processed_(false) { + PictureLayerTiling* tiling) + : tiling_(tiling), phase_(VISIBLE_RECT), current_tile_(NULL) { + if (!tiling_->has_visible_rect_tiles_) { + AdvancePhase(); + return; + } + + visible_iterator_ = TilingData::Iterator(&tiling_->tiling_data_, + tiling_->current_visible_rect_, + false /* include_borders */); if (!visible_iterator_) { AdvancePhase(); return; @@ -827,23 +1083,56 @@ PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator( current_tile_ = tiling_->TileAt(visible_iterator_.index_x(), visible_iterator_.index_y()); - if (!current_tile_ || !TileNeedsRaster(current_tile_)) + if (!current_tile_ || !TileNeedsRaster(current_tile_)) { ++(*this); + return; + } + tiling_->UpdateTileAndTwinPriority(current_tile_); } PictureLayerTiling::TilingRasterTileIterator::~TilingRasterTileIterator() {} void PictureLayerTiling::TilingRasterTileIterator::AdvancePhase() { - DCHECK_LT(type_, TilePriority::EVENTUALLY); + DCHECK_LT(phase_, EVENTUALLY_RECT); do { - type_ = static_cast<TilePriority::PriorityBin>(type_ + 1); - if (type_ == TilePriority::EVENTUALLY) { - spiral_iterator_ = TilingData::SpiralDifferenceIterator( - &tiling_->tiling_data_, - eventually_rect_in_content_space_, - skewport_in_content_space_, - visible_rect_in_content_space_); + phase_ = static_cast<Phase>(phase_ + 1); + switch (phase_) { + case VISIBLE_RECT: + NOTREACHED(); + return; + case SKEWPORT_RECT: + if (!tiling_->has_skewport_rect_tiles_) + continue; + + spiral_iterator_ = TilingData::SpiralDifferenceIterator( + &tiling_->tiling_data_, + tiling_->current_skewport_rect_, + tiling_->current_visible_rect_, + tiling_->current_visible_rect_); + break; + case SOON_BORDER_RECT: + if (!tiling_->has_soon_border_rect_tiles_) + continue; + + spiral_iterator_ = TilingData::SpiralDifferenceIterator( + &tiling_->tiling_data_, + tiling_->current_soon_border_rect_, + tiling_->current_skewport_rect_, + tiling_->current_visible_rect_); + break; + case EVENTUALLY_RECT: + if (!tiling_->has_eventually_rect_tiles_) { + current_tile_ = NULL; + return; + } + + spiral_iterator_ = TilingData::SpiralDifferenceIterator( + &tiling_->tiling_data_, + tiling_->current_eventually_rect_, + tiling_->current_skewport_rect_, + tiling_->current_soon_border_rect_); + break; } while (spiral_iterator_) { @@ -854,11 +1143,14 @@ void PictureLayerTiling::TilingRasterTileIterator::AdvancePhase() { ++spiral_iterator_; } - if (!spiral_iterator_ && type_ == TilePriority::EVENTUALLY) { + if (!spiral_iterator_ && phase_ == EVENTUALLY_RECT) { current_tile_ = NULL; break; } } while (!spiral_iterator_); + + if (current_tile_) + tiling_->UpdateTileAndTwinPriority(current_tile_); } PictureLayerTiling::TilingRasterTileIterator& @@ -867,8 +1159,8 @@ operator++() { current_tile_ = NULL; while (!current_tile_ || !TileNeedsRaster(current_tile_)) { std::pair<int, int> next_index; - switch (type_) { - case TilePriority::NOW: + switch (phase_) { + case VISIBLE_RECT: ++visible_iterator_; if (!visible_iterator_) { AdvancePhase(); @@ -876,27 +1168,16 @@ operator++() { } next_index = visible_iterator_.index(); break; - case TilePriority::SOON: + case SKEWPORT_RECT: + case SOON_BORDER_RECT: ++spiral_iterator_; if (!spiral_iterator_) { - if (skewport_processed_) { - AdvancePhase(); - return *this; - } - skewport_processed_ = true; - spiral_iterator_ = TilingData::SpiralDifferenceIterator( - &tiling_->tiling_data_, - soon_border_rect_in_content_space_, - skewport_in_content_space_, - visible_rect_in_content_space_); - if (!spiral_iterator_) { - AdvancePhase(); - return *this; - } + AdvancePhase(); + return *this; } next_index = spiral_iterator_.index(); break; - case TilePriority::EVENTUALLY: + case EVENTUALLY_RECT: ++spiral_iterator_; if (!spiral_iterator_) { current_tile_ = NULL; @@ -907,32 +1188,44 @@ operator++() { } current_tile_ = tiling_->TileAt(next_index.first, next_index.second); } + + if (current_tile_) + tiling_->UpdateTileAndTwinPriority(current_tile_); return *this; } PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator() - : is_valid_(false), tiling_(NULL) {} + : eviction_tiles_(NULL), current_eviction_tiles_index_(0u) { +} PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator( PictureLayerTiling* tiling, - TreePriority tree_priority) - : is_valid_(false), tiling_(tiling), tree_priority_(tree_priority) {} - -PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {} + 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::operator bool() { - if (!IsValid()) - Initialize(); +PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() { +} - return IsValid() && tile_iterator_ != tiling_->eviction_tiles_cache_.end(); +PictureLayerTiling::TilingEvictionTileIterator::operator bool() const { + return eviction_tiles_ && + current_eviction_tiles_index_ != eviction_tiles_->size(); } Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() { - if (!IsValid()) - Initialize(); + DCHECK(*this); + return (*eviction_tiles_)[current_eviction_tiles_index_]; +} +const Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() const { DCHECK(*this); - return *tile_iterator_; + return (*eviction_tiles_)[current_eviction_tiles_index_]; } PictureLayerTiling::TilingEvictionTileIterator& @@ -940,24 +1233,11 @@ PictureLayerTiling::TilingEvictionTileIterator:: operator++() { DCHECK(*this); do { - ++tile_iterator_; - } while (tile_iterator_ != tiling_->eviction_tiles_cache_.end() && - (!(*tile_iterator_)->HasResources())); + ++current_eviction_tiles_index_; + } while (current_eviction_tiles_index_ != eviction_tiles_->size() && + !(*eviction_tiles_)[current_eviction_tiles_index_]->HasResources()); return *this; } -void PictureLayerTiling::TilingEvictionTileIterator::Initialize() { - if (!tiling_) - return; - - tiling_->UpdateEvictionCacheIfNeeded(tree_priority_); - tile_iterator_ = tiling_->eviction_tiles_cache_.begin(); - is_valid_ = true; - if (tile_iterator_ != tiling_->eviction_tiles_cache_.end() && - !(*tile_iterator_)->HasResources()) { - ++(*this); - } -} - } // namespace cc diff --git a/chromium/cc/resources/picture_layer_tiling.h b/chromium/cc/resources/picture_layer_tiling.h index fc7505c99ad..17da548c916 100644 --- a/chromium/cc/resources/picture_layer_tiling.h +++ b/chromium/cc/resources/picture_layer_tiling.h @@ -5,6 +5,7 @@ #ifndef CC_RESOURCES_PICTURE_LAYER_TILING_H_ #define CC_RESOURCES_PICTURE_LAYER_TILING_H_ +#include <set> #include <utility> #include <vector> @@ -16,11 +17,19 @@ #include "cc/base/tiling_data.h" #include "cc/resources/tile.h" #include "cc/resources/tile_priority.h" -#include "ui/gfx/rect.h" +#include "cc/trees/occlusion.h" +#include "ui/gfx/geometry/rect.h" + +namespace base { +namespace debug { +class TracedValue; +} +} namespace cc { class PictureLayerTiling; +class PicturePileImpl; class CC_EXPORT PictureLayerTilingClient { public: @@ -29,15 +38,21 @@ class CC_EXPORT PictureLayerTilingClient { virtual scoped_refptr<Tile> CreateTile( PictureLayerTiling* tiling, const gfx::Rect& content_rect) = 0; - virtual void UpdatePile(Tile* tile) = 0; + virtual RasterSource* GetRasterSource() = 0; virtual gfx::Size CalculateTileSize( const gfx::Size& content_bounds) const = 0; - virtual const Region* GetInvalidation() = 0; - virtual const PictureLayerTiling* GetTwinTiling( + // This invalidation region defines the area (if any, it can by null) that + // tiles can not be shared between pending and active trees. + virtual const Region* GetPendingInvalidation() = 0; + virtual const PictureLayerTiling* GetPendingOrActiveTwinTiling( const PictureLayerTiling* tiling) const = 0; + virtual PictureLayerTiling* GetRecycledTwinTiling( + const PictureLayerTiling* tiling) = 0; virtual size_t GetMaxTilesForInterestArea() const = 0; virtual float GetSkewportTargetTimeInSeconds() const = 0; virtual int GetSkewportExtrapolationLimitInContentPixels() const = 0; + virtual WhichTree GetTree() const = 0; + virtual bool RequiresHighResToDraw() const = 0; protected: virtual ~PictureLayerTilingClient() {} @@ -45,75 +60,80 @@ class CC_EXPORT PictureLayerTilingClient { class CC_EXPORT PictureLayerTiling { public: + static const int kBorderTexels = 1; + + enum EvictionCategory { + EVENTUALLY, + EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION, + SOON, + SOON_AND_REQUIRED_FOR_ACTIVATION, + NOW, + NOW_AND_REQUIRED_FOR_ACTIVATION + }; + class CC_EXPORT TilingRasterTileIterator { public: TilingRasterTileIterator(); - TilingRasterTileIterator(PictureLayerTiling* tiling, WhichTree tree); + explicit TilingRasterTileIterator(PictureLayerTiling* tiling); ~TilingRasterTileIterator(); operator bool() const { return !!current_tile_; } + const Tile* operator*() const { return current_tile_; } Tile* operator*() { return current_tile_; } - TilePriority::PriorityBin get_type() const { return type_; } - - TilingRasterTileIterator& operator++(); - - gfx::Rect TileBounds() const { - DCHECK(*this); - if (type_ == TilePriority::NOW) { - return tiling_->tiling_data_.TileBounds(visible_iterator_.index_x(), - visible_iterator_.index_y()); + TilePriority::PriorityBin get_type() const { + switch (phase_) { + case VISIBLE_RECT: + return TilePriority::NOW; + case SKEWPORT_RECT: + case SOON_BORDER_RECT: + return TilePriority::SOON; + case EVENTUALLY_RECT: + return TilePriority::EVENTUALLY; } - return tiling_->tiling_data_.TileBounds(spiral_iterator_.index_x(), - spiral_iterator_.index_y()); + NOTREACHED(); + return TilePriority::EVENTUALLY; } + TilingRasterTileIterator& operator++(); + private: + enum Phase { + VISIBLE_RECT, + SKEWPORT_RECT, + SOON_BORDER_RECT, + EVENTUALLY_RECT + }; + void AdvancePhase(); bool TileNeedsRaster(Tile* tile) const { - RasterMode mode = tile->DetermineRasterModeForTree(tree_); - return tile->NeedsRasterForMode(mode); + return tile->NeedsRaster() && !tiling_->IsTileOccluded(tile); } PictureLayerTiling* tiling_; - TilePriority::PriorityBin type_; - gfx::Rect visible_rect_in_content_space_; - gfx::Rect skewport_in_content_space_; - gfx::Rect eventually_rect_in_content_space_; - gfx::Rect soon_border_rect_in_content_space_; - WhichTree tree_; + Phase phase_; Tile* current_tile_; TilingData::Iterator visible_iterator_; TilingData::SpiralDifferenceIterator spiral_iterator_; - bool skewport_processed_; }; class CC_EXPORT TilingEvictionTileIterator { public: TilingEvictionTileIterator(); TilingEvictionTileIterator(PictureLayerTiling* tiling, - TreePriority tree_priority); + TreePriority tree_priority, + EvictionCategory category); ~TilingEvictionTileIterator(); - operator bool(); + operator bool() const; + const Tile* operator*() const; Tile* operator*(); TilingEvictionTileIterator& operator++(); - TilePriority::PriorityBin get_type() { - DCHECK(*this); - const TilePriority& priority = - (*tile_iterator_)->priority_for_tree_priority(tree_priority_); - return priority.priority_bin; - } private: - void Initialize(); - bool IsValid() const { return is_valid_; } - - bool is_valid_; - PictureLayerTiling* tiling_; - TreePriority tree_priority_; - std::vector<Tile*>::iterator tile_iterator_; + const std::vector<Tile*>* eviction_tiles_; + size_t current_eviction_tiles_index_; }; ~PictureLayerTiling(); @@ -124,16 +144,19 @@ class CC_EXPORT PictureLayerTiling { const gfx::Size& layer_bounds, PictureLayerTilingClient* client); gfx::Size layer_bounds() const { return layer_bounds_; } - void SetLayerBounds(const gfx::Size& layer_bounds); - void Invalidate(const Region& layer_region); - void RemoveTilesInRegion(const Region& layer_region); + void UpdateTilesToCurrentPile(const Region& layer_invalidation, + const gfx::Size& new_layer_bounds); void CreateMissingTilesInLiveTilesRect(); + void RemoveTilesInRegion(const Region& layer_region); void SetClient(PictureLayerTilingClient* client); void set_resolution(TileResolution resolution) { resolution_ = resolution; } TileResolution resolution() const { return resolution_; } + void set_can_require_tiles_for_activation(bool can_require_tiles) { + can_require_tiles_for_activation_ = can_require_tiles; + } - gfx::Rect TilingRect() const; + gfx::Size tiling_size() const { return tiling_data_.tiling_size(); } gfx::Rect live_tiles_rect() const { return live_tiles_rect_; } gfx::Size tile_size() const { return tiling_data_.max_texture_size(); } float contents_scale() const { return contents_scale_; } @@ -144,17 +167,46 @@ class CC_EXPORT PictureLayerTiling { } void CreateAllTilesForTesting() { - SetLiveTilesRect(tiling_data_.tiling_rect()); + SetLiveTilesRect(gfx::Rect(tiling_data_.tiling_size())); } + const TilingData& TilingDataForTesting() const { return tiling_data_; } + std::vector<Tile*> AllTilesForTesting() const { std::vector<Tile*> all_tiles; - for (TileMap::const_iterator it = tiles_.begin(); - it != tiles_.end(); ++it) + for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) all_tiles.push_back(it->second.get()); return all_tiles; } + void UpdateAllTilePrioritiesForTesting() { + for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) + UpdateTileAndTwinPriority(it->second.get()); + } + + std::vector<scoped_refptr<Tile>> AllRefTilesForTesting() const { + std::vector<scoped_refptr<Tile>> all_tiles; + for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) + all_tiles.push_back(it->second); + return all_tiles; + } + + void SetAllTilesOccludedForTesting() { + gfx::Rect viewport_in_layer_space = + ScaleToEnclosingRect(current_visible_rect_, 1.0f / contents_scale_); + current_occlusion_in_layer_space_ = + Occlusion(gfx::Transform(), + SimpleEnclosedRegion(viewport_in_layer_space), + SimpleEnclosedRegion(viewport_in_layer_space)); + } + + const gfx::Rect& GetCurrentVisibleRectForTesting() const { + return current_visible_rect_; + } + + bool IsTileOccluded(const Tile* tile) const; + bool IsTileRequiredForActivation(const Tile* tile) const; + // Iterate over all tiles to fill content_rect. Even if tiles are invalid // (i.e. no valid resource) this tiling should still iterate over them. // The union of all geometry_rect calls for each element iterated over should @@ -206,30 +258,21 @@ class CC_EXPORT PictureLayerTiling { void Reset(); - void UpdateTilePriorities(WhichTree tree, - const gfx::Rect& visible_layer_rect, - float layer_contents_scale, - double current_frame_time_in_seconds); - - // Copies the src_tree priority into the dst_tree priority for all tiles. - // The src_tree priority is reset to the lowest priority possible. This - // also updates the pile on each tile to be the current client's pile. - void DidBecomeActive(); - - // Resets the active priority for all tiles in a tiling, when an active - // tiling is becoming recycled. This may include some tiles which are - // not in the the pending tiling (due to invalidations). This must - // be called before DidBecomeActive, as it resets the active priority - // while DidBecomeActive promotes pending priority on a similar set of tiles. - void DidBecomeRecycled(); - - void UpdateTilesToCurrentPile(); - - bool NeedsUpdateForFrameAtTime(double frame_time_in_seconds) { - return frame_time_in_seconds != last_impl_frame_time_in_seconds_; + void ComputeTilePriorityRects(WhichTree tree, + const gfx::Rect& viewport_in_layer_space, + float ideal_contents_scale, + double current_frame_time_in_seconds, + const Occlusion& occlusion_in_layer_space); + + bool NeedsUpdateForFrameAtTimeAndViewport( + double frame_time_in_seconds, + const gfx::Rect& viewport_in_layer_space) { + return frame_time_in_seconds != last_impl_frame_time_in_seconds_ || + viewport_in_layer_space != last_viewport_in_layer_space_; } - scoped_ptr<base::Value> AsValue() const; + void GetAllTilesForTracing(std::set<const Tile*>* tiles) const; + void AsValueInto(base::debug::TracedValue* array) const; size_t GPUMemoryUsageInBytes() const; struct RectExpansionCache { @@ -258,13 +301,16 @@ class CC_EXPORT PictureLayerTiling { friend class TilingEvictionTileIterator; typedef std::pair<int, int> TileMapKey; - typedef base::hash_map<TileMapKey, scoped_refptr<Tile> > TileMap; + typedef base::hash_map<TileMapKey, scoped_refptr<Tile>> TileMap; PictureLayerTiling(float contents_scale, const gfx::Size& layer_bounds, PictureLayerTilingClient* client); void SetLiveTilesRect(const gfx::Rect& live_tiles_rect); + void VerifyLiveTilesRect(); Tile* CreateTile(int i, int j, const PictureLayerTiling* twin_tiling); + // Returns true if the Tile existed and was removed from the tiling. + bool RemoveTileAt(int i, int j, PictureLayerTiling* recycled_twin); // Computes a skewport. The calculation extrapolates the last visible // rect and the current visible rect to expand the skewport to where it @@ -275,7 +321,16 @@ class CC_EXPORT PictureLayerTiling { const; void UpdateEvictionCacheIfNeeded(TreePriority tree_priority); - void DoInvalidate(const Region& layer_region, bool recreate_tiles); + const std::vector<Tile*>* GetEvictionTiles(TreePriority tree_priority, + EvictionCategory category); + + void Invalidate(const Region& layer_region); + + void DoInvalidate(const Region& layer_region, + bool recreate_invalidated_tiles); + + void UpdateTileAndTwinPriority(Tile* tile) const; + void UpdateTilePriority(Tile* tile) const; // Given properties. float contents_scale_; @@ -290,14 +345,35 @@ class CC_EXPORT PictureLayerTiling { // State saved for computing velocities based upon finite differences. double last_impl_frame_time_in_seconds_; + gfx::Rect last_viewport_in_layer_space_; gfx::Rect last_visible_rect_in_content_space_; + float content_to_screen_scale_; - gfx::Rect current_visible_rect_in_content_space_; - gfx::Rect current_skewport_; - gfx::Rect current_eventually_rect_; + bool can_require_tiles_for_activation_; + + // Iteration rects in content space + gfx::Rect current_visible_rect_; + gfx::Rect current_skewport_rect_; gfx::Rect current_soon_border_rect_; + gfx::Rect current_eventually_rect_; + + bool has_visible_rect_tiles_; + bool has_skewport_rect_tiles_; + bool has_soon_border_rect_tiles_; + bool has_eventually_rect_tiles_; + + Occlusion current_occlusion_in_layer_space_; + + // TODO(reveman): Remove this in favour of an array of eviction_tiles_ when we + // change all enums to have a consistent way of getting the count/last + // element. + std::vector<Tile*> eviction_tiles_now_; + std::vector<Tile*> eviction_tiles_now_and_required_for_activation_; + std::vector<Tile*> eviction_tiles_soon_; + std::vector<Tile*> eviction_tiles_soon_and_required_for_activation_; + std::vector<Tile*> eviction_tiles_eventually_; + std::vector<Tile*> eviction_tiles_eventually_and_required_for_activation_; - std::vector<Tile*> eviction_tiles_cache_; bool eviction_tiles_cache_valid_; TreePriority eviction_cache_tree_priority_; diff --git a/chromium/cc/resources/picture_layer_tiling_perftest.cc b/chromium/cc/resources/picture_layer_tiling_perftest.cc index 1e698b9e0ec..8f91763c79f 100644 --- a/chromium/cc/resources/picture_layer_tiling_perftest.cc +++ b/chromium/cc/resources/picture_layer_tiling_perftest.cc @@ -4,7 +4,13 @@ #include "cc/debug/lap_timer.h" #include "cc/resources/picture_layer_tiling.h" +#include "cc/resources/resource_provider.h" +#include "cc/resources/scoped_resource.h" +#include "cc/test/fake_output_surface.h" +#include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_picture_layer_tiling_client.h" +#include "cc/test/test_context_provider.h" +#include "cc/test/test_shared_bitmap_manager.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/perf/perf_test.h" @@ -22,24 +28,39 @@ class PictureLayerTilingPerfTest : public testing::Test { PictureLayerTilingPerfTest() : timer_(kWarmupRuns, base::TimeDelta::FromMilliseconds(kTimeLimitMillis), - kTimeCheckInterval) {} + kTimeCheckInterval), + context_provider_(TestContextProvider::Create()) { + output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass(); + CHECK(output_surface_->BindToClient(&output_surface_client_)); + + shared_bitmap_manager_.reset(new TestSharedBitmapManager()); + resource_provider_ = ResourceProvider::Create(output_surface_.get(), + shared_bitmap_manager_.get(), + NULL, + NULL, + 0, + false, + 1).Pass(); + } - virtual void SetUp() OVERRIDE { + virtual void SetUp() override { picture_layer_tiling_client_.SetTileSize(gfx::Size(256, 256)); picture_layer_tiling_client_.set_max_tiles_for_interest_area(250); + picture_layer_tiling_client_.set_tree(PENDING_TREE); picture_layer_tiling_ = PictureLayerTiling::Create( 1, gfx::Size(256 * 50, 256 * 50), &picture_layer_tiling_client_); picture_layer_tiling_->CreateAllTilesForTesting(); } - virtual void TearDown() OVERRIDE { + virtual void TearDown() override { picture_layer_tiling_.reset(NULL); } void RunInvalidateTest(const std::string& test_name, const Region& region) { timer_.Reset(); do { - picture_layer_tiling_->Invalidate(region); + picture_layer_tiling_->UpdateTilesToCurrentPile( + region, picture_layer_tiling_->tiling_size()); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -47,18 +68,19 @@ class PictureLayerTilingPerfTest : public testing::Test { "invalidation", "", test_name, timer_.LapsPerSecond(), "runs/s", true); } - void RunUpdateTilePrioritiesStationaryTest(const std::string& test_name, - const gfx::Transform& transform) { + void RunComputeTilePriorityRectsStationaryTest( + const std::string& test_name, + const gfx::Transform& transform) { gfx::Rect viewport_rect(0, 0, 1024, 768); timer_.Reset(); do { - picture_layer_tiling_->UpdateTilePriorities( - ACTIVE_TREE, viewport_rect, 1.f, timer_.NumLaps() + 1); + picture_layer_tiling_->ComputeTilePriorityRects( + PENDING_TREE, viewport_rect, 1.f, timer_.NumLaps() + 1, Occlusion()); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); - perf_test::PrintResult("update_tile_priorities_stationary", + perf_test::PrintResult("compute_tile_priority_rects_stationary", "", test_name, timer_.LapsPerSecond(), @@ -66,8 +88,9 @@ class PictureLayerTilingPerfTest : public testing::Test { true); } - void RunUpdateTilePrioritiesScrollingTest(const std::string& test_name, - const gfx::Transform& transform) { + void RunComputeTilePriorityRectsScrollingTest( + const std::string& test_name, + const gfx::Transform& transform) { gfx::Size viewport_size(1024, 768); gfx::Rect viewport_rect(viewport_size); int xoffsets[] = {10, 0, -10, 0}; @@ -78,8 +101,8 @@ class PictureLayerTilingPerfTest : public testing::Test { timer_.Reset(); do { - picture_layer_tiling_->UpdateTilePriorities( - ACTIVE_TREE, viewport_rect, 1.f, timer_.NumLaps() + 1); + picture_layer_tiling_->ComputeTilePriorityRects( + PENDING_TREE, viewport_rect, 1.f, timer_.NumLaps() + 1, Occlusion()); viewport_rect = gfx::Rect(viewport_rect.x() + xoffsets[offsetIndex], viewport_rect.y() + yoffsets[offsetIndex], @@ -93,7 +116,31 @@ class PictureLayerTilingPerfTest : public testing::Test { timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); - perf_test::PrintResult("update_tile_priorities_scrolling", + perf_test::PrintResult("compute_tile_priority_rects_scrolling", + "", + test_name, + timer_.LapsPerSecond(), + "runs/s", + true); + } + + void RunRasterIteratorConstructTest(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( + ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion()); + + timer_.Reset(); + do { + PictureLayerTiling::TilingRasterTileIterator it( + picture_layer_tiling_.get()); + timer_.NextLap(); + } while (!timer_.HasTimeLimitExpired()); + + perf_test::PrintResult("tiling_raster_tile_iterator_construct", "", test_name, timer_.LapsPerSecond(), @@ -101,28 +148,61 @@ class PictureLayerTilingPerfTest : public testing::Test { true); } - void RunTilingRasterTileIteratorTest(const std::string& test_name, - int num_tiles, - const gfx::Rect& viewport) { + void RunRasterIteratorConstructAndIterateTest(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_->UpdateTilePriorities( - ACTIVE_TREE, viewport, 1.0f, 1.0); + picture_layer_tiling_client_.set_tree(ACTIVE_TREE); + picture_layer_tiling_->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion()); timer_.Reset(); do { int count = num_tiles; - for (PictureLayerTiling::TilingRasterTileIterator it( - picture_layer_tiling_.get(), ACTIVE_TREE); - it && count; - ++it) { - --count; + PictureLayerTiling::TilingRasterTileIterator it( + picture_layer_tiling_.get()); + while (count--) { + ASSERT_TRUE(it) << "count: " << count; + ASSERT_TRUE(*it != NULL) << "count: " << count; + ++it; } timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); - perf_test::PrintResult("tiling_raster_tile_iterator", + perf_test::PrintResult("tiling_raster_tile_iterator_construct_and_iterate", + "", + test_name, + timer_.LapsPerSecond(), + "runs/s", + 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( + ACTIVE_TREE, 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(), @@ -130,11 +210,78 @@ class PictureLayerTilingPerfTest : public testing::Test { 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( + ACTIVE_TREE, 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_; LapTimer timer_; + + scoped_refptr<ContextProvider> context_provider_; + FakeOutputSurfaceClient output_surface_client_; + scoped_ptr<FakeOutputSurface> output_surface_; + scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; + scoped_ptr<ResourceProvider> resource_provider_; }; TEST_F(PictureLayerTilingPerfTest, Invalidate) { @@ -150,29 +297,62 @@ TEST_F(PictureLayerTilingPerfTest, Invalidate) { #if defined(OS_ANDROID) // TODO(vmpstr): Investigate why this is noisy (crbug.com/310220). -TEST_F(PictureLayerTilingPerfTest, DISABLED_UpdateTilePriorities) { +TEST_F(PictureLayerTilingPerfTest, DISABLED_ComputeTilePriorityRects) { #else -TEST_F(PictureLayerTilingPerfTest, UpdateTilePriorities) { +TEST_F(PictureLayerTilingPerfTest, ComputeTilePriorityRects) { #endif // defined(OS_ANDROID) gfx::Transform transform; - RunUpdateTilePrioritiesStationaryTest("no_transform", transform); - RunUpdateTilePrioritiesScrollingTest("no_transform", transform); + RunComputeTilePriorityRectsStationaryTest("no_transform", transform); + RunComputeTilePriorityRectsScrollingTest("no_transform", transform); transform.Rotate(10); - RunUpdateTilePrioritiesStationaryTest("rotation", transform); - RunUpdateTilePrioritiesScrollingTest("rotation", transform); + RunComputeTilePriorityRectsStationaryTest("rotation", transform); + RunComputeTilePriorityRectsScrollingTest("rotation", transform); transform.ApplyPerspectiveDepth(10); - RunUpdateTilePrioritiesStationaryTest("perspective", transform); - RunUpdateTilePrioritiesScrollingTest("perspective", transform); + RunComputeTilePriorityRectsStationaryTest("perspective", transform); + RunComputeTilePriorityRectsScrollingTest("perspective", transform); +} + +TEST_F(PictureLayerTilingPerfTest, TilingRasterTileIteratorConstruct) { + RunRasterIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100)); + RunRasterIteratorConstructTest("50_0_100x100", gfx::Rect(50, 0, 100, 100)); + RunRasterIteratorConstructTest("100_0_100x100", gfx::Rect(100, 0, 100, 100)); + RunRasterIteratorConstructTest("150_0_100x100", gfx::Rect(150, 0, 100, 100)); +} + +TEST_F(PictureLayerTilingPerfTest, + TilingRasterTileIteratorConstructAndIterate) { + RunRasterIteratorConstructAndIterateTest( + "32_100x100", 32, gfx::Rect(0, 0, 100, 100)); + RunRasterIteratorConstructAndIterateTest( + "32_500x500", 32, gfx::Rect(0, 0, 500, 500)); + RunRasterIteratorConstructAndIterateTest( + "64_100x100", 64, gfx::Rect(0, 0, 100, 100)); + RunRasterIteratorConstructAndIterateTest( + "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, TilingRasterTileIterator) { - RunTilingRasterTileIteratorTest("32_100x100", 32, gfx::Rect(0, 0, 100, 100)); - RunTilingRasterTileIteratorTest("32_500x500", 32, gfx::Rect(0, 0, 500, 500)); - RunTilingRasterTileIteratorTest("64_100x100", 64, gfx::Rect(0, 0, 100, 100)); - RunTilingRasterTileIteratorTest("64_500x500", 64, gfx::Rect(0, 0, 500, 500)); +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 diff --git a/chromium/cc/resources/picture_layer_tiling_set.cc b/chromium/cc/resources/picture_layer_tiling_set.cc index fe55d76ef13..b2b86b5464c 100644 --- a/chromium/cc/resources/picture_layer_tiling_set.cc +++ b/chromium/cc/resources/picture_layer_tiling_set.cc @@ -19,12 +19,8 @@ class LargestToSmallestScaleFunctor { } // namespace - -PictureLayerTilingSet::PictureLayerTilingSet( - PictureLayerTilingClient* client, - const gfx::Size& layer_bounds) - : client_(client), - layer_bounds_(layer_bounds) { +PictureLayerTilingSet::PictureLayerTilingSet(PictureLayerTilingClient* client) + : client_(client) { } PictureLayerTilingSet::~PictureLayerTilingSet() { @@ -36,13 +32,17 @@ void PictureLayerTilingSet::SetClient(PictureLayerTilingClient* client) { tilings_[i]->SetClient(client_); } +void PictureLayerTilingSet::RemoveTilesInRegion(const Region& region) { + for (size_t i = 0; i < tilings_.size(); ++i) + tilings_[i]->RemoveTilesInRegion(region); +} + bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other, const gfx::Size& new_layer_bounds, const Region& layer_invalidation, float minimum_contents_scale) { if (new_layer_bounds.IsEmpty()) { RemoveAllTilings(); - layer_bounds_ = new_layer_bounds; return false; } @@ -69,18 +69,18 @@ bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other, if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) { this_tiling->set_resolution(other.tilings_[i]->resolution()); - // These two calls must come before updating the pile, because they may - // destroy tiles that the new pile cannot raster. - this_tiling->SetLayerBounds(new_layer_bounds); - this_tiling->Invalidate(layer_invalidation); - - this_tiling->UpdateTilesToCurrentPile(); + this_tiling->UpdateTilesToCurrentPile(layer_invalidation, + new_layer_bounds); this_tiling->CreateMissingTilesInLiveTilesRect(); if (this_tiling->resolution() == HIGH_RESOLUTION) have_high_res_tiling = true; DCHECK(this_tiling->tile_size() == - client_->CalculateTileSize(this_tiling->TilingRect().size())); + client_->CalculateTileSize(this_tiling->tiling_size())) + << "tile_size: " << this_tiling->tile_size().ToString() + << " tiling_size: " << this_tiling->tiling_size().ToString() + << " CalculateTileSize: " + << client_->CalculateTileSize(this_tiling->tiling_size()).ToString(); continue; } scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create( @@ -94,22 +94,17 @@ bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other, } tilings_.sort(LargestToSmallestScaleFunctor()); - layer_bounds_ = new_layer_bounds; return have_high_res_tiling; } -void PictureLayerTilingSet::RemoveTilesInRegion(const Region& region) { - for (size_t i = 0; i < tilings_.size(); ++i) - tilings_[i]->RemoveTilesInRegion(region); -} - -PictureLayerTiling* PictureLayerTilingSet::AddTiling(float contents_scale) { +PictureLayerTiling* PictureLayerTilingSet::AddTiling( + float contents_scale, + const gfx::Size& layer_bounds) { for (size_t i = 0; i < tilings_.size(); ++i) DCHECK_NE(tilings_[i]->contents_scale(), contents_scale); - tilings_.push_back(PictureLayerTiling::Create(contents_scale, - layer_bounds_, - client_)); + tilings_.push_back( + PictureLayerTiling::Create(contents_scale, layer_bounds, client_)); PictureLayerTiling* appended = tilings_.back(); tilings_.sort(LargestToSmallestScaleFunctor()); @@ -218,7 +213,14 @@ Tile* PictureLayerTilingSet::CoverageIterator::operator*() const { return *tiling_iter_; } -PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling() { +TileResolution PictureLayerTilingSet::CoverageIterator::resolution() const { + const PictureLayerTiling* tiling = CurrentTiling(); + DCHECK(tiling); + return tiling->resolution(); +} + +PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling() + const { if (current_tiling_ < 0) return NULL; if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size()) @@ -307,21 +309,12 @@ PictureLayerTilingSet::CoverageIterator::operator bool() const { region_iter_.has_rect(); } -void PictureLayerTilingSet::DidBecomeActive() { - for (size_t i = 0; i < tilings_.size(); ++i) - tilings_[i]->DidBecomeActive(); -} - -void PictureLayerTilingSet::DidBecomeRecycled() { - for (size_t i = 0; i < tilings_.size(); ++i) - tilings_[i]->DidBecomeRecycled(); -} - -scoped_ptr<base::Value> PictureLayerTilingSet::AsValue() const { - scoped_ptr<base::ListValue> state(new base::ListValue()); - for (size_t i = 0; i < tilings_.size(); ++i) - state->Append(tilings_[i]->AsValue().release()); - return state.PassAs<base::Value>(); +void PictureLayerTilingSet::AsValueInto(base::debug::TracedValue* state) const { + for (size_t i = 0; i < tilings_.size(); ++i) { + state->BeginDictionary(); + tilings_[i]->AsValueInto(state); + state->EndDictionary(); + } } size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const { @@ -331,4 +324,51 @@ size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const { return amount; } +PictureLayerTilingSet::TilingRange PictureLayerTilingSet::GetTilingRange( + TilingRangeType type) const { + // Doesn't seem to be the case right now but if it ever becomes a performance + // problem to compute these ranges each time this function is called, we can + // compute them only when the tiling set has changed instead. + TilingRange high_res_range(0, 0); + TilingRange low_res_range(tilings_.size(), tilings_.size()); + for (size_t i = 0; i < tilings_.size(); ++i) { + const PictureLayerTiling* tiling = tilings_[i]; + if (tiling->resolution() == HIGH_RESOLUTION) + high_res_range = TilingRange(i, i + 1); + if (tiling->resolution() == LOW_RESOLUTION) + low_res_range = TilingRange(i, i + 1); + } + + TilingRange range(0, 0); + switch (type) { + case HIGHER_THAN_HIGH_RES: + range = TilingRange(0, high_res_range.start); + break; + case HIGH_RES: + range = high_res_range; + break; + case BETWEEN_HIGH_AND_LOW_RES: + // TODO(vmpstr): This code assumes that high res tiling will come before + // low res tiling, however there are cases where this assumption is + // violated. As a result, it's better to be safe in these situations, + // since otherwise we can end up accessing a tiling that doesn't exist. + // See crbug.com/429397 for high res tiling appearing after low res + // tiling discussion/fixes. + if (high_res_range.start <= low_res_range.start) + range = TilingRange(high_res_range.end, low_res_range.start); + else + range = TilingRange(low_res_range.end, high_res_range.start); + break; + case LOW_RES: + range = low_res_range; + break; + case LOWER_THAN_LOW_RES: + range = TilingRange(low_res_range.end, tilings_.size()); + break; + } + + DCHECK_LE(range.start, range.end); + return range; +} + } // namespace cc diff --git a/chromium/cc/resources/picture_layer_tiling_set.h b/chromium/cc/resources/picture_layer_tiling_set.h index 67b267c2803..ddde1d7be42 100644 --- a/chromium/cc/resources/picture_layer_tiling_set.h +++ b/chromium/cc/resources/picture_layer_tiling_set.h @@ -8,19 +8,40 @@ #include "cc/base/region.h" #include "cc/base/scoped_ptr_vector.h" #include "cc/resources/picture_layer_tiling.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" + +namespace base { +namespace debug { +class TracedValue; +} +} namespace cc { class CC_EXPORT PictureLayerTilingSet { public: - PictureLayerTilingSet(PictureLayerTilingClient* client, - const gfx::Size& layer_bounds); + enum TilingRangeType { + HIGHER_THAN_HIGH_RES, + HIGH_RES, + BETWEEN_HIGH_AND_LOW_RES, + LOW_RES, + LOWER_THAN_LOW_RES + }; + struct TilingRange { + TilingRange(size_t start, size_t end) : start(start), end(end) {} + + size_t start; + size_t end; + }; + + explicit PictureLayerTilingSet(PictureLayerTilingClient* client); ~PictureLayerTilingSet(); void SetClient(PictureLayerTilingClient* client); const PictureLayerTilingClient* client() const { return client_; } + void RemoveTilesInRegion(const Region& region); + // Make this set of tilings match the same set of content scales from |other|. // Delete any tilings that don't meet |minimum_contents_scale|. Recreate // any tiles that intersect |layer_invalidation|. Update the size of all @@ -31,11 +52,8 @@ class CC_EXPORT PictureLayerTilingSet { const Region& layer_invalidation, float minimum_contents_scale); - void RemoveTilesInRegion(const Region& region); - - gfx::Size layer_bounds() const { return layer_bounds_; } - - PictureLayerTiling* AddTiling(float contents_scale); + PictureLayerTiling* AddTiling(float contents_scale, + const gfx::Size& layer_bounds); size_t num_tilings() const { return tilings_.size(); } int NumHighResTilings() const; PictureLayerTiling* tiling_at(size_t idx) { return tilings_[idx]; } @@ -54,9 +72,6 @@ class CC_EXPORT PictureLayerTilingSet { // Remove all tiles; keep all tilings. void RemoveAllTiles(); - void DidBecomeActive(); - void DidBecomeRecycled(); - // For a given rect, iterates through tiles that can fill it. If no // set of tiles with resources can fill the rect, then it will iterate // through null tiles with valid geometry_rect() until the rect is full. @@ -84,7 +99,8 @@ class CC_EXPORT PictureLayerTilingSet { CoverageIterator& operator++(); operator bool() const; - PictureLayerTiling* CurrentTiling(); + TileResolution resolution() const; + PictureLayerTiling* CurrentTiling() const; private: int NextTiling() const; @@ -101,12 +117,13 @@ class CC_EXPORT PictureLayerTilingSet { Region::Iterator region_iter_; }; - scoped_ptr<base::Value> AsValue() const; + void AsValueInto(base::debug::TracedValue* array) const; size_t GPUMemoryUsageInBytes() const; + TilingRange GetTilingRange(TilingRangeType type) const; + private: PictureLayerTilingClient* client_; - gfx::Size layer_bounds_; ScopedPtrVector<PictureLayerTiling> tilings_; friend class Iterator; diff --git a/chromium/cc/resources/picture_layer_tiling_set_unittest.cc b/chromium/cc/resources/picture_layer_tiling_set_unittest.cc index 259301b8444..0fe8b3c9587 100644 --- a/chromium/cc/resources/picture_layer_tiling_set_unittest.cc +++ b/chromium/cc/resources/picture_layer_tiling_set_unittest.cc @@ -7,15 +7,13 @@ #include <map> #include <vector> -#include "cc/resources/resource_pool.h" #include "cc/resources/resource_provider.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_picture_layer_tiling_client.h" -#include "cc/test/fake_tile_manager_client.h" #include "cc/test/test_shared_bitmap_manager.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/size_conversions.h" +#include "ui/gfx/geometry/size_conversions.h" namespace cc { namespace { @@ -23,12 +21,12 @@ namespace { TEST(PictureLayerTilingSetTest, NoResources) { FakePictureLayerTilingClient client; gfx::Size layer_bounds(1000, 800); - PictureLayerTilingSet set(&client, layer_bounds); + PictureLayerTilingSet set(&client); client.SetTileSize(gfx::Size(256, 256)); - set.AddTiling(1.0); - set.AddTiling(1.5); - set.AddTiling(2.0); + set.AddTiling(1.0, layer_bounds); + set.AddTiling(1.5, layer_bounds); + set.AddTiling(2.0, layer_bounds); float contents_scale = 2.0; gfx::Size content_bounds( @@ -53,6 +51,140 @@ TEST(PictureLayerTilingSetTest, NoResources) { EXPECT_TRUE(remaining.IsEmpty()); } +TEST(PictureLayerTilingSetTest, TilingRange) { + FakePictureLayerTilingClient client; + gfx::Size layer_bounds(10, 10); + PictureLayerTilingSet::TilingRange higher_than_high_res_range(0, 0); + PictureLayerTilingSet::TilingRange high_res_range(0, 0); + PictureLayerTilingSet::TilingRange between_high_and_low_res_range(0, 0); + PictureLayerTilingSet::TilingRange low_res_range(0, 0); + PictureLayerTilingSet::TilingRange lower_than_low_res_range(0, 0); + PictureLayerTiling* high_res_tiling; + PictureLayerTiling* low_res_tiling; + + PictureLayerTilingSet set(&client); + set.AddTiling(2.0, layer_bounds); + high_res_tiling = set.AddTiling(1.0, layer_bounds); + high_res_tiling->set_resolution(HIGH_RESOLUTION); + set.AddTiling(0.5, layer_bounds); + low_res_tiling = set.AddTiling(0.25, layer_bounds); + low_res_tiling->set_resolution(LOW_RESOLUTION); + set.AddTiling(0.125, layer_bounds); + + higher_than_high_res_range = + set.GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES); + EXPECT_EQ(0u, higher_than_high_res_range.start); + EXPECT_EQ(1u, higher_than_high_res_range.end); + + high_res_range = set.GetTilingRange(PictureLayerTilingSet::HIGH_RES); + EXPECT_EQ(1u, high_res_range.start); + EXPECT_EQ(2u, high_res_range.end); + + between_high_and_low_res_range = + set.GetTilingRange(PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES); + EXPECT_EQ(2u, between_high_and_low_res_range.start); + EXPECT_EQ(3u, between_high_and_low_res_range.end); + + low_res_range = set.GetTilingRange(PictureLayerTilingSet::LOW_RES); + EXPECT_EQ(3u, low_res_range.start); + EXPECT_EQ(4u, low_res_range.end); + + lower_than_low_res_range = + set.GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES); + EXPECT_EQ(4u, lower_than_low_res_range.start); + EXPECT_EQ(5u, lower_than_low_res_range.end); + + PictureLayerTilingSet set_without_low_res(&client); + set_without_low_res.AddTiling(2.0, layer_bounds); + high_res_tiling = set_without_low_res.AddTiling(1.0, layer_bounds); + high_res_tiling->set_resolution(HIGH_RESOLUTION); + set_without_low_res.AddTiling(0.5, layer_bounds); + set_without_low_res.AddTiling(0.25, layer_bounds); + + higher_than_high_res_range = set_without_low_res.GetTilingRange( + PictureLayerTilingSet::HIGHER_THAN_HIGH_RES); + EXPECT_EQ(0u, higher_than_high_res_range.start); + EXPECT_EQ(1u, higher_than_high_res_range.end); + + high_res_range = + set_without_low_res.GetTilingRange(PictureLayerTilingSet::HIGH_RES); + EXPECT_EQ(1u, high_res_range.start); + EXPECT_EQ(2u, high_res_range.end); + + between_high_and_low_res_range = set_without_low_res.GetTilingRange( + PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES); + EXPECT_EQ(2u, between_high_and_low_res_range.start); + EXPECT_EQ(4u, between_high_and_low_res_range.end); + + low_res_range = + set_without_low_res.GetTilingRange(PictureLayerTilingSet::LOW_RES); + EXPECT_EQ(0u, low_res_range.end - low_res_range.start); + + lower_than_low_res_range = set_without_low_res.GetTilingRange( + PictureLayerTilingSet::LOWER_THAN_LOW_RES); + EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start); + + PictureLayerTilingSet set_with_only_high_and_low_res(&client); + high_res_tiling = set_with_only_high_and_low_res.AddTiling(1.0, layer_bounds); + high_res_tiling->set_resolution(HIGH_RESOLUTION); + low_res_tiling = set_with_only_high_and_low_res.AddTiling(0.5, layer_bounds); + low_res_tiling->set_resolution(LOW_RESOLUTION); + + higher_than_high_res_range = set_with_only_high_and_low_res.GetTilingRange( + PictureLayerTilingSet::HIGHER_THAN_HIGH_RES); + EXPECT_EQ(0u, + higher_than_high_res_range.end - higher_than_high_res_range.start); + + high_res_range = set_with_only_high_and_low_res.GetTilingRange( + PictureLayerTilingSet::HIGH_RES); + EXPECT_EQ(0u, high_res_range.start); + EXPECT_EQ(1u, high_res_range.end); + + between_high_and_low_res_range = + set_with_only_high_and_low_res.GetTilingRange( + PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES); + EXPECT_EQ(0u, + between_high_and_low_res_range.end - + between_high_and_low_res_range.start); + + low_res_range = set_with_only_high_and_low_res.GetTilingRange( + PictureLayerTilingSet::LOW_RES); + EXPECT_EQ(1u, low_res_range.start); + EXPECT_EQ(2u, low_res_range.end); + + lower_than_low_res_range = set_with_only_high_and_low_res.GetTilingRange( + PictureLayerTilingSet::LOWER_THAN_LOW_RES); + EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start); + + PictureLayerTilingSet set_with_only_high_res(&client); + high_res_tiling = set_with_only_high_res.AddTiling(1.0, layer_bounds); + high_res_tiling->set_resolution(HIGH_RESOLUTION); + + higher_than_high_res_range = set_with_only_high_res.GetTilingRange( + PictureLayerTilingSet::HIGHER_THAN_HIGH_RES); + EXPECT_EQ(0u, + higher_than_high_res_range.end - higher_than_high_res_range.start); + + high_res_range = + set_with_only_high_res.GetTilingRange(PictureLayerTilingSet::HIGH_RES); + EXPECT_EQ(0u, high_res_range.start); + EXPECT_EQ(1u, high_res_range.end); + + between_high_and_low_res_range = set_with_only_high_res.GetTilingRange( + PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES); + EXPECT_EQ(0u, + between_high_and_low_res_range.end - + between_high_and_low_res_range.start); + + low_res_range = + set_with_only_high_res.GetTilingRange(PictureLayerTilingSet::LOW_RES); + EXPECT_EQ(0u, low_res_range.end - low_res_range.start); + + lower_than_low_res_range = set_with_only_high_res.GetTilingRange( + PictureLayerTilingSet::LOWER_THAN_LOW_RES); + EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start); +} + class PictureLayerTilingSetTestWithResources : public testing::Test { public: void runTest( @@ -68,17 +200,24 @@ class PictureLayerTilingSetTestWithResources : public testing::Test { scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); - scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false); + scoped_ptr<ResourceProvider> resource_provider = + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager.get(), + NULL, + NULL, + 0, + false, + 1); FakePictureLayerTilingClient client(resource_provider.get()); client.SetTileSize(gfx::Size(256, 256)); + client.set_tree(PENDING_TREE); gfx::Size layer_bounds(1000, 800); - PictureLayerTilingSet set(&client, layer_bounds); + PictureLayerTilingSet set(&client); float scale = min_scale; for (int i = 0; i < num_tilings; ++i, scale += scale_increment) { - PictureLayerTiling* tiling = set.AddTiling(scale); + PictureLayerTiling* tiling = set.AddTiling(scale, layer_bounds); tiling->CreateAllTilesForTesting(); std::vector<Tile*> tiles = tiling->AllTilesForTesting(); client.tile_manager()->InitializeTilesWithResourcesForTesting(tiles); @@ -153,9 +292,11 @@ class PictureLayerTilingSetSyncTest : public testing::Test { source_bounds_(gfx::Size(30, 20)), target_bounds_(gfx::Size(30, 30)) { source_client_.SetTileSize(tile_size_); + source_client_.set_tree(PENDING_TREE); target_client_.SetTileSize(tile_size_); - source_.reset(new PictureLayerTilingSet(&source_client_, source_bounds_)); - target_.reset(new PictureLayerTilingSet(&target_client_, target_bounds_)); + target_client_.set_tree(PENDING_TREE); + source_.reset(new PictureLayerTilingSet(&source_client_)); + target_.reset(new PictureLayerTilingSet(&target_client_)); } // Sync from source to target. @@ -182,10 +323,9 @@ class PictureLayerTilingSetSyncTest : public testing::Test { SyncTilings(new_bounds, invalidation, minimum_scale); } - void VerifyTargetEqualsSource(const gfx::Size& new_bounds) const { + void VerifyTargetEqualsSource(const gfx::Size& new_bounds) { ASSERT_FALSE(new_bounds.IsEmpty()); EXPECT_EQ(target_->num_tilings(), source_->num_tilings()); - EXPECT_EQ(target_->layer_bounds().ToString(), new_bounds.ToString()); for (size_t i = 0; i < target_->num_tilings(); ++i) { ASSERT_GT(source_->num_tilings(), i); @@ -202,7 +342,7 @@ class PictureLayerTilingSetSyncTest : public testing::Test { ValidateTargetTilingSet(); } - void ValidateTargetTilingSet() const { + void ValidateTargetTilingSet() { // Tilings should be sorted largest to smallest. if (target_->num_tilings() > 0) { float last_scale = target_->tiling_at(0)->contents_scale(); @@ -214,23 +354,28 @@ class PictureLayerTilingSetSyncTest : public testing::Test { } for (size_t i = 0; i < target_->num_tilings(); ++i) - ValidateTiling(target_->tiling_at(i), target_client_.pile()); + ValidateTiling(target_->tiling_at(i), target_client_.GetRasterSource()); } void ValidateTiling(const PictureLayerTiling* tiling, - const PicturePileImpl* pile) const { - if (tiling->TilingRect().IsEmpty()) + const RasterSource* raster_source) { + if (tiling->tiling_size().IsEmpty()) { EXPECT_TRUE(tiling->live_tiles_rect().IsEmpty()); - else if (!tiling->live_tiles_rect().IsEmpty()) - EXPECT_TRUE(tiling->TilingRect().Contains(tiling->live_tiles_rect())); + } else if (!tiling->live_tiles_rect().IsEmpty()) { + gfx::Rect tiling_rect(tiling->tiling_size()); + EXPECT_TRUE(tiling_rect.Contains(tiling->live_tiles_rect())); + } std::vector<Tile*> tiles = tiling->AllTilesForTesting(); for (size_t i = 0; i < tiles.size(); ++i) { const Tile* tile = tiles[i]; ASSERT_TRUE(!!tile); - EXPECT_EQ(tile->picture_pile(), pile); + EXPECT_EQ(tile->raster_source(), raster_source); EXPECT_TRUE(tile->content_rect().Intersects(tiling->live_tiles_rect())) - << "All tiles must be inside the live tiles rect."; + << "All tiles must be inside the live tiles rect." + << " Tile rect: " << tile->content_rect().ToString() + << " Live rect: " << tiling->live_tiles_rect().ToString() + << " Scale: " << tiling->contents_scale(); } for (PictureLayerTiling::CoverageIterator iter( @@ -255,21 +400,20 @@ class PictureLayerTilingSetSyncTest : public testing::Test { TEST_F(PictureLayerTilingSetSyncTest, EmptyBounds) { float source_scales[] = {1.f, 1.2f}; for (size_t i = 0; i < arraysize(source_scales); ++i) - source_->AddTiling(source_scales[i]); + source_->AddTiling(source_scales[i], source_bounds_); - gfx::Size new_bounds; - SyncTilings(new_bounds); + gfx::Size empty_bounds; + SyncTilings(empty_bounds); EXPECT_EQ(target_->num_tilings(), 0u); - EXPECT_EQ(target_->layer_bounds().ToString(), new_bounds.ToString()); } TEST_F(PictureLayerTilingSetSyncTest, AllNew) { float source_scales[] = {0.5f, 1.f, 1.2f}; for (size_t i = 0; i < arraysize(source_scales); ++i) - source_->AddTiling(source_scales[i]); + source_->AddTiling(source_scales[i], source_bounds_); float target_scales[] = {0.75f, 1.4f, 3.f}; for (size_t i = 0; i < arraysize(target_scales); ++i) - target_->AddTiling(target_scales[i]); + target_->AddTiling(target_scales[i], target_bounds_); gfx::Size new_bounds(15, 40); SyncTilings(new_bounds); @@ -288,10 +432,10 @@ Tile* FindTileAtOrigin(PictureLayerTiling* tiling) { TEST_F(PictureLayerTilingSetSyncTest, KeepExisting) { float source_scales[] = {0.7f, 1.f, 1.1f, 2.f}; for (size_t i = 0; i < arraysize(source_scales); ++i) - source_->AddTiling(source_scales[i]); + source_->AddTiling(source_scales[i], source_bounds_); float target_scales[] = {0.5f, 1.f, 2.f}; for (size_t i = 0; i < arraysize(target_scales); ++i) - target_->AddTiling(target_scales[i]); + target_->AddTiling(target_scales[i], target_bounds_); PictureLayerTiling* tiling1 = source_->TilingAtScale(1.f); ASSERT_TRUE(tiling1); @@ -323,7 +467,7 @@ TEST_F(PictureLayerTilingSetSyncTest, KeepExisting) { TEST_F(PictureLayerTilingSetSyncTest, EmptySet) { float target_scales[] = {0.2f, 1.f}; for (size_t i = 0; i < arraysize(target_scales); ++i) - target_->AddTiling(target_scales[i]); + target_->AddTiling(target_scales[i], target_bounds_); gfx::Size new_bounds(15, 40); SyncTilings(new_bounds); @@ -333,10 +477,10 @@ TEST_F(PictureLayerTilingSetSyncTest, EmptySet) { TEST_F(PictureLayerTilingSetSyncTest, MinimumScale) { float source_scales[] = {0.7f, 1.f, 1.1f, 2.f}; for (size_t i = 0; i < arraysize(source_scales); ++i) - source_->AddTiling(source_scales[i]); + source_->AddTiling(source_scales[i], source_bounds_); float target_scales[] = {0.5f, 0.7f, 1.f, 1.1f, 2.f}; for (size_t i = 0; i < arraysize(target_scales); ++i) - target_->AddTiling(target_scales[i]); + target_->AddTiling(target_scales[i], target_bounds_); gfx::Size new_bounds(15, 40); float minimum_scale = 1.5f; @@ -348,8 +492,8 @@ TEST_F(PictureLayerTilingSetSyncTest, MinimumScale) { } TEST_F(PictureLayerTilingSetSyncTest, Invalidation) { - source_->AddTiling(2.f); - target_->AddTiling(2.f); + source_->AddTiling(2.f, source_bounds_); + target_->AddTiling(2.f, target_bounds_); target_->tiling_at(0)->CreateAllTilesForTesting(); Region layer_invalidation; @@ -366,7 +510,7 @@ TEST_F(PictureLayerTilingSetSyncTest, Invalidation) { } std::vector<Tile*> old_tiles = target_->tiling_at(0)->AllTilesForTesting(); - std::map<gfx::Point, scoped_refptr<Tile> > old_tile_map; + std::map<gfx::Point, scoped_refptr<Tile>> old_tile_map; for (size_t i = 0; i < old_tiles.size(); ++i) old_tile_map[old_tiles[i]->content_rect().origin()] = old_tiles[i]; @@ -376,7 +520,7 @@ TEST_F(PictureLayerTilingSetSyncTest, Invalidation) { std::vector<Tile*> new_tiles = target_->tiling_at(0)->AllTilesForTesting(); for (size_t i = 0; i < new_tiles.size(); ++i) { const Tile* tile = new_tiles[i]; - std::map<gfx::Point, scoped_refptr<Tile> >::iterator find = + std::map<gfx::Point, scoped_refptr<Tile>>::iterator find = old_tile_map.find(tile->content_rect().origin()); if (content_invalidation.Intersects(tile->content_rect())) EXPECT_NE(tile, find->second.get()); @@ -386,8 +530,8 @@ TEST_F(PictureLayerTilingSetSyncTest, Invalidation) { } TEST_F(PictureLayerTilingSetSyncTest, TileSizeChange) { - source_->AddTiling(1.f); - target_->AddTiling(1.f); + source_->AddTiling(1.f, source_bounds_); + target_->AddTiling(1.f, target_bounds_); target_->tiling_at(0)->CreateAllTilesForTesting(); std::vector<Tile*> original_tiles = diff --git a/chromium/cc/resources/picture_layer_tiling_unittest.cc b/chromium/cc/resources/picture_layer_tiling_unittest.cc index bfdd6fce8a5..f793097b7f4 100644 --- a/chromium/cc/resources/picture_layer_tiling_unittest.cc +++ b/chromium/cc/resources/picture_layer_tiling_unittest.cc @@ -15,8 +15,9 @@ #include "cc/test/test_context_provider.h" #include "cc/test/test_shared_bitmap_manager.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/rect_conversions.h" -#include "ui/gfx/size_conversions.h" +#include "ui/gfx/geometry/quad_f.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/size_conversions.h" namespace cc { namespace { @@ -40,10 +41,11 @@ static void UpdateAllTilePriorities(PictureLayerTilingSet* set, float layer_contents_scale, double current_frame_time_in_seconds) { for (size_t i = 0; i < set->num_tilings(); ++i) { - set->tiling_at(i)->UpdateTilePriorities(tree, - visible_layer_rect, - layer_contents_scale, - current_frame_time_in_seconds); + set->tiling_at(i)->ComputeTilePriorityRects(tree, + visible_layer_rect, + layer_contents_scale, + current_frame_time_in_seconds, + Occlusion()); } } @@ -62,7 +64,13 @@ class TestablePictureLayerTiling : public PictureLayerTiling { client)); } + gfx::Rect live_tiles_rect() const { return live_tiles_rect_; } + bool eviction_tiles_cache_valid() const { + return eviction_tiles_cache_valid_; + } + using PictureLayerTiling::ComputeSkewport; + using PictureLayerTiling::RemoveTileAt; protected: TestablePictureLayerTiling(float contents_scale, @@ -80,6 +88,7 @@ class PictureLayerTilingIteratorTest : public testing::Test { float contents_scale, const gfx::Size& layer_bounds) { client_.SetTileSize(tile_size); + client_.set_tree(PENDING_TREE); tiling_ = TestablePictureLayerTiling::Create(contents_scale, layer_bounds, &client_); @@ -169,7 +178,7 @@ class PictureLayerTilingIteratorTest : public testing::Test { const gfx::Rect& dest_rect) { float dest_to_contents_scale = tiling_->contents_scale() / rect_scale; gfx::Rect clamped_rect = gfx::ScaleToEnclosingRect( - tiling_->TilingRect(), 1.f / dest_to_contents_scale); + gfx::Rect(tiling_->tiling_size()), 1.f / dest_to_contents_scale); clamped_rect.Intersect(dest_rect); VerifyTilesExactlyCoverRect(rect_scale, dest_rect, clamped_rect); } @@ -187,7 +196,8 @@ class PictureLayerTilingIteratorTest : public testing::Test { }; TEST_F(PictureLayerTilingIteratorTest, ResizeDeletesTiles) { - // Verifies that a resize deletes tiles that used to be on the edge. + // Verifies that a resize with invalidation for newly exposed pixels will + // deletes tiles that intersect that invalidation. gfx::Size tile_size(100, 100); gfx::Size original_layer_size(10, 10); Initialize(tile_size, 1.f, original_layer_size); @@ -199,8 +209,225 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeDeletesTiles) { // Stop creating tiles so that any invalidations are left as holes. client_.set_allow_create_tile(false); - tiling_->SetLayerBounds(gfx::Size(200, 200)); + Region invalidation = + SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size)); + tiling_->UpdateTilesToCurrentPile(invalidation, gfx::Size(200, 200)); + EXPECT_FALSE(tiling_->TileAt(0, 0)); +} + +TEST_F(PictureLayerTilingIteratorTest, CreateMissingTilesStaysInsideLiveRect) { + // The tiling has three rows and columns. + Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 250)); + EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x()); + EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y()); + + // The live tiles rect is at the very edge of the right-most and + // bottom-most tiles. Their border pixels would still be inside the live + // tiles rect, but the tiles should not exist just for that. + int right = tiling_->TilingDataForTesting().TileBounds(2, 2).x(); + int bottom = tiling_->TilingDataForTesting().TileBounds(2, 2).y(); + + SetLiveRectAndVerifyTiles(gfx::Rect(right, bottom)); + EXPECT_FALSE(tiling_->TileAt(2, 0)); + EXPECT_FALSE(tiling_->TileAt(2, 1)); + EXPECT_FALSE(tiling_->TileAt(2, 2)); + EXPECT_FALSE(tiling_->TileAt(1, 2)); + EXPECT_FALSE(tiling_->TileAt(0, 2)); + + // Verify CreateMissingTilesInLiveTilesRect respects this. + tiling_->CreateMissingTilesInLiveTilesRect(); + EXPECT_FALSE(tiling_->TileAt(2, 0)); + EXPECT_FALSE(tiling_->TileAt(2, 1)); + EXPECT_FALSE(tiling_->TileAt(2, 2)); + EXPECT_FALSE(tiling_->TileAt(1, 2)); + EXPECT_FALSE(tiling_->TileAt(0, 2)); +} + +TEST_F(PictureLayerTilingIteratorTest, ResizeTilingOverTileBorders) { + // The tiling has four rows and three columns. + Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350)); + EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x()); + EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y()); + + // The live tiles rect covers the whole tiling. + SetLiveRectAndVerifyTiles(gfx::Rect(250, 350)); + + // Tiles in the bottom row and right column exist. + EXPECT_TRUE(tiling_->TileAt(2, 0)); + EXPECT_TRUE(tiling_->TileAt(2, 1)); + EXPECT_TRUE(tiling_->TileAt(2, 2)); + EXPECT_TRUE(tiling_->TileAt(2, 3)); + EXPECT_TRUE(tiling_->TileAt(1, 3)); + EXPECT_TRUE(tiling_->TileAt(0, 3)); + + int right = tiling_->TilingDataForTesting().TileBounds(2, 2).x(); + int bottom = tiling_->TilingDataForTesting().TileBounds(2, 3).y(); + + // Shrink the tiling so that the last tile row/column is entirely in the + // border pixels of the interior tiles. That row/column is removed. + Region invalidation; + tiling_->UpdateTilesToCurrentPile(invalidation, + gfx::Size(right + 1, bottom + 1)); + EXPECT_EQ(2, tiling_->TilingDataForTesting().num_tiles_x()); + EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y()); + + // The live tiles rect was clamped to the pile size. + EXPECT_EQ(gfx::Rect(right + 1, bottom + 1), tiling_->live_tiles_rect()); + + // Since the row/column is gone, the tiles should be gone too. + EXPECT_FALSE(tiling_->TileAt(2, 0)); + EXPECT_FALSE(tiling_->TileAt(2, 1)); + EXPECT_FALSE(tiling_->TileAt(2, 2)); + EXPECT_FALSE(tiling_->TileAt(2, 3)); + EXPECT_FALSE(tiling_->TileAt(1, 3)); + EXPECT_FALSE(tiling_->TileAt(0, 3)); + + // Growing outside the current right/bottom tiles border pixels should create + // the tiles again, even though the live rect has not changed size. + tiling_->UpdateTilesToCurrentPile(invalidation, + gfx::Size(right + 2, bottom + 2)); + EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x()); + EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y()); + + // Not changed. + EXPECT_EQ(gfx::Rect(right + 1, bottom + 1), tiling_->live_tiles_rect()); + + // The last row/column tiles are inside the live tiles rect. + EXPECT_TRUE(gfx::Rect(right + 1, bottom + 1).Intersects( + tiling_->TilingDataForTesting().TileBounds(2, 0))); + EXPECT_TRUE(gfx::Rect(right + 1, bottom + 1).Intersects( + tiling_->TilingDataForTesting().TileBounds(0, 3))); + + EXPECT_TRUE(tiling_->TileAt(2, 0)); + EXPECT_TRUE(tiling_->TileAt(2, 1)); + EXPECT_TRUE(tiling_->TileAt(2, 2)); + EXPECT_TRUE(tiling_->TileAt(2, 3)); + EXPECT_TRUE(tiling_->TileAt(1, 3)); + EXPECT_TRUE(tiling_->TileAt(0, 3)); +} + +TEST_F(PictureLayerTilingIteratorTest, ResizeLiveTileRectOverTileBorders) { + // The tiling has three rows and columns. + Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350)); + EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x()); + EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y()); + + // The live tiles rect covers the whole tiling. + SetLiveRectAndVerifyTiles(gfx::Rect(250, 350)); + + // Tiles in the bottom row and right column exist. + EXPECT_TRUE(tiling_->TileAt(2, 0)); + EXPECT_TRUE(tiling_->TileAt(2, 1)); + EXPECT_TRUE(tiling_->TileAt(2, 2)); + EXPECT_TRUE(tiling_->TileAt(2, 3)); + EXPECT_TRUE(tiling_->TileAt(1, 3)); + EXPECT_TRUE(tiling_->TileAt(0, 3)); + + // Shrink the live tiles rect to the very edge of the right-most and + // bottom-most tiles. Their border pixels would still be inside the live + // tiles rect, but the tiles should not exist just for that. + int right = tiling_->TilingDataForTesting().TileBounds(2, 3).x(); + int bottom = tiling_->TilingDataForTesting().TileBounds(2, 3).y(); + + SetLiveRectAndVerifyTiles(gfx::Rect(right, bottom)); + EXPECT_FALSE(tiling_->TileAt(2, 0)); + EXPECT_FALSE(tiling_->TileAt(2, 1)); + EXPECT_FALSE(tiling_->TileAt(2, 2)); + EXPECT_FALSE(tiling_->TileAt(2, 3)); + EXPECT_FALSE(tiling_->TileAt(1, 3)); + EXPECT_FALSE(tiling_->TileAt(0, 3)); + + // Including the bottom row and right column again, should create the tiles. + SetLiveRectAndVerifyTiles(gfx::Rect(right + 1, bottom + 1)); + EXPECT_TRUE(tiling_->TileAt(2, 0)); + EXPECT_TRUE(tiling_->TileAt(2, 1)); + EXPECT_TRUE(tiling_->TileAt(2, 2)); + EXPECT_TRUE(tiling_->TileAt(2, 3)); + EXPECT_TRUE(tiling_->TileAt(1, 2)); + EXPECT_TRUE(tiling_->TileAt(0, 2)); + + // Shrink the live tiles rect to the very edge of the left-most and + // top-most tiles. Their border pixels would still be inside the live + // tiles rect, but the tiles should not exist just for that. + int left = tiling_->TilingDataForTesting().TileBounds(0, 0).right(); + int top = tiling_->TilingDataForTesting().TileBounds(0, 0).bottom(); + + SetLiveRectAndVerifyTiles(gfx::Rect(left, top, 250 - left, 350 - top)); + EXPECT_FALSE(tiling_->TileAt(0, 3)); + EXPECT_FALSE(tiling_->TileAt(0, 2)); + EXPECT_FALSE(tiling_->TileAt(0, 1)); + EXPECT_FALSE(tiling_->TileAt(0, 0)); + EXPECT_FALSE(tiling_->TileAt(1, 0)); + EXPECT_FALSE(tiling_->TileAt(2, 0)); + + // Including the top row and left column again, should create the tiles. + SetLiveRectAndVerifyTiles( + gfx::Rect(left - 1, top - 1, 250 - left, 350 - top)); + EXPECT_TRUE(tiling_->TileAt(0, 3)); + EXPECT_TRUE(tiling_->TileAt(0, 2)); + EXPECT_TRUE(tiling_->TileAt(0, 1)); + EXPECT_TRUE(tiling_->TileAt(0, 0)); + EXPECT_TRUE(tiling_->TileAt(1, 0)); + EXPECT_TRUE(tiling_->TileAt(2, 0)); +} + +TEST_F(PictureLayerTilingIteratorTest, ResizeLiveTileRectOverSameTiles) { + // The tiling has four rows and three columns. + Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350)); + EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x()); + EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y()); + + // The live tiles rect covers the whole tiling. + SetLiveRectAndVerifyTiles(gfx::Rect(250, 350)); + + // All tiles exist. + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 4; ++j) + EXPECT_TRUE(tiling_->TileAt(i, j)) << i << "," << j; + } + + // Shrink the live tiles rect, but still cover all the tiles. + SetLiveRectAndVerifyTiles(gfx::Rect(1, 1, 249, 349)); + + // All tiles still exist. + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 4; ++j) + EXPECT_TRUE(tiling_->TileAt(i, j)) << i << "," << j; + } + + // Grow the live tiles rect, but still cover all the same tiles. + SetLiveRectAndVerifyTiles(gfx::Rect(0, 0, 250, 350)); + + // All tiles still exist. + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 4; ++j) + EXPECT_TRUE(tiling_->TileAt(i, j)) << i << "," << j; + } +} + +TEST_F(PictureLayerTilingIteratorTest, ResizeOverBorderPixelsDeletesTiles) { + // Verifies that a resize with invalidation for newly exposed pixels will + // deletes tiles that intersect that invalidation. + gfx::Size tile_size(100, 100); + gfx::Size original_layer_size(99, 99); + Initialize(tile_size, 1.f, original_layer_size); + SetLiveRectAndVerifyTiles(gfx::Rect(original_layer_size)); + + // Tiling only has one tile, since its total size is less than one. + EXPECT_TRUE(tiling_->TileAt(0, 0)); + + // Stop creating tiles so that any invalidations are left as holes. + client_.set_allow_create_tile(false); + + Region invalidation = + SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size)); + tiling_->UpdateTilesToCurrentPile(invalidation, gfx::Size(200, 200)); EXPECT_FALSE(tiling_->TileAt(0, 0)); + + // The original tile was the same size after resize, but it would include new + // border pixels. + EXPECT_EQ(gfx::Rect(original_layer_size), + tiling_->TilingDataForTesting().TileBounds(0, 0)); } TEST_F(PictureLayerTilingIteratorTest, LiveTilesExactlyCoverLiveTileRect) { @@ -307,6 +534,7 @@ TEST_F(PictureLayerTilingIteratorTest, NonContainedDestRect) { TEST(PictureLayerTilingTest, SkewportLimits) { FakePictureLayerTilingClient client; client.set_skewport_extrapolation_limit_in_content_pixels(75); + client.set_tree(ACTIVE_TREE); scoped_ptr<TestablePictureLayerTiling> tiling; gfx::Rect viewport(0, 0, 100, 100); @@ -315,7 +543,8 @@ TEST(PictureLayerTilingTest, SkewportLimits) { client.SetTileSize(gfx::Size(100, 100)); tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client); - tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.f, 1.0); + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.f, 1.0, Occlusion()); // Move viewport down 50 pixels in 0.5 seconds. gfx::Rect down_skewport = @@ -378,9 +607,11 @@ TEST(PictureLayerTilingTest, ComputeSkewport) { gfx::Size layer_bounds(200, 200); client.SetTileSize(gfx::Size(100, 100)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client); - tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.f, 1.0); + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.f, 1.0, Occlusion()); // Move viewport down 50 pixels in 0.5 seconds. gfx::Rect down_skewport = @@ -436,6 +667,7 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) { gfx::Size layer_bounds(1500, 1500); client.SetTileSize(gfx::Size(10, 10)); + client.set_tree(ACTIVE_TREE); // Tiling at 0.25 scale: this should create 47x47 tiles of size 10x10. // The reason is that each tile has a one pixel border, so tile at (1, 2) @@ -446,7 +678,9 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) { gfx::Rect viewport_in_content_space = gfx::ToEnclosedRect(gfx::ScaleRect(viewport, 0.25f)); - tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.f, 1.0); + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.f, 1.0, Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); gfx::Rect soon_rect = viewport; soon_rect.Inset(-312.f, -312.f, -312.f, -312.f); @@ -475,11 +709,12 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) { Tile* tile = tiling->TileAt(i, j); TilePriority priority = tile->priority(ACTIVE_TREE); - if (viewport_in_content_space.Intersects(tile->content_rect())) { + gfx::Rect tile_rect = tiling->TilingDataForTesting().TileBounds(i, j); + if (viewport_in_content_space.Intersects(tile_rect)) { EXPECT_EQ(TilePriority::NOW, priority.priority_bin); EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible); have_now = true; - } else if (soon_rect_in_content_space.Intersects(tile->content_rect())) { + } else if (soon_rect_in_content_space.Intersects(tile_rect)) { EXPECT_EQ(TilePriority::SOON, priority.priority_bin); have_soon = true; } else { @@ -529,7 +764,9 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) { EXPECT_EQ(25, skewport.width()); EXPECT_EQ(35, skewport.height()); - tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.f, 2.0); + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.f, 2.0, Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); have_now = false; have_eventually = false; @@ -542,14 +779,15 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) { Tile* tile = tiling->TileAt(i, j); TilePriority priority = tile->priority(ACTIVE_TREE); - if (viewport_in_content_space.Intersects(tile->content_rect())) { + gfx::Rect tile_rect = tiling->TilingDataForTesting().TileBounds(i, j); + if (viewport_in_content_space.Intersects(tile_rect)) { EXPECT_EQ(TilePriority::NOW, priority.priority_bin) << "i: " << i << " j: " << j; EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible) << "i: " << i << " j: " << j; have_now = true; - } else if (skewport.Intersects(tile->content_rect()) || - soon_rect_in_content_space.Intersects(tile->content_rect())) { + } else if (skewport.Intersects(tile_rect) || + soon_rect_in_content_space.Intersects(tile_rect)) { EXPECT_EQ(TilePriority::SOON, priority.priority_bin) << "i: " << i << " j: " << j; EXPECT_GT(priority.distance_to_visible, 0.f) << "i: " << i @@ -576,19 +814,49 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) { EXPECT_FLOAT_EQ(28.f, priority.distance_to_visible); priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE); - EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible); + EXPECT_FLOAT_EQ(4.f, priority.distance_to_visible); // Change the underlying layer scale. - tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 2.0f, 3.0); + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 2.0f, 3.0, Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE); - EXPECT_FLOAT_EQ(34.f, priority.distance_to_visible); + EXPECT_FLOAT_EQ(136.f, priority.distance_to_visible); priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE); - EXPECT_FLOAT_EQ(14.f, priority.distance_to_visible); + EXPECT_FLOAT_EQ(56.f, priority.distance_to_visible); priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE); - EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible); + EXPECT_FLOAT_EQ(8.f, priority.distance_to_visible); + + // Test additional scales. + tiling = TestablePictureLayerTiling::Create(0.2f, layer_bounds, &client); + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.0f, 4.0, Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); + + priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE); + EXPECT_FLOAT_EQ(110.f, priority.distance_to_visible); + + priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE); + EXPECT_FLOAT_EQ(70.f, priority.distance_to_visible); + + priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE); + EXPECT_FLOAT_EQ(60.f, priority.distance_to_visible); + + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 0.5f, 5.0, Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); + + priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE); + EXPECT_FLOAT_EQ(55.f, priority.distance_to_visible); + + priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE); + EXPECT_FLOAT_EQ(35.f, priority.distance_to_visible); + + priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE); + EXPECT_FLOAT_EQ(30.f, priority.distance_to_visible); } TEST(PictureLayerTilingTest, ExpandRectEqual) { @@ -609,7 +877,11 @@ TEST(PictureLayerTilingTest, ExpandRectSmaller) { EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); EXPECT_EQ(out.width() - in.width(), out.height() - in.height()); - EXPECT_NEAR(100 * 100, out.width() * out.height(), 50); + + // |in| represents the visible rect, and |out| represents the eventually rect. + // If the eventually rect doesn't contain the visible rect, we will start + // losing tiles. + EXPECT_TRUE(out.Contains(in)); EXPECT_TRUE(bounds.Contains(out)); } @@ -820,9 +1092,12 @@ TEST(PictureLayerTilingTest, TilingRasterTileIteratorStaticViewport) { soon_rect.Inset(-312.f, -312.f, -312.f, -312.f); client.SetTileSize(gfx::Size(30, 30)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client); - tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.0f, 1.0); + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); PictureLayerTiling::TilingRasterTileIterator empty_iterator; EXPECT_FALSE(empty_iterator); @@ -840,7 +1115,7 @@ TEST(PictureLayerTilingTest, TilingRasterTileIteratorStaticViewport) { // 3. Third iteration ensures that no tiles are returned, since they were all // marked as ready to draw. for (int i = 0; i < 3; ++i) { - PictureLayerTiling::TilingRasterTileIterator it(tiling.get(), ACTIVE_TREE); + PictureLayerTiling::TilingRasterTileIterator it(tiling.get()); // There are 3 bins in TilePriority. bool have_tiles[3] = {}; @@ -860,10 +1135,8 @@ TEST(PictureLayerTilingTest, TilingRasterTileIteratorStaticViewport) { // On the second iteration, mark everything as ready to draw (solid color). if (i == 1) { - ManagedTileState::TileVersion& tile_version = - last_tile->GetTileVersionForTesting( - last_tile->DetermineRasterModeForTree(ACTIVE_TREE)); - tile_version.SetSolidColorForTesting(SK_ColorRED); + ManagedTileState::DrawInfo& draw_info = last_tile->draw_info(); + draw_info.SetSolidColorForTesting(SK_ColorRED); } ++it; int eventually_bin_order_correct_count = 0; @@ -898,10 +1171,8 @@ TEST(PictureLayerTilingTest, TilingRasterTileIteratorStaticViewport) { // On the second iteration, mark everything as ready to draw (solid // color). if (i == 1) { - ManagedTileState::TileVersion& tile_version = - last_tile->GetTileVersionForTesting( - last_tile->DetermineRasterModeForTree(ACTIVE_TREE)); - tile_version.SetSolidColorForTesting(SK_ColorRED); + ManagedTileState::DrawInfo& draw_info = last_tile->draw_info(); + draw_info.SetSolidColorForTesting(SK_ColorRED); } } @@ -927,10 +1198,14 @@ TEST(PictureLayerTilingTest, TilingRasterTileIteratorMovingViewport) { gfx::Size layer_bounds(1000, 1000); client.SetTileSize(gfx::Size(30, 30)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.f, layer_bounds, &client); - tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.0f, 1.0); - tiling->UpdateTilePriorities(ACTIVE_TREE, moved_viewport, 1.0f, 2.0); + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion()); + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, moved_viewport, 1.0f, 2.0, Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); gfx::Rect soon_rect = moved_viewport; soon_rect.Inset(-312.f, -312.f, -312.f, -312.f); @@ -940,9 +1215,7 @@ TEST(PictureLayerTilingTest, TilingRasterTileIteratorMovingViewport) { Tile* last_tile = NULL; int eventually_bin_order_correct_count = 0; int eventually_bin_order_incorrect_count = 0; - for (PictureLayerTiling::TilingRasterTileIterator it(tiling.get(), - ACTIVE_TREE); - it; + for (PictureLayerTiling::TilingRasterTileIterator it(tiling.get()); it; ++it) { if (!last_tile) last_tile = *it; @@ -991,59 +1264,95 @@ TEST(PictureLayerTilingTest, TilingEvictionTileIteratorStaticViewport) { CHECK(output_surface->BindToClient(&output_surface_client)); TestSharedBitmapManager shared_bitmap_manager; scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create( - output_surface.get(), &shared_bitmap_manager, 0, false, 1, false); + 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(200, 200); + 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->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.0f, 1.0); + tiling->ComputeTilePriorityRects( + ACTIVE_TREE, 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::TilingEvictionTileIterator it( + tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::NOW); // Tiles don't have resources to evict. EXPECT_FALSE(it); // Sanity check. - EXPECT_EQ(64u, all_tiles.size()); + 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); + 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); + } - std::set<Tile*> eviction_tiles; - Tile* last_tile = *it; + it = PictureLayerTiling::TilingEvictionTileIterator( + tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::SOON); + EXPECT_TRUE(it); for (; it; ++it) { Tile* tile = *it; EXPECT_TRUE(tile); - EXPECT_LE(tile->priority(ACTIVE_TREE).priority_bin, - last_tile->priority(ACTIVE_TREE).priority_bin); - if (tile->priority(ACTIVE_TREE).priority_bin == - last_tile->priority(ACTIVE_TREE).priority_bin) { - EXPECT_LE(tile->priority(ACTIVE_TREE).distance_to_visible, - last_tile->priority(ACTIVE_TREE).distance_to_visible); - } - last_tile = 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) { @@ -1052,18 +1361,21 @@ TEST_F(PictureLayerTilingIteratorTest, TilesExist) { VerifyTilesExactlyCoverRect(1.f, gfx::Rect(layer_bounds)); VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, false)); - tiling_->UpdateTilePriorities( + client_.set_tree(ACTIVE_TREE); + tiling_->ComputeTilePriorityRects( ACTIVE_TREE, gfx::Rect(layer_bounds), // visible content rect 1.f, // current contents scale - 1.0); // current frame time + 1.0, // current frame time + Occlusion()); VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true)); // Make the viewport rect empty. All tiles are killed and become zombies. - tiling_->UpdateTilePriorities(ACTIVE_TREE, - gfx::Rect(), // visible content rect - 1.f, // current contents scale - 2.0); // current frame time + tiling_->ComputeTilePriorityRects(ACTIVE_TREE, + gfx::Rect(), // visible content rect + 1.f, // current contents scale + 2.0, // current frame time + Occlusion()); VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, false)); } @@ -1075,18 +1387,21 @@ TEST_F(PictureLayerTilingIteratorTest, TilesExistGiantViewport) { gfx::Rect giant_rect(-10000000, -10000000, 1000000000, 1000000000); - tiling_->UpdateTilePriorities( + client_.set_tree(ACTIVE_TREE); + tiling_->ComputeTilePriorityRects( ACTIVE_TREE, gfx::Rect(layer_bounds), // visible content rect 1.f, // current contents scale - 1.0); // current frame time + 1.0, // current frame time + Occlusion()); VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true)); // If the visible content rect is empty, it should still have live tiles. - tiling_->UpdateTilePriorities(ACTIVE_TREE, - giant_rect, // visible content rect - 1.f, // current contents scale - 2.0); // current frame time + tiling_->ComputeTilePriorityRects(ACTIVE_TREE, + giant_rect, // visible content rect + 1.f, // current contents scale + 2.0, // current frame time + Occlusion()); VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true)); } @@ -1101,10 +1416,12 @@ TEST_F(PictureLayerTilingIteratorTest, TilesExistOutsideViewport) { gfx::Rect viewport_rect(1100, 0, 1000, 1000); EXPECT_FALSE(viewport_rect.Intersects(gfx::Rect(layer_bounds))); - tiling_->UpdateTilePriorities(ACTIVE_TREE, - viewport_rect, // visible content rect - 1.f, // current contents scale - 1.0); // current frame time + client_.set_tree(ACTIVE_TREE); + tiling_->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_rect, // visible content rect + 1.f, // current contents scale + 1.0, // current frame time + Occlusion()); VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true)); } @@ -1128,56 +1445,28 @@ TEST_F(PictureLayerTilingIteratorTest, gfx::Rect visible_rect(8000, 8000, 50, 50); + client_.set_tree(ACTIVE_TREE); set_max_tiles_for_interest_area(1); - tiling_->UpdateTilePriorities(ACTIVE_TREE, - visible_rect, // visible content rect - 1.f, // current contents scale - 1.0); // current frame time + tiling_->ComputeTilePriorityRects(ACTIVE_TREE, + visible_rect, // visible content rect + 1.f, // current contents scale + 1.0, // current frame time + Occlusion()); VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TilesIntersectingRectExist, visible_rect, true)); } -static void CountExistingTiles(int *count, - Tile* tile, - const gfx::Rect& geometry_rect) { - if (tile != NULL) - ++(*count); -} - -TEST_F(PictureLayerTilingIteratorTest, - TilesExistLargeViewportAndLayerWithLargeVisibleArea) { - gfx::Size layer_bounds(10000, 10000); - Initialize(gfx::Size(100, 100), 1.f, layer_bounds); - VerifyTilesExactlyCoverRect(1.f, gfx::Rect(layer_bounds)); - VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, false)); - - set_max_tiles_for_interest_area(1); - tiling_->UpdateTilePriorities( - ACTIVE_TREE, - gfx::Rect(layer_bounds), // visible content rect - 1.f, // current contents scale - 1.0); // current frame time - - int num_tiles = 0; - VerifyTiles(1.f, - gfx::Rect(layer_bounds), - base::Bind(&CountExistingTiles, &num_tiles)); - // If we're making a rect the size of one tile, it can only overlap up to 4 - // tiles depending on its position. - EXPECT_LE(num_tiles, 4); - VerifyTiles(1.f, gfx::Rect(), base::Bind(&TileExists, false)); -} - TEST_F(PictureLayerTilingIteratorTest, AddTilingsToMatchScale) { gfx::Size layer_bounds(1099, 801); gfx::Size tile_size(100, 100); client_.SetTileSize(tile_size); + client_.set_tree(PENDING_TREE); - PictureLayerTilingSet active_set(&client_, layer_bounds); + PictureLayerTilingSet active_set(&client_); - active_set.AddTiling(1.f); + active_set.AddTiling(1.f, layer_bounds); VerifyTiles(active_set.tiling_at(0), 1.f, @@ -1197,7 +1486,7 @@ TEST_F(PictureLayerTilingIteratorTest, AddTilingsToMatchScale) { base::Bind(&TileExists, true)); // Add the same tilings to the pending set. - PictureLayerTilingSet pending_set(&client_, layer_bounds); + PictureLayerTilingSet pending_set(&client_); Region invalidation; pending_set.SyncTilings(active_set, layer_bounds, invalidation, 0.f); @@ -1207,7 +1496,7 @@ TEST_F(PictureLayerTilingIteratorTest, AddTilingsToMatchScale) { gfx::Rect(layer_bounds), base::Bind(&TileExists, false)); - // UpdateTilePriorities on the pending tiling at the same frame time. The + // ComputeTilePriorityRects on the pending tiling at the same frame time. The // pending tiling should get tiles. UpdateAllTilePriorities(&pending_set, PENDING_TREE, @@ -1221,7 +1510,7 @@ TEST_F(PictureLayerTilingIteratorTest, AddTilingsToMatchScale) { base::Bind(&TileExists, true)); } -TEST(UpdateTilePrioritiesTest, VisibleTiles) { +TEST(ComputeTilePriorityRectsTest, VisibleTiles) { // The TilePriority of visible tiles should have zero distance_to_visible // and time_to_visible. @@ -1239,14 +1528,17 @@ TEST(UpdateTilePrioritiesTest, VisibleTiles) { current_screen_transform, device_viewport); client.SetTileSize(gfx::Size(100, 100)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale current_layer_bounds, &client); - tiling->UpdateTilePriorities(ACTIVE_TREE, - viewport_in_layer_space, - current_layer_contents_scale, - current_frame_time_in_seconds); + tiling->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_in_layer_space, + current_layer_contents_scale, + current_frame_time_in_seconds, + Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); ASSERT_TRUE(tiling->TileAt(0, 0)); ASSERT_TRUE(tiling->TileAt(0, 1)); @@ -1270,7 +1562,7 @@ TEST(UpdateTilePrioritiesTest, VisibleTiles) { EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin); } -TEST(UpdateTilePrioritiesTest, OffscreenTiles) { +TEST(ComputeTilePriorityRectsTest, OffscreenTiles) { // The TilePriority of offscreen tiles (without movement) should have nonzero // distance_to_visible and infinite time_to_visible. @@ -1292,14 +1584,17 @@ TEST(UpdateTilePrioritiesTest, OffscreenTiles) { current_screen_transform, device_viewport); client.SetTileSize(gfx::Size(100, 100)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale current_layer_bounds, &client); - tiling->UpdateTilePriorities(ACTIVE_TREE, - viewport_in_layer_space, - current_layer_contents_scale, - current_frame_time_in_seconds); + tiling->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_in_layer_space, + current_layer_contents_scale, + current_frame_time_in_seconds, + Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); ASSERT_TRUE(tiling->TileAt(0, 0)); ASSERT_TRUE(tiling->TileAt(0, 1)); @@ -1333,7 +1628,7 @@ TEST(UpdateTilePrioritiesTest, OffscreenTiles) { EXPECT_GT(right.distance_to_visible, left.distance_to_visible); } -TEST(UpdateTilePrioritiesTest, PartiallyOffscreenLayer) { +TEST(ComputeTilePriorityRectsTest, PartiallyOffscreenLayer) { // Sanity check that a layer with some tiles visible and others offscreen has // correct TilePriorities for each tile. @@ -1355,14 +1650,17 @@ TEST(UpdateTilePrioritiesTest, PartiallyOffscreenLayer) { current_screen_transform, device_viewport); client.SetTileSize(gfx::Size(100, 100)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale current_layer_bounds, &client); - tiling->UpdateTilePriorities(ACTIVE_TREE, - viewport_in_layer_space, - current_layer_contents_scale, - current_frame_time_in_seconds); + tiling->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_in_layer_space, + current_layer_contents_scale, + current_frame_time_in_seconds, + Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); ASSERT_TRUE(tiling->TileAt(0, 0)); ASSERT_TRUE(tiling->TileAt(0, 1)); @@ -1386,9 +1684,9 @@ TEST(UpdateTilePrioritiesTest, PartiallyOffscreenLayer) { EXPECT_NE(TilePriority::NOW, priority.priority_bin); } -TEST(UpdateTilePrioritiesTest, PartiallyOffscreenRotatedLayer) { +TEST(ComputeTilePriorityRectsTest, PartiallyOffscreenRotatedLayer) { // Each tile of a layer may be affected differently by a transform; Check - // that UpdateTilePriorities correctly accounts for the transform between + // that ComputeTilePriorityRects correctly accounts for the transform between // layer space and screen space. FakePictureLayerTilingClient client; @@ -1412,14 +1710,17 @@ TEST(UpdateTilePrioritiesTest, PartiallyOffscreenRotatedLayer) { current_screen_transform, device_viewport); client.SetTileSize(gfx::Size(100, 100)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale current_layer_bounds, &client); - tiling->UpdateTilePriorities(ACTIVE_TREE, - viewport_in_layer_space, - current_layer_contents_scale, - current_frame_time_in_seconds); + tiling->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_in_layer_space, + current_layer_contents_scale, + current_frame_time_in_seconds, + Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); ASSERT_TRUE(tiling->TileAt(0, 0)); ASSERT_TRUE(tiling->TileAt(0, 1)); @@ -1452,7 +1753,7 @@ TEST(UpdateTilePrioritiesTest, PartiallyOffscreenRotatedLayer) { EXPECT_EQ(bottom_right.distance_to_visible, top_right.distance_to_visible); } -TEST(UpdateTilePrioritiesTest, PerspectiveLayer) { +TEST(ComputeTilePriorityRectsTest, PerspectiveLayer) { // Perspective transforms need to take a different code path. // This test checks tile priorities of a perspective layer. @@ -1493,14 +1794,17 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayer) { current_screen_transform, device_viewport); client.SetTileSize(gfx::Size(100, 100)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale current_layer_bounds, &client); - tiling->UpdateTilePriorities(ACTIVE_TREE, - viewport_in_layer_space, - current_layer_contents_scale, - current_frame_time_in_seconds); + tiling->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_in_layer_space, + current_layer_contents_scale, + current_frame_time_in_seconds, + Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); ASSERT_TRUE(tiling->TileAt(0, 0)); ASSERT_TRUE(tiling->TileAt(0, 1)); @@ -1538,7 +1842,7 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayer) { EXPECT_GT(bottom_left.distance_to_visible, top_left.distance_to_visible); } -TEST(UpdateTilePrioritiesTest, PerspectiveLayerClippedByW) { +TEST(ComputeTilePriorityRectsTest, PerspectiveLayerClippedByW) { // Perspective transforms need to take a different code path. // This test checks tile priorities of a perspective layer. @@ -1584,14 +1888,17 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayerClippedByW) { current_screen_transform, device_viewport); client.SetTileSize(gfx::Size(100, 100)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale current_layer_bounds, &client); - tiling->UpdateTilePriorities(ACTIVE_TREE, - viewport_in_layer_space, - current_layer_contents_scale, - current_frame_time_in_seconds); + tiling->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_in_layer_space, + current_layer_contents_scale, + current_frame_time_in_seconds, + Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); ASSERT_TRUE(tiling->TileAt(0, 0)); ASSERT_TRUE(tiling->TileAt(0, 1)); @@ -1619,7 +1926,7 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayerClippedByW) { EXPECT_NE(TilePriority::NOW, priority.priority_bin); } -TEST(UpdateTilePrioritiesTest, BasicMotion) { +TEST(ComputeTilePriorityRectsTest, BasicMotion) { // Test that time_to_visible is computed correctly when // there is some motion. @@ -1645,21 +1952,25 @@ TEST(UpdateTilePrioritiesTest, BasicMotion) { current_screen_transform, device_viewport); client.SetTileSize(gfx::Size(100, 100)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale current_layer_bounds, &client); // previous ("last") frame - tiling->UpdateTilePriorities(ACTIVE_TREE, - viewport_in_layer_space, - last_layer_contents_scale, - last_frame_time_in_seconds); + tiling->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_in_layer_space, + last_layer_contents_scale, + last_frame_time_in_seconds, + Occlusion()); // current frame - tiling->UpdateTilePriorities(ACTIVE_TREE, - viewport_in_layer_space, - current_layer_contents_scale, - current_frame_time_in_seconds); + tiling->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_in_layer_space, + current_layer_contents_scale, + current_frame_time_in_seconds, + Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); ASSERT_TRUE(tiling->TileAt(0, 0)); ASSERT_TRUE(tiling->TileAt(0, 1)); @@ -1685,9 +1996,9 @@ TEST(UpdateTilePrioritiesTest, BasicMotion) { EXPECT_NE(TilePriority::NOW, priority.priority_bin); } -TEST(UpdateTilePrioritiesTest, RotationMotion) { +TEST(ComputeTilePriorityRectsTest, RotationMotion) { // Each tile of a layer may be affected differently by a transform; Check - // that UpdateTilePriorities correctly accounts for the transform between + // that ComputeTilePriorityRects correctly accounts for the transform between // layer space and screen space. FakePictureLayerTilingClient client; @@ -1720,21 +2031,25 @@ TEST(UpdateTilePrioritiesTest, RotationMotion) { current_screen_transform, device_viewport); client.SetTileSize(gfx::Size(100, 100)); + client.set_tree(ACTIVE_TREE); tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale current_layer_bounds, &client); // previous ("last") frame - tiling->UpdateTilePriorities(ACTIVE_TREE, - viewport_in_layer_space, - last_layer_contents_scale, - last_frame_time_in_seconds); + tiling->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_in_layer_space, + last_layer_contents_scale, + last_frame_time_in_seconds, + Occlusion()); // current frame - tiling->UpdateTilePriorities(ACTIVE_TREE, - viewport_in_layer_space, - current_layer_contents_scale, - current_frame_time_in_seconds); + tiling->ComputeTilePriorityRects(ACTIVE_TREE, + viewport_in_layer_space, + current_layer_contents_scale, + current_frame_time_in_seconds, + Occlusion()); + tiling->UpdateAllTilePrioritiesForTesting(); ASSERT_TRUE(tiling->TileAt(0, 0)); ASSERT_TRUE(tiling->TileAt(0, 1)); @@ -1754,5 +2069,114 @@ TEST(UpdateTilePrioritiesTest, RotationMotion) { EXPECT_EQ(TilePriority::NOW, priority.priority_bin); } +TEST(PictureLayerTilingTest, RecycledTilesCleared) { + // This test performs the following: + // Setup: + // - Two tilings, one active one recycled with all tiles shared. + // Procedure: + // - Viewport moves somewhere far away and active tiling clears tiles. + // - Viewport moves back and a new active tiling tile is created. + // Result: + // - Recycle tiling does _not_ have the tile in the same location (thus it + // will be shared next time a pending tiling is created). + + FakePictureLayerTilingClient active_client; + scoped_ptr<TestablePictureLayerTiling> active_tiling; + + active_client.SetTileSize(gfx::Size(100, 100)); + active_client.set_tree(ACTIVE_TREE); + active_client.set_max_tiles_for_interest_area(10); + active_tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale + gfx::Size(10000, 10000), + &active_client); + // Create all tiles on this tiling. + active_tiling->ComputeTilePriorityRects( + ACTIVE_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion()); + + FakePictureLayerTilingClient recycle_client; + recycle_client.SetTileSize(gfx::Size(100, 100)); + recycle_client.set_tree(PENDING_TREE); + recycle_client.set_twin_tiling(active_tiling.get()); + recycle_client.set_max_tiles_for_interest_area(10); + + scoped_ptr<TestablePictureLayerTiling> recycle_tiling; + recycle_tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale + gfx::Size(10000, 10000), + &recycle_client); + + // Create all tiles on the second tiling. All tiles should be shared. + recycle_tiling->ComputeTilePriorityRects( + PENDING_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion()); + + // Set the second tiling as recycled. + active_client.set_twin_tiling(NULL); + active_client.set_recycled_twin_tiling(recycle_tiling.get()); + recycle_client.set_twin_tiling(NULL); + + // Verify that tiles exist and are shared. + EXPECT_TRUE(active_tiling->TileAt(0, 0)); + EXPECT_TRUE(recycle_tiling->TileAt(0, 0)); + EXPECT_EQ(active_tiling->TileAt(0, 0), recycle_tiling->TileAt(0, 0)); + + // Move the viewport far away from the (0, 0) tile. + active_tiling->ComputeTilePriorityRects( + ACTIVE_TREE, gfx::Rect(9000, 9000, 100, 100), 1.0f, 2.0, Occlusion()); + // Ensure the tile was deleted on both tilings. + EXPECT_FALSE(active_tiling->TileAt(0, 0)); + EXPECT_FALSE(recycle_tiling->TileAt(0, 0)); + + // Move the viewport back to (0, 0) tile. + active_tiling->ComputeTilePriorityRects( + ACTIVE_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 3.0, Occlusion()); + + // Ensure that we now have a tile here, but the recycle tiling does not. + EXPECT_TRUE(active_tiling->TileAt(0, 0)); + EXPECT_FALSE(recycle_tiling->TileAt(0, 0)); +} + +TEST(PictureLayerTilingTest, RecycledTilesClearedOnReset) { + FakePictureLayerTilingClient active_client; + scoped_ptr<TestablePictureLayerTiling> active_tiling; + + active_client.SetTileSize(gfx::Size(100, 100)); + active_client.set_tree(ACTIVE_TREE); + active_tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale + gfx::Size(100, 100), + &active_client); + // Create all tiles on this tiling. + active_tiling->ComputeTilePriorityRects( + ACTIVE_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion()); + + FakePictureLayerTilingClient recycle_client; + recycle_client.SetTileSize(gfx::Size(100, 100)); + recycle_client.set_tree(PENDING_TREE); + recycle_client.set_twin_tiling(active_tiling.get()); + recycle_client.set_max_tiles_for_interest_area(10); + + scoped_ptr<TestablePictureLayerTiling> recycle_tiling; + recycle_tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale + gfx::Size(100, 100), + &recycle_client); + + // Create all tiles on the recycle tiling. All tiles should be shared. + recycle_tiling->ComputeTilePriorityRects( + PENDING_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion()); + + // Set the second tiling as recycled. + active_client.set_twin_tiling(NULL); + active_client.set_recycled_twin_tiling(recycle_tiling.get()); + recycle_client.set_twin_tiling(NULL); + + // Verify that tiles exist and are shared. + EXPECT_TRUE(active_tiling->TileAt(0, 0)); + EXPECT_TRUE(recycle_tiling->TileAt(0, 0)); + EXPECT_EQ(active_tiling->TileAt(0, 0), recycle_tiling->TileAt(0, 0)); + + // Reset the active tiling. The recycle tiles should be released too. + active_tiling->Reset(); + EXPECT_FALSE(active_tiling->TileAt(0, 0)); + EXPECT_FALSE(recycle_tiling->TileAt(0, 0)); +} + } // namespace } // namespace cc diff --git a/chromium/cc/resources/picture_pile.cc b/chromium/cc/resources/picture_pile.cc index 6341e88b368..ec843a57d1b 100644 --- a/chromium/cc/resources/picture_pile.cc +++ b/chromium/cc/resources/picture_pile.cc @@ -10,31 +10,33 @@ #include "cc/base/region.h" #include "cc/debug/rendering_stats_instrumentation.h" -#include "cc/resources/picture_pile_impl.h" #include "cc/resources/raster_worker_pool.h" -#include "cc/resources/tile_priority.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; // TODO(humper): The density threshold here is somewhat arbitrary; need a // way to set // this from the command line so we can write a benchmark // script and find a sweet spot. const float kDensityThreshold = 0.5f; -bool rect_sort_y(const gfx::Rect &r1, const gfx::Rect &r2) { +bool rect_sort_y(const gfx::Rect& r1, const gfx::Rect& r2) { return r1.y() < r2.y() || (r1.y() == r2.y() && r1.x() < r2.x()); } -bool rect_sort_x(const gfx::Rect &r1, const gfx::Rect &r2) { +bool rect_sort_x(const gfx::Rect& r1, const gfx::Rect& r2) { return r1.x() < r2.x() || (r1.x() == r2.x() && r1.y() < r2.y()); } -float do_clustering(const std::vector<gfx::Rect>& tiles, - std::vector<gfx::Rect>* clustered_rects) { +float PerformClustering(const std::vector<gfx::Rect>& tiles, + std::vector<gfx::Rect>* clustered_rects) { // These variables track the record area and invalid area // for the entire clustering int total_record_area = 0; @@ -89,7 +91,7 @@ float do_clustering(const std::vector<gfx::Rect>& tiles, return static_cast<float>(total_invalid_area) / static_cast<float>(total_record_area); - } +} float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, std::vector<gfx::Rect>* record_rects) { @@ -113,20 +115,25 @@ float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, float vertical_density; std::vector<gfx::Rect> vertical_clustering; - vertical_density = do_clustering(invalid_tiles_vertical, - &vertical_clustering); + vertical_density = PerformClustering(invalid_tiles_vertical, + &vertical_clustering); + + // If vertical density is optimal, then we can return early. + if (vertical_density == 1.f) { + *record_rects = vertical_clustering; + return vertical_density; + } // Now try again with a horizontal sort, see which one is best - // TODO(humper): Heuristics for skipping this step? std::vector<gfx::Rect> invalid_tiles_horizontal = invalid_tiles; - std::sort(invalid_tiles_vertical.begin(), - invalid_tiles_vertical.end(), + std::sort(invalid_tiles_horizontal.begin(), + invalid_tiles_horizontal.end(), rect_sort_x); float horizontal_density; std::vector<gfx::Rect> horizontal_clustering; - horizontal_density = do_clustering(invalid_tiles_vertical, - &horizontal_clustering); + horizontal_density = PerformClustering(invalid_tiles_horizontal, + &horizontal_clustering); if (vertical_density < horizontal_density) { *record_rects = horizontal_clustering; @@ -141,7 +148,10 @@ float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, namespace cc { -PicturePile::PicturePile() : is_suitable_for_gpu_rasterization_(true) {} +PicturePile::PicturePile() + : is_suitable_for_gpu_rasterization_(true), + pixel_record_distance_(kPixelDistanceToRecord) { +} PicturePile::~PicturePile() { } @@ -152,6 +162,7 @@ bool PicturePile::UpdateAndExpandInvalidation( SkColor background_color, bool contents_opaque, bool contents_fill_bounds_completely, + const gfx::Size& layer_size, const gfx::Rect& visible_layer_rect, int frame_number, Picture::RecordingMode recording_mode, @@ -160,53 +171,280 @@ bool PicturePile::UpdateAndExpandInvalidation( contents_opaque_ = contents_opaque; contents_fill_bounds_completely_ = contents_fill_bounds_completely; + bool updated = false; + + Region resize_invalidation; + gfx::Size old_tiling_size = tiling_size(); + if (old_tiling_size != layer_size) { + tiling_.SetTilingSize(layer_size); + updated = true; + } + gfx::Rect interest_rect = visible_layer_rect; - interest_rect.Inset( - -kPixelDistanceToRecord, - -kPixelDistanceToRecord, - -kPixelDistanceToRecord, - -kPixelDistanceToRecord); + interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_); recorded_viewport_ = interest_rect; - recorded_viewport_.Intersect(tiling_rect()); + recorded_viewport_.Intersect(gfx::Rect(tiling_size())); gfx::Rect interest_rect_over_tiles = tiling_.ExpandRectToTileBounds(interest_rect); - Region invalidation_expanded_to_full_tiles; - - bool invalidated = false; - for (Region::Iterator i(*invalidation); i.has_rect(); i.next()) { - gfx::Rect invalid_rect = i.rect(); - // Split this inflated invalidation across tile boundaries and apply it - // to all tiles that it touches. - bool include_borders = true; - for (TilingData::Iterator iter(&tiling_, invalid_rect, include_borders); - iter; - ++iter) { - const PictureMapKey& key = iter.index(); - - PictureMap::iterator picture_it = picture_map_.find(key); - if (picture_it == picture_map_.end()) + gfx::Size min_tiling_size( + std::min(tiling_size().width(), old_tiling_size.width()), + std::min(tiling_size().height(), old_tiling_size.height())); + gfx::Size max_tiling_size( + std::max(tiling_size().width(), old_tiling_size.width()), + std::max(tiling_size().height(), old_tiling_size.height())); + + if (old_tiling_size != layer_size) { + has_any_recordings_ = false; + + // Drop recordings that are outside the new or old layer bounds or that + // changed size. Newly exposed areas are considered invalidated. + // Previously exposed areas that are now outside of bounds also need to + // be invalidated, as they may become part of raster when scale < 1. + std::vector<PictureMapKey> to_erase; + int min_toss_x = tiling_.num_tiles_x(); + if (max_tiling_size.width() > min_tiling_size.width()) { + min_toss_x = + tiling_.FirstBorderTileXIndexFromSrcCoord(min_tiling_size.width()); + } + int min_toss_y = tiling_.num_tiles_y(); + if (max_tiling_size.height() > min_tiling_size.height()) { + min_toss_y = + tiling_.FirstBorderTileYIndexFromSrcCoord(min_tiling_size.height()); + } + for (PictureMap::const_iterator it = picture_map_.begin(); + it != picture_map_.end(); + ++it) { + const PictureMapKey& key = it->first; + if (key.first < min_toss_x && key.second < min_toss_y) { + has_any_recordings_ |= !!it->second.GetPicture(); continue; + } + to_erase.push_back(key); + } - // Inform the grid cell that it has been invalidated in this frame. - invalidated = picture_it->second.Invalidate(frame_number) || invalidated; + for (size_t i = 0; i < to_erase.size(); ++i) + picture_map_.erase(to_erase[i]); + + // If a recording is dropped and not re-recorded below, invalidate that + // full recording to cause any raster tiles that would use it to be + // dropped. + // If the recording will be replaced below, invalidate newly exposed + // areas and previously exposed areas to force raster tiles that include the + // old recording to know there is new recording to display. + gfx::Rect min_tiling_rect_over_tiles = + tiling_.ExpandRectToTileBounds(gfx::Rect(min_tiling_size)); + if (min_toss_x < tiling_.num_tiles_x()) { + // The bounds which we want to invalidate are the tiles along the old + // edge of the pile when expanding, or the new edge of the pile when + // shrinking. In either case, it's the difference of the two, so we'll + // call this bounding box the DELTA EDGE RECT. + // + // In the picture below, the delta edge rect would be the bounding box of + // tiles {h,i,j}. |min_toss_x| would be equal to the horizontal index of + // the same tiles. + // + // min pile edge-v max pile edge-v + // ---------------+ - - - - - - - -+ + // mmppssvvyybbeeh|h . + // mmppssvvyybbeeh|h . + // nnqqttwwzzccffi|i . + // nnqqttwwzzccffi|i . + // oorruuxxaaddggj|j . + // oorruuxxaaddggj|j . + // ---------------+ - - - - - - - -+ <- min pile edge + // . + // - - - - - - - - - - - - - - - -+ <- max pile edge + // + // If you were to slide a vertical beam from the left edge of the + // delta edge rect toward the right, it would either hit the right edge + // of the delta edge rect, or the interest rect (expanded to the bounds + // of the tiles it touches). The same is true for a beam parallel to + // any of the four edges, sliding across the delta edge rect. We use + // the union of these four rectangles generated by these beams to + // determine which part of the delta edge rect is outside of the expanded + // interest rect. + // + // Case 1: Intersect rect is outside the delta edge rect. It can be + // either on the left or the right. The |left_rect| and |right_rect|, + // cover this case, one will be empty and one will cover the full + // delta edge rect. In the picture below, |left_rect| would cover the + // delta edge rect, and |right_rect| would be empty. + // +----------------------+ |^^^^^^^^^^^^^^^| + // |===> DELTA EDGE RECT | | | + // |===> | | INTEREST RECT | + // |===> | | | + // |===> | | | + // +----------------------+ |vvvvvvvvvvvvvvv| + // + // Case 2: Interest rect is inside the delta edge rect. It will always + // fill the entire delta edge rect horizontally since the old edge rect + // is a single tile wide, and the interest rect has been expanded to the + // bounds of the tiles it touches. In this case the |left_rect| and + // |right_rect| will be empty, but the case is handled by the |top_rect| + // and |bottom_rect|. In the picture below, neither the |top_rect| nor + // |bottom_rect| would empty, they would each cover the area of the old + // edge rect outside the expanded interest rect. + // +-----------------+ + // |:::::::::::::::::| + // |:::::::::::::::::| + // |vvvvvvvvvvvvvvvvv| + // | | + // +-----------------+ + // | INTEREST RECT | + // | | + // +-----------------+ + // | | + // | DELTA EDGE RECT | + // +-----------------+ + // + // Lastly, we need to consider tiles inside the expanded interest rect. + // For those tiles, we want to invalidate exactly the newly exposed + // pixels. In the picture below the tiles in the delta edge rect have + // been resized and the area covered by periods must be invalidated. The + // |exposed_rect| will cover exactly that area. + // v-min pile edge + // +---------+-------+ + // | ........| + // | ........| + // | DELTA EDGE.RECT.| + // | ........| + // | ........| + // | ........| + // | ........| + // | ........| + // | ........| + // +---------+-------+ + + int left = tiling_.TilePositionX(min_toss_x); + int right = left + tiling_.TileSizeX(min_toss_x); + int top = min_tiling_rect_over_tiles.y(); + int bottom = min_tiling_rect_over_tiles.bottom(); + + int left_until = std::min(interest_rect_over_tiles.x(), right); + int right_until = std::max(interest_rect_over_tiles.right(), left); + int top_until = std::min(interest_rect_over_tiles.y(), bottom); + int bottom_until = std::max(interest_rect_over_tiles.bottom(), top); + + int exposed_left = min_tiling_size.width(); + int exposed_left_until = max_tiling_size.width(); + int exposed_top = top; + int exposed_bottom = max_tiling_size.height(); + DCHECK_GE(exposed_left, left); + + gfx::Rect left_rect(left, top, left_until - left, bottom - top); + gfx::Rect right_rect(right_until, top, right - right_until, bottom - top); + gfx::Rect top_rect(left, top, right - left, top_until - top); + gfx::Rect bottom_rect( + left, bottom_until, right - left, bottom - bottom_until); + gfx::Rect exposed_rect(exposed_left, + exposed_top, + exposed_left_until - exposed_left, + exposed_bottom - exposed_top); + resize_invalidation.Union(left_rect); + resize_invalidation.Union(right_rect); + resize_invalidation.Union(top_rect); + resize_invalidation.Union(bottom_rect); + resize_invalidation.Union(exposed_rect); + } + if (min_toss_y < tiling_.num_tiles_y()) { + // The same thing occurs here as in the case above, but the invalidation + // rect is the bounding box around the bottom row of tiles in the min + // pile. This would be tiles {o,r,u,x,a,d,g,j} in the above picture. + + int top = tiling_.TilePositionY(min_toss_y); + int bottom = top + tiling_.TileSizeY(min_toss_y); + int left = min_tiling_rect_over_tiles.x(); + int right = min_tiling_rect_over_tiles.right(); + + int top_until = std::min(interest_rect_over_tiles.y(), bottom); + int bottom_until = std::max(interest_rect_over_tiles.bottom(), top); + int left_until = std::min(interest_rect_over_tiles.x(), right); + int right_until = std::max(interest_rect_over_tiles.right(), left); + + int exposed_top = min_tiling_size.height(); + int exposed_top_until = max_tiling_size.height(); + int exposed_left = left; + int exposed_right = max_tiling_size.width(); + DCHECK_GE(exposed_top, top); + + gfx::Rect left_rect(left, top, left_until - left, bottom - top); + gfx::Rect right_rect(right_until, top, right - right_until, bottom - top); + gfx::Rect top_rect(left, top, right - left, top_until - top); + gfx::Rect bottom_rect( + left, bottom_until, right - left, bottom - bottom_until); + gfx::Rect exposed_rect(exposed_left, + exposed_top, + exposed_right - exposed_left, + exposed_top_until - exposed_top); + resize_invalidation.Union(left_rect); + resize_invalidation.Union(right_rect); + resize_invalidation.Union(top_rect); + resize_invalidation.Union(bottom_rect); + resize_invalidation.Union(exposed_rect); } + } - // Expand invalidation that is outside tiles that intersect the interest - // rect. These tiles are no longer valid and should be considerered fully - // invalid, so we can know to not keep around raster tiles that intersect - // with these recording tiles. - gfx::Rect invalid_rect_outside_interest_rect_tiles = invalid_rect; - // TODO(danakj): We should have a Rect-subtract-Rect-to-2-rects operator - // instead of using Rect::Subtract which gives you the bounding box of the - // subtraction. - invalid_rect_outside_interest_rect_tiles.Subtract(interest_rect_over_tiles); - invalidation_expanded_to_full_tiles.Union(tiling_.ExpandRectToTileBounds( - invalid_rect_outside_interest_rect_tiles)); + // Detect cases where the full pile is invalidated, in this situation we + // can just drop/invalidate everything. + if (invalidation->Contains(gfx::Rect(old_tiling_size)) || + invalidation->Contains(gfx::Rect(tiling_size()))) { + for (auto& it : picture_map_) + updated = it.second.Invalidate(frame_number) || updated; + } else { + // Expand invalidation that is on tiles that aren't in the interest rect and + // will not be re-recorded below. These tiles are no longer valid and should + // be considerered fully invalid, so we can know to not keep around raster + // tiles that intersect with these recording tiles. + Region invalidation_expanded_to_full_tiles; + + for (Region::Iterator i(*invalidation); i.has_rect(); i.next()) { + gfx::Rect invalid_rect = i.rect(); + + // This rect covers the bounds (excluding borders) of all tiles whose + // bounds (including borders) touch the |interest_rect|. This matches + // the iteration of the |invalid_rect| below which includes borders when + // calling Invalidate() on pictures. + gfx::Rect invalid_rect_outside_interest_rect_tiles = + tiling_.ExpandRectToTileBounds(invalid_rect); + // We subtract the |interest_rect_over_tiles| which represents the bounds + // of tiles that will be re-recorded below. This matches the iteration of + // |interest_rect| below which includes borders. + // TODO(danakj): We should have a Rect-subtract-Rect-to-2-rects operator + // instead of using Rect::Subtract which gives you the bounding box of the + // subtraction. + invalid_rect_outside_interest_rect_tiles.Subtract( + interest_rect_over_tiles); + invalidation_expanded_to_full_tiles.Union( + invalid_rect_outside_interest_rect_tiles); + + // Split this inflated invalidation across tile boundaries and apply it + // to all tiles that it touches. + bool include_borders = true; + for (TilingData::Iterator iter(&tiling_, invalid_rect, include_borders); + iter; + ++iter) { + const PictureMapKey& key = iter.index(); + + PictureMap::iterator picture_it = picture_map_.find(key); + if (picture_it == picture_map_.end()) + continue; + + // Inform the grid cell that it has been invalidated in this frame. + updated = picture_it->second.Invalidate(frame_number) || updated; + // Invalidate drops the picture so the whole tile better be invalidated + // if it won't be re-recorded below. + DCHECK_IMPLIES(!tiling_.TileBounds(key.first, key.second) + .Intersects(interest_rect_over_tiles), + invalidation_expanded_to_full_tiles.Contains( + tiling_.TileBounds(key.first, key.second))); + } + } + invalidation->Union(invalidation_expanded_to_full_tiles); } - invalidation->Union(invalidation_expanded_to_full_tiles); + invalidation->Union(resize_invalidation); // Make a list of all invalid tiles; we will attempt to // cluster these into multiple invalidation regions. @@ -244,7 +482,7 @@ bool PicturePile::UpdateAndExpandInvalidation( ClusterTiles(invalid_tiles, &record_rects); if (record_rects.empty()) - return invalidated; + return updated; for (std::vector<gfx::Rect>::iterator it = record_rects.begin(); it != record_rects.end(); @@ -254,13 +492,12 @@ bool PicturePile::UpdateAndExpandInvalidation( int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); scoped_refptr<Picture> picture; - int num_raster_threads = RasterWorkerPool::GetNumRasterThreads(); // Note: Currently, gathering of pixel refs when using a single // raster thread doesn't provide any benefit. This might change // in the future but we avoid it for now to reduce the cost of // Picture::Create. - bool gather_pixel_refs = num_raster_threads > 1; + bool gather_pixel_refs = RasterWorkerPool::GetNumRasterThreads() > 1; { base::TimeDelta best_duration = base::TimeDelta::Max(); @@ -270,7 +507,6 @@ bool PicturePile::UpdateAndExpandInvalidation( painter, tile_grid_info_, gather_pixel_refs, - num_raster_threads, recording_mode); // Note the '&&' with previous is-suitable state. // This means that once a picture-pile becomes unsuitable for gpu @@ -302,6 +538,7 @@ bool PicturePile::UpdateAndExpandInvalidation( found_tile_for_recorded_picture = true; } } + DetermineIfSolidColor(); DCHECK(found_tile_for_recorded_picture); } @@ -310,4 +547,54 @@ bool PicturePile::UpdateAndExpandInvalidation( return true; } +void PicturePile::SetEmptyBounds() { + tiling_.SetTilingSize(gfx::Size()); + Clear(); +} + +bool PicturePile::CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const { + bool include_borders = false; + for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); + tile_iter; ++tile_iter) { + PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); + if (map_iter == picture_map_.end()) + return false; + if (!map_iter->second.GetPicture()) + return false; + } + return true; +} + +void PicturePile::DetermineIfSolidColor() { + is_solid_color_ = false; + solid_color_ = SK_ColorTRANSPARENT; + + if (picture_map_.empty()) { + return; + } + + PictureMap::const_iterator it = picture_map_.begin(); + const Picture* picture = it->second.GetPicture(); + + // Missing recordings due to frequent invalidations or being too far away + // from the interest rect will cause the a null picture to exist. + if (!picture) + return; + + // Don't bother doing more work if the first image is too complicated. + if (picture->ApproximateOpCount() > kOpCountThatIsOkToAnalyze) + return; + + // Make sure all of the mapped images point to the same picture. + for (++it; it != picture_map_.end(); ++it) { + if (it->second.GetPicture() != picture) + return; + } + skia::AnalysisCanvas canvas(recorded_viewport_.width(), + recorded_viewport_.height()); + canvas.translate(-recorded_viewport_.x(), -recorded_viewport_.y()); + picture->Raster(&canvas, nullptr, Region(), 1.0f); + is_solid_color_ = canvas.GetColorIfSolid(&solid_color_); +} + } // namespace cc diff --git a/chromium/cc/resources/picture_pile.h b/chromium/cc/resources/picture_pile.h index 86ef32f2182..18e1e5273aa 100644 --- a/chromium/cc/resources/picture_pile.h +++ b/chromium/cc/resources/picture_pile.h @@ -5,8 +5,9 @@ #ifndef CC_RESOURCES_PICTURE_PILE_H_ #define CC_RESOURCES_PICTURE_PILE_H_ +#include "base/memory/ref_counted.h" #include "cc/resources/picture_pile_base.h" -#include "ui/gfx/rect.h" +#include "ui/gfx/geometry/rect.h" namespace cc { class PicturePileImpl; @@ -16,6 +17,7 @@ class RenderingStatsInstrumentation; class CC_EXPORT PicturePile : public PicturePileBase { public: PicturePile(); + ~PicturePile() override; // Re-record parts of the picture that are invalid. // Invalidations are in layer space, and will be expanded to cover everything @@ -28,11 +30,14 @@ class CC_EXPORT PicturePile : public PicturePileBase { SkColor background_color, bool contents_opaque, bool contents_fill_bounds_completely, + const gfx::Size& layer_size, const gfx::Rect& visible_layer_rect, int frame_number, Picture::RecordingMode recording_mode, RenderingStatsInstrumentation* stats_instrumentation); + void SetEmptyBounds(); + void set_slow_down_raster_scale_factor(int factor) { slow_down_raster_scale_factor_for_debug_ = factor; } @@ -48,13 +53,20 @@ class CC_EXPORT PicturePile : public PicturePileBase { is_suitable_for_gpu_rasterization_ = false; } + void SetPixelRecordDistanceForTesting(int d) { pixel_record_distance_ = d; } + protected: - virtual ~PicturePile(); + // An internal CanRaster check that goes to the picture_map rather than + // using the recorded_viewport hint. + bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const; private: friend class PicturePileImpl; + void DetermineIfSolidColor(); + bool is_suitable_for_gpu_rasterization_; + int pixel_record_distance_; DISALLOW_COPY_AND_ASSIGN(PicturePile); }; diff --git a/chromium/cc/resources/picture_pile_base.cc b/chromium/cc/resources/picture_pile_base.cc index 8f8bf534874..1184cf1e2a6 100644 --- a/chromium/cc/resources/picture_pile_base.cc +++ b/chromium/cc/resources/picture_pile_base.cc @@ -8,12 +8,12 @@ #include <set> #include <vector> +#include "base/debug/trace_event_argument.h" #include "base/logging.h" #include "base/values.h" -#include "cc/base/math_util.h" #include "cc/debug/traced_value.h" #include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/rect_conversions.h" +#include "ui/gfx/geometry/rect_conversions.h" namespace { // Dimensions of the tiles in this picture pile as well as the dimensions of @@ -46,7 +46,10 @@ PicturePileBase::PicturePileBase() contents_fill_bounds_completely_(false), show_debug_picture_borders_(false), clear_canvas_with_debug_color_(kDefaultClearCanvasSetting), - has_any_recordings_(false) { + has_any_recordings_(false), + is_mask_(false), + is_solid_color_(false), + solid_color_(SK_ColorTRANSPARENT) { tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize)); tile_grid_info_.fTileInterval.setEmpty(); tile_grid_info_.fMargin.setEmpty(); @@ -66,70 +69,15 @@ PicturePileBase::PicturePileBase(const PicturePileBase* other) contents_fill_bounds_completely_(other->contents_fill_bounds_completely_), show_debug_picture_borders_(other->show_debug_picture_borders_), clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), - has_any_recordings_(other->has_any_recordings_) {} - -PicturePileBase::PicturePileBase(const PicturePileBase* other, - unsigned thread_index) - : tiling_(other->tiling_), - recorded_viewport_(other->recorded_viewport_), - min_contents_scale_(other->min_contents_scale_), - tile_grid_info_(other->tile_grid_info_), - background_color_(other->background_color_), - slow_down_raster_scale_factor_for_debug_( - other->slow_down_raster_scale_factor_for_debug_), - contents_opaque_(other->contents_opaque_), - contents_fill_bounds_completely_(other->contents_fill_bounds_completely_), - show_debug_picture_borders_(other->show_debug_picture_borders_), - clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), - has_any_recordings_(other->has_any_recordings_) { - for (PictureMap::const_iterator it = other->picture_map_.begin(); - it != other->picture_map_.end(); - ++it) { - picture_map_[it->first] = it->second.CloneForThread(thread_index); - } + has_any_recordings_(other->has_any_recordings_), + is_mask_(other->is_mask_), + is_solid_color_(other->is_solid_color_), + solid_color_(other->solid_color_) { } PicturePileBase::~PicturePileBase() { } -void PicturePileBase::SetTilingRect(const gfx::Rect& new_tiling_rect) { - if (tiling_rect() == new_tiling_rect) - return; - - gfx::Rect old_tiling_rect = tiling_rect(); - tiling_.SetTilingRect(new_tiling_rect); - - has_any_recordings_ = false; - - // Don't waste time in Resize figuring out what these hints should be. - recorded_viewport_ = gfx::Rect(); - - if (new_tiling_rect.origin() != old_tiling_rect.origin()) { - picture_map_.clear(); - return; - } - - // Find all tiles that contain any pixels outside the new rect. - std::vector<PictureMapKey> to_erase; - int min_toss_x = tiling_.FirstBorderTileXIndexFromSrcCoord( - std::min(old_tiling_rect.right(), new_tiling_rect.right())); - int min_toss_y = tiling_.FirstBorderTileYIndexFromSrcCoord( - std::min(old_tiling_rect.bottom(), new_tiling_rect.bottom())); - for (PictureMap::const_iterator it = picture_map_.begin(); - it != picture_map_.end(); - ++it) { - const PictureMapKey& key = it->first; - if (key.first < min_toss_x && key.second < min_toss_y) { - has_any_recordings_ |= !!it->second.GetPicture(); - continue; - } - to_erase.push_back(key); - } - - for (size_t i = 0; i < to_erase.size(); ++i) - picture_map_.erase(to_erase[i]); -} - void PicturePileBase::SetMinContentsScale(float min_contents_scale) { DCHECK(min_contents_scale); if (min_contents_scale_ == min_contents_scale) @@ -182,6 +130,8 @@ void PicturePileBase::SetBufferPixels(int new_buffer_pixels) { void PicturePileBase::Clear() { picture_map_.clear(); recorded_viewport_ = gfx::Rect(); + has_any_recordings_ = false; + is_solid_color_ = false; } bool PicturePileBase::HasRecordingAt(int x, int y) { @@ -191,72 +141,18 @@ bool PicturePileBase::HasRecordingAt(int x, int y) { return !!found->second.GetPicture(); } -bool PicturePileBase::CanRaster(float contents_scale, - const gfx::Rect& content_rect) { - if (tiling_.tiling_rect().IsEmpty()) - return false; - gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( - content_rect, 1.f / contents_scale); - layer_rect.Intersect(tiling_.tiling_rect()); - - // Common case inside of viewport to avoid the slower map lookups. - if (recorded_viewport_.Contains(layer_rect)) { - // Sanity check that there are no false positives in recorded_viewport_. - DCHECK(CanRasterSlowTileCheck(layer_rect)); - return true; - } - - return CanRasterSlowTileCheck(layer_rect); -} - -bool PicturePileBase::CanRasterSlowTileCheck( - const gfx::Rect& layer_rect) const { - bool include_borders = false; - for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); - tile_iter; - ++tile_iter) { - PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); - if (map_iter == picture_map_.end()) - return false; - if (!map_iter->second.GetPicture()) - return false; - } - return true; -} - -gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) { +gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) const { gfx::Rect tile = tiling_.TileBounds(key.first, key.second); return PadRect(tile); } -gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) { +gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) const { gfx::Rect padded_rect = rect; padded_rect.Inset( -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels()); return padded_rect; } -scoped_ptr<base::Value> PicturePileBase::AsValue() const { - scoped_ptr<base::ListValue> pictures(new base::ListValue()); - gfx::Rect tiling_rect(tiling_.tiling_rect()); - std::set<void*> appended_pictures; - bool include_borders = true; - for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders); - tile_iter; - ++tile_iter) { - PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); - if (map_iter == picture_map_.end()) - continue; - - Picture* picture = map_iter->second.GetPicture(); - if (picture && (appended_pictures.count(picture) == 0)) { - appended_pictures.insert(picture); - pictures->Append(TracedValue::CreateIDRef(picture).release()); - } - } - return pictures.PassAs<base::Value>(); -} - PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {} PicturePileBase::PictureInfo::~PictureInfo() {} @@ -275,7 +171,7 @@ bool PicturePileBase::PictureInfo::Invalidate(int frame_number) { AdvanceInvalidationHistory(frame_number); invalidation_history_.set(0); - bool did_invalidate = !!picture_; + bool did_invalidate = !!picture_.get(); picture_ = NULL; return did_invalidate; } @@ -288,7 +184,7 @@ bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number, // need a recording if we're within frequent invalidation distance threshold // or the invalidation is not frequent enough (below invalidation frequency // threshold). - return !picture_ && + return !picture_.get() && ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) || (GetInvalidationFrequency() < kInvalidationFrequencyThreshold)); } @@ -297,18 +193,10 @@ void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) { picture_ = picture; } -Picture* PicturePileBase::PictureInfo::GetPicture() const { +const Picture* PicturePileBase::PictureInfo::GetPicture() const { return picture_.get(); } -PicturePileBase::PictureInfo PicturePileBase::PictureInfo::CloneForThread( - int thread_index) const { - PictureInfo info = *this; - if (picture_.get()) - info.picture_ = picture_->GetCloneForDrawingOnThread(thread_index); - return info; -} - float PicturePileBase::PictureInfo::GetInvalidationFrequency() const { return invalidation_history_.count() / static_cast<float>(INVALIDATION_FRAMES_TRACKED); diff --git a/chromium/cc/resources/picture_pile_base.h b/chromium/cc/resources/picture_pile_base.h index 9f8acffd294..66d37d81b88 100644 --- a/chromium/cc/resources/picture_pile_base.h +++ b/chromium/cc/resources/picture_pile_base.h @@ -10,27 +10,27 @@ #include <utility> #include "base/containers/hash_tables.h" -#include "base/memory/ref_counted.h" #include "cc/base/cc_export.h" #include "cc/base/region.h" #include "cc/base/tiling_data.h" #include "cc/resources/picture.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" namespace base { +namespace debug { +class TracedValue; +} class Value; } namespace cc { -class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { +class CC_EXPORT PicturePileBase { public: PicturePileBase(); explicit PicturePileBase(const PicturePileBase* other); - PicturePileBase(const PicturePileBase* other, unsigned thread_index); - void SetTilingRect(const gfx::Rect& tiling_rect); - gfx::Rect tiling_rect() const { return tiling_.tiling_rect(); } + gfx::Size tiling_size() const { return tiling_.tiling_size(); } void SetMinContentsScale(float min_contents_scale); // If non-empty, all pictures tiles inside this rect are recorded. There may @@ -42,10 +42,11 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { int num_tiles_y() const { return tiling_.num_tiles_y(); } gfx::Rect tile_bounds(int x, int y) const { return tiling_.TileBounds(x, y); } bool HasRecordingAt(int x, int y); - bool CanRaster(float contents_scale, const gfx::Rect& content_rect); - // If this pile contains any valid recordings. May have false positives. - bool HasRecordings() const { return has_any_recordings_; } + bool is_solid_color() const { return is_solid_color_; } + SkColor solid_color() const { return solid_color_; } + + void set_is_mask(bool is_mask) { is_mask_ = is_mask; } static void ComputeTileGridInfo(const gfx::Size& tile_grid_size, SkTileGridFactory::TileGridInfo* info); @@ -53,7 +54,16 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { void SetTileGridSize(const gfx::Size& tile_grid_size); TilingData& tiling() { return tiling_; } - scoped_ptr<base::Value> AsValue() const; + SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const { + return tile_grid_info_; + } + + void SetRecordedViewportForTesting(const gfx::Rect& viewport) { + recorded_viewport_ = viewport; + } + void SetHasAnyRecordingsForTesting(bool has_recordings) { + has_any_recordings_ = has_recordings; + } protected: class CC_EXPORT PictureInfo { @@ -67,9 +77,8 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { bool Invalidate(int frame_number); bool NeedsRecording(int frame_number, int distance_to_visible); - PictureInfo CloneForThread(int thread_index) const; void SetPicture(scoped_refptr<Picture> picture); - Picture* GetPicture() const; + const Picture* GetPicture() const; float GetInvalidationFrequencyForTesting() const { return GetInvalidationFrequency(); @@ -80,7 +89,7 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { float GetInvalidationFrequency() const; int last_frame_number_; - scoped_refptr<Picture> picture_; + scoped_refptr<const Picture> picture_; std::bitset<INVALIDATION_FRAMES_TRACKED> invalidation_history_; }; @@ -92,12 +101,8 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { int buffer_pixels() const { return tiling_.border_texels(); } void Clear(); - gfx::Rect PaddedRect(const PictureMapKey& key); - gfx::Rect PadRect(const gfx::Rect& rect); - - // An internal CanRaster check that goes to the picture_map rather than - // using the recorded_viewport hint. - bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const; + gfx::Rect PaddedRect(const PictureMapKey& key) const; + gfx::Rect PadRect(const gfx::Rect& rect) const; // A picture pile is a tiled set of pictures. The picture map is a map of tile // indices to picture infos. @@ -115,11 +120,15 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { // A hint about whether there are any recordings. This may be a false // positive. bool has_any_recordings_; + bool is_mask_; + bool is_solid_color_; + SkColor solid_color_; private: + friend class PicturePileImpl; + void SetBufferPixels(int buffer_pixels); - friend class base::RefCounted<PicturePileBase>; DISALLOW_COPY_AND_ASSIGN(PicturePileBase); }; diff --git a/chromium/cc/resources/picture_pile_impl.cc b/chromium/cc/resources/picture_pile_impl.cc index 90713b4fc7e..de25c04721b 100644 --- a/chromium/cc/resources/picture_pile_impl.cc +++ b/chromium/cc/resources/picture_pile_impl.cc @@ -9,29 +9,13 @@ #include "cc/base/region.h" #include "cc/debug/debug_colors.h" #include "cc/resources/picture_pile_impl.h" -#include "cc/resources/raster_worker_pool.h" #include "skia/ext/analysis_canvas.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPictureRecorder.h" -#include "third_party/skia/include/core/SkSize.h" -#include "ui/gfx/rect_conversions.h" -#include "ui/gfx/size_conversions.h" -#include "ui/gfx/skia_util.h" +#include "ui/gfx/geometry/rect_conversions.h" namespace cc { -PicturePileImpl::ClonesForDrawing::ClonesForDrawing( - const PicturePileImpl* pile, int num_threads) { - for (int i = 0; i < num_threads; i++) { - scoped_refptr<PicturePileImpl> clone = - PicturePileImpl::CreateCloneForDrawing(pile, i); - clones_.push_back(clone); - } -} - -PicturePileImpl::ClonesForDrawing::~ClonesForDrawing() { -} - scoped_refptr<PicturePileImpl> PicturePileImpl::Create() { return make_scoped_refptr(new PicturePileImpl); } @@ -41,63 +25,60 @@ scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther( return make_scoped_refptr(new PicturePileImpl(other)); } -scoped_refptr<PicturePileImpl> PicturePileImpl::CreateCloneForDrawing( - const PicturePileImpl* other, unsigned thread_index) { - return make_scoped_refptr(new PicturePileImpl(other, thread_index)); -} - PicturePileImpl::PicturePileImpl() - : clones_for_drawing_(ClonesForDrawing(this, 0)) { + : background_color_(SK_ColorTRANSPARENT), + contents_opaque_(false), + contents_fill_bounds_completely_(false), + is_solid_color_(false), + solid_color_(SK_ColorTRANSPARENT), + has_any_recordings_(false), + is_mask_(false), + clear_canvas_with_debug_color_(false), + min_contents_scale_(0.f), + slow_down_raster_scale_factor_for_debug_(0), + likely_to_be_used_for_transform_animation_(false) { } PicturePileImpl::PicturePileImpl(const PicturePileBase* other) - : PicturePileBase(other), - clones_for_drawing_(ClonesForDrawing( - this, RasterWorkerPool::GetNumRasterThreads())) { -} - -PicturePileImpl::PicturePileImpl( - const PicturePileImpl* other, unsigned thread_index) - : PicturePileBase(other, thread_index), - clones_for_drawing_(ClonesForDrawing(this, 0)) { + : picture_map_(other->picture_map_), + tiling_(other->tiling_), + background_color_(other->background_color_), + contents_opaque_(other->contents_opaque_), + contents_fill_bounds_completely_(other->contents_fill_bounds_completely_), + is_solid_color_(other->is_solid_color_), + solid_color_(other->solid_color_), + recorded_viewport_(other->recorded_viewport_), + has_any_recordings_(other->has_any_recordings_), + is_mask_(other->is_mask_), + clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), + min_contents_scale_(other->min_contents_scale_), + slow_down_raster_scale_factor_for_debug_( + other->slow_down_raster_scale_factor_for_debug_), + likely_to_be_used_for_transform_animation_(false) { } PicturePileImpl::~PicturePileImpl() { } -PicturePileImpl* PicturePileImpl::GetCloneForDrawingOnThread( - unsigned thread_index) const { - CHECK_GT(clones_for_drawing_.clones_.size(), thread_index); - return clones_for_drawing_.clones_[thread_index].get(); -} - -void PicturePileImpl::RasterDirect( - SkCanvas* canvas, - const gfx::Rect& canvas_rect, - float contents_scale, - RenderingStatsInstrumentation* rendering_stats_instrumentation) { +void PicturePileImpl::RasterDirect(SkCanvas* canvas, + const gfx::Rect& canvas_rect, + float contents_scale) const { RasterCommon(canvas, NULL, canvas_rect, contents_scale, - rendering_stats_instrumentation, false); } -void PicturePileImpl::RasterForAnalysis( - skia::AnalysisCanvas* canvas, - const gfx::Rect& canvas_rect, - float contents_scale, - RenderingStatsInstrumentation* stats_instrumentation) { - RasterCommon( - canvas, canvas, canvas_rect, contents_scale, stats_instrumentation, true); +void PicturePileImpl::RasterForAnalysis(skia::AnalysisCanvas* canvas, + const gfx::Rect& canvas_rect, + float contents_scale) const { + RasterCommon(canvas, canvas, canvas_rect, contents_scale, true); } -void PicturePileImpl::RasterToBitmap( - SkCanvas* canvas, - const gfx::Rect& canvas_rect, - float contents_scale, - RenderingStatsInstrumentation* rendering_stats_instrumentation) { +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. @@ -113,7 +94,7 @@ void PicturePileImpl::RasterToBitmap( // 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(tiling_.tiling_rect(), contents_scale)); + 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 @@ -159,14 +140,13 @@ void PicturePileImpl::RasterToBitmap( NULL, canvas_rect, contents_scale, - rendering_stats_instrumentation, false); } void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect, const gfx::Rect& content_rect, float contents_scale, - PictureRegionMap* results) { + PictureRegionMap* results) const { DCHECK(results); // Rasterize the collection of relevant picture piles. gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( @@ -197,11 +177,11 @@ void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect, for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); tile_iter; ++tile_iter) { - PictureMap::iterator map_iter = picture_map_.find(tile_iter.index()); + PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); if (map_iter == picture_map_.end()) continue; - PictureInfo& info = map_iter->second; - Picture* picture = info.GetPicture(); + const PictureInfo& info = map_iter->second; + const Picture* picture = info.GetPicture(); if (!picture) continue; @@ -263,13 +243,12 @@ void PicturePileImpl::RasterCommon( SkDrawPictureCallback* callback, const gfx::Rect& canvas_rect, float contents_scale, - RenderingStatsInstrumentation* rendering_stats_instrumentation, - bool is_analysis) { + bool is_analysis) const { DCHECK(contents_scale >= min_contents_scale_); canvas->translate(-canvas_rect.x(), -canvas_rect.y()); gfx::Rect content_tiling_rect = gfx::ToEnclosingRect( - gfx::ScaleRect(tiling_.tiling_rect(), contents_scale)); + gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale)); content_tiling_rect.Intersect(canvas_rect); canvas->clipRect(gfx::RectToSkRect(content_tiling_rect), @@ -288,7 +267,7 @@ void PicturePileImpl::RasterCommon( for (PictureRegionMap::iterator it = picture_region_map.begin(); it != picture_region_map.end(); ++it) { - Picture* picture = it->first; + const Picture* picture = it->first; Region negated_clip_region = it->second; #ifndef NDEBUG @@ -299,34 +278,10 @@ void PicturePileImpl::RasterCommon( total_clip.Union(positive_clip); #endif // NDEBUG - base::TimeDelta best_duration = base::TimeDelta::Max(); int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); - int rasterized_pixel_count = 0; - - for (int j = 0; j < repeat_count; ++j) { - base::TimeTicks start_time; - if (rendering_stats_instrumentation) - start_time = rendering_stats_instrumentation->StartRecording(); - - rasterized_pixel_count = picture->Raster( - canvas, callback, negated_clip_region, contents_scale); - if (rendering_stats_instrumentation) { - base::TimeDelta duration = - rendering_stats_instrumentation->EndRecording(start_time); - best_duration = std::min(best_duration, duration); - } - } - - if (rendering_stats_instrumentation) { - if (is_analysis) { - rendering_stats_instrumentation->AddAnalysis(best_duration, - rasterized_pixel_count); - } else { - rendering_stats_instrumentation->AddRaster(best_duration, - rasterized_pixel_count); - } - } + for (int j = 0; j < repeat_count; ++j) + picture->Raster(canvas, callback, negated_clip_region, contents_scale); } #ifndef NDEBUG @@ -345,52 +300,106 @@ void PicturePileImpl::RasterCommon( skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() { TRACE_EVENT0("cc", "PicturePileImpl::GetFlattenedPicture"); - gfx::Rect tiling_rect(tiling_.tiling_rect()); + gfx::Rect tiling_rect(tiling_.tiling_size()); SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(tiling_rect.width(), tiling_rect.height()); if (!tiling_rect.IsEmpty()) - RasterToBitmap(canvas, tiling_rect, 1.0, NULL); + PlaybackToCanvas(canvas, tiling_rect, 1.0); skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording()); return picture; } -void PicturePileImpl::AnalyzeInRect( +void PicturePileImpl::PerformSolidColorAnalysis( const gfx::Rect& content_rect, float contents_scale, - PicturePileImpl::Analysis* analysis) { - AnalyzeInRect(content_rect, contents_scale, analysis, NULL); -} - -void PicturePileImpl::AnalyzeInRect( - const gfx::Rect& content_rect, - float contents_scale, - PicturePileImpl::Analysis* analysis, - RenderingStatsInstrumentation* stats_instrumentation) { + RasterSource::SolidColorAnalysis* analysis) const { DCHECK(analysis); - TRACE_EVENT0("cc", "PicturePileImpl::AnalyzeInRect"); + TRACE_EVENT0("cc", "PicturePileImpl::PerformSolidColorAnalysis"); gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( content_rect, 1.0f / contents_scale); - layer_rect.Intersect(tiling_.tiling_rect()); + layer_rect.Intersect(gfx::Rect(tiling_.tiling_size())); skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height()); - RasterForAnalysis(&canvas, layer_rect, 1.0f, stats_instrumentation); + RasterForAnalysis(&canvas, layer_rect, 1.0f); analysis->is_solid_color = canvas.GetColorIfSolid(&analysis->solid_color); } -// Since there are situations when we can skip analysis, the variables have to -// be set to their safest values. That is, we have to assume that the tile is -// not solid color. As well, we have to assume that the tile has text so we -// don't early out incorrectly. -PicturePileImpl::Analysis::Analysis() : is_solid_color(false) { +void PicturePileImpl::GatherPixelRefs( + const gfx::Rect& content_rect, + float contents_scale, + std::vector<SkPixelRef*>* pixel_refs) const { + DCHECK_EQ(0u, pixel_refs->size()); + for (PixelRefIterator iter(content_rect, contents_scale, this); iter; + ++iter) { + pixel_refs->push_back(*iter); + } +} + +bool PicturePileImpl::CoversRect(const gfx::Rect& content_rect, + float contents_scale) const { + if (tiling_.tiling_size().IsEmpty()) + return false; + gfx::Rect layer_rect = + gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale); + layer_rect.Intersect(gfx::Rect(tiling_.tiling_size())); + + // Common case inside of viewport to avoid the slower map lookups. + if (recorded_viewport_.Contains(layer_rect)) { + // Sanity check that there are no false positives in recorded_viewport_. + DCHECK(CanRasterSlowTileCheck(layer_rect)); + return true; + } + + return CanRasterSlowTileCheck(layer_rect); +} + +gfx::Rect PicturePileImpl::PaddedRect(const PictureMapKey& key) const { + gfx::Rect padded_rect = tiling_.TileBounds(key.first, key.second); + padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(), + -buffer_pixels()); + return padded_rect; +} + +bool PicturePileImpl::CanRasterSlowTileCheck( + const gfx::Rect& layer_rect) const { + bool include_borders = false; + for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); + tile_iter; ++tile_iter) { + PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); + if (map_iter == picture_map_.end()) + return false; + if (!map_iter->second.GetPicture()) + return false; + } + return true; } -PicturePileImpl::Analysis::~Analysis() { +bool PicturePileImpl::SuitableForDistanceFieldText() const { + return likely_to_be_used_for_transform_animation_; +} + +void PicturePileImpl::AsValueInto(base::debug::TracedValue* pictures) const { + gfx::Rect tiling_rect(tiling_.tiling_size()); + std::set<const void*> appended_pictures; + bool include_borders = true; + for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders); + tile_iter; ++tile_iter) { + PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); + if (map_iter == picture_map_.end()) + continue; + + const Picture* picture = map_iter->second.GetPicture(); + if (picture && (appended_pictures.count(picture) == 0)) { + appended_pictures.insert(picture); + TracedValue::AppendIDRef(picture, pictures); + } + } } PicturePileImpl::PixelRefIterator::PixelRefIterator( @@ -444,11 +453,11 @@ void PicturePileImpl::PixelRefIterator::AdvanceToTilePictureWithPixelRefs() { } void PicturePileImpl::DidBeginTracing() { - std::set<void*> processed_pictures; + std::set<const void*> processed_pictures; for (PictureMap::iterator it = picture_map_.begin(); it != picture_map_.end(); ++it) { - Picture* picture = it->second.GetPicture(); + const Picture* picture = it->second.GetPicture(); if (picture && (processed_pictures.count(picture) == 0)) { picture->EmitTraceSnapshot(); processed_pictures.insert(picture); diff --git a/chromium/cc/resources/picture_pile_impl.h b/chromium/cc/resources/picture_pile_impl.h index ba193811075..479846bb0ff 100644 --- a/chromium/cc/resources/picture_pile_impl.h +++ b/chromium/cc/resources/picture_pile_impl.h @@ -14,72 +14,61 @@ #include "cc/base/cc_export.h" #include "cc/debug/rendering_stats_instrumentation.h" #include "cc/resources/picture_pile_base.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 CC_EXPORT PicturePileImpl : public PicturePileBase { +// TODO(vmpstr): Clean up PicturePileBase and make it a member. +class CC_EXPORT PicturePileImpl : public RasterSource { public: static scoped_refptr<PicturePileImpl> Create(); static scoped_refptr<PicturePileImpl> CreateFromOther( const PicturePileBase* other); - // Get paint-safe version of this picture for a specific thread. - PicturePileImpl* GetCloneForDrawingOnThread(unsigned thread_index) const; - - // Raster a subrect of this PicturePileImpl into the given canvas. - // It's only safe to call paint on a cloned version. It is assumed - // that contents_scale has already been applied to this canvas. - // Writes the total number of pixels rasterized and the time spent - // rasterizing to the stats if the respective pointer is not - // NULL. When slow-down-raster-scale-factor is set to a value - // greater than 1, the reported rasterize time is the minimum - // measured value over all runs. - void RasterDirect( - SkCanvas* canvas, - const gfx::Rect& canvas_rect, + // RasterSource overrides. See RasterSource header for full description. + // When slow-down-raster-scale-factor is set to a value greater than 1, the + // reported rasterize time (in stats_instrumentation) is the minimum measured + // value over all runs. + void PlaybackToCanvas(SkCanvas* canvas, + const gfx::Rect& canvas_rect, + float contents_scale) const override; + void PerformSolidColorAnalysis( + const gfx::Rect& content_rect, float contents_scale, - RenderingStatsInstrumentation* rendering_stats_instrumentation); + RasterSource::SolidColorAnalysis* analysis) 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 SuitableForDistanceFieldText() const override; - // Similar to the above RasterDirect method, but this is a convenience method - // for when it is known that the raster is going to an intermediate bitmap - // that itself will then be blended and thus that a canvas clear is required. - // Note that this function may write outside the canvas_rect. - void RasterToBitmap( - SkCanvas* canvas, - const gfx::Rect& canvas_rect, - float contents_scale, - RenderingStatsInstrumentation* stats_instrumentation); - - // Called when analyzing a tile. We can use AnalysisCanvas as - // SkDrawPictureCallback, which allows us to early out from analysis. - void RasterForAnalysis( - skia::AnalysisCanvas* canvas, - const gfx::Rect& canvas_rect, - float contents_scale, - RenderingStatsInstrumentation* stats_instrumentation); + // Raster into the canvas without applying clips. + void RasterDirect(SkCanvas* canvas, + const gfx::Rect& canvas_rect, + float contents_scale) const; + // Tracing functionality. + void DidBeginTracing(); skia::RefPtr<SkPicture> GetFlattenedPicture(); - struct CC_EXPORT Analysis { - Analysis(); - ~Analysis(); - - bool is_solid_color; - SkColor solid_color; - }; - - void AnalyzeInRect(const gfx::Rect& content_rect, - float contents_scale, - Analysis* analysis); + void set_likely_to_be_used_for_transform_animation() { + likely_to_be_used_for_transform_animation_ = true; + } - void AnalyzeInRect(const gfx::Rect& content_rect, - float contents_scale, - Analysis* analysis, - RenderingStatsInstrumentation* stats_instrumentation); + gfx::Size tiling_size() const { return tiling_.tiling_size(); } + bool is_solid_color() const { return is_solid_color_; } + SkColor solid_color() const { return solid_color_; } + // If this pile contains any valid recordings. May have false positives. + bool HasRecordings() const { return has_any_recordings_; } + void AsValueInto(base::debug::TracedValue* array) const; + bool is_mask() const { return is_mask_; } + // Iterator used to return SkPixelRefs from this picture pile. + // Public for testing. class CC_EXPORT PixelRefIterator { public: PixelRefIterator(const gfx::Rect& content_rect, @@ -102,51 +91,64 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase { std::set<const void*> processed_pictures_; }; - void DidBeginTracing(); - protected: friend class PicturePile; friend class PixelRefIterator; + // TODO(vmpstr): Change this when pictures are split from invalidation info, + // and when PicturePileBase goes away. + using PictureMapKey = PicturePileBase::PictureMapKey; + using PictureMap = PicturePileBase::PictureMap; + using PictureInfo = PicturePileBase::PictureInfo; + PicturePileImpl(); explicit PicturePileImpl(const PicturePileBase* other); - virtual ~PicturePileImpl(); + ~PicturePileImpl() override; + + int buffer_pixels() const { return tiling_.border_texels(); } + + PictureMap picture_map_; + TilingData tiling_; + SkColor background_color_; + bool contents_opaque_; + bool contents_fill_bounds_completely_; + bool is_solid_color_; + SkColor solid_color_; + gfx::Rect recorded_viewport_; + bool has_any_recordings_; + bool is_mask_; + bool clear_canvas_with_debug_color_; + float min_contents_scale_; + int slow_down_raster_scale_factor_for_debug_; private: - class ClonesForDrawing { - public: - ClonesForDrawing(const PicturePileImpl* pile, int num_threads); - ~ClonesForDrawing(); - - typedef std::vector<scoped_refptr<PicturePileImpl> > PicturePileVector; - PicturePileVector clones_; - }; + typedef std::map<const Picture*, Region> PictureRegionMap; - static scoped_refptr<PicturePileImpl> CreateCloneForDrawing( - const PicturePileImpl* other, unsigned thread_index); - - PicturePileImpl(const PicturePileImpl* other, unsigned thread_index); + // 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; - private: - typedef std::map<Picture*, Region> PictureRegionMap; void CoalesceRasters(const gfx::Rect& canvas_rect, const gfx::Rect& content_rect, float contents_scale, - PictureRegionMap* result); + PictureRegionMap* result) const; void RasterCommon( SkCanvas* canvas, SkDrawPictureCallback* callback, const gfx::Rect& canvas_rect, float contents_scale, - RenderingStatsInstrumentation* rendering_stats_instrumentation, - bool is_analysis); - - // Once instantiated, |clones_for_drawing_| can't be modified. This - // guarantees thread-safe access during the life time of a PicturePileImpl - // instance. This member variable must be last so that other member - // variables have already been initialized and can be clonable. - const ClonesForDrawing clones_for_drawing_; + bool is_analysis) const; + + // An internal CanRaster check that goes to the picture_map rather than + // using the recorded_viewport hint. + bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const; + + gfx::Rect PaddedRect(const PictureMapKey& key) const; + + bool likely_to_be_used_for_transform_animation_; DISALLOW_COPY_AND_ASSIGN(PicturePileImpl); }; diff --git a/chromium/cc/resources/picture_pile_impl_perftest.cc b/chromium/cc/resources/picture_pile_impl_perftest.cc index 7ced0eaa1be..7e24724197c 100644 --- a/chromium/cc/resources/picture_pile_impl_perftest.cc +++ b/chromium/cc/resources/picture_pile_impl_perftest.cc @@ -6,7 +6,6 @@ #include "cc/debug/lap_timer.h" #include "cc/test/fake_picture_pile_impl.h" -#include "cc/test/fake_rendering_stats_instrumentation.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/perf/perf_test.h" @@ -33,10 +32,10 @@ class PicturePileImplPerfTest : public testing::Test { // Content rect that will align with top-left tile at scale 1.0. gfx::Rect content_rect(0, 0, kTileSize, kTileSize); - PicturePileImpl::Analysis analysis; + RasterSource::SolidColorAnalysis analysis; timer_.Reset(); do { - pile->AnalyzeInRect(content_rect, contents_scale, &analysis); + pile->PerformSolidColorAnalysis(content_rect, contents_scale, &analysis); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -51,17 +50,12 @@ class PicturePileImplPerfTest : public testing::Test { gfx::Rect content_rect(0, 0, kTileSize, kTileSize); SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1); - bitmap.allocPixels(); + bitmap.allocN32Pixels(1, 1); SkCanvas canvas(bitmap); - FakeRenderingStatsInstrumentation rendering_stats_instrumentation; timer_.Reset(); do { - pile->RasterToBitmap(&canvas, - content_rect, - contents_scale, - &rendering_stats_instrumentation); + pile->PlaybackToCanvas(&canvas, content_rect, contents_scale); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); diff --git a/chromium/cc/resources/picture_pile_impl_unittest.cc b/chromium/cc/resources/picture_pile_impl_unittest.cc index 40d1615a943..6dcf740e1ab 100644 --- a/chromium/cc/resources/picture_pile_impl_unittest.cc +++ b/chromium/cc/resources/picture_pile_impl_unittest.cc @@ -4,14 +4,13 @@ #include "base/memory/scoped_ptr.h" #include "cc/test/fake_picture_pile_impl.h" -#include "cc/test/fake_rendering_stats_instrumentation.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/SkPixelRef.h" #include "third_party/skia/include/core/SkShader.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/size_conversions.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size_conversions.h" namespace cc { namespace { @@ -37,9 +36,9 @@ TEST(PicturePileImplTest, AnalyzeIsSolidUnscaled) { // Ensure everything is solid for (int y = 0; y <= 300; y += 100) { for (int x = 0; x <= 300; x += 100) { - PicturePileImpl::Analysis analysis; + RasterSource::SolidColorAnalysis analysis; gfx::Rect rect(x, y, 100, 100); - pile->AnalyzeInRect(rect, 1.0, &analysis); + pile->PerformSolidColorAnalysis(rect, 1.0, &analysis); EXPECT_TRUE(analysis.is_solid_color) << rect.ToString(); EXPECT_EQ(analysis.solid_color, solid_color) << rect.ToString(); } @@ -49,27 +48,28 @@ TEST(PicturePileImplTest, AnalyzeIsSolidUnscaled) { pile->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1), non_solid_paint); pile->RerecordPile(); - PicturePileImpl::Analysis analysis; - pile->AnalyzeInRect(gfx::Rect(0, 0, 100, 100), 1.0, &analysis); + RasterSource::SolidColorAnalysis analysis; + pile->PerformSolidColorAnalysis(gfx::Rect(0, 0, 100, 100), 1.0, &analysis); EXPECT_FALSE(analysis.is_solid_color); - pile->AnalyzeInRect(gfx::Rect(100, 0, 100, 100), 1.0, &analysis); + pile->PerformSolidColorAnalysis(gfx::Rect(100, 0, 100, 100), 1.0, &analysis); EXPECT_TRUE(analysis.is_solid_color); EXPECT_EQ(analysis.solid_color, solid_color); // Boundaries should be clipped analysis.is_solid_color = false; - pile->AnalyzeInRect(gfx::Rect(350, 0, 100, 100), 1.0, &analysis); + pile->PerformSolidColorAnalysis(gfx::Rect(350, 0, 100, 100), 1.0, &analysis); EXPECT_TRUE(analysis.is_solid_color); EXPECT_EQ(analysis.solid_color, solid_color); analysis.is_solid_color = false; - pile->AnalyzeInRect(gfx::Rect(0, 350, 100, 100), 1.0, &analysis); + pile->PerformSolidColorAnalysis(gfx::Rect(0, 350, 100, 100), 1.0, &analysis); EXPECT_TRUE(analysis.is_solid_color); EXPECT_EQ(analysis.solid_color, solid_color); analysis.is_solid_color = false; - pile->AnalyzeInRect(gfx::Rect(350, 350, 100, 100), 1.0, &analysis); + pile->PerformSolidColorAnalysis(gfx::Rect(350, 350, 100, 100), 1.0, + &analysis); EXPECT_TRUE(analysis.is_solid_color); EXPECT_EQ(analysis.solid_color, solid_color); } @@ -95,9 +95,9 @@ TEST(PicturePileImplTest, AnalyzeIsSolidScaled) { // Ensure everything is solid for (int y = 0; y <= 30; y += 10) { for (int x = 0; x <= 30; x += 10) { - PicturePileImpl::Analysis analysis; + RasterSource::SolidColorAnalysis analysis; gfx::Rect rect(x, y, 10, 10); - pile->AnalyzeInRect(rect, 0.1f, &analysis); + pile->PerformSolidColorAnalysis(rect, 0.1f, &analysis); EXPECT_TRUE(analysis.is_solid_color) << rect.ToString(); EXPECT_EQ(analysis.solid_color, solid_color) << rect.ToString(); } @@ -107,27 +107,27 @@ TEST(PicturePileImplTest, AnalyzeIsSolidScaled) { pile->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1), non_solid_paint); pile->RerecordPile(); - PicturePileImpl::Analysis analysis; - pile->AnalyzeInRect(gfx::Rect(0, 0, 10, 10), 0.1f, &analysis); + RasterSource::SolidColorAnalysis analysis; + pile->PerformSolidColorAnalysis(gfx::Rect(0, 0, 10, 10), 0.1f, &analysis); EXPECT_FALSE(analysis.is_solid_color); - pile->AnalyzeInRect(gfx::Rect(10, 0, 10, 10), 0.1f, &analysis); + pile->PerformSolidColorAnalysis(gfx::Rect(10, 0, 10, 10), 0.1f, &analysis); EXPECT_TRUE(analysis.is_solid_color); EXPECT_EQ(analysis.solid_color, solid_color); // Boundaries should be clipped analysis.is_solid_color = false; - pile->AnalyzeInRect(gfx::Rect(35, 0, 10, 10), 0.1f, &analysis); + pile->PerformSolidColorAnalysis(gfx::Rect(35, 0, 10, 10), 0.1f, &analysis); EXPECT_TRUE(analysis.is_solid_color); EXPECT_EQ(analysis.solid_color, solid_color); analysis.is_solid_color = false; - pile->AnalyzeInRect(gfx::Rect(0, 35, 10, 10), 0.1f, &analysis); + pile->PerformSolidColorAnalysis(gfx::Rect(0, 35, 10, 10), 0.1f, &analysis); EXPECT_TRUE(analysis.is_solid_color); EXPECT_EQ(analysis.solid_color, solid_color); analysis.is_solid_color = false; - pile->AnalyzeInRect(gfx::Rect(35, 35, 10, 10), 0.1f, &analysis); + pile->PerformSolidColorAnalysis(gfx::Rect(35, 35, 10, 10), 0.1f, &analysis); EXPECT_TRUE(analysis.is_solid_color); EXPECT_EQ(analysis.solid_color, solid_color); } @@ -138,10 +138,10 @@ TEST(PicturePileImplTest, AnalyzeIsSolidEmpty) { scoped_refptr<FakePicturePileImpl> pile = FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - PicturePileImpl::Analysis analysis; + RasterSource::SolidColorAnalysis analysis; EXPECT_FALSE(analysis.is_solid_color); - pile->AnalyzeInRect(gfx::Rect(0, 0, 400, 400), 1.f, &analysis); + pile->PerformSolidColorAnalysis(gfx::Rect(0, 0, 400, 400), 1.f, &analysis); EXPECT_TRUE(analysis.is_solid_color); EXPECT_EQ(analysis.solid_color, SkColorSetARGB(0, 0, 0, 0)); @@ -685,12 +685,7 @@ TEST_P(FullContentsTest, RasterFullContents) { SkCanvas canvas(bitmap); canvas.clear(SK_ColorTRANSPARENT); - FakeRenderingStatsInstrumentation rendering_stats_instrumentation; - - pile->RasterToBitmap(&canvas, - canvas_rect, - contents_scale, - &rendering_stats_instrumentation); + pile->PlaybackToCanvas(&canvas, canvas_rect, contents_scale); SkColor* pixels = reinterpret_cast<SkColor*>(bitmap.getPixels()); int num_pixels = bitmap.width() * bitmap.height(); @@ -737,9 +732,7 @@ TEST(PicturePileImpl, RasterContentsTransparent) { bitmap.allocN32Pixels(canvas_rect.width(), canvas_rect.height()); SkCanvas canvas(bitmap); - FakeRenderingStatsInstrumentation rendering_stats_instrumentation; - pile->RasterToBitmap( - &canvas, canvas_rect, contents_scale, &rendering_stats_instrumentation); + pile->PlaybackToCanvas(&canvas, canvas_rect, contents_scale); SkColor* pixels = reinterpret_cast<SkColor*>(bitmap.getPixels()); int num_pixels = bitmap.width() * bitmap.height(); @@ -780,17 +773,10 @@ TEST_P(OverlapTest, NoOverlap) { gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale))); SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, - content_bounds.width(), - content_bounds.height()); - bitmap.allocPixels(); + bitmap.allocN32Pixels(content_bounds.width(), content_bounds.height()); SkCanvas canvas(bitmap); - FakeRenderingStatsInstrumentation rendering_stats_instrumentation; - pile->RasterToBitmap(&canvas, - gfx::Rect(content_bounds), - contents_scale, - &rendering_stats_instrumentation); + pile->PlaybackToCanvas(&canvas, gfx::Rect(content_bounds), contents_scale); for (int y = 0; y < bitmap.height(); y++) { for (int x = 0; x < bitmap.width(); x++) { diff --git a/chromium/cc/resources/picture_pile_unittest.cc b/chromium/cc/resources/picture_pile_unittest.cc index 681166ea877..00b1b0c97fb 100644 --- a/chromium/cc/resources/picture_pile_unittest.cc +++ b/chromium/cc/resources/picture_pile_unittest.cc @@ -9,14 +9,16 @@ #include "cc/test/fake_content_layer_client.h" #include "cc/test/fake_rendering_stats_instrumentation.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/rect_conversions.h" -#include "ui/gfx/size_conversions.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/size_conversions.h" namespace cc { namespace { class TestPicturePile : public PicturePile { public: + ~TestPicturePile() override {} + using PicturePile::buffer_pixels; using PicturePile::CanRasterSlowTileCheck; using PicturePile::Clear; @@ -24,76 +26,169 @@ class TestPicturePile : public PicturePile { PictureMap& picture_map() { return picture_map_; } const gfx::Rect& recorded_viewport() const { return recorded_viewport_; } - bool CanRasterLayerRect(const gfx::Rect& layer_rect) { - return CanRaster(1.f, layer_rect); + bool CanRasterLayerRect(gfx::Rect layer_rect) { + layer_rect.Intersect(gfx::Rect(tiling_.tiling_size())); + if (recorded_viewport_.Contains(layer_rect)) + return true; + return CanRasterSlowTileCheck(layer_rect); } + bool HasRecordings() const { return has_any_recordings_; } + typedef PicturePile::PictureInfo PictureInfo; typedef PicturePile::PictureMapKey PictureMapKey; typedef PicturePile::PictureMap PictureMap; - - protected: - virtual ~TestPicturePile() {} }; -class PicturePileTest : public testing::Test { +class PicturePileTestBase { public: - PicturePileTest() - : pile_(new TestPicturePile()), - background_color_(SK_ColorBLUE), + PicturePileTestBase() + : background_color_(SK_ColorBLUE), min_scale_(0.125), frame_number_(0), - contents_opaque_(false) { - pile_->SetTilingRect(gfx::Rect(pile_->tiling().max_texture_size())); - pile_->SetTileGridSize(gfx::Size(1000, 1000)); - pile_->SetMinContentsScale(min_scale_); + contents_opaque_(false) {} + + void InitializeData() { + pile_.SetTileGridSize(gfx::Size(1000, 1000)); + pile_.SetMinContentsScale(min_scale_); + client_ = FakeContentLayerClient(); + SetTilingSize(pile_.tiling().max_texture_size()); } - gfx::Rect tiling_rect() const { return pile_->tiling_rect(); } + void SetTilingSize(const gfx::Size& tiling_size) { + Region invalidation; + gfx::Rect viewport_rect(tiling_size); + UpdateAndExpandInvalidation(&invalidation, tiling_size, viewport_rect); + } + + gfx::Size tiling_size() const { return pile_.tiling_size(); } + gfx::Rect tiling_rect() const { return gfx::Rect(pile_.tiling_size()); } bool UpdateAndExpandInvalidation(Region* invalidation, + const gfx::Size& layer_size, const gfx::Rect& visible_layer_rect) { frame_number_++; - return pile_->UpdateAndExpandInvalidation(&client_, - invalidation, - background_color_, - contents_opaque_, - false, - visible_layer_rect, - frame_number_, - Picture::RECORD_NORMALLY, - &stats_instrumentation_); + return pile_.UpdateAndExpandInvalidation(&client_, + invalidation, + background_color_, + contents_opaque_, + false, + layer_size, + visible_layer_rect, + frame_number_, + Picture::RECORD_NORMALLY, + &stats_instrumentation_); } bool UpdateWholePile() { Region invalidation = tiling_rect(); - bool result = UpdateAndExpandInvalidation(&invalidation, tiling_rect()); + bool result = UpdateAndExpandInvalidation( + &invalidation, tiling_size(), tiling_rect()); EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString()); return result; } FakeContentLayerClient client_; FakeRenderingStatsInstrumentation stats_instrumentation_; - scoped_refptr<TestPicturePile> pile_; + TestPicturePile pile_; SkColor background_color_; float min_scale_; int frame_number_; bool contents_opaque_; }; -TEST_F(PicturePileTest, SmallInvalidateInflated) { - UpdateWholePile(); +class PicturePileTest : public PicturePileTestBase, public testing::Test { + public: + virtual void SetUp() override { InitializeData(); } +}; + +TEST_F(PicturePileTest, InvalidationOnTileBorderOutsideInterestRect) { + // Don't expand the interest rect past what we invalidate. + pile_.SetPixelRecordDistanceForTesting(0); + + gfx::Size tile_size(100, 100); + pile_.tiling().SetMaxTextureSize(tile_size); + + gfx::Size pile_size(400, 400); + SetTilingSize(pile_size); + + // We have multiple tiles. + EXPECT_GT(pile_.tiling().num_tiles_x(), 2); + EXPECT_GT(pile_.tiling().num_tiles_y(), 2); + + // Record everything. + Region invalidation(tiling_rect()); + UpdateAndExpandInvalidation(&invalidation, tiling_size(), tiling_rect()); + + // +----------+-----------------+-----------+ + // | | VVVV 1,0| | + // | | VVVV | | + // | | VVVV | | + // | ...|.................|... | + // | ...|.................|... | + // +----------+-----------------+-----------+ + // | ...| |... | + // | ...| |... | + // | ...| |... | + // | ...| |... | + // | ...| 1,1|... | + // +----------+-----------------+-----------+ + // | ...|.................|... | + // | ...|.................|... | + // +----------+-----------------+-----------+ + // + // .. = border pixels for tile 1,1 + // VV = interest rect (what we will record) + // + // The first invalidation is inside VV, so it does not touch border pixels of + // tile 1,1. + // + // The second invalidation goes below VV into the .. border pixels of 1,1. + // This is the VV interest rect which will be entirely inside 1,0 and not + // touch the border of 1,1. + gfx::Rect interest_rect( + pile_.tiling().TilePositionX(1) + pile_.tiling().border_texels(), + 0, + 10, + pile_.tiling().TileSizeY(0) - pile_.tiling().border_texels()); + + // Invalidate tile 1,0 only. This is a rect that avoids the borders of any + // other tiles. + gfx::Rect invalidate_tile = interest_rect; + // This should cause the tile 1,0 to be invalidated and re-recorded. The + // invalidation did not need to be expanded. + invalidation = invalidate_tile; + UpdateAndExpandInvalidation(&invalidation, tiling_size(), interest_rect); + EXPECT_EQ(invalidate_tile, invalidation); + + // Invalidate tile 1,0 and 1,1 by invalidating something that only touches the + // border of 1,1 (and is inside the tile bounds of 1,0). This is a 10px wide + // strip from the top of the tiling onto the border pixels of tile 1,1 that + // avoids border pixels of any other tiles. + gfx::Rect invalidate_border = interest_rect; + invalidate_border.Inset(0, 0, 0, -1); + // This should cause the tile 1,0 and 1,1 to be invalidated. The 1,1 tile will + // not be re-recorded since it does not touch the interest rect, so the + // invalidation should be expanded to cover all of 1,1. + invalidation = invalidate_border; + UpdateAndExpandInvalidation(&invalidation, tiling_size(), interest_rect); + Region expected_invalidation = invalidate_border; + expected_invalidation.Union(pile_.tiling().TileBounds(1, 1)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); +} + +TEST_F(PicturePileTest, SmallInvalidateInflated) { // Invalidate something inside a tile. Region invalidate_rect(gfx::Rect(50, 50, 1, 1)); - UpdateAndExpandInvalidation(&invalidate_rect, tiling_rect()); + UpdateAndExpandInvalidation(&invalidate_rect, tiling_size(), tiling_rect()); EXPECT_EQ(gfx::Rect(50, 50, 1, 1).ToString(), invalidate_rect.ToString()); - EXPECT_EQ(1, pile_->tiling().num_tiles_x()); - EXPECT_EQ(1, pile_->tiling().num_tiles_y()); + EXPECT_EQ(1, pile_.tiling().num_tiles_x()); + EXPECT_EQ(1, pile_.tiling().num_tiles_y()); TestPicturePile::PictureInfo& picture_info = - pile_->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second; + pile_.picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second; // We should have a picture. EXPECT_TRUE(!!picture_info.GetPicture()); gfx::Rect picture_rect = gfx::ScaleToEnclosedRect( @@ -106,64 +201,59 @@ TEST_F(PicturePileTest, SmallInvalidateInflated) { } TEST_F(PicturePileTest, LargeInvalidateInflated) { - UpdateWholePile(); - // Invalidate something inside a tile. Region invalidate_rect(gfx::Rect(50, 50, 100, 100)); - UpdateAndExpandInvalidation(&invalidate_rect, tiling_rect()); + UpdateAndExpandInvalidation(&invalidate_rect, tiling_size(), tiling_rect()); EXPECT_EQ(gfx::Rect(50, 50, 100, 100).ToString(), invalidate_rect.ToString()); - EXPECT_EQ(1, pile_->tiling().num_tiles_x()); - EXPECT_EQ(1, pile_->tiling().num_tiles_y()); + EXPECT_EQ(1, pile_.tiling().num_tiles_x()); + EXPECT_EQ(1, pile_.tiling().num_tiles_y()); TestPicturePile::PictureInfo& picture_info = - pile_->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second; + pile_.picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second; EXPECT_TRUE(!!picture_info.GetPicture()); - int expected_inflation = pile_->buffer_pixels(); + int expected_inflation = pile_.buffer_pixels(); - Picture* base_picture = picture_info.GetPicture(); - gfx::Rect base_picture_rect = pile_->tiling_rect(); + const Picture* base_picture = picture_info.GetPicture(); + gfx::Rect base_picture_rect(pile_.tiling_size()); base_picture_rect.Inset(-expected_inflation, -expected_inflation); EXPECT_EQ(base_picture_rect.ToString(), base_picture->LayerRect().ToString()); } TEST_F(PicturePileTest, InvalidateOnTileBoundaryInflated) { - gfx::Rect new_tiling_rect = - gfx::ToEnclosedRect(gfx::ScaleRect(pile_->tiling_rect(), 2.f)); - pile_->SetTilingRect(new_tiling_rect); + gfx::Size new_tiling_size = + gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 2.f)); + // This creates initial pictures. + SetTilingSize(new_tiling_size); // Due to border pixels, we should have 3 tiles. - EXPECT_EQ(3, pile_->tiling().num_tiles_x()); - EXPECT_EQ(3, pile_->tiling().num_tiles_y()); + EXPECT_EQ(3, pile_.tiling().num_tiles_x()); + EXPECT_EQ(3, pile_.tiling().num_tiles_y()); // We should have 1/.125 - 1 = 7 border pixels. - EXPECT_EQ(7, pile_->buffer_pixels()); - EXPECT_EQ(7, pile_->tiling().border_texels()); + EXPECT_EQ(7, pile_.buffer_pixels()); + EXPECT_EQ(7, pile_.tiling().border_texels()); - // Update the whole layer to create initial pictures. - UpdateWholePile(); - - // Invalidate everything again to have a non zero invalidation - // frequency. + // Invalidate everything to have a non zero invalidation frequency. UpdateWholePile(); // Invalidate something just over a tile boundary by a single pixel. // This will invalidate the tile (1, 1), as well as 1 row of pixels in (1, 0). Region invalidate_rect( - gfx::Rect(pile_->tiling().TileBoundsWithBorder(0, 0).right(), - pile_->tiling().TileBoundsWithBorder(0, 0).bottom() - 1, + gfx::Rect(pile_.tiling().TileBoundsWithBorder(0, 0).right(), + pile_.tiling().TileBoundsWithBorder(0, 0).bottom() - 1, 50, 50)); Region expected_invalidation = invalidate_rect; - UpdateAndExpandInvalidation(&invalidate_rect, tiling_rect()); + UpdateAndExpandInvalidation(&invalidate_rect, tiling_size(), tiling_rect()); EXPECT_EQ(expected_invalidation.ToString(), invalidate_rect.ToString()); - for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) { - for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) { + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { TestPicturePile::PictureInfo& picture_info = - pile_->picture_map() + pile_.picture_map() .find(TestPicturePile::PictureMapKey(i, j)) ->second; @@ -182,13 +272,34 @@ TEST_F(PicturePileTest, InvalidateOnTileBoundaryInflated) { } } +TEST_F(PicturePileTest, InvalidateOnFullLayer) { + UpdateWholePile(); + + // Everything was invalidated once so far. + for (auto& it : pile_.picture_map()) { + EXPECT_FLOAT_EQ( + 1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED, + it.second.GetInvalidationFrequencyForTesting()); + } + + // Invalidate everything, + Region invalidation = tiling_rect(); + UpdateAndExpandInvalidation(&invalidation, tiling_size(), tiling_rect()); + + // Everything was invalidated again. + for (auto& it : pile_.picture_map()) { + EXPECT_FLOAT_EQ( + 2.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED, + it.second.GetInvalidationFrequencyForTesting()); + } +} + TEST_F(PicturePileTest, StopRecordingOffscreenInvalidations) { - gfx::Rect new_tiling_rect = - gfx::ToEnclosedRect(gfx::ScaleRect(pile_->tiling_rect(), 4.f)); - pile_->SetTilingRect(new_tiling_rect); + gfx::Size new_tiling_size = + gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 4.f)); + SetTilingSize(new_tiling_size); - gfx::Rect viewport( - tiling_rect().x(), tiling_rect().y(), tiling_rect().width(), 1); + gfx::Rect viewport(tiling_size().width(), 1); // Update the whole pile until the invalidation frequency is high. for (int frame = 0; frame < 33; ++frame) { @@ -196,10 +307,10 @@ TEST_F(PicturePileTest, StopRecordingOffscreenInvalidations) { } // Make sure we have a high invalidation frequency. - for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) { - for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) { + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { TestPicturePile::PictureInfo& picture_info = - pile_->picture_map() + pile_.picture_map() .find(TestPicturePile::PictureMapKey(i, j)) ->second; EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting()) @@ -208,14 +319,14 @@ TEST_F(PicturePileTest, StopRecordingOffscreenInvalidations) { } // Update once more with a small viewport. - Region invalidation = tiling_rect(); - UpdateAndExpandInvalidation(&invalidation, viewport); + Region invalidation(tiling_rect()); + UpdateAndExpandInvalidation(&invalidation, tiling_size(), viewport); EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString()); - for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) { - for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) { + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { TestPicturePile::PictureInfo& picture_info = - pile_->picture_map() + pile_.picture_map() .find(TestPicturePile::PictureMapKey(i, j)) ->second; EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting()); @@ -232,24 +343,25 @@ TEST_F(PicturePileTest, StopRecordingOffscreenInvalidations) { // Update a partial tile that doesn't get recorded. We should expand the // invalidation to the entire tiles that overlap it. Region small_invalidation = - gfx::Rect(pile_->tiling().TileBounds(3, 4).x(), - pile_->tiling().TileBounds(3, 4).y() + 10, + gfx::Rect(pile_.tiling().TileBounds(3, 4).x(), + pile_.tiling().TileBounds(3, 4).y() + 10, 1, 1); - UpdateAndExpandInvalidation(&small_invalidation, viewport); + UpdateAndExpandInvalidation(&small_invalidation, tiling_size(), viewport); EXPECT_TRUE(small_invalidation.Contains(gfx::UnionRects( - pile_->tiling().TileBounds(2, 4), pile_->tiling().TileBounds(3, 4)))) + pile_.tiling().TileBounds(2, 4), pile_.tiling().TileBounds(3, 4)))) << small_invalidation.ToString(); // Now update with no invalidation and full viewport Region empty_invalidation; - UpdateAndExpandInvalidation(&empty_invalidation, tiling_rect()); + UpdateAndExpandInvalidation( + &empty_invalidation, tiling_size(), tiling_rect()); EXPECT_EQ(Region().ToString(), empty_invalidation.ToString()); - for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) { - for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) { + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { TestPicturePile::PictureInfo& picture_info = - pile_->picture_map() + pile_.picture_map() .find(TestPicturePile::PictureMapKey(i, j)) ->second; // Expect the invalidation frequency to be less than 1, since we just @@ -263,18 +375,16 @@ TEST_F(PicturePileTest, StopRecordingOffscreenInvalidations) { } TEST_F(PicturePileTest, ClearingInvalidatesRecordedRect) { - UpdateWholePile(); - gfx::Rect rect(0, 0, 5, 5); - EXPECT_TRUE(pile_->CanRasterLayerRect(rect)); - EXPECT_TRUE(pile_->CanRasterSlowTileCheck(rect)); + EXPECT_TRUE(pile_.CanRasterLayerRect(rect)); + EXPECT_TRUE(pile_.CanRasterSlowTileCheck(rect)); - pile_->Clear(); + pile_.Clear(); // Make sure both the cache-aware check (using recorded region) and the normal // check are both false after clearing. - EXPECT_FALSE(pile_->CanRasterLayerRect(rect)); - EXPECT_FALSE(pile_->CanRasterSlowTileCheck(rect)); + EXPECT_FALSE(pile_.CanRasterLayerRect(rect)); + EXPECT_FALSE(pile_.CanRasterSlowTileCheck(rect)); } TEST_F(PicturePileTest, FrequentInvalidationCanRaster) { @@ -282,27 +392,27 @@ TEST_F(PicturePileTest, FrequentInvalidationCanRaster) { // and doesn't get re-recorded, then CanRaster is not true for any // tiles touching it, but is true for adjacent tiles, even if it // overlaps on borders (edge case). - gfx::Rect new_tiling_rect = - gfx::ToEnclosedRect(gfx::ScaleRect(pile_->tiling_rect(), 4.f)); - pile_->SetTilingRect(new_tiling_rect); + gfx::Size new_tiling_size = + gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 4.f)); + SetTilingSize(new_tiling_size); - gfx::Rect tile01_borders = pile_->tiling().TileBoundsWithBorder(0, 1); - gfx::Rect tile02_borders = pile_->tiling().TileBoundsWithBorder(0, 2); - gfx::Rect tile01_noborders = pile_->tiling().TileBounds(0, 1); - gfx::Rect tile02_noborders = pile_->tiling().TileBounds(0, 2); + gfx::Rect tile01_borders = pile_.tiling().TileBoundsWithBorder(0, 1); + gfx::Rect tile02_borders = pile_.tiling().TileBoundsWithBorder(0, 2); + gfx::Rect tile01_noborders = pile_.tiling().TileBounds(0, 1); + gfx::Rect tile02_noborders = pile_.tiling().TileBounds(0, 2); // Sanity check these two tiles are overlapping with borders, since this is // what the test is trying to repro. EXPECT_TRUE(tile01_borders.Intersects(tile02_borders)); EXPECT_FALSE(tile01_noborders.Intersects(tile02_noborders)); UpdateWholePile(); - EXPECT_TRUE(pile_->CanRasterLayerRect(tile01_noborders)); - EXPECT_TRUE(pile_->CanRasterSlowTileCheck(tile01_noborders)); - EXPECT_TRUE(pile_->CanRasterLayerRect(tile02_noborders)); - EXPECT_TRUE(pile_->CanRasterSlowTileCheck(tile02_noborders)); + EXPECT_TRUE(pile_.CanRasterLayerRect(tile01_noborders)); + EXPECT_TRUE(pile_.CanRasterSlowTileCheck(tile01_noborders)); + EXPECT_TRUE(pile_.CanRasterLayerRect(tile02_noborders)); + EXPECT_TRUE(pile_.CanRasterSlowTileCheck(tile02_noborders)); // Sanity check that an initial paint goes down the fast path of having // a valid recorded viewport. - EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty()); + EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty()); // Update the whole layer until the invalidation frequency is high. for (int frame = 0; frame < 33; ++frame) { @@ -310,75 +420,1163 @@ TEST_F(PicturePileTest, FrequentInvalidationCanRaster) { } // Update once more with a small viewport. - gfx::Rect viewport(0, 0, tiling_rect().width(), 1); + gfx::Rect viewport(tiling_size().width(), 1); Region invalidation(tiling_rect()); - UpdateAndExpandInvalidation(&invalidation, viewport); + UpdateAndExpandInvalidation(&invalidation, tiling_size(), viewport); EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString()); // Sanity check some pictures exist and others don't. - EXPECT_TRUE(pile_->picture_map() + EXPECT_TRUE(pile_.picture_map() .find(TestPicturePile::PictureMapKey(0, 1)) ->second.GetPicture()); - EXPECT_FALSE(pile_->picture_map() + EXPECT_FALSE(pile_.picture_map() .find(TestPicturePile::PictureMapKey(0, 2)) ->second.GetPicture()); - EXPECT_TRUE(pile_->CanRasterLayerRect(tile01_noborders)); - EXPECT_TRUE(pile_->CanRasterSlowTileCheck(tile01_noborders)); - EXPECT_FALSE(pile_->CanRasterLayerRect(tile02_noborders)); - EXPECT_FALSE(pile_->CanRasterSlowTileCheck(tile02_noborders)); + EXPECT_TRUE(pile_.CanRasterLayerRect(tile01_noborders)); + EXPECT_TRUE(pile_.CanRasterSlowTileCheck(tile01_noborders)); + EXPECT_FALSE(pile_.CanRasterLayerRect(tile02_noborders)); + EXPECT_FALSE(pile_.CanRasterSlowTileCheck(tile02_noborders)); } TEST_F(PicturePileTest, NoInvalidationValidViewport) { // This test validates that the recorded_viewport cache of full tiles // is still valid for some use cases. If it's not, it's a performance // issue because CanRaster checks will go down the slow path. - UpdateWholePile(); - EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty()); + EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty()); // No invalidation, same viewport. Region invalidation; - UpdateAndExpandInvalidation(&invalidation, tiling_rect()); - EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty()); + UpdateAndExpandInvalidation(&invalidation, tiling_size(), tiling_rect()); + EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty()); EXPECT_EQ(Region().ToString(), invalidation.ToString()); // Partial invalidation, same viewport. invalidation = gfx::Rect(0, 0, 1, 1); - UpdateAndExpandInvalidation(&invalidation, tiling_rect()); - EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty()); + UpdateAndExpandInvalidation(&invalidation, tiling_size(), tiling_rect()); + EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty()); EXPECT_EQ(gfx::Rect(0, 0, 1, 1).ToString(), invalidation.ToString()); // No invalidation, changing viewport. invalidation = Region(); - UpdateAndExpandInvalidation(&invalidation, gfx::Rect(5, 5, 5, 5)); - EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty()); + UpdateAndExpandInvalidation( + &invalidation, tiling_size(), gfx::Rect(5, 5, 5, 5)); + EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty()); EXPECT_EQ(Region().ToString(), invalidation.ToString()); } +TEST_F(PicturePileTest, BigFullLayerInvalidation) { + gfx::Size huge_layer_size(100000000, 100000000); + gfx::Rect viewport(300000, 400000, 5000, 6000); + + // Resize the pile. + Region invalidation; + UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); + + // Invalidating a huge layer should be fast. + base::TimeTicks start = base::TimeTicks::Now(); + invalidation = gfx::Rect(huge_layer_size); + UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); + base::TimeTicks end = base::TimeTicks::Now(); + base::TimeDelta length = end - start; + // This is verrrry generous to avoid flake. + EXPECT_LT(length.InSeconds(), 5); +} + +TEST_F(PicturePileTest, BigFullLayerInvalidationWithResizeGrow) { + gfx::Size huge_layer_size(100000000, 100000000); + gfx::Rect viewport(300000, 400000, 5000, 6000); + + // Resize the pile. + Region invalidation; + UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); + + // Resize the pile even larger, while invalidating everything in the old size. + // Invalidating the whole thing should be fast. + base::TimeTicks start = base::TimeTicks::Now(); + gfx::Size bigger_layer_size(huge_layer_size.width() * 2, + huge_layer_size.height() * 2); + invalidation = gfx::Rect(huge_layer_size); + UpdateAndExpandInvalidation(&invalidation, bigger_layer_size, viewport); + base::TimeTicks end = base::TimeTicks::Now(); + base::TimeDelta length = end - start; + // This is verrrry generous to avoid flake. + EXPECT_LT(length.InSeconds(), 5); +} + +TEST_F(PicturePileTest, BigFullLayerInvalidationWithResizeShrink) { + gfx::Size huge_layer_size(100000000, 100000000); + gfx::Rect viewport(300000, 400000, 5000, 6000); + + // Resize the pile. + Region invalidation; + UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); + + // Resize the pile smaller, while invalidating everything in the new size. + // Invalidating the whole thing should be fast. + base::TimeTicks start = base::TimeTicks::Now(); + gfx::Size smaller_layer_size(huge_layer_size.width() - 1000, + huge_layer_size.height() - 1000); + invalidation = gfx::Rect(smaller_layer_size); + UpdateAndExpandInvalidation(&invalidation, smaller_layer_size, viewport); + base::TimeTicks end = base::TimeTicks::Now(); + base::TimeDelta length = end - start; + // This is verrrry generous to avoid flake. + EXPECT_LT(length.InSeconds(), 5); +} + TEST_F(PicturePileTest, InvalidationOutsideRecordingRect) { - gfx::Rect huge_layer_rect(10000000, 20000000); + gfx::Size huge_layer_size(10000000, 20000000); gfx::Rect viewport(300000, 400000, 5000, 6000); - pile_->SetTilingRect(huge_layer_rect); + // Resize the pile and set up the interest rect. + Region invalidation; + UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); // Invalidation inside the recording rect does not need to be expanded. - Region invalidation = viewport; - UpdateAndExpandInvalidation(&invalidation, viewport); + invalidation = viewport; + UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); EXPECT_EQ(viewport.ToString(), invalidation.ToString()); // Invalidation outside the recording rect should expand to the tiles it // covers. gfx::Rect recorded_over_tiles = - pile_->tiling().ExpandRectToTileBounds(pile_->recorded_viewport()); + pile_.tiling().ExpandRectToTileBounds(pile_.recorded_viewport()); gfx::Rect invalidation_outside( recorded_over_tiles.right(), recorded_over_tiles.y(), 30, 30); invalidation = invalidation_outside; - UpdateAndExpandInvalidation(&invalidation, viewport); + UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); gfx::Rect expanded_recorded_viewport = - pile_->tiling().ExpandRectToTileBounds(pile_->recorded_viewport()); + pile_.tiling().ExpandRectToTileBounds(pile_.recorded_viewport()); Region expected_invalidation = - pile_->tiling().ExpandRectToTileBounds(invalidation_outside); + pile_.tiling().ExpandRectToTileBounds(invalidation_outside); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); +} + +enum Corner { + TOP_LEFT, + TOP_RIGHT, + BOTTOM_LEFT, + BOTTOM_RIGHT, +}; + +class PicturePileResizeCornerTest : public PicturePileTestBase, + public testing::TestWithParam<Corner> { + protected: + virtual void SetUp() override { InitializeData(); } + + static gfx::Rect CornerSinglePixelRect(Corner corner, const gfx::Size& s) { + switch (corner) { + case TOP_LEFT: + return gfx::Rect(0, 0, 1, 1); + case TOP_RIGHT: + return gfx::Rect(s.width() - 1, 0, 1, 1); + case BOTTOM_LEFT: + return gfx::Rect(0, s.height() - 1, 1, 1); + case BOTTOM_RIGHT: + return gfx::Rect(s.width() - 1, s.height() - 1, 1, 1); + } + NOTREACHED(); + return gfx::Rect(); + } +}; + +TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { + Corner corner = GetParam(); + + // This size chosen to be larger than the interest rect size, which is + // at least kPixelDistanceToRecord * 2 in each dimension. + int tile_size = 100000; + // The small number subtracted keeps the last tile in each axis larger than + // the interest rect also. + int offset = -100; + gfx::Size base_tiling_size(6 * tile_size + offset, 6 * tile_size + offset); + gfx::Size grow_down_tiling_size(6 * tile_size + offset, + 8 * tile_size + offset); + gfx::Size grow_right_tiling_size(8 * tile_size + offset, + 6 * tile_size + offset); + gfx::Size grow_both_tiling_size(8 * tile_size + offset, + 8 * tile_size + offset); + + Region invalidation; + Region expected_invalidation; + + pile_.tiling().SetMaxTextureSize(gfx::Size(tile_size, tile_size)); + SetTilingSize(base_tiling_size); + + // We should have a recording for every tile. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + UpdateAndExpandInvalidation( + &invalidation, + grow_down_tiling_size, + CornerSinglePixelRect(corner, grow_down_tiling_size)); + + // We should have lost all of the recordings in the bottom row as none of them + // are in the current interest rect (which is either the above or below it). + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(8, pile_.tiling().num_tiles_y()); + for (int i = 0; i < 6; ++i) { + for (int j = 0; j < 6; ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_EQ(j < 5, it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated all new pixels in the recording. + expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), + gfx::Rect(base_tiling_size)); + // But the new pixels don't cover the whole bottom row. + gfx::Rect bottom_row = gfx::UnionRects(pile_.tiling().TileBounds(0, 5), + pile_.tiling().TileBounds(5, 5)); + EXPECT_FALSE(expected_invalidation.Contains(bottom_row)); + // We invalidated the entire old bottom row. + expected_invalidation.Union(bottom_row); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, + base_tiling_size, + CornerSinglePixelRect(corner, base_tiling_size)); + + // When shrinking, we should have lost all the recordings in the bottom row + // not touching the interest rect. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + case TOP_RIGHT: + expect_tile = j < 5; + break; + case BOTTOM_LEFT: + // The interest rect in the bottom left tile means we'll record it. + expect_tile = j < 5 || (j == 5 && i == 0); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = j < 5 || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()); + } + } + + // When shrinking, the previously exposed region is invalidated. + expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), + gfx::Rect(base_tiling_size)); + // The whole bottom row of tiles (except any with the interest rect) are + // dropped. + gfx::Rect bottom_row_minus_existing_corner = gfx::UnionRects( + pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5)); + switch (corner) { + case TOP_LEFT: + case TOP_RIGHT: + // No tiles are kept in the changed region because it doesn't + // intersect with the interest rect. + break; + case BOTTOM_LEFT: + bottom_row_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(0, 5)); + break; + case BOTTOM_RIGHT: + bottom_row_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(5, 5)); + break; + } + + expected_invalidation.Union(bottom_row_minus_existing_corner); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation( + &invalidation, + grow_right_tiling_size, + CornerSinglePixelRect(corner, grow_right_tiling_size)); + + // We should have lost all of the recordings in the right column as none of + // them are in the current interest rect (which is either entirely left or + // right of it). + EXPECT_EQ(8, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < 6; ++i) { + for (int j = 0; j < 6; ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_EQ(i < 5, it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated all new pixels in the recording. + expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), + gfx::Rect(base_tiling_size)); + // But the new pixels don't cover the whole right_column. + gfx::Rect right_column = gfx::UnionRects(pile_.tiling().TileBounds(5, 0), + pile_.tiling().TileBounds(5, 5)); + EXPECT_FALSE(expected_invalidation.Contains(right_column)); + // We invalidated the entire old right column. + expected_invalidation.Union(right_column); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, + base_tiling_size, + CornerSinglePixelRect(corner, base_tiling_size)); + + // When shrinking, we should have lost all the recordings in the right column + // not touching the interest rect. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + case BOTTOM_LEFT: + // No tiles are kept in the changed region because it doesn't + // intersect with the interest rect. + expect_tile = i < 5; + break; + case TOP_RIGHT: + // The interest rect in the top right tile means we'll record it. + expect_tile = i < 5 || (j == 0 && i == 5); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = i < 5 || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()); + } + } + + // When shrinking, the previously exposed region is invalidated. + expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), + gfx::Rect(base_tiling_size)); + // The whole right column of tiles (except for ones with the interest rect) + // are dropped. + gfx::Rect right_column_minus_existing_corner = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); + switch (corner) { + case TOP_LEFT: + case BOTTOM_LEFT: + break; + case TOP_RIGHT: + right_column_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(5, 0)); + break; + case BOTTOM_RIGHT: + right_column_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(5, 5)); + break; + } + expected_invalidation.Union(right_column_minus_existing_corner); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation( + &invalidation, + grow_both_tiling_size, + CornerSinglePixelRect(corner, grow_both_tiling_size)); + + // We should have lost the recordings in the right column and bottom row. + EXPECT_EQ(8, pile_.tiling().num_tiles_x()); + EXPECT_EQ(8, pile_.tiling().num_tiles_y()); + for (int i = 0; i < 6; ++i) { + for (int j = 0; j < 6; ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_EQ(i < 5 && j < 5, it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated all new pixels in the recording. + expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), + gfx::Rect(base_tiling_size)); + // But the new pixels don't cover the whole right column or bottom row. + Region right_column_and_bottom_row = + UnionRegions(gfx::UnionRects(pile_.tiling().TileBounds(5, 0), + pile_.tiling().TileBounds(5, 5)), + gfx::UnionRects(pile_.tiling().TileBounds(0, 5), + pile_.tiling().TileBounds(5, 5))); + EXPECT_FALSE(expected_invalidation.Contains(right_column_and_bottom_row)); + // We invalidated the entire old right column and the old bottom row. + expected_invalidation.Union(right_column_and_bottom_row); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, base_tiling_size, + CornerSinglePixelRect(corner, base_tiling_size)); + + // We should have lost the recordings in the right column and bottom row, + // except where it intersects the interest rect. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + expect_tile = i < 5 && j < 5; + break; + case TOP_RIGHT: + // The interest rect in the top right tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5); + break; + case BOTTOM_LEFT: + // The interest rect in the bottom left tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()) + << i << "," << j; + } + } + + // We invalidated all previous pixels in the recording. + expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), + gfx::Rect(base_tiling_size)); + // The whole right column and bottom row of tiles (except for ones with the + // interest rect) are dropped. + Region right_column_and_bottom_row_minus_existing_corner = + right_column_and_bottom_row; + switch (corner) { + case TOP_LEFT: + break; + case BOTTOM_LEFT: + right_column_and_bottom_row_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(0, 5)); + break; + case TOP_RIGHT: + right_column_and_bottom_row_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(5, 0)); + break; + case BOTTOM_RIGHT: + right_column_and_bottom_row_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(5, 5)); + break; + } + expected_invalidation.Union( + right_column_and_bottom_row_minus_existing_corner); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); +} + +TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) { + Corner corner = GetParam(); + + // This size chosen to be larger than the interest rect size, which is + // at least kPixelDistanceToRecord * 2 in each dimension. + int tile_size = 100000; + // The small number subtracted keeps the last tile in each axis larger than + // the interest rect also. + int offset = -100; + gfx::Size base_tiling_size(6 * tile_size + offset, 6 * tile_size + offset); + gfx::Size grow_down_tiling_size(6 * tile_size + offset, + 6 * tile_size + offset + 5); + gfx::Size grow_right_tiling_size(6 * tile_size + offset + 5, + 6 * tile_size + offset); + gfx::Size grow_both_tiling_size(6 * tile_size + offset + 5, + 6 * tile_size + offset + 5); + + Region invalidation; + Region expected_invalidation; + + pile_.tiling().SetMaxTextureSize(gfx::Size(tile_size, tile_size)); + SetTilingSize(base_tiling_size); + + // We should have a recording for every tile. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // In this test (unlike the large resize test), as all growing and shrinking + // happens within tiles, the resulting invalidation is symmetrical, so use + // this enum to repeat the test both ways. + enum ChangeDirection { GROW, SHRINK, LAST_DIRECTION = SHRINK }; + + // Grow downward. + for (int dir = 0; dir <= LAST_DIRECTION; ++dir) { + gfx::Size new_tiling_size = + dir == GROW ? grow_down_tiling_size : base_tiling_size; + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, new_tiling_size, + CornerSinglePixelRect(corner, new_tiling_size)); + + // We should have lost the recordings in the bottom row that do not + // intersect the interest rect. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + case TOP_RIGHT: + expect_tile = j < 5; + break; + case BOTTOM_LEFT: + // The interest rect in the bottom left tile means we'll record it. + expect_tile = j < 5 || (j == 5 && i == 0); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = j < 5 || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the bottom row outside the new interest rect. The tile + // that insects the interest rect in invalidated only on its newly + // exposed or previously exposed pixels. + if (dir == GROW) { + // Only calculate the expected invalidation while growing, as the tile + // bounds post-growing is the newly exposed / previously exposed sizes. + // Post-shrinking, the tile bounds are smaller, so can't be used. + switch (corner) { + case TOP_LEFT: + case TOP_RIGHT: + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5)); + break; + case BOTTOM_LEFT: + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(1, 5), pile_.tiling().TileBounds(5, 5)); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size))); + break; + case BOTTOM_RIGHT: + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(4, 5)); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size))); + break; + } + } + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + } + + // Grow right. + for (int dir = 0; dir <= LAST_DIRECTION; ++dir) { + gfx::Size new_tiling_size = + dir == GROW ? grow_right_tiling_size : base_tiling_size; + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, new_tiling_size, + CornerSinglePixelRect(corner, new_tiling_size)); + + // We should have lost the recordings in the right column. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + case BOTTOM_LEFT: + expect_tile = i < 5; + break; + case TOP_RIGHT: + // The interest rect in the top right tile means we'll record it. + expect_tile = i < 5 || (j == 0 && i == 5); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = i < 5 || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the right column outside the new interest rect. The tile + // that insects the interest rect in invalidated only on its new or + // previously exposed pixels. + if (dir == GROW) { + // Calculate the expected invalidation the first time through the loop. + switch (corner) { + case TOP_LEFT: + case BOTTOM_LEFT: + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); + break; + case TOP_RIGHT: + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 1), pile_.tiling().TileBounds(5, 5)); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size))); + break; + case BOTTOM_RIGHT: + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 4)); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size))); + break; + } + } + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + } + + // Grow both. + for (int dir = 0; dir <= LAST_DIRECTION; ++dir) { + gfx::Size new_tiling_size = + dir == GROW ? grow_both_tiling_size : base_tiling_size; + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, new_tiling_size, + CornerSinglePixelRect(corner, new_tiling_size)); + + // We should have lost the recordings in the right column and bottom row. + // The tile that insects the interest rect in invalidated only on its new + // or previously exposed pixels. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + expect_tile = i < 5 && j < 5; + break; + case TOP_RIGHT: + // The interest rect in the top right tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5); + break; + case BOTTOM_LEFT: + // The interest rect in the bottom left tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()) + << i << "," << j; + } + } + + // We invalidated the right column and the bottom row outside the new + // interest rect. The tile that insects the interest rect in invalidated + // only on its new or previous exposed pixels. + if (dir == GROW) { + // Calculate the expected invalidation the first time through the loop. + switch (corner) { + case TOP_LEFT: + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); + expected_invalidation.Union( + gfx::UnionRects(pile_.tiling().TileBounds(0, 5), + pile_.tiling().TileBounds(5, 5))); + break; + case TOP_RIGHT: + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 1), pile_.tiling().TileBounds(5, 5)); + expected_invalidation.Union( + gfx::UnionRects(pile_.tiling().TileBounds(0, 5), + pile_.tiling().TileBounds(5, 5))); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size))); + break; + case BOTTOM_LEFT: + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); + expected_invalidation.Union( + gfx::UnionRects(pile_.tiling().TileBounds(1, 5), + pile_.tiling().TileBounds(5, 5))); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size))); + break; + case BOTTOM_RIGHT: + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 4)); + expected_invalidation.Union( + gfx::UnionRects(pile_.tiling().TileBounds(0, 5), + pile_.tiling().TileBounds(4, 5))); + expected_invalidation.Union(SubtractRegions( + pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size))); + break; + } + } + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + } +} + +INSTANTIATE_TEST_CASE_P( + PicturePileResizeCornerTests, + PicturePileResizeCornerTest, + ::testing::Values(TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT)); + +TEST_F(PicturePileTest, ResizePileInsideInterestRect) { + // This size chosen to be small enough that all the rects below fit inside the + // the interest rect, so they are smaller than kPixelDistanceToRecord in each + // dimension. + int tile_size = 100; + gfx::Size base_tiling_size(5 * tile_size, 5 * tile_size); + gfx::Size grow_down_tiling_size(5 * tile_size, 7 * tile_size); + gfx::Size grow_right_tiling_size(7 * tile_size, 5 * tile_size); + gfx::Size grow_both_tiling_size(7 * tile_size, 7 * tile_size); + + Region invalidation; + Region expected_invalidation; + + pile_.tiling().SetMaxTextureSize(gfx::Size(tile_size, tile_size)); + SetTilingSize(base_tiling_size); + + // We should have a recording for every tile. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + UpdateAndExpandInvalidation( + &invalidation, grow_down_tiling_size, gfx::Rect(1, 1)); + + // We should have a recording for every tile. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(8, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the newly exposed pixels on the bottom row of tiles. + expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), + gfx::Rect(base_tiling_size)); + Region bottom_row_new_pixels = + SubtractRegions(gfx::UnionRects(pile_.tiling().TileBounds(0, 5), + pile_.tiling().TileBounds(5, 5)), + gfx::Rect(base_tiling_size)); + EXPECT_TRUE(expected_invalidation.Contains(bottom_row_new_pixels)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1)); + + // We should have a recording for every tile. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the previously exposed pixels on the bottom row of tiles. + expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_TRUE(expected_invalidation.Contains(bottom_row_new_pixels)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation( + &invalidation, grow_right_tiling_size, gfx::Rect(1, 1)); + + // We should have a recording for every tile. + EXPECT_EQ(8, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the newly exposed pixels on the right column of tiles. + expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), + gfx::Rect(base_tiling_size)); + Region right_column_new_pixels = + SubtractRegions(gfx::UnionRects(pile_.tiling().TileBounds(5, 0), + pile_.tiling().TileBounds(5, 5)), + gfx::Rect(base_tiling_size)); + EXPECT_TRUE(expected_invalidation.Contains(right_column_new_pixels)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1)); + + // We should have lost the recordings that are now outside the tiling only. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the previously exposed pixels on the right column of tiles. + expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_TRUE(expected_invalidation.Contains(right_column_new_pixels)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation( + &invalidation, grow_both_tiling_size, gfx::Rect(1, 1)); + + // We should have a recording for every tile. + EXPECT_EQ(8, pile_.tiling().num_tiles_x()); + EXPECT_EQ(8, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the newly exposed pixels on the bottom row and right column + // of tiles. + expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), + gfx::Rect(base_tiling_size)); + Region bottom_row_and_right_column_new_pixels = SubtractRegions( + UnionRegions(gfx::UnionRects(pile_.tiling().TileBounds(0, 5), + pile_.tiling().TileBounds(5, 5)), + gfx::UnionRects(pile_.tiling().TileBounds(5, 0), + pile_.tiling().TileBounds(5, 5))), + gfx::Rect(base_tiling_size)); + EXPECT_TRUE( + expected_invalidation.Contains(bottom_row_and_right_column_new_pixels)); EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect()); + + // We should have lost the recordings that are now outside the tiling only. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the previously exposed pixels on the bottom row and right + // column of tiles. + expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_TRUE( + expected_invalidation.Contains(bottom_row_and_right_column_new_pixels)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); +} + +TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) { + // This size chosen to be small enough that all the rects below fit inside the + // the interest rect, so they are smaller than kPixelDistanceToRecord in each + // dimension. + int tile_size = 100; + gfx::Size base_tiling_size(5 * tile_size, 5 * tile_size); + gfx::Size grow_down_tiling_size(5 * tile_size, 5 * tile_size + 5); + gfx::Size grow_right_tiling_size(5 * tile_size + 5, 5 * tile_size); + gfx::Size grow_both_tiling_size(5 * tile_size + 5, 5 * tile_size + 5); + + Region invalidation; + Region expected_invalidation; + + pile_.tiling().SetMaxTextureSize(gfx::Size(tile_size, tile_size)); + SetTilingSize(base_tiling_size); + + // We should have a recording for every tile. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + UpdateAndExpandInvalidation( + &invalidation, grow_down_tiling_size, gfx::Rect(1, 1)); + + // We should have a recording for every tile. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the newly exposed pixels. + expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1)); + + // We should have a recording for every tile. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the previously exposed pixels. + expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation( + &invalidation, grow_right_tiling_size, gfx::Rect(1, 1)); + + // We should have a recording for every tile. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the newly exposed pixels. + expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1)); + + // We should have lost the recordings that are now outside the tiling only. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the previously exposed pixels. + expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation( + &invalidation, grow_both_tiling_size, gfx::Rect(1, 1)); + + // We should have a recording for every tile. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the newly exposed pixels. + expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); + + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect()); + + // We should have lost the recordings that are now outside the tiling only. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the previously exposed pixels. + expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); +} + +TEST_F(PicturePileTest, SolidRectangleIsSolid) { + // If the client has no contents, the solid state will be true. + Region invalidation1(tiling_rect()); + UpdateAndExpandInvalidation(&invalidation1, tiling_size(), tiling_rect()); + EXPECT_TRUE(pile_.is_solid_color()); + EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), pile_.solid_color()); + + // If there is a single rect that covers the view, the solid + // state will be true. + SkPaint paint; + paint.setColor(SK_ColorCYAN); + client_.add_draw_rect(tiling_rect(), paint); + Region invalidation2(tiling_rect()); + UpdateAndExpandInvalidation(&invalidation2, tiling_size(), tiling_rect()); + EXPECT_TRUE(pile_.is_solid_color()); + EXPECT_EQ(SK_ColorCYAN, pile_.solid_color()); + + // If a second smaller rect is draw that doesn't cover the viewport + // completely, the solid state will be false. + gfx::Rect smallRect = tiling_rect(); + smallRect.Inset(10, 10, 10, 10); + client_.add_draw_rect(smallRect, paint); + Region invalidation3(tiling_rect()); + UpdateAndExpandInvalidation(&invalidation3, tiling_size(), tiling_rect()); + EXPECT_FALSE(pile_.is_solid_color()); + + // If a third rect is drawn over everything, we should be solid again. + paint.setColor(SK_ColorRED); + client_.add_draw_rect(tiling_rect(), paint); + Region invalidation4(tiling_rect()); + UpdateAndExpandInvalidation(&invalidation4, tiling_size(), tiling_rect()); + EXPECT_TRUE(pile_.is_solid_color()); + EXPECT_EQ(SK_ColorRED, pile_.solid_color()); + + // If we draw too many, we don't bother doing the analysis and we should no + // longer be in a solid state. There are 8 rects, two clips and a translate. + client_.add_draw_rect(tiling_rect(), paint); + client_.add_draw_rect(tiling_rect(), paint); + client_.add_draw_rect(tiling_rect(), paint); + client_.add_draw_rect(tiling_rect(), paint); + client_.add_draw_rect(tiling_rect(), paint); + Region invalidation5(tiling_rect()); + UpdateAndExpandInvalidation(&invalidation5, tiling_size(), tiling_rect()); + EXPECT_FALSE(pile_.is_solid_color()); +} + +TEST_F(PicturePileTest, NonSolidRectangleOnOffsettedLayerIsNonSolid) { + gfx::Rect visible_rect(tiling_rect()); + visible_rect.Offset(gfx::Vector2d(1000, 1000)); + // The picture pile requires that the tiling completely encompass the viewport + // to make this test work correctly since the recorded viewport is an + // intersection of the tile size and viewport rect. This is possibly a flaw + // in |PicturePile|. + gfx::Size tiling_size(visible_rect.right(), visible_rect.bottom()); + // |Setup()| will create pictures here that mess with the test, clear it! + pile_.Clear(); + + SkPaint paint; + paint.setColor(SK_ColorCYAN); + + // Add a rect that doesn't cover the viewport completely, the solid state + // will be false. + gfx::Rect smallRect = visible_rect; + smallRect.Inset(10, 10, 10, 10); + client_.add_draw_rect(smallRect, paint); + Region invalidation(visible_rect); + UpdateAndExpandInvalidation(&invalidation, tiling_size, visible_rect); + EXPECT_FALSE(pile_.is_solid_color()); +} + +TEST_F(PicturePileTest, SetEmptyBounds) { + EXPECT_TRUE(pile_.is_solid_color()); + EXPECT_FALSE(pile_.tiling_size().IsEmpty()); + EXPECT_FALSE(pile_.picture_map().empty()); + EXPECT_TRUE(pile_.HasRecordings()); + pile_.SetEmptyBounds(); + EXPECT_FALSE(pile_.is_solid_color()); + EXPECT_TRUE(pile_.tiling_size().IsEmpty()); + EXPECT_TRUE(pile_.picture_map().empty()); + EXPECT_FALSE(pile_.HasRecordings()); } } // namespace diff --git a/chromium/cc/resources/picture_unittest.cc b/chromium/cc/resources/picture_unittest.cc index 1367c5fd89a..07faf0cf4a6 100644 --- a/chromium/cc/resources/picture_unittest.cc +++ b/chromium/cc/resources/picture_unittest.cc @@ -11,10 +11,8 @@ #include "cc/test/skia_common.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBBHFactory.h" -#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkGraphics.h" -#include "third_party/skia/include/core/SkPixelRef.h" -#include "ui/gfx/rect.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/skia_util.h" namespace cc { @@ -45,73 +43,56 @@ TEST(PictureTest, AsBase64String) { Picture::CreateFromValue(tmp.get()); EXPECT_FALSE(invalid_picture.get()); - Picture::RecordingMode kRecordingModes[] = {Picture::RECORD_NORMALLY, - Picture::RECORD_WITH_SKRECORD}; - // Single full-size rect picture. content_layer_client.add_draw_rect(layer_rect, red_paint); - for (size_t i = 0; i < arraysize(kRecordingModes); ++i) { - scoped_refptr<Picture> one_rect_picture = - Picture::Create(layer_rect, - &content_layer_client, - tile_grid_info, - false, - 0, - kRecordingModes[i]); - scoped_ptr<base::Value> serialized_one_rect(one_rect_picture->AsValue()); - - // Reconstruct the picture. - scoped_refptr<Picture> one_rect_picture_check = - Picture::CreateFromValue(serialized_one_rect.get()); - EXPECT_TRUE(!!one_rect_picture_check.get()); - - // Check for equivalence. - unsigned char one_rect_buffer[4 * 100 * 100] = {0}; - DrawPicture(one_rect_buffer, layer_rect, one_rect_picture); - unsigned char one_rect_buffer_check[4 * 100 * 100] = {0}; - DrawPicture(one_rect_buffer_check, layer_rect, one_rect_picture_check); - - EXPECT_EQ(one_rect_picture->LayerRect(), - one_rect_picture_check->LayerRect()); - EXPECT_EQ(one_rect_picture->OpaqueRect(), - one_rect_picture_check->OpaqueRect()); - EXPECT_TRUE(memcmp(one_rect_buffer, one_rect_buffer_check, 4 * 100 * 100) == - 0); - } + scoped_refptr<Picture> one_rect_picture = + Picture::Create(layer_rect, + &content_layer_client, + tile_grid_info, + false, + Picture::RECORD_NORMALLY); + scoped_ptr<base::Value> serialized_one_rect(one_rect_picture->AsValue()); + + // Reconstruct the picture. + scoped_refptr<Picture> one_rect_picture_check = + Picture::CreateFromValue(serialized_one_rect.get()); + EXPECT_TRUE(!!one_rect_picture_check.get()); + + // Check for equivalence. + unsigned char one_rect_buffer[4 * 100 * 100] = {0}; + DrawPicture(one_rect_buffer, layer_rect, one_rect_picture); + unsigned char one_rect_buffer_check[4 * 100 * 100] = {0}; + DrawPicture(one_rect_buffer_check, layer_rect, one_rect_picture_check); + + EXPECT_EQ(one_rect_picture->LayerRect(), one_rect_picture_check->LayerRect()); + EXPECT_EQ(0, memcmp(one_rect_buffer, one_rect_buffer_check, 4 * 100 * 100)); // Two rect picture. content_layer_client.add_draw_rect(gfx::Rect(25, 25, 50, 50), green_paint); - for (size_t i = 0; i < arraysize(kRecordingModes); ++i) { - scoped_refptr<Picture> two_rect_picture = - Picture::Create(layer_rect, - &content_layer_client, - tile_grid_info, - false, - 0, - Picture::RECORD_NORMALLY); - - scoped_ptr<base::Value> serialized_two_rect(two_rect_picture->AsValue()); - - // Reconstruct the picture. - scoped_refptr<Picture> two_rect_picture_check = - Picture::CreateFromValue(serialized_two_rect.get()); - EXPECT_TRUE(!!two_rect_picture_check.get()); - - // Check for equivalence. - unsigned char two_rect_buffer[4 * 100 * 100] = {0}; - DrawPicture(two_rect_buffer, layer_rect, two_rect_picture); - unsigned char two_rect_buffer_check[4 * 100 * 100] = {0}; - DrawPicture(two_rect_buffer_check, layer_rect, two_rect_picture_check); - - EXPECT_EQ(two_rect_picture->LayerRect(), - two_rect_picture_check->LayerRect()); - EXPECT_EQ(two_rect_picture->OpaqueRect(), - two_rect_picture_check->OpaqueRect()); - EXPECT_TRUE(memcmp(two_rect_buffer, two_rect_buffer_check, 4 * 100 * 100) == - 0); - } + scoped_refptr<Picture> two_rect_picture = + Picture::Create(layer_rect, + &content_layer_client, + tile_grid_info, + false, + Picture::RECORD_NORMALLY); + + scoped_ptr<base::Value> serialized_two_rect(two_rect_picture->AsValue()); + + // Reconstruct the picture. + scoped_refptr<Picture> two_rect_picture_check = + Picture::CreateFromValue(serialized_two_rect.get()); + EXPECT_TRUE(!!two_rect_picture_check.get()); + + // Check for equivalence. + unsigned char two_rect_buffer[4 * 100 * 100] = {0}; + DrawPicture(two_rect_buffer, layer_rect, two_rect_picture); + unsigned char two_rect_buffer_check[4 * 100 * 100] = {0}; + DrawPicture(two_rect_buffer_check, layer_rect, two_rect_picture_check); + + EXPECT_EQ(two_rect_picture->LayerRect(), two_rect_picture_check->LayerRect()); + EXPECT_EQ(0, memcmp(two_rect_buffer, two_rect_buffer_check, 4 * 100 * 100)); } TEST(PictureTest, PixelRefIterator) { @@ -152,7 +133,6 @@ TEST(PictureTest, PixelRefIterator) { &content_layer_client, tile_grid_info, true, - 0, Picture::RECORD_NORMALLY); // Default iterator does not have any pixel refs @@ -253,7 +233,6 @@ TEST(PictureTest, PixelRefIteratorNonZeroLayer) { &content_layer_client, tile_grid_info, true, - 0, Picture::RECORD_NORMALLY); // Default iterator does not have any pixel refs @@ -377,7 +356,6 @@ TEST(PictureTest, PixelRefIteratorOnePixelQuery) { &content_layer_client, tile_grid_info, true, - 0, Picture::RECORD_NORMALLY); for (int y = 0; y < 4; ++y) { @@ -427,7 +405,6 @@ TEST(PictureTest, CreateFromSkpValue) { &content_layer_client, tile_grid_info, false, - 0, Picture::RECORD_NORMALLY); scoped_ptr<base::Value> serialized_one_rect( one_rect_picture->AsValue()); @@ -446,8 +423,6 @@ TEST(PictureTest, CreateFromSkpValue) { EXPECT_EQ(100, one_rect_picture_check->LayerRect().width()); EXPECT_EQ(200, one_rect_picture_check->LayerRect().height()); - EXPECT_EQ(100, one_rect_picture_check->OpaqueRect().width()); - EXPECT_EQ(200, one_rect_picture_check->OpaqueRect().height()); } TEST(PictureTest, RecordingModes) { @@ -467,45 +442,33 @@ TEST(PictureTest, RecordingModes) { &content_layer_client, tile_grid_info, false, - 0, Picture::RECORD_NORMALLY); EXPECT_TRUE(content_layer_client.last_canvas() != NULL); EXPECT_EQ(ContentLayerClient::GRAPHICS_CONTEXT_ENABLED, content_layer_client.last_context_status()); - EXPECT_TRUE(picture); + EXPECT_TRUE(picture.get()); picture = Picture::Create(layer_rect, &content_layer_client, tile_grid_info, false, - 0, Picture::RECORD_WITH_SK_NULL_CANVAS); EXPECT_TRUE(content_layer_client.last_canvas() != NULL); EXPECT_EQ(ContentLayerClient::GRAPHICS_CONTEXT_ENABLED, content_layer_client.last_context_status()); - EXPECT_TRUE(picture); + EXPECT_TRUE(picture.get()); picture = Picture::Create(layer_rect, &content_layer_client, tile_grid_info, false, - 0, Picture::RECORD_WITH_PAINTING_DISABLED); EXPECT_TRUE(content_layer_client.last_canvas() != NULL); EXPECT_EQ(ContentLayerClient::GRAPHICS_CONTEXT_DISABLED, content_layer_client.last_context_status()); - EXPECT_TRUE(picture); - - picture = Picture::Create(layer_rect, - &content_layer_client, - tile_grid_info, - false, - 0, - Picture::RECORD_WITH_SKRECORD); - EXPECT_TRUE(content_layer_client.last_canvas() != NULL); - EXPECT_TRUE(picture); + EXPECT_TRUE(picture.get()); - EXPECT_EQ(4, Picture::RECORDING_MODE_COUNT); + EXPECT_EQ(3, Picture::RECORDING_MODE_COUNT); } } // namespace diff --git a/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc b/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc index 1df2362a5ae..175e7d40f22 100644 --- a/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc +++ b/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc @@ -8,12 +8,53 @@ #include "base/containers/stack_container.h" #include "base/debug/trace_event.h" +#include "base/debug/trace_event_argument.h" +#include "base/strings/stringprintf.h" #include "cc/debug/traced_value.h" +#include "cc/resources/raster_buffer.h" #include "cc/resources/resource.h" +#include "gpu/command_buffer/client/gles2_interface.h" namespace cc { namespace { +class RasterBufferImpl : public RasterBuffer { + public: + RasterBufferImpl(ResourceProvider* resource_provider, + const Resource* resource) + : resource_provider_(resource_provider), + resource_(resource), + memory_(NULL), + stride_(0) { + resource_provider_->AcquirePixelBuffer(resource_->id()); + memory_ = resource_provider_->MapPixelBuffer(resource_->id(), &stride_); + } + + ~RasterBufferImpl() override { + resource_provider_->ReleasePixelBuffer(resource_->id()); + } + + // Overridden from RasterBuffer: + void Playback(const RasterSource* raster_source, + const gfx::Rect& rect, + float scale) override { + if (!memory_) + return; + + RasterWorkerPool::PlaybackToMemory(memory_, resource_->format(), + resource_->size(), stride_, + raster_source, rect, scale); + } + + private: + ResourceProvider* resource_provider_; + const Resource* resource_; + uint8_t* memory_; + int stride_; + + DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); +}; + const int kCheckForCompletedRasterTasksDelayMs = 6; const size_t kMaxScheduledRasterTasks = 48; @@ -21,17 +62,50 @@ const size_t kMaxScheduledRasterTasks = 48; typedef base::StackVector<RasterTask*, kMaxScheduledRasterTasks> RasterTaskVector; +TaskSetCollection NonEmptyTaskSetsFromTaskCounts(const size_t* task_counts) { + TaskSetCollection task_sets; + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + if (task_counts[task_set]) + task_sets[task_set] = true; + } + return task_sets; +} + +void AddTaskSetsToTaskCounts(size_t* task_counts, + const TaskSetCollection& task_sets) { + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + if (task_sets[task_set]) + task_counts[task_set]++; + } +} + +void RemoveTaskSetsFromTaskCounts(size_t* task_counts, + const TaskSetCollection& task_sets) { + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + if (task_sets[task_set]) + task_counts[task_set]--; + } +} + } // namespace +PixelBufferRasterWorkerPool::RasterTaskState::RasterTaskState( + RasterTask* task, + const TaskSetCollection& task_sets) + : type(UNSCHEDULED), task(task), task_sets(task_sets) { +} + // static scoped_ptr<RasterWorkerPool> PixelBufferRasterWorkerPool::Create( base::SequencedTaskRunner* task_runner, TaskGraphRunner* task_graph_runner, + ContextProvider* context_provider, ResourceProvider* resource_provider, size_t max_transfer_buffer_usage_bytes) { return make_scoped_ptr<RasterWorkerPool>( new PixelBufferRasterWorkerPool(task_runner, task_graph_runner, + context_provider, resource_provider, max_transfer_buffer_usage_bytes)); } @@ -39,23 +113,19 @@ scoped_ptr<RasterWorkerPool> PixelBufferRasterWorkerPool::Create( PixelBufferRasterWorkerPool::PixelBufferRasterWorkerPool( base::SequencedTaskRunner* task_runner, TaskGraphRunner* task_graph_runner, + ContextProvider* context_provider, ResourceProvider* resource_provider, size_t max_transfer_buffer_usage_bytes) : task_runner_(task_runner), task_graph_runner_(task_graph_runner), namespace_token_(task_graph_runner->GetNamespaceToken()), + context_provider_(context_provider), resource_provider_(resource_provider), shutdown_(false), scheduled_raster_task_count_(0u), - raster_tasks_required_for_activation_count_(0u), bytes_pending_upload_(0u), max_bytes_pending_upload_(max_transfer_buffer_usage_bytes), has_performed_uploads_since_last_flush_(false), - should_notify_client_if_no_tasks_are_pending_(false), - should_notify_client_if_no_tasks_required_for_activation_are_pending_( - false), - raster_finished_task_pending_(false), - raster_required_for_activation_finished_task_pending_(false), check_for_completed_raster_task_notifier_( task_runner, base::Bind(&PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks, @@ -63,6 +133,8 @@ PixelBufferRasterWorkerPool::PixelBufferRasterWorkerPool( base::TimeDelta::FromMilliseconds( kCheckForCompletedRasterTasksDelayMs)), raster_finished_weak_ptr_factory_(this) { + DCHECK(context_provider_); + std::fill(task_counts_, task_counts_ + kNumberOfTaskSets, 0); } PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() { @@ -70,7 +142,7 @@ PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() { DCHECK_EQ(0u, raster_tasks_with_pending_upload_.size()); DCHECK_EQ(0u, completed_raster_tasks_.size()); DCHECK_EQ(0u, completed_image_decode_tasks_.size()); - DCHECK_EQ(0u, raster_tasks_required_for_activation_count_); + DCHECK(NonEmptyTaskSetsFromTaskCounts(task_counts_).none()); } Rasterizer* PixelBufferRasterWorkerPool::AsRasterizer() { return this; } @@ -91,7 +163,7 @@ void PixelBufferRasterWorkerPool::Shutdown() { CheckForCompletedRasterizerTasks(); CheckForCompletedUploads(); - check_for_completed_raster_task_notifier_.Cancel(); + check_for_completed_raster_task_notifier_.Shutdown(); for (RasterTaskState::Vector::iterator it = raster_task_states_.begin(); it != raster_task_states_.end(); @@ -110,19 +182,11 @@ void PixelBufferRasterWorkerPool::Shutdown() { void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::ScheduleTasks"); - DCHECK_EQ(queue->required_for_activation_count, - static_cast<size_t>( - std::count_if(queue->items.begin(), - queue->items.end(), - RasterTaskQueue::Item::IsRequiredForActivation))); - - if (!should_notify_client_if_no_tasks_are_pending_) + if (should_notify_client_if_no_tasks_are_pending_.none()) TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); - should_notify_client_if_no_tasks_are_pending_ = true; - should_notify_client_if_no_tasks_required_for_activation_are_pending_ = true; - - raster_tasks_required_for_activation_count_ = 0u; + should_notify_client_if_no_tasks_are_pending_.set(); + std::fill(task_counts_, task_counts_ + kNumberOfTaskSets, 0); // Update raster task state and remove items from old queue. for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); @@ -150,21 +214,19 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { if (state_it != raster_task_states_.end()) { RasterTaskState& state = *state_it; - state.required_for_activation = item.required_for_activation; + state.task_sets = item.task_sets; // |raster_tasks_required_for_activation_count| accounts for all tasks // that need to complete before we can send a "ready to activate" signal. // Tasks that have already completed should not be part of this count. - if (state.type != RasterTaskState::COMPLETED) { - raster_tasks_required_for_activation_count_ += - item.required_for_activation; - } + if (state.type != RasterTaskState::COMPLETED) + AddTaskSetsToTaskCounts(task_counts_, item.task_sets); + continue; } DCHECK(!task->HasBeenScheduled()); - raster_task_states_.push_back( - RasterTaskState(task, item.required_for_activation)); - raster_tasks_required_for_activation_count_ += item.required_for_activation; + raster_task_states_.push_back(RasterTaskState(task, item.task_sets)); + AddTaskSetsToTaskCounts(task_counts_, item.task_sets); } // Determine what tasks in old queue need to be canceled. @@ -196,8 +258,8 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { state.type = RasterTaskState::COMPLETED; } - // No longer required for activation. - state.required_for_activation = false; + // No longer in any task set. + state.task_sets.reset(); } raster_tasks_.Swap(queue); @@ -216,12 +278,7 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { check_for_completed_raster_task_notifier_.Schedule(); TRACE_EVENT_ASYNC_STEP_INTO1( - "cc", - "ScheduledTasks", - this, - StateName(), - "state", - TracedValue::FromValue(StateAsValue().release())); + "cc", "ScheduledTasks", this, StateName(), "state", StateAsValue()); } void PixelBufferRasterWorkerPool::CheckForCompletedTasks() { @@ -259,51 +316,30 @@ void PixelBufferRasterWorkerPool::CheckForCompletedTasks() { completed_raster_tasks_.clear(); } -SkCanvas* PixelBufferRasterWorkerPool::AcquireCanvasForRaster( - RasterTask* task) { - DCHECK(std::find_if(raster_task_states_.begin(), - raster_task_states_.end(), - RasterTaskState::TaskComparator(task)) != - raster_task_states_.end()); - resource_provider_->AcquirePixelRasterBuffer(task->resource()->id()); - return resource_provider_->MapPixelRasterBuffer(task->resource()->id()); +scoped_ptr<RasterBuffer> PixelBufferRasterWorkerPool::AcquireBufferForRaster( + const Resource* resource) { + return make_scoped_ptr<RasterBuffer>( + new RasterBufferImpl(resource_provider_, resource)); } -void PixelBufferRasterWorkerPool::ReleaseCanvasForRaster(RasterTask* task) { - DCHECK(std::find_if(raster_task_states_.begin(), - raster_task_states_.end(), - RasterTaskState::TaskComparator(task)) != - raster_task_states_.end()); - resource_provider_->ReleasePixelRasterBuffer(task->resource()->id()); +void PixelBufferRasterWorkerPool::ReleaseBufferForRaster( + scoped_ptr<RasterBuffer> buffer) { + // Nothing to do here. RasterBufferImpl destructor cleans up after itself. } -void PixelBufferRasterWorkerPool::OnRasterFinished() { - TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::OnRasterFinished"); - - // |should_notify_client_if_no_tasks_are_pending_| can be set to false as - // a result of a scheduled CheckForCompletedRasterTasks() call. No need to - // perform another check in that case as we've already notified the client. - if (!should_notify_client_if_no_tasks_are_pending_) +void PixelBufferRasterWorkerPool::OnRasterFinished(TaskSet task_set) { + TRACE_EVENT2("cc", + "PixelBufferRasterWorkerPool::OnRasterFinished", + "task_set", + task_set, + "should_notify_client_if_no_tasks_are_pending", + should_notify_client_if_no_tasks_are_pending_[task_set]); + + // There's no need to call CheckForCompletedRasterTasks() if the client has + // already been notified. + if (!should_notify_client_if_no_tasks_are_pending_[task_set]) return; - raster_finished_task_pending_ = false; - - // Call CheckForCompletedRasterTasks() when we've finished running all - // raster tasks needed since last time ScheduleTasks() was called. - // This reduces latency between the time when all tasks have finished - // running and the time when the client is notified. - CheckForCompletedRasterTasks(); -} - -void PixelBufferRasterWorkerPool::OnRasterRequiredForActivationFinished() { - TRACE_EVENT0( - "cc", - "PixelBufferRasterWorkerPool::OnRasterRequiredForActivationFinished"); - - // Analogous to OnRasterTasksFinished(), there's no need to call - // CheckForCompletedRasterTasks() if the client has already been notified. - if (!should_notify_client_if_no_tasks_required_for_activation_are_pending_) - return; - raster_required_for_activation_finished_task_pending_ = false; + raster_finished_tasks_pending_[task_set] = false; // This reduces latency between the time when all tasks required for // activation have finished running and the time when the client is @@ -315,7 +351,7 @@ void PixelBufferRasterWorkerPool::FlushUploads() { if (!has_performed_uploads_since_last_flush_) return; - resource_provider_->ShallowFlushIfSupported(); + context_provider_->ContextGL()->ShallowFlushCHROMIUM(); has_performed_uploads_since_last_flush_ = false; } @@ -343,8 +379,10 @@ void PixelBufferRasterWorkerPool::CheckForCompletedUploads() { } DCHECK(client_); + TaskSetCollection tasks_that_should_be_forced_to_complete = + client_->TasksThatShouldBeForcedToComplete(); bool should_force_some_uploads_to_complete = - shutdown_ || client_->ShouldForceTasksRequiredForActivationToComplete(); + shutdown_ || tasks_that_should_be_forced_to_complete.any(); if (should_force_some_uploads_to_complete) { RasterTask::Vector tasks_with_uploads_to_force; @@ -358,9 +396,10 @@ void PixelBufferRasterWorkerPool::CheckForCompletedUploads() { DCHECK(state_it != raster_task_states_.end()); const RasterTaskState& state = *state_it; - // Force all uploads required for activation to complete. + // Force all uploads to complete for which the client requests to do so. // During shutdown, force all pending uploads to complete. - if (shutdown_ || state.required_for_activation) { + if (shutdown_ || + (state.task_sets & tasks_that_should_be_forced_to_complete).any()) { tasks_with_uploads_to_force.push_back(task); tasks_with_completed_uploads.push_back(task); it = raster_tasks_with_pending_upload_.erase(it); @@ -403,20 +442,15 @@ void PixelBufferRasterWorkerPool::CheckForCompletedUploads() { task->CompleteOnOriginThread(this); task->DidComplete(); - // Async set pixels commands are not necessarily processed in-sequence with - // drawing commands. Read lock fences are required to ensure that async - // commands don't access the resource while used for drawing. - resource_provider_->EnableReadLockFences(task->resource()->id(), true); - DCHECK(std::find(completed_raster_tasks_.begin(), completed_raster_tasks_.end(), task) == completed_raster_tasks_.end()); completed_raster_tasks_.push_back(task); state.type = RasterTaskState::COMPLETED; - DCHECK_LE(static_cast<size_t>(state.required_for_activation), - raster_tasks_required_for_activation_count_); - raster_tasks_required_for_activation_count_ -= - state.required_for_activation; + // Triggers if the current task belongs to a set that should be empty. + DCHECK((state.task_sets & ~NonEmptyTaskSetsFromTaskCounts(task_counts_)) + .none()); + RemoveTaskSetsFromTaskCounts(task_counts_, state.task_sets); } } @@ -427,70 +461,57 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() { // Since this function can be called directly, cancel any pending checks. check_for_completed_raster_task_notifier_.Cancel(); - DCHECK(should_notify_client_if_no_tasks_are_pending_); + DCHECK(should_notify_client_if_no_tasks_are_pending_.any()); CheckForCompletedRasterizerTasks(); CheckForCompletedUploads(); FlushUploads(); // Determine what client notifications to generate. - bool will_notify_client_that_no_tasks_required_for_activation_are_pending = - (should_notify_client_if_no_tasks_required_for_activation_are_pending_ && - !raster_required_for_activation_finished_task_pending_ && - !HasPendingTasksRequiredForActivation()); - bool will_notify_client_that_no_tasks_are_pending = - (should_notify_client_if_no_tasks_are_pending_ && - !raster_required_for_activation_finished_task_pending_ && - !raster_finished_task_pending_ && !HasPendingTasks()); + TaskSetCollection will_notify_client_that_no_tasks_are_pending = + should_notify_client_if_no_tasks_are_pending_ & + ~raster_finished_tasks_pending_ & ~PendingTasks(); // Adjust the need to generate notifications before scheduling more tasks. - should_notify_client_if_no_tasks_required_for_activation_are_pending_ &= - !will_notify_client_that_no_tasks_required_for_activation_are_pending; should_notify_client_if_no_tasks_are_pending_ &= - !will_notify_client_that_no_tasks_are_pending; + ~will_notify_client_that_no_tasks_are_pending; scheduled_raster_task_count_ = 0; if (PendingRasterTaskCount()) ScheduleMoreTasks(); TRACE_EVENT_ASYNC_STEP_INTO1( - "cc", - "ScheduledTasks", - this, - StateName(), - "state", - TracedValue::FromValue(StateAsValue().release())); + "cc", "ScheduledTasks", this, StateName(), "state", StateAsValue()); // Schedule another check for completed raster tasks while there are // pending raster tasks or pending uploads. - if (HasPendingTasks()) + if (PendingTasks().any()) check_for_completed_raster_task_notifier_.Schedule(); - // Generate client notifications. - if (will_notify_client_that_no_tasks_required_for_activation_are_pending) { - DCHECK(!HasPendingTasksRequiredForActivation()); - client_->DidFinishRunningTasksRequiredForActivation(); - } - if (will_notify_client_that_no_tasks_are_pending) { + if (should_notify_client_if_no_tasks_are_pending_.none()) TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); - DCHECK(!HasPendingTasksRequiredForActivation()); - client_->DidFinishRunningTasks(); + + // Generate client notifications. + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + if (will_notify_client_that_no_tasks_are_pending[task_set]) { + DCHECK(!PendingTasks()[task_set]); + client_->DidFinishRunningTasks(task_set); + } } } void PixelBufferRasterWorkerPool::ScheduleMoreTasks() { TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::ScheduleMoreTasks"); - RasterTaskVector tasks; - RasterTaskVector tasks_required_for_activation; + RasterTaskVector tasks[kNumberOfTaskSets]; unsigned priority = kRasterTaskPriorityBase; graph_.Reset(); size_t bytes_pending_upload = bytes_pending_upload_; - bool did_throttle_raster_tasks = false; - bool did_throttle_raster_tasks_required_for_activation = false; + TaskSetCollection did_throttle_raster_tasks; + size_t scheduled_raster_task_count = 0; for (RasterTaskQueue::Item::Vector::const_iterator it = raster_tasks_.items.begin(); @@ -498,6 +519,7 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() { ++it) { const RasterTaskQueue::Item& item = *it; RasterTask* task = item.task; + DCHECK(item.task_sets.any()); // |raster_task_states_| contains the state of all tasks that we have not // yet run reply callbacks for. @@ -518,13 +540,14 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() { continue; } - // All raster tasks need to be throttled by bytes of pending uploads. + // All raster tasks need to be throttled by bytes of pending uploads, + // but if it's the only task allow it to complete no matter what its size, + // to prevent starvation of the task queue. size_t new_bytes_pending_upload = bytes_pending_upload; new_bytes_pending_upload += task->resource()->bytes(); - if (new_bytes_pending_upload > max_bytes_pending_upload_) { - did_throttle_raster_tasks = true; - if (item.required_for_activation) - did_throttle_raster_tasks_required_for_activation = true; + if (new_bytes_pending_upload > max_bytes_pending_upload_ && + bytes_pending_upload) { + did_throttle_raster_tasks |= item.task_sets; continue; } @@ -536,10 +559,8 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() { } // Throttle raster tasks based on kMaxScheduledRasterTasks. - if (tasks.container().size() >= kMaxScheduledRasterTasks) { - did_throttle_raster_tasks = true; - if (item.required_for_activation) - did_throttle_raster_tasks_required_for_activation = true; + if (scheduled_raster_task_count >= kMaxScheduledRasterTasks) { + did_throttle_raster_tasks |= item.task_sets; continue; } @@ -553,81 +574,57 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() { InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); - tasks.container().push_back(task); - if (item.required_for_activation) - tasks_required_for_activation.container().push_back(task); + ++scheduled_raster_task_count; + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + if (item.task_sets[task_set]) + tasks[task_set].container().push_back(task); + } } // Cancel existing OnRasterFinished callbacks. raster_finished_weak_ptr_factory_.InvalidateWeakPtrs(); - scoped_refptr<RasterizerTask> - new_raster_required_for_activation_finished_task; - - size_t scheduled_raster_task_required_for_activation_count = - tasks_required_for_activation.container().size(); - DCHECK_LE(scheduled_raster_task_required_for_activation_count, - raster_tasks_required_for_activation_count_); - // Schedule OnRasterTasksRequiredForActivationFinished call only when - // notification is pending and throttling is not preventing all pending - // tasks required for activation from being scheduled. - if (!did_throttle_raster_tasks_required_for_activation && - should_notify_client_if_no_tasks_required_for_activation_are_pending_) { - new_raster_required_for_activation_finished_task = - CreateRasterRequiredForActivationFinishedTask( - raster_tasks_.required_for_activation_count, - task_runner_.get(), - base::Bind(&PixelBufferRasterWorkerPool:: - OnRasterRequiredForActivationFinished, - raster_finished_weak_ptr_factory_.GetWeakPtr())); - raster_required_for_activation_finished_task_pending_ = true; - InsertNodeForTask(&graph_, - new_raster_required_for_activation_finished_task.get(), - kRasterRequiredForActivationFinishedTaskPriority, - scheduled_raster_task_required_for_activation_count); - for (RasterTaskVector::ContainerType::const_iterator it = - tasks_required_for_activation.container().begin(); - it != tasks_required_for_activation.container().end(); - ++it) { - graph_.edges.push_back(TaskGraph::Edge( - *it, new_raster_required_for_activation_finished_task.get())); + scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets]; + size_t scheduled_task_counts[kNumberOfTaskSets] = {0}; + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + scheduled_task_counts[task_set] = tasks[task_set].container().size(); + DCHECK_LE(scheduled_task_counts[task_set], task_counts_[task_set]); + // Schedule OnRasterFinished call for task set only when notification is + // pending and throttling is not preventing all pending tasks in the set + // from being scheduled. + if (!did_throttle_raster_tasks[task_set] && + should_notify_client_if_no_tasks_are_pending_[task_set]) { + new_raster_finished_tasks[task_set] = CreateRasterFinishedTask( + task_runner_.get(), + base::Bind(&PixelBufferRasterWorkerPool::OnRasterFinished, + raster_finished_weak_ptr_factory_.GetWeakPtr(), + task_set)); + raster_finished_tasks_pending_[task_set] = true; + InsertNodeForTask(&graph_, + new_raster_finished_tasks[task_set].get(), + kRasterFinishedTaskPriority, + scheduled_task_counts[task_set]); + for (RasterTaskVector::ContainerType::const_iterator it = + tasks[task_set].container().begin(); + it != tasks[task_set].container().end(); + ++it) { + graph_.edges.push_back( + TaskGraph::Edge(*it, new_raster_finished_tasks[task_set].get())); + } } } - scoped_refptr<RasterizerTask> new_raster_finished_task; - - size_t scheduled_raster_task_count = tasks.container().size(); DCHECK_LE(scheduled_raster_task_count, PendingRasterTaskCount()); - // Schedule OnRasterTasksFinished call only when notification is pending - // and throttling is not preventing all pending tasks from being scheduled. - if (!did_throttle_raster_tasks && - should_notify_client_if_no_tasks_are_pending_) { - new_raster_finished_task = CreateRasterFinishedTask( - task_runner_.get(), - base::Bind(&PixelBufferRasterWorkerPool::OnRasterFinished, - raster_finished_weak_ptr_factory_.GetWeakPtr())); - raster_finished_task_pending_ = true; - InsertNodeForTask(&graph_, - new_raster_finished_task.get(), - kRasterFinishedTaskPriority, - scheduled_raster_task_count); - for (RasterTaskVector::ContainerType::const_iterator it = - tasks.container().begin(); - it != tasks.container().end(); - ++it) { - graph_.edges.push_back( - TaskGraph::Edge(*it, new_raster_finished_task.get())); - } - } ScheduleTasksOnOriginThread(this, &graph_); task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); scheduled_raster_task_count_ = scheduled_raster_task_count; - raster_finished_task_ = new_raster_finished_task; - raster_required_for_activation_finished_task_ = - new_raster_required_for_activation_finished_task; + std::copy(new_raster_finished_tasks, + new_raster_finished_tasks + kNumberOfTaskSets, + raster_finished_tasks_); } unsigned PixelBufferRasterWorkerPool::PendingRasterTaskCount() const { @@ -637,12 +634,8 @@ unsigned PixelBufferRasterWorkerPool::PendingRasterTaskCount() const { return raster_task_states_.size() - num_completed_raster_tasks; } -bool PixelBufferRasterWorkerPool::HasPendingTasks() const { - return PendingRasterTaskCount() || !raster_tasks_with_pending_upload_.empty(); -} - -bool PixelBufferRasterWorkerPool::HasPendingTasksRequiredForActivation() const { - return !!raster_tasks_required_for_activation_count_; +TaskSetCollection PixelBufferRasterWorkerPool::PendingTasks() const { + return NonEmptyTaskSetsFromTaskCounts(task_counts_); } const char* PixelBufferRasterWorkerPool::StateName() const { @@ -686,30 +679,23 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterizerTasks() { RasterTaskState& state = *state_it; DCHECK_EQ(RasterTaskState::SCHEDULED, state.type); - // Balanced with MapPixelRasterBuffer() call in AcquireCanvasForRaster(). - bool content_has_changed = resource_provider_->UnmapPixelRasterBuffer( - raster_task->resource()->id()); + resource_provider_->UnmapPixelBuffer(raster_task->resource()->id()); - // |content_has_changed| can be false as result of task being canceled or - // task implementation deciding not to modify bitmap (ie. analysis of raster - // commands detected content as a solid color). - if (!content_has_changed) { + if (!raster_task->HasFinishedRunning()) { + // When priorites change, a raster task can be canceled as a result of + // no longer being of high enough priority to fit in our throttled + // raster task budget. The task has not yet completed in this case. raster_task->WillComplete(); raster_task->CompleteOnOriginThread(this); raster_task->DidComplete(); - if (!raster_task->HasFinishedRunning()) { - // When priorites change, a raster task can be canceled as a result of - // no longer being of high enough priority to fit in our throttled - // raster task budget. The task has not yet completed in this case. - RasterTaskQueue::Item::Vector::const_iterator item_it = - std::find_if(raster_tasks_.items.begin(), - raster_tasks_.items.end(), - RasterTaskQueue::Item::TaskComparator(raster_task)); - if (item_it != raster_tasks_.items.end()) { - state.type = RasterTaskState::UNSCHEDULED; - continue; - } + RasterTaskQueue::Item::Vector::const_iterator item_it = + std::find_if(raster_tasks_.items.begin(), + raster_tasks_.items.end(), + RasterTaskQueue::Item::TaskComparator(raster_task)); + if (item_it != raster_tasks_.items.end()) { + state.type = RasterTaskState::UNSCHEDULED; + continue; } DCHECK(std::find(completed_raster_tasks_.begin(), @@ -717,15 +703,13 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterizerTasks() { raster_task) == completed_raster_tasks_.end()); completed_raster_tasks_.push_back(raster_task); state.type = RasterTaskState::COMPLETED; - DCHECK_LE(static_cast<size_t>(state.required_for_activation), - raster_tasks_required_for_activation_count_); - raster_tasks_required_for_activation_count_ -= - state.required_for_activation; + // Triggers if the current task belongs to a set that should be empty. + DCHECK((state.task_sets & ~NonEmptyTaskSetsFromTaskCounts(task_counts_)) + .none()); + RemoveTaskSetsFromTaskCounts(task_counts_, state.task_sets); continue; } - DCHECK(raster_task->HasFinishedRunning()); - resource_provider_->BeginSetPixels(raster_task->resource()->id()); has_performed_uploads_since_last_flush_ = true; @@ -736,29 +720,30 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterizerTasks() { completed_tasks_.clear(); } -scoped_ptr<base::Value> PixelBufferRasterWorkerPool::StateAsValue() const { - scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); - +scoped_refptr<base::debug::ConvertableToTraceFormat> +PixelBufferRasterWorkerPool::StateAsValue() const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); state->SetInteger("completed_count", completed_raster_tasks_.size()); - state->SetInteger("pending_count", raster_task_states_.size()); + state->BeginArray("pending_count"); + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) + state->AppendInteger(task_counts_[task_set]); + state->EndArray(); state->SetInteger("pending_upload_count", raster_tasks_with_pending_upload_.size()); - state->SetInteger("pending_required_for_activation_count", - raster_tasks_required_for_activation_count_); - state->Set("throttle_state", ThrottleStateAsValue().release()); - return state.PassAs<base::Value>(); + state->BeginDictionary("throttle_state"); + ThrottleStateAsValueInto(state.get()); + state->EndDictionary(); + return state; } -scoped_ptr<base::Value> PixelBufferRasterWorkerPool::ThrottleStateAsValue() - const { - scoped_ptr<base::DictionaryValue> throttle_state(new base::DictionaryValue); - +void PixelBufferRasterWorkerPool::ThrottleStateAsValueInto( + base::debug::TracedValue* throttle_state) const { throttle_state->SetInteger("bytes_available_for_upload", max_bytes_pending_upload_ - bytes_pending_upload_); throttle_state->SetInteger("bytes_pending_upload", bytes_pending_upload_); throttle_state->SetInteger("scheduled_raster_task_count", scheduled_raster_task_count_); - return throttle_state.PassAs<base::Value>(); } } // namespace cc diff --git a/chromium/cc/resources/pixel_buffer_raster_worker_pool.h b/chromium/cc/resources/pixel_buffer_raster_worker_pool.h index a2f15fd6f51..7fb45ecd641 100644 --- a/chromium/cc/resources/pixel_buffer_raster_worker_pool.h +++ b/chromium/cc/resources/pixel_buffer_raster_worker_pool.h @@ -11,9 +11,17 @@ #include "base/memory/weak_ptr.h" #include "base/values.h" #include "cc/base/delayed_unique_notifier.h" +#include "cc/output/context_provider.h" #include "cc/resources/raster_worker_pool.h" #include "cc/resources/rasterizer.h" +namespace base { +namespace debug { +class ConvertableToTraceFormat; +class TracedValue; +} +} + namespace cc { class ResourceProvider; @@ -21,26 +29,28 @@ class CC_EXPORT PixelBufferRasterWorkerPool : public RasterWorkerPool, public Rasterizer, public RasterizerTaskClient { public: - virtual ~PixelBufferRasterWorkerPool(); + ~PixelBufferRasterWorkerPool() override; static scoped_ptr<RasterWorkerPool> Create( base::SequencedTaskRunner* task_runner, TaskGraphRunner* task_graph_runner, + ContextProvider* context_provider, ResourceProvider* resource_provider, size_t max_transfer_buffer_usage_bytes); // Overridden from RasterWorkerPool: - virtual Rasterizer* AsRasterizer() OVERRIDE; + Rasterizer* AsRasterizer() override; // Overridden from Rasterizer: - virtual void SetClient(RasterizerClient* client) OVERRIDE; - virtual void Shutdown() OVERRIDE; - virtual void ScheduleTasks(RasterTaskQueue* queue) OVERRIDE; - virtual void CheckForCompletedTasks() OVERRIDE; + void SetClient(RasterizerClient* client) override; + void Shutdown() override; + void ScheduleTasks(RasterTaskQueue* queue) override; + void CheckForCompletedTasks() override; // Overridden from RasterizerTaskClient: - virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) OVERRIDE; - virtual void ReleaseCanvasForRaster(RasterTask* task) OVERRIDE; + scoped_ptr<RasterBuffer> AcquireBufferForRaster( + const Resource* resource) override; + void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override; private: struct RasterTaskState { @@ -58,42 +68,39 @@ class CC_EXPORT PixelBufferRasterWorkerPool : public RasterWorkerPool, typedef std::vector<RasterTaskState> Vector; - RasterTaskState(RasterTask* task, bool required_for_activation) - : type(UNSCHEDULED), - task(task), - required_for_activation(required_for_activation) {} + RasterTaskState(RasterTask* task, const TaskSetCollection& task_sets); enum { UNSCHEDULED, SCHEDULED, UPLOADING, COMPLETED } type; RasterTask* task; - bool required_for_activation; + TaskSetCollection task_sets; }; - typedef std::deque<scoped_refptr<RasterTask> > RasterTaskDeque; + typedef std::deque<scoped_refptr<RasterTask>> RasterTaskDeque; PixelBufferRasterWorkerPool(base::SequencedTaskRunner* task_runner, TaskGraphRunner* task_graph_runner, + ContextProvider* context_provider, ResourceProvider* resource_provider, size_t max_transfer_buffer_usage_bytes); - void OnRasterFinished(); - void OnRasterRequiredForActivationFinished(); + void OnRasterFinished(TaskSet task_set); void FlushUploads(); void CheckForCompletedUploads(); void CheckForCompletedRasterTasks(); void ScheduleMoreTasks(); unsigned PendingRasterTaskCount() const; - bool HasPendingTasks() const; - bool HasPendingTasksRequiredForActivation() const; + TaskSetCollection PendingTasks() const; void CheckForCompletedRasterizerTasks(); const char* StateName() const; - scoped_ptr<base::Value> StateAsValue() const; - scoped_ptr<base::Value> ThrottleStateAsValue() const; + scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const; + void ThrottleStateAsValueInto(base::debug::TracedValue* throttle_state) const; scoped_refptr<base::SequencedTaskRunner> task_runner_; TaskGraphRunner* task_graph_runner_; const NamespaceToken namespace_token_; RasterizerClient* client_; + ContextProvider* context_provider_; ResourceProvider* resource_provider_; bool shutdown_; @@ -105,29 +112,26 @@ class CC_EXPORT PixelBufferRasterWorkerPool : public RasterWorkerPool, RasterizerTask::Vector completed_image_decode_tasks_; size_t scheduled_raster_task_count_; - size_t raster_tasks_required_for_activation_count_; + size_t task_counts_[kNumberOfTaskSets]; size_t bytes_pending_upload_; size_t max_bytes_pending_upload_; bool has_performed_uploads_since_last_flush_; - bool should_notify_client_if_no_tasks_are_pending_; - bool should_notify_client_if_no_tasks_required_for_activation_are_pending_; - bool raster_finished_task_pending_; - bool raster_required_for_activation_finished_task_pending_; + TaskSetCollection should_notify_client_if_no_tasks_are_pending_; + TaskSetCollection raster_finished_tasks_pending_; DelayedUniqueNotifier check_for_completed_raster_task_notifier_; - base::WeakPtrFactory<PixelBufferRasterWorkerPool> - raster_finished_weak_ptr_factory_; - - scoped_refptr<RasterizerTask> raster_finished_task_; - scoped_refptr<RasterizerTask> raster_required_for_activation_finished_task_; + scoped_refptr<RasterizerTask> raster_finished_tasks_[kNumberOfTaskSets]; // Task graph used when scheduling tasks and vector used to gather // completed tasks. TaskGraph graph_; Task::Vector completed_tasks_; + base::WeakPtrFactory<PixelBufferRasterWorkerPool> + raster_finished_weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(PixelBufferRasterWorkerPool); }; diff --git a/chromium/cc/resources/platform_color.h b/chromium/cc/resources/platform_color.h index ecdf7c166f2..4945dccadc5 100644 --- a/chromium/cc/resources/platform_color.h +++ b/chromium/cc/resources/platform_color.h @@ -44,7 +44,7 @@ class PlatformColor { case SOURCE_FORMAT_RGBA8: return format == RGBA_8888 || format == RGBA_4444; case SOURCE_FORMAT_BGRA8: - return format == BGRA_8888; + return format == BGRA_8888 || format == RGBA_4444; } NOTREACHED(); return false; diff --git a/chromium/cc/resources/prioritized_resource.h b/chromium/cc/resources/prioritized_resource.h index 7920f811042..e3bb2bc4d1c 100644 --- a/chromium/cc/resources/prioritized_resource.h +++ b/chromium/cc/resources/prioritized_resource.h @@ -9,12 +9,11 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" -#include "cc/resources/priority_calculator.h" #include "cc/resources/resource.h" #include "cc/resources/resource_provider.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/size.h" -#include "ui/gfx/vector2d.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/vector2d.h" namespace cc { diff --git a/chromium/cc/resources/prioritized_resource_manager.cc b/chromium/cc/resources/prioritized_resource_manager.cc index 81af9fbf6dc..657c14f4ddf 100644 --- a/chromium/cc/resources/prioritized_resource_manager.cc +++ b/chromium/cc/resources/prioritized_resource_manager.cc @@ -7,7 +7,6 @@ #include <algorithm> #include "base/debug/trace_event.h" -#include "base/stl_util.h" #include "cc/resources/prioritized_resource.h" #include "cc/resources/priority_calculator.h" #include "cc/trees/proxy.h" @@ -455,7 +454,7 @@ PrioritizedResource::Backing* PrioritizedResourceManager::CreateBacking( size, GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, - ResourceProvider::TextureUsageAny, + ResourceProvider::TextureHintImmutable, format); PrioritizedResource::Backing* backing = new PrioritizedResource::Backing( resource_id, resource_provider, size, format); diff --git a/chromium/cc/resources/prioritized_resource_manager.h b/chromium/cc/resources/prioritized_resource_manager.h index 092b1d720fd..b7583f4315f 100644 --- a/chromium/cc/resources/prioritized_resource_manager.h +++ b/chromium/cc/resources/prioritized_resource_manager.h @@ -16,22 +16,10 @@ #include "cc/resources/prioritized_resource.h" #include "cc/resources/priority_calculator.h" #include "cc/resources/resource.h" -#include "cc/trees/proxy.h" -#include "ui/gfx/size.h" - -#if defined(COMPILER_GCC) -namespace BASE_HASH_NAMESPACE { -template <> struct hash<cc::PrioritizedResource*> { - size_t operator()(cc::PrioritizedResource* ptr) const { - return hash<size_t>()(reinterpret_cast<size_t>(ptr)); - } -}; -} // namespace BASE_HASH_NAMESPACE -#endif // COMPILER +#include "ui/gfx/geometry/size.h" namespace cc { -class PriorityCalculator; class Proxy; class CC_EXPORT PrioritizedResourceManager { diff --git a/chromium/cc/resources/prioritized_resource_unittest.cc b/chromium/cc/resources/prioritized_resource_unittest.cc index 14eb317461c..8869e706036 100644 --- a/chromium/cc/resources/prioritized_resource_unittest.cc +++ b/chromium/cc/resources/prioritized_resource_unittest.cc @@ -28,14 +28,18 @@ class PrioritizedResourceTest : public testing::Test { DebugScopedSetImplThread impl_thread(&proxy_); CHECK(output_surface_->BindToClient(&output_surface_client_)); shared_bitmap_manager_.reset(new TestSharedBitmapManager()); - resource_provider_ = ResourceProvider::Create( - output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, - false); + resource_provider_ = ResourceProvider::Create(output_surface_.get(), + shared_bitmap_manager_.get(), + NULL, + NULL, + 0, + false, + 1); } virtual ~PrioritizedResourceTest() { DebugScopedSetImplThread impl_thread(&proxy_); - resource_provider_.reset(); + resource_provider_ = nullptr; } size_t TexturesMemorySize(size_t texture_count) { @@ -273,7 +277,7 @@ TEST_F(PrioritizedResourceTest, ReduceWastedMemory) { EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); // Destroy one texture, not enough is wasted to cause cleanup. - textures[0] = scoped_ptr<PrioritizedResource>(); + textures[0] = nullptr; PrioritizeTexturesAndBackings(resource_manager.get()); { DebugScopedSetImplThreadAndMainThreadBlocked @@ -286,7 +290,7 @@ TEST_F(PrioritizedResourceTest, ReduceWastedMemory) { // Destroy half the textures, leaving behind the backings. Now a cleanup // should happen. for (size_t i = 0; i < kMaxTextures / 2; ++i) - textures[i] = scoped_ptr<PrioritizedResource>(); + textures[i] = nullptr; PrioritizeTexturesAndBackings(resource_manager.get()); { DebugScopedSetImplThreadAndMainThreadBlocked @@ -353,7 +357,7 @@ TEST_F(PrioritizedResourceTest, InUseNotWastedMemory) { // sent to a parent compositor though, so they should not be considered wasted // and a cleanup should not happen. for (size_t i = 0; i < kMaxTextures / 2; ++i) - textures[i] = scoped_ptr<PrioritizedResource>(); + textures[i] = nullptr; PrioritizeTexturesAndBackings(resource_manager.get()); { DebugScopedSetImplThreadAndMainThreadBlocked @@ -561,7 +565,7 @@ TEST_F(PrioritizedResourceTest, EvictingTexturesInParent) { // Drop all the textures. Now we have backings that can be recycled. for (size_t i = 0; i < 8; ++i) - textures[0].reset(); + textures[0] = nullptr; PrioritizeTexturesAndBackings(resource_manager.get()); // The next commit finishes. @@ -724,7 +728,7 @@ TEST_F(PrioritizedResourceTest, ResourceManagerDestroyedFirst) { impl_thread_and_main_thread_blocked(&proxy_); resource_manager->ClearAllMemory(resource_provider()); } - resource_manager.reset(); + resource_manager = nullptr; EXPECT_FALSE(texture->can_acquire_backing_texture()); EXPECT_FALSE(texture->have_backing_texture()); @@ -754,7 +758,7 @@ TEST_F(PrioritizedResourceTest, TextureMovedToNewManager) { impl_thread_and_main_thread_blocked(&proxy_); resource_manager_one->ClearAllMemory(resource_provider()); } - resource_manager_one.reset(); + resource_manager_one = nullptr; EXPECT_FALSE(texture->can_acquire_backing_texture()); EXPECT_FALSE(texture->have_backing_texture()); diff --git a/chromium/cc/resources/prioritized_tile_set.cc b/chromium/cc/resources/prioritized_tile_set.cc deleted file mode 100644 index b7b3b5a741e..00000000000 --- a/chromium/cc/resources/prioritized_tile_set.cc +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/resources/prioritized_tile_set.h" - -#include <algorithm> - -#include "cc/resources/managed_tile_state.h" -#include "cc/resources/tile.h" - -namespace cc { - -class BinComparator { - public: - bool operator()(const Tile* a, - const Tile* b) const { - const ManagedTileState& ams = a->managed_state(); - const ManagedTileState& bms = b->managed_state(); - - if (ams.priority_bin != bms.priority_bin) - return ams.priority_bin < bms.priority_bin; - - if (ams.required_for_activation != bms.required_for_activation) - return ams.required_for_activation; - - if (ams.resolution != bms.resolution) - return ams.resolution < bms.resolution; - - if (ams.distance_to_visible != bms.distance_to_visible) - return ams.distance_to_visible < bms.distance_to_visible; - - gfx::Rect a_rect = a->content_rect(); - gfx::Rect b_rect = b->content_rect(); - if (a_rect.y() != b_rect.y()) - return a_rect.y() < b_rect.y(); - return a_rect.x() < b_rect.x(); - } -}; - -namespace { - -typedef std::vector<Tile*> TileVector; - -void SortBinTiles(ManagedTileBin bin, TileVector* tiles) { - switch (bin) { - case NOW_AND_READY_TO_DRAW_BIN: - case NEVER_BIN: - break; - case NOW_BIN: - case SOON_BIN: - case EVENTUALLY_AND_ACTIVE_BIN: - case EVENTUALLY_BIN: - case AT_LAST_AND_ACTIVE_BIN: - case AT_LAST_BIN: - std::sort(tiles->begin(), tiles->end(), BinComparator()); - break; - default: - NOTREACHED(); - } -} - -} // namespace - -PrioritizedTileSet::PrioritizedTileSet() { - for (int bin = 0; bin < NUM_BINS; ++bin) - bin_sorted_[bin] = true; -} - -PrioritizedTileSet::~PrioritizedTileSet() {} - -void PrioritizedTileSet::InsertTile(Tile* tile, ManagedTileBin bin) { - tiles_[bin].push_back(tile); - bin_sorted_[bin] = false; -} - -void PrioritizedTileSet::Clear() { - for (int bin = 0; bin < NUM_BINS; ++bin) { - tiles_[bin].clear(); - bin_sorted_[bin] = true; - } -} - -void PrioritizedTileSet::SortBinIfNeeded(ManagedTileBin bin) { - if (!bin_sorted_[bin]) { - SortBinTiles(bin, &tiles_[bin]); - bin_sorted_[bin] = true; - } -} - -PrioritizedTileSet::Iterator::Iterator( - PrioritizedTileSet* tile_set, bool use_priority_ordering) - : tile_set_(tile_set), - current_bin_(NOW_AND_READY_TO_DRAW_BIN), - use_priority_ordering_(use_priority_ordering) { - if (use_priority_ordering_) - tile_set_->SortBinIfNeeded(current_bin_); - iterator_ = tile_set->tiles_[current_bin_].begin(); - if (iterator_ == tile_set_->tiles_[current_bin_].end()) - AdvanceList(); -} - -PrioritizedTileSet::Iterator::~Iterator() {} - -void PrioritizedTileSet::Iterator::DisablePriorityOrdering() { - use_priority_ordering_ = false; -} - -PrioritizedTileSet::Iterator& -PrioritizedTileSet::Iterator::operator++() { - // We can't increment past the end of the tiles. - DCHECK(iterator_ != tile_set_->tiles_[current_bin_].end()); - - ++iterator_; - if (iterator_ == tile_set_->tiles_[current_bin_].end()) - AdvanceList(); - return *this; -} - -Tile* PrioritizedTileSet::Iterator::operator*() { - DCHECK(iterator_ != tile_set_->tiles_[current_bin_].end()); - return *iterator_; -} - -void PrioritizedTileSet::Iterator::AdvanceList() { - DCHECK(iterator_ == tile_set_->tiles_[current_bin_].end()); - - while (current_bin_ != NEVER_BIN) { - current_bin_ = static_cast<ManagedTileBin>(current_bin_ + 1); - - if (use_priority_ordering_) - tile_set_->SortBinIfNeeded(current_bin_); - - iterator_ = tile_set_->tiles_[current_bin_].begin(); - if (iterator_ != tile_set_->tiles_[current_bin_].end()) - break; - } -} - -} // namespace cc diff --git a/chromium/cc/resources/prioritized_tile_set.h b/chromium/cc/resources/prioritized_tile_set.h deleted file mode 100644 index 15d0e4f8b48..00000000000 --- a/chromium/cc/resources/prioritized_tile_set.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CC_RESOURCES_PRIORITIZED_TILE_SET_H_ -#define CC_RESOURCES_PRIORITIZED_TILE_SET_H_ - -#include <vector> - -#include "cc/base/cc_export.h" -#include "cc/resources/managed_tile_state.h" - -namespace cc { -class Tile; - -class CC_EXPORT PrioritizedTileSet { - public: - PrioritizedTileSet(); - ~PrioritizedTileSet(); - - void InsertTile(Tile* tile, ManagedTileBin bin); - void Clear(); - - class CC_EXPORT Iterator { - public: - Iterator(PrioritizedTileSet* set, bool use_priority_ordering); - - ~Iterator(); - - void DisablePriorityOrdering(); - - Iterator& operator++(); - Tile* operator->() { return *(*this); } - Tile* operator*(); - operator bool() const { - return iterator_ != tile_set_->tiles_[current_bin_].end(); - } - - private: - void AdvanceList(); - - PrioritizedTileSet* tile_set_; - ManagedTileBin current_bin_; - std::vector<Tile*>::iterator iterator_; - bool use_priority_ordering_; - }; - - private: - friend class Iterator; - - void SortBinIfNeeded(ManagedTileBin bin); - - std::vector<Tile*> tiles_[NUM_BINS]; - bool bin_sorted_[NUM_BINS]; -}; - -} // namespace cc - -#endif // CC_RESOURCES_PRIORITIZED_TILE_SET_H_ diff --git a/chromium/cc/resources/prioritized_tile_set_unittest.cc b/chromium/cc/resources/prioritized_tile_set_unittest.cc deleted file mode 100644 index f0a01d25900..00000000000 --- a/chromium/cc/resources/prioritized_tile_set_unittest.cc +++ /dev/null @@ -1,732 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <algorithm> -#include <vector> - -#include "cc/resources/managed_tile_state.h" -#include "cc/resources/prioritized_tile_set.h" -#include "cc/resources/tile.h" -#include "cc/test/fake_output_surface.h" -#include "cc/test/fake_output_surface_client.h" -#include "cc/test/fake_picture_pile_impl.h" -#include "cc/test/fake_tile_manager.h" -#include "cc/test/fake_tile_manager_client.h" -#include "cc/test/test_shared_bitmap_manager.h" -#include "cc/test/test_tile_priorities.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace cc { - -class BinComparator { - public: - bool operator()(const scoped_refptr<Tile>& a, - const scoped_refptr<Tile>& b) const { - const ManagedTileState& ams = a->managed_state(); - const ManagedTileState& bms = b->managed_state(); - - if (ams.priority_bin != bms.priority_bin) - return ams.priority_bin < bms.priority_bin; - - if (ams.required_for_activation != bms.required_for_activation) - return ams.required_for_activation; - - if (ams.resolution != bms.resolution) - return ams.resolution < bms.resolution; - - if (ams.distance_to_visible != bms.distance_to_visible) - return ams.distance_to_visible < bms.distance_to_visible; - - gfx::Rect a_rect = a->content_rect(); - gfx::Rect b_rect = b->content_rect(); - if (a_rect.y() != b_rect.y()) - return a_rect.y() < b_rect.y(); - return a_rect.x() < b_rect.x(); - } -}; - -namespace { - -class PrioritizedTileSetTest : public testing::Test { - public: - PrioritizedTileSetTest() { - output_surface_ = FakeOutputSurface::Create3d().Pass(); - CHECK(output_surface_->BindToClient(&output_surface_client_)); - - shared_bitmap_manager_.reset(new TestSharedBitmapManager()); - resource_provider_ = - ResourceProvider::Create( - output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, - false) - .Pass(); - resource_pool_ = ResourcePool::Create( - resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888); - tile_manager_.reset( - new FakeTileManager(&tile_manager_client_, resource_pool_.get())); - picture_pile_ = FakePicturePileImpl::CreateInfiniteFilledPile(); - } - - scoped_refptr<Tile> CreateTile() { - return tile_manager_->CreateTile(picture_pile_.get(), - settings_.default_tile_size, - gfx::Rect(), - gfx::Rect(), - 1.0, - 0, - 0, - 0); - } - - private: - LayerTreeSettings settings_; - FakeOutputSurfaceClient output_surface_client_; - scoped_ptr<FakeOutputSurface> output_surface_; - scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; - scoped_ptr<ResourceProvider> resource_provider_; - scoped_ptr<ResourcePool> resource_pool_; - FakeTileManagerClient tile_manager_client_; - scoped_ptr<FakeTileManager> tile_manager_; - scoped_refptr<FakePicturePileImpl> picture_pile_; -}; - -TEST_F(PrioritizedTileSetTest, EmptyIterator) { - // Creating an iterator to an empty set should work (but create iterator that - // isn't valid). - - PrioritizedTileSet set; - - PrioritizedTileSet::Iterator it(&set, true); - EXPECT_FALSE(it); -} - -TEST_F(PrioritizedTileSetTest, NonEmptyIterator) { - PrioritizedTileSet set; - scoped_refptr<Tile> tile = CreateTile(); - set.InsertTile(tile, NOW_BIN); - - PrioritizedTileSet::Iterator it(&set, true); - EXPECT_TRUE(it); - EXPECT_TRUE(*it == tile.get()); - ++it; - EXPECT_FALSE(it); -} - -TEST_F(PrioritizedTileSetTest, NowAndReadyToDrawBin) { - // Ensure that tiles in NOW_AND_READY_TO_DRAW_BIN aren't sorted. - - PrioritizedTileSet set; - TilePriority priorities[4] = { - TilePriorityForEventualBin(), - TilePriorityForNowBin(), - TilePriority(), - TilePriorityForSoonBin()}; - - std::vector<scoped_refptr<Tile> > tiles; - for (int priority = 0; priority < 4; ++priority) { - for (int i = 0; i < 5; ++i) { - scoped_refptr<Tile> tile = CreateTile(); - tile->SetPriority(ACTIVE_TREE, priorities[priority]); - tile->SetPriority(PENDING_TREE, priorities[priority]); - tiles.push_back(tile); - set.InsertTile(tile, NOW_AND_READY_TO_DRAW_BIN); - } - } - - // Tiles should appear in the same order as inserted. - int i = 0; - for (PrioritizedTileSet::Iterator it(&set, true); - it; - ++it) { - EXPECT_TRUE(*it == tiles[i].get()); - ++i; - } - EXPECT_EQ(20, i); -} - -TEST_F(PrioritizedTileSetTest, NowBin) { - // Ensure that tiles in NOW_BIN are sorted according to BinComparator. - - PrioritizedTileSet set; - TilePriority priorities[4] = { - TilePriorityForEventualBin(), - TilePriorityForNowBin(), - TilePriority(), - TilePriorityForSoonBin()}; - - std::vector<scoped_refptr<Tile> > tiles; - for (int priority = 0; priority < 4; ++priority) { - for (int i = 0; i < 5; ++i) { - scoped_refptr<Tile> tile = CreateTile(); - tile->SetPriority(ACTIVE_TREE, priorities[priority]); - tile->SetPriority(PENDING_TREE, priorities[priority]); - tiles.push_back(tile); - set.InsertTile(tile, NOW_BIN); - } - } - - // Tiles should appear in BinComparator order. - std::sort(tiles.begin(), tiles.end(), BinComparator()); - - int i = 0; - for (PrioritizedTileSet::Iterator it(&set, true); - it; - ++it) { - EXPECT_TRUE(*it == tiles[i].get()); - ++i; - } - EXPECT_EQ(20, i); -} - -TEST_F(PrioritizedTileSetTest, SoonBin) { - // Ensure that tiles in SOON_BIN are sorted according to BinComparator. - - PrioritizedTileSet set; - TilePriority priorities[4] = { - TilePriorityForEventualBin(), - TilePriorityForNowBin(), - TilePriority(), - TilePriorityForSoonBin()}; - - std::vector<scoped_refptr<Tile> > tiles; - for (int priority = 0; priority < 4; ++priority) { - for (int i = 0; i < 5; ++i) { - scoped_refptr<Tile> tile = CreateTile(); - tile->SetPriority(ACTIVE_TREE, priorities[priority]); - tile->SetPriority(PENDING_TREE, priorities[priority]); - tiles.push_back(tile); - set.InsertTile(tile, SOON_BIN); - } - } - - // Tiles should appear in BinComparator order. - std::sort(tiles.begin(), tiles.end(), BinComparator()); - - int i = 0; - for (PrioritizedTileSet::Iterator it(&set, true); - it; - ++it) { - EXPECT_TRUE(*it == tiles[i].get()); - ++i; - } - EXPECT_EQ(20, i); -} - -TEST_F(PrioritizedTileSetTest, SoonBinNoPriority) { - // Ensure that when not using priority iterator, SOON_BIN tiles - // are not sorted. - - PrioritizedTileSet set; - TilePriority priorities[4] = { - TilePriorityForEventualBin(), - TilePriorityForNowBin(), - TilePriority(), - TilePriorityForSoonBin()}; - - std::vector<scoped_refptr<Tile> > tiles; - for (int priority = 0; priority < 4; ++priority) { - for (int i = 0; i < 5; ++i) { - scoped_refptr<Tile> tile = CreateTile(); - tile->SetPriority(ACTIVE_TREE, priorities[priority]); - tile->SetPriority(PENDING_TREE, priorities[priority]); - tiles.push_back(tile); - set.InsertTile(tile, SOON_BIN); - } - } - - int i = 0; - for (PrioritizedTileSet::Iterator it(&set, false); - it; - ++it) { - EXPECT_TRUE(*it == tiles[i].get()); - ++i; - } - EXPECT_EQ(20, i); -} - -TEST_F(PrioritizedTileSetTest, EventuallyAndActiveBin) { - // Ensure that EVENTUALLY_AND_ACTIVE_BIN tiles are sorted. - - PrioritizedTileSet set; - TilePriority priorities[4] = { - TilePriorityForEventualBin(), - TilePriorityForNowBin(), - TilePriority(), - TilePriorityForSoonBin()}; - - std::vector<scoped_refptr<Tile> > tiles; - for (int priority = 0; priority < 4; ++priority) { - for (int i = 0; i < 5; ++i) { - scoped_refptr<Tile> tile = CreateTile(); - tile->SetPriority(ACTIVE_TREE, priorities[priority]); - tile->SetPriority(PENDING_TREE, priorities[priority]); - tiles.push_back(tile); - set.InsertTile(tile, EVENTUALLY_AND_ACTIVE_BIN); - } - } - - // Tiles should appear in BinComparator order. - std::sort(tiles.begin(), tiles.end(), BinComparator()); - - int i = 0; - for (PrioritizedTileSet::Iterator it(&set, true); - it; - ++it) { - EXPECT_TRUE(*it == tiles[i].get()); - ++i; - } - EXPECT_EQ(20, i); -} - -TEST_F(PrioritizedTileSetTest, EventuallyBin) { - // Ensure that EVENTUALLY_BIN tiles are sorted. - - PrioritizedTileSet set; - TilePriority priorities[4] = { - TilePriorityForEventualBin(), - TilePriorityForNowBin(), - TilePriority(), - TilePriorityForSoonBin()}; - - std::vector<scoped_refptr<Tile> > tiles; - for (int priority = 0; priority < 4; ++priority) { - for (int i = 0; i < 5; ++i) { - scoped_refptr<Tile> tile = CreateTile(); - tile->SetPriority(ACTIVE_TREE, priorities[priority]); - tile->SetPriority(PENDING_TREE, priorities[priority]); - tiles.push_back(tile); - set.InsertTile(tile, EVENTUALLY_BIN); - } - } - - // Tiles should appear in BinComparator order. - std::sort(tiles.begin(), tiles.end(), BinComparator()); - - int i = 0; - for (PrioritizedTileSet::Iterator it(&set, true); - it; - ++it) { - EXPECT_TRUE(*it == tiles[i].get()); - ++i; - } - EXPECT_EQ(20, i); -} - -TEST_F(PrioritizedTileSetTest, AtLastAndActiveBin) { - // Ensure that AT_LAST_AND_ACTIVE_BIN tiles are sorted. - - PrioritizedTileSet set; - TilePriority priorities[4] = { - TilePriorityForEventualBin(), - TilePriorityForNowBin(), - TilePriority(), - TilePriorityForSoonBin()}; - - std::vector<scoped_refptr<Tile> > tiles; - for (int priority = 0; priority < 4; ++priority) { - for (int i = 0; i < 5; ++i) { - scoped_refptr<Tile> tile = CreateTile(); - tile->SetPriority(ACTIVE_TREE, priorities[priority]); - tile->SetPriority(PENDING_TREE, priorities[priority]); - tiles.push_back(tile); - set.InsertTile(tile, AT_LAST_AND_ACTIVE_BIN); - } - } - - // Tiles should appear in BinComparator order. - std::sort(tiles.begin(), tiles.end(), BinComparator()); - - int i = 0; - for (PrioritizedTileSet::Iterator it(&set, true); - it; - ++it) { - EXPECT_TRUE(*it == tiles[i].get()); - ++i; - } - EXPECT_EQ(20, i); -} - -TEST_F(PrioritizedTileSetTest, AtLastBin) { - // Ensure that AT_LAST_BIN tiles are sorted. - - PrioritizedTileSet set; - TilePriority priorities[4] = { - TilePriorityForEventualBin(), - TilePriorityForNowBin(), - TilePriority(), - TilePriorityForSoonBin()}; - - std::vector<scoped_refptr<Tile> > tiles; - for (int priority = 0; priority < 4; ++priority) { - for (int i = 0; i < 5; ++i) { - scoped_refptr<Tile> tile = CreateTile(); - tile->SetPriority(ACTIVE_TREE, priorities[priority]); - tile->SetPriority(PENDING_TREE, priorities[priority]); - tiles.push_back(tile); - set.InsertTile(tile, AT_LAST_BIN); - } - } - - // Tiles should appear in BinComparator order. - std::sort(tiles.begin(), tiles.end(), BinComparator()); - - int i = 0; - for (PrioritizedTileSet::Iterator it(&set, true); - it; - ++it) { - EXPECT_TRUE(*it == tiles[i].get()); - ++i; - } - EXPECT_EQ(20, i); -} - -TEST_F(PrioritizedTileSetTest, TilesForEachBin) { - // Aggregate test with one tile for each of the bins, which - // should appear in order of the bins. - - scoped_refptr<Tile> now_and_ready_to_draw_bin = CreateTile(); - scoped_refptr<Tile> now_bin = CreateTile(); - scoped_refptr<Tile> soon_bin = CreateTile(); - scoped_refptr<Tile> eventually_and_active_bin = CreateTile(); - scoped_refptr<Tile> eventually_bin = CreateTile(); - scoped_refptr<Tile> at_last_bin = CreateTile(); - scoped_refptr<Tile> at_last_and_active_bin = CreateTile(); - - PrioritizedTileSet set; - set.InsertTile(soon_bin, SOON_BIN); - set.InsertTile(at_last_and_active_bin, AT_LAST_AND_ACTIVE_BIN); - set.InsertTile(eventually_bin, EVENTUALLY_BIN); - set.InsertTile(now_bin, NOW_BIN); - set.InsertTile(eventually_and_active_bin, EVENTUALLY_AND_ACTIVE_BIN); - set.InsertTile(at_last_bin, AT_LAST_BIN); - set.InsertTile(now_and_ready_to_draw_bin, NOW_AND_READY_TO_DRAW_BIN); - - // Tiles should appear in order. - PrioritizedTileSet::Iterator it(&set, true); - EXPECT_TRUE(*it == now_and_ready_to_draw_bin.get()); - ++it; - EXPECT_TRUE(*it == now_bin.get()); - ++it; - EXPECT_TRUE(*it == soon_bin.get()); - ++it; - EXPECT_TRUE(*it == eventually_and_active_bin.get()); - ++it; - EXPECT_TRUE(*it == eventually_bin.get()); - ++it; - EXPECT_TRUE(*it == at_last_and_active_bin.get()); - ++it; - EXPECT_TRUE(*it == at_last_bin.get()); - ++it; - EXPECT_FALSE(it); -} - -TEST_F(PrioritizedTileSetTest, ManyTilesForEachBin) { - // Aggregate test with many tiles in each of the bins of various - // priorities. Ensure that they are all returned in a sorted order. - - std::vector<scoped_refptr<Tile> > now_and_ready_to_draw_bins; - std::vector<scoped_refptr<Tile> > now_bins; - std::vector<scoped_refptr<Tile> > soon_bins; - std::vector<scoped_refptr<Tile> > eventually_and_active_bins; - std::vector<scoped_refptr<Tile> > eventually_bins; - std::vector<scoped_refptr<Tile> > at_last_bins; - std::vector<scoped_refptr<Tile> > at_last_and_active_bins; - - TilePriority priorities[4] = { - TilePriorityForEventualBin(), - TilePriorityForNowBin(), - TilePriority(), - TilePriorityForSoonBin()}; - - PrioritizedTileSet set; - for (int priority = 0; priority < 4; ++priority) { - for (int i = 0; i < 5; ++i) { - scoped_refptr<Tile> tile = CreateTile(); - tile->SetPriority(ACTIVE_TREE, priorities[priority]); - tile->SetPriority(PENDING_TREE, priorities[priority]); - - now_and_ready_to_draw_bins.push_back(tile); - now_bins.push_back(tile); - soon_bins.push_back(tile); - eventually_and_active_bins.push_back(tile); - eventually_bins.push_back(tile); - at_last_bins.push_back(tile); - at_last_and_active_bins.push_back(tile); - - set.InsertTile(tile, NOW_AND_READY_TO_DRAW_BIN); - set.InsertTile(tile, NOW_BIN); - set.InsertTile(tile, SOON_BIN); - set.InsertTile(tile, EVENTUALLY_AND_ACTIVE_BIN); - set.InsertTile(tile, EVENTUALLY_BIN); - set.InsertTile(tile, AT_LAST_BIN); - set.InsertTile(tile, AT_LAST_AND_ACTIVE_BIN); - } - } - - PrioritizedTileSet::Iterator it(&set, true); - std::vector<scoped_refptr<Tile> >::iterator vector_it; - - // Now and ready are not sorted. - for (vector_it = now_and_ready_to_draw_bins.begin(); - vector_it != now_and_ready_to_draw_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // Now bins are sorted. - std::sort(now_bins.begin(), now_bins.end(), BinComparator()); - for (vector_it = now_bins.begin(); vector_it != now_bins.end(); ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // Soon bins are sorted. - std::sort(soon_bins.begin(), soon_bins.end(), BinComparator()); - for (vector_it = soon_bins.begin(); vector_it != soon_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // Eventually and active bins are sorted. - std::sort(eventually_and_active_bins.begin(), - eventually_and_active_bins.end(), - BinComparator()); - for (vector_it = eventually_and_active_bins.begin(); - vector_it != eventually_and_active_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // Eventually bins are sorted. - std::sort(eventually_bins.begin(), eventually_bins.end(), BinComparator()); - for (vector_it = eventually_bins.begin(); vector_it != eventually_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // At last and active bins are sorted. - std::sort(at_last_and_active_bins.begin(), - at_last_and_active_bins.end(), - BinComparator()); - for (vector_it = at_last_and_active_bins.begin(); - vector_it != at_last_and_active_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // At last bins are sorted. - std::sort(at_last_bins.begin(), at_last_bins.end(), BinComparator()); - for (vector_it = at_last_bins.begin(); vector_it != at_last_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - EXPECT_FALSE(it); -} - -TEST_F(PrioritizedTileSetTest, ManyTilesForEachBinDisablePriority) { - // Aggregate test with many tiles for each of the bins. Tiles should - // appear in order, until DisablePriorityOrdering is called. After that - // tiles should appear in the order they were inserted. - - std::vector<scoped_refptr<Tile> > now_and_ready_to_draw_bins; - std::vector<scoped_refptr<Tile> > now_bins; - std::vector<scoped_refptr<Tile> > soon_bins; - std::vector<scoped_refptr<Tile> > eventually_and_active_bins; - std::vector<scoped_refptr<Tile> > eventually_bins; - std::vector<scoped_refptr<Tile> > at_last_bins; - std::vector<scoped_refptr<Tile> > at_last_and_active_bins; - - TilePriority priorities[4] = { - TilePriorityForEventualBin(), - TilePriorityForNowBin(), - TilePriority(), - TilePriorityForSoonBin()}; - - PrioritizedTileSet set; - for (int priority = 0; priority < 4; ++priority) { - for (int i = 0; i < 5; ++i) { - scoped_refptr<Tile> tile = CreateTile(); - tile->SetPriority(ACTIVE_TREE, priorities[priority]); - tile->SetPriority(PENDING_TREE, priorities[priority]); - - now_and_ready_to_draw_bins.push_back(tile); - now_bins.push_back(tile); - soon_bins.push_back(tile); - eventually_and_active_bins.push_back(tile); - eventually_bins.push_back(tile); - at_last_bins.push_back(tile); - at_last_and_active_bins.push_back(tile); - - set.InsertTile(tile, NOW_AND_READY_TO_DRAW_BIN); - set.InsertTile(tile, NOW_BIN); - set.InsertTile(tile, SOON_BIN); - set.InsertTile(tile, EVENTUALLY_AND_ACTIVE_BIN); - set.InsertTile(tile, EVENTUALLY_BIN); - set.InsertTile(tile, AT_LAST_BIN); - set.InsertTile(tile, AT_LAST_AND_ACTIVE_BIN); - } - } - - PrioritizedTileSet::Iterator it(&set, true); - std::vector<scoped_refptr<Tile> >::iterator vector_it; - - // Now and ready are not sorted. - for (vector_it = now_and_ready_to_draw_bins.begin(); - vector_it != now_and_ready_to_draw_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // Now bins are sorted. - std::sort(now_bins.begin(), now_bins.end(), BinComparator()); - for (vector_it = now_bins.begin(); vector_it != now_bins.end(); ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // Soon bins are sorted. - std::sort(soon_bins.begin(), soon_bins.end(), BinComparator()); - for (vector_it = soon_bins.begin(); vector_it != soon_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // After we disable priority ordering, we already have sorted the next vector. - it.DisablePriorityOrdering(); - - // Eventually and active bins are sorted. - std::sort(eventually_and_active_bins.begin(), - eventually_and_active_bins.end(), - BinComparator()); - for (vector_it = eventually_and_active_bins.begin(); - vector_it != eventually_and_active_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // Eventually bins are not sorted. - for (vector_it = eventually_bins.begin(); vector_it != eventually_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // At last and active bins are not sorted. - for (vector_it = at_last_and_active_bins.begin(); - vector_it != at_last_and_active_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - // At last bins are not sorted. - for (vector_it = at_last_bins.begin(); vector_it != at_last_bins.end(); - ++vector_it) { - EXPECT_TRUE(*vector_it == *it); - ++it; - } - - EXPECT_FALSE(it); -} - -TEST_F(PrioritizedTileSetTest, TilesForFirstAndLastBins) { - // Make sure that if we have empty lists between two non-empty lists, - // we just get two tiles from the iterator. - - scoped_refptr<Tile> now_and_ready_to_draw_bin = CreateTile(); - scoped_refptr<Tile> at_last_bin = CreateTile(); - - PrioritizedTileSet set; - set.InsertTile(at_last_bin, AT_LAST_BIN); - set.InsertTile(now_and_ready_to_draw_bin, NOW_AND_READY_TO_DRAW_BIN); - - // Only two tiles should appear and they should appear in order. - PrioritizedTileSet::Iterator it(&set, true); - EXPECT_TRUE(*it == now_and_ready_to_draw_bin.get()); - ++it; - EXPECT_TRUE(*it == at_last_bin.get()); - ++it; - EXPECT_FALSE(it); -} - -TEST_F(PrioritizedTileSetTest, MultipleIterators) { - // Ensure that multiple iterators don't interfere with each other. - - scoped_refptr<Tile> now_and_ready_to_draw_bin = CreateTile(); - scoped_refptr<Tile> now_bin = CreateTile(); - scoped_refptr<Tile> soon_bin = CreateTile(); - scoped_refptr<Tile> eventually_bin = CreateTile(); - scoped_refptr<Tile> at_last_bin = CreateTile(); - - PrioritizedTileSet set; - set.InsertTile(soon_bin, SOON_BIN); - set.InsertTile(eventually_bin, EVENTUALLY_BIN); - set.InsertTile(now_bin, NOW_BIN); - set.InsertTile(at_last_bin, AT_LAST_BIN); - set.InsertTile(now_and_ready_to_draw_bin, NOW_AND_READY_TO_DRAW_BIN); - - // Tiles should appear in order. - PrioritizedTileSet::Iterator it(&set, true); - EXPECT_TRUE(*it == now_and_ready_to_draw_bin.get()); - ++it; - EXPECT_TRUE(*it == now_bin.get()); - ++it; - EXPECT_TRUE(*it == soon_bin.get()); - ++it; - EXPECT_TRUE(*it == eventually_bin.get()); - ++it; - EXPECT_TRUE(*it == at_last_bin.get()); - ++it; - EXPECT_FALSE(it); - - // Creating multiple iterators shouldn't affect old iterators. - PrioritizedTileSet::Iterator second_it(&set, true); - EXPECT_TRUE(second_it); - EXPECT_FALSE(it); - - ++second_it; - EXPECT_TRUE(second_it); - ++second_it; - EXPECT_TRUE(second_it); - EXPECT_FALSE(it); - - PrioritizedTileSet::Iterator third_it(&set, true); - EXPECT_TRUE(third_it); - ++second_it; - ++second_it; - EXPECT_TRUE(second_it); - EXPECT_TRUE(third_it); - EXPECT_FALSE(it); - - ++third_it; - ++third_it; - EXPECT_TRUE(third_it); - EXPECT_TRUE(*third_it == soon_bin.get()); - EXPECT_TRUE(second_it); - EXPECT_TRUE(*second_it == at_last_bin.get()); - EXPECT_FALSE(it); - - ++second_it; - EXPECT_TRUE(third_it); - EXPECT_FALSE(second_it); - EXPECT_FALSE(it); - - set.Clear(); - - PrioritizedTileSet::Iterator empty_it(&set, true); - EXPECT_FALSE(empty_it); -} - -} // namespace -} // namespace cc - diff --git a/chromium/cc/resources/priority_calculator.cc b/chromium/cc/resources/priority_calculator.cc index 2a0cd189da1..5f5916fda9c 100644 --- a/chromium/cc/resources/priority_calculator.cc +++ b/chromium/cc/resources/priority_calculator.cc @@ -6,7 +6,7 @@ #include <algorithm> -#include "ui/gfx/rect.h" +#include "ui/gfx/geometry/rect.h" namespace cc { diff --git a/chromium/cc/resources/raster_buffer.cc b/chromium/cc/resources/raster_buffer.cc new file mode 100644 index 00000000000..8f5671720e3 --- /dev/null +++ b/chromium/cc/resources/raster_buffer.cc @@ -0,0 +1,15 @@ +// 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_buffer.h" + +namespace cc { + +RasterBuffer::RasterBuffer() { +} + +RasterBuffer::~RasterBuffer() { +} + +} // namespace cc diff --git a/chromium/cc/resources/raster_buffer.h b/chromium/cc/resources/raster_buffer.h new file mode 100644 index 00000000000..2a72203da4b --- /dev/null +++ b/chromium/cc/resources/raster_buffer.h @@ -0,0 +1,26 @@ +// 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_BUFFER_H_ +#define CC_RESOURCES_RASTER_BUFFER_H_ + +#include "cc/base/cc_export.h" +#include "ui/gfx/geometry/rect.h" + +namespace cc { +class RasterSource; + +class CC_EXPORT RasterBuffer { + public: + RasterBuffer(); + virtual ~RasterBuffer(); + + virtual void Playback(const RasterSource* raster_source, + const gfx::Rect& rect, + float scale) = 0; +}; + +} // namespace cc + +#endif // CC_RESOURCES_RASTER_BUFFER_H_ diff --git a/chromium/cc/resources/raster_mode.cc b/chromium/cc/resources/raster_mode.cc deleted file mode 100644 index 5da8ee76e9b..00000000000 --- a/chromium/cc/resources/raster_mode.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/resources/raster_mode.h" - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/values.h" - -namespace cc { - -scoped_ptr<base::Value> RasterModeAsValue(RasterMode raster_mode) { - switch (raster_mode) { - case HIGH_QUALITY_RASTER_MODE: - return scoped_ptr<base::Value>( - new base::StringValue("HIGH_QUALITY_RASTER_MODE")); - case LOW_QUALITY_RASTER_MODE: - return scoped_ptr<base::Value>( - new base::StringValue("LOW_QUALITY_RASTER_MODE")); - default: - NOTREACHED() << "Unrecognized RasterMode value " << raster_mode; - return scoped_ptr<base::Value>( - new base::StringValue("<unknown RasterMode value>")); - } -} - -} // namespace cc diff --git a/chromium/cc/resources/raster_mode.h b/chromium/cc/resources/raster_mode.h deleted file mode 100644 index 0a2b4c9b076..00000000000 --- a/chromium/cc/resources/raster_mode.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CC_RESOURCES_RASTER_MODE_H_ -#define CC_RESOURCES_RASTER_MODE_H_ - -#include "base/memory/scoped_ptr.h" - -namespace base { -class Value; -} - -namespace cc { - -// Note that the order of these matters, from "better" to "worse" in terms of -// quality. -enum RasterMode { - HIGH_QUALITY_RASTER_MODE = 0, - LOW_QUALITY_RASTER_MODE = 1, - NUM_RASTER_MODES = 2 -}; - -scoped_ptr<base::Value> RasterModeAsValue(RasterMode mode); - -} // namespace cc - -#endif // CC_RESOURCES_RASTER_MODE_H_ diff --git a/chromium/cc/resources/raster_source.h b/chromium/cc/resources/raster_source.h new file mode 100644 index 00000000000..3e2540830bf --- /dev/null +++ b/chromium/cc/resources/raster_source.h @@ -0,0 +1,71 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_RESOURCES_RASTER_SOURCE_H_ +#define CC_RESOURCES_RASTER_SOURCE_H_ + +#include <vector> + +#include "base/memory/ref_counted.h" +#include "cc/base/cc_export.h" +#include "third_party/skia/include/core/SkColor.h" + +class SkCanvas; + +namespace cc { + +class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> { + public: + struct CC_EXPORT SolidColorAnalysis { + SolidColorAnalysis() + : is_solid_color(false), solid_color(SK_ColorTRANSPARENT) {} + ~SolidColorAnalysis() {} + + bool is_solid_color; + SkColor solid_color; + }; + + // Raster a subrect of this RasterSource into the given canvas. It is + // assumed that contents_scale has already been applied to this canvas. + // Writes the total number of pixels rasterized and the time spent + // rasterizing to the stats if the respective pointer is not nullptr. + virtual void PlaybackToCanvas(SkCanvas* canvas, + const gfx::Rect& canvas_rect, + float contents_scale) const = 0; + + // Analyze to determine if the given rect at given scale is of solid color in + // this raster source. + virtual void PerformSolidColorAnalysis( + const gfx::Rect& content_rect, + float contents_scale, + SolidColorAnalysis* analysis) const = 0; + + // Populate the given list with all SkPixelRefs that may overlap the given + // rect at given scale. + virtual void GatherPixelRefs(const gfx::Rect& content_rect, + float contents_scale, + std::vector<SkPixelRef*>* pixel_refs) const = 0; + + // Return true iff this raster source can raster the given rect at given + // scale. + virtual bool CoversRect(const gfx::Rect& content_rect, + float contents_scale) const = 0; + + // Return true iff this raster source would benefit from using distance + // field text. + virtual bool SuitableForDistanceFieldText() const = 0; + + protected: + friend class base::RefCountedThreadSafe<RasterSource>; + + RasterSource() {} + virtual ~RasterSource() {} + + private: + DISALLOW_COPY_AND_ASSIGN(RasterSource); +}; + +} // namespace cc + +#endif // CC_RESOURCES_RASTER_SOURCE_H_ diff --git a/chromium/cc/resources/raster_tile_priority_queue.cc b/chromium/cc/resources/raster_tile_priority_queue.cc new file mode 100644 index 00000000000..667d54d89c1 --- /dev/null +++ b/chromium/cc/resources/raster_tile_priority_queue.cc @@ -0,0 +1,310 @@ +// 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_tile_priority_queue.h" + +namespace cc { + +namespace { + +class RasterOrderComparator { + public: + explicit RasterOrderComparator(TreePriority tree_priority) + : tree_priority_(tree_priority) {} + + bool operator()( + const RasterTilePriorityQueue::PairedPictureLayerQueue* a, + const RasterTilePriorityQueue::PairedPictureLayerQueue* b) const { + // Note that in this function, we have to return true if and only if + // a is strictly lower priority than b. Note that for the sake of + // completeness, empty queue is considered to have lowest priority. + if (a->IsEmpty() || b->IsEmpty()) + return b->IsEmpty() < a->IsEmpty(); + + WhichTree a_tree = a->NextTileIteratorTree(tree_priority_); + const PictureLayerImpl::LayerRasterTileIterator* a_iterator = + a_tree == ACTIVE_TREE ? &a->active_iterator : &a->pending_iterator; + + WhichTree b_tree = b->NextTileIteratorTree(tree_priority_); + const PictureLayerImpl::LayerRasterTileIterator* b_iterator = + b_tree == ACTIVE_TREE ? &b->active_iterator : &b->pending_iterator; + + const Tile* a_tile = **a_iterator; + const Tile* b_tile = **b_iterator; + + const TilePriority& a_priority = + a_tile->priority_for_tree_priority(tree_priority_); + const TilePriority& b_priority = + b_tile->priority_for_tree_priority(tree_priority_); + bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY; + + // In smoothness mode, we should return pending NOW tiles before active + // EVENTUALLY tiles. So if both priorities here are eventually, we need to + // check the pending priority. + if (prioritize_low_res && + a_priority.priority_bin == TilePriority::EVENTUALLY && + b_priority.priority_bin == TilePriority::EVENTUALLY) { + bool a_is_pending_now = + a_tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW; + bool b_is_pending_now = + b_tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW; + if (a_is_pending_now || b_is_pending_now) + return a_is_pending_now < b_is_pending_now; + + // In case neither one is pending now, fall through. + } + + // If the bin is the same but the resolution is not, then the order will be + // determined by whether we prioritize low res or not. + // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile + // class but instead produced by the iterators. + if (b_priority.priority_bin == a_priority.priority_bin && + b_priority.resolution != a_priority.resolution) { + // Non ideal resolution should be sorted lower than other resolutions. + if (a_priority.resolution == NON_IDEAL_RESOLUTION) + return true; + + if (b_priority.resolution == NON_IDEAL_RESOLUTION) + return false; + + if (prioritize_low_res) + return b_priority.resolution == LOW_RESOLUTION; + return b_priority.resolution == HIGH_RESOLUTION; + } + + return b_priority.IsHigherPriorityThan(a_priority); + } + + private: + TreePriority tree_priority_; +}; + +WhichTree HigherPriorityTree( + TreePriority tree_priority, + const PictureLayerImpl::LayerRasterTileIterator* active_iterator, + const PictureLayerImpl::LayerRasterTileIterator* pending_iterator, + const Tile* shared_tile) { + switch (tree_priority) { + case SMOOTHNESS_TAKES_PRIORITY: { + const Tile* active_tile = shared_tile ? shared_tile : **active_iterator; + const Tile* pending_tile = shared_tile ? shared_tile : **pending_iterator; + + const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE); + const TilePriority& pending_priority = + pending_tile->priority(PENDING_TREE); + + // If we're down to eventually bin tiles on the active tree, process the + // pending tree to allow tiles required for activation to be initialized + // when memory policy only allows prepaint. + if (active_priority.priority_bin == TilePriority::EVENTUALLY && + pending_priority.priority_bin == TilePriority::NOW) { + return PENDING_TREE; + } + return ACTIVE_TREE; + } + case NEW_CONTENT_TAKES_PRIORITY: + return PENDING_TREE; + case SAME_PRIORITY_FOR_BOTH_TREES: { + const Tile* active_tile = shared_tile ? shared_tile : **active_iterator; + const Tile* pending_tile = shared_tile ? shared_tile : **pending_iterator; + + const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE); + const TilePriority& pending_priority = + pending_tile->priority(PENDING_TREE); + + if (active_priority.IsHigherPriorityThan(pending_priority)) + return ACTIVE_TREE; + return PENDING_TREE; + } + default: + NOTREACHED(); + return ACTIVE_TREE; + } +} + +} // namespace + +RasterTilePriorityQueue::RasterTilePriorityQueue() { +} + +RasterTilePriorityQueue::~RasterTilePriorityQueue() { +} + +void RasterTilePriorityQueue::Build( + const std::vector<PictureLayerImpl::Pair>& paired_layers, + TreePriority tree_priority) { + tree_priority_ = tree_priority; + for (std::vector<PictureLayerImpl::Pair>::const_iterator it = + paired_layers.begin(); + it != paired_layers.end(); + ++it) { + paired_queues_.push_back( + make_scoped_ptr(new PairedPictureLayerQueue(*it, tree_priority_))); + } + paired_queues_.make_heap(RasterOrderComparator(tree_priority_)); +} + +void RasterTilePriorityQueue::Reset() { + paired_queues_.clear(); +} + +bool RasterTilePriorityQueue::IsEmpty() const { + return paired_queues_.empty() || paired_queues_.front()->IsEmpty(); +} + +Tile* RasterTilePriorityQueue::Top() { + DCHECK(!IsEmpty()); + return paired_queues_.front()->Top(tree_priority_); +} + +void RasterTilePriorityQueue::Pop() { + DCHECK(!IsEmpty()); + + paired_queues_.pop_heap(RasterOrderComparator(tree_priority_)); + PairedPictureLayerQueue* paired_queue = paired_queues_.back(); + paired_queue->Pop(tree_priority_); + paired_queues_.push_heap(RasterOrderComparator(tree_priority_)); +} + +RasterTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue() { +} + +RasterTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue( + const PictureLayerImpl::Pair& layer_pair, + TreePriority tree_priority) + : active_iterator(layer_pair.active + ? PictureLayerImpl::LayerRasterTileIterator( + layer_pair.active, + tree_priority == SMOOTHNESS_TAKES_PRIORITY) + : PictureLayerImpl::LayerRasterTileIterator()), + pending_iterator(layer_pair.pending + ? PictureLayerImpl::LayerRasterTileIterator( + layer_pair.pending, + tree_priority == SMOOTHNESS_TAKES_PRIORITY) + : PictureLayerImpl::LayerRasterTileIterator()), + has_both_layers(layer_pair.active && layer_pair.pending) { + if (has_both_layers) + SkipTilesReturnedByTwin(tree_priority); + TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), + "PairedPictureLayerQueue::PairedPictureLayerQueue", + TRACE_EVENT_SCOPE_THREAD, + "state", + StateAsValue()); +} + +RasterTilePriorityQueue::PairedPictureLayerQueue::~PairedPictureLayerQueue() { + TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), + "PairedPictureLayerQueue::~PairedPictureLayerQueue", + TRACE_EVENT_SCOPE_THREAD, + "state", + StateAsValue()); +} + +bool RasterTilePriorityQueue::PairedPictureLayerQueue::IsEmpty() const { + return !active_iterator && !pending_iterator; +} + +Tile* RasterTilePriorityQueue::PairedPictureLayerQueue::Top( + TreePriority tree_priority) { + DCHECK(!IsEmpty()); + + WhichTree next_tree = NextTileIteratorTree(tree_priority); + PictureLayerImpl::LayerRasterTileIterator* next_iterator = + next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator; + DCHECK(*next_iterator); + Tile* tile = **next_iterator; + DCHECK(returned_tiles_for_debug.find(tile) == returned_tiles_for_debug.end()); + return tile; +} + +void RasterTilePriorityQueue::PairedPictureLayerQueue::Pop( + TreePriority tree_priority) { + DCHECK(!IsEmpty()); + + WhichTree next_tree = NextTileIteratorTree(tree_priority); + PictureLayerImpl::LayerRasterTileIterator* next_iterator = + next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator; + DCHECK(*next_iterator); + DCHECK(returned_tiles_for_debug.insert(**next_iterator).second); + ++(*next_iterator); + + if (has_both_layers) + SkipTilesReturnedByTwin(tree_priority); + + // If no empty, use Top to do DCHECK the next iterator. + DCHECK(IsEmpty() || Top(tree_priority)); +} + +void RasterTilePriorityQueue::PairedPictureLayerQueue::SkipTilesReturnedByTwin( + TreePriority tree_priority) { + // We have both layers (active and pending) thus we can encounter shared + // tiles twice (from the active iterator and from the pending iterator). + while (!IsEmpty()) { + WhichTree next_tree = NextTileIteratorTree(tree_priority); + PictureLayerImpl::LayerRasterTileIterator* next_iterator = + next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator; + + // Accept all non-shared tiles. + const Tile* tile = **next_iterator; + if (!tile->is_shared()) + break; + + // Accept a shared tile if the next tree is the higher priority one + // corresponding the iterator (active or pending) which usually (but due + // to spiral iterators not always) returns the shared tile first. + if (next_tree == HigherPriorityTree(tree_priority, nullptr, nullptr, tile)) + break; + + ++(*next_iterator); + } +} + +WhichTree +RasterTilePriorityQueue::PairedPictureLayerQueue::NextTileIteratorTree( + TreePriority tree_priority) const { + DCHECK(!IsEmpty()); + + // If we only have one iterator with tiles, return it. + if (!active_iterator) + return PENDING_TREE; + if (!pending_iterator) + return ACTIVE_TREE; + + // Now both iterators have tiles, so we have to decide based on tree priority. + return HigherPriorityTree( + tree_priority, &active_iterator, &pending_iterator, nullptr); +} + +scoped_refptr<base::debug::ConvertableToTraceFormat> +RasterTilePriorityQueue::PairedPictureLayerQueue::StateAsValue() const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); + state->BeginDictionary("active_iterator"); + TilePriority::PriorityBin active_priority_bin = + active_iterator ? (*active_iterator)->priority(ACTIVE_TREE).priority_bin + : TilePriority::EVENTUALLY; + TilePriority::PriorityBin pending_priority_bin = + active_iterator ? (*active_iterator)->priority(PENDING_TREE).priority_bin + : TilePriority::EVENTUALLY; + state->SetBoolean("has_tile", !!active_iterator); + state->SetInteger("active_priority_bin", active_priority_bin); + state->SetInteger("pending_priority_bin", pending_priority_bin); + state->EndDictionary(); + + state->BeginDictionary("pending_iterator"); + active_priority_bin = + pending_iterator ? (*pending_iterator)->priority(ACTIVE_TREE).priority_bin + : TilePriority::EVENTUALLY; + pending_priority_bin = + pending_iterator + ? (*pending_iterator)->priority(PENDING_TREE).priority_bin + : TilePriority::EVENTUALLY; + state->SetBoolean("has_tile", !!pending_iterator); + state->SetInteger("active_priority_bin", active_priority_bin); + state->SetInteger("pending_priority_bin", pending_priority_bin); + state->EndDictionary(); + return state; +} + +} // namespace cc diff --git a/chromium/cc/resources/raster_tile_priority_queue.h b/chromium/cc/resources/raster_tile_priority_queue.h new file mode 100644 index 00000000000..3f04e97ae9d --- /dev/null +++ b/chromium/cc/resources/raster_tile_priority_queue.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_RASTER_TILE_PRIORITY_QUEUE_H_ +#define CC_RESOURCES_RASTER_TILE_PRIORITY_QUEUE_H_ + +#include <set> +#include <utility> +#include <vector> + +#include "cc/base/cc_export.h" +#include "cc/layers/picture_layer_impl.h" +#include "cc/resources/tile_priority.h" + +namespace cc { + +class CC_EXPORT RasterTilePriorityQueue { + public: + struct PairedPictureLayerQueue { + PairedPictureLayerQueue(); + PairedPictureLayerQueue(const PictureLayerImpl::Pair& layer_pair, + TreePriority tree_priority); + ~PairedPictureLayerQueue(); + + bool IsEmpty() const; + Tile* Top(TreePriority tree_priority); + void Pop(TreePriority tree_priority); + + WhichTree NextTileIteratorTree(TreePriority tree_priority) const; + void SkipTilesReturnedByTwin(TreePriority tree_priority); + + scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const; + + PictureLayerImpl::LayerRasterTileIterator active_iterator; + PictureLayerImpl::LayerRasterTileIterator pending_iterator; + bool has_both_layers; + + // Set of returned tiles (excluding the current one) for DCHECKing. + std::set<const Tile*> returned_tiles_for_debug; + }; + + RasterTilePriorityQueue(); + ~RasterTilePriorityQueue(); + + void Build(const std::vector<PictureLayerImpl::Pair>& paired_layers, + TreePriority tree_priority); + void Reset(); + + bool IsEmpty() const; + Tile* Top(); + void Pop(); + + 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_; + TreePriority tree_priority_; + + DISALLOW_COPY_AND_ASSIGN(RasterTilePriorityQueue); +}; + +} // namespace cc + +#endif // CC_RESOURCES_RASTER_TILE_PRIORITY_QUEUE_H_ diff --git a/chromium/cc/resources/raster_worker_pool.cc b/chromium/cc/resources/raster_worker_pool.cc index d01bdc80cf4..ca26edd6a41 100644 --- a/chromium/cc/resources/raster_worker_pool.cc +++ b/chromium/cc/resources/raster_worker_pool.cc @@ -6,28 +6,19 @@ #include <algorithm> -#include "base/atomic_sequence_num.h" -#include "base/debug/trace_event_synthetic_delay.h" +#include "base/debug/trace_event.h" #include "base/lazy_instance.h" #include "base/strings/stringprintf.h" #include "base/threading/simple_thread.h" -#include "base/threading/thread_local.h" #include "cc/base/scoped_ptr_deque.h" +#include "cc/resources/raster_source.h" +#include "skia/ext/refptr.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkSurface.h" namespace cc { namespace { -// Synthetic delay for raster tasks that are required for activation. Global to -// avoid static initializer on critical path. -struct RasterRequiredForActivationSyntheticDelayInitializer { - RasterRequiredForActivationSyntheticDelayInitializer() - : delay(base::debug::TraceEventSyntheticDelay::Lookup( - "cc.RasterRequiredForActivation")) {} - base::debug::TraceEventSyntheticDelay* delay; -}; -static base::LazyInstance<RasterRequiredForActivationSyntheticDelayInitializer> - g_raster_required_for_activation_delay = LAZY_INSTANCE_INITIALIZER; - class RasterTaskGraphRunner : public TaskGraphRunner, public base::DelegateSimpleThread::Delegate { public: @@ -48,36 +39,13 @@ class RasterTaskGraphRunner : public TaskGraphRunner, } } - virtual ~RasterTaskGraphRunner() { NOTREACHED(); } - - size_t GetPictureCloneIndexForCurrentThread() { - // Use index 0 if called on non-raster thread. - ThreadLocalState* thread_local_state = current_tls_.Get(); - return thread_local_state ? current_tls_.Get()->picture_clone_index : 0; - } + ~RasterTaskGraphRunner() override { NOTREACHED(); } private: - struct ThreadLocalState { - explicit ThreadLocalState(size_t picture_clone_index) - : picture_clone_index(picture_clone_index) {} - - size_t picture_clone_index; - }; - // Overridden from base::DelegateSimpleThread::Delegate: - virtual void Run() OVERRIDE { - // Use picture clone index 0..num_threads. - int picture_clone_index = picture_clone_index_sequence_.GetNext(); - DCHECK_LE(0, picture_clone_index); - DCHECK_GT(RasterWorkerPool::GetNumRasterThreads(), picture_clone_index); - current_tls_.Set(new ThreadLocalState(picture_clone_index)); - - TaskGraphRunner::Run(); - } + void Run() override { TaskGraphRunner::Run(); } ScopedPtrDeque<base::DelegateSimpleThread> workers_; - base::AtomicSequenceNumber picture_clone_index_sequence_; - base::ThreadLocalPointer<ThreadLocalState> current_tls_; }; base::LazyInstance<RasterTaskGraphRunner>::Leaky g_task_graph_runner = @@ -96,18 +64,18 @@ class RasterFinishedTaskImpl : public RasterizerTask { on_raster_finished_callback_(on_raster_finished_callback) {} // Overridden from Task: - virtual void RunOnWorkerThread() OVERRIDE { + void RunOnWorkerThread() override { TRACE_EVENT0("cc", "RasterFinishedTaskImpl::RunOnWorkerThread"); RasterFinished(); } // Overridden from RasterizerTask: - virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {} - virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {} - virtual void RunReplyOnOriginThread() OVERRIDE {} + void ScheduleOnOriginThread(RasterizerTaskClient* client) override {} + void CompleteOnOriginThread(RasterizerTaskClient* client) override {} + void RunReplyOnOriginThread() override {} protected: - virtual ~RasterFinishedTaskImpl() {} + ~RasterFinishedTaskImpl() override {} void RasterFinished() { task_runner_->PostTask(FROM_HERE, on_raster_finished_callback_); @@ -120,57 +88,15 @@ class RasterFinishedTaskImpl : public RasterizerTask { DISALLOW_COPY_AND_ASSIGN(RasterFinishedTaskImpl); }; -class RasterRequiredForActivationFinishedTaskImpl - : public RasterFinishedTaskImpl { - public: - RasterRequiredForActivationFinishedTaskImpl( - base::SequencedTaskRunner* task_runner, - const base::Closure& on_raster_finished_callback, - size_t tasks_required_for_activation_count) - : RasterFinishedTaskImpl(task_runner, on_raster_finished_callback), - tasks_required_for_activation_count_( - tasks_required_for_activation_count) { - if (tasks_required_for_activation_count_) { - g_raster_required_for_activation_delay.Get().delay->BeginParallel( - &activation_delay_end_time_); - } - } - - // Overridden from Task: - virtual void RunOnWorkerThread() OVERRIDE { - TRACE_EVENT0( - "cc", "RasterRequiredForActivationFinishedTaskImpl::RunOnWorkerThread"); - - if (tasks_required_for_activation_count_) { - g_raster_required_for_activation_delay.Get().delay->EndParallel( - activation_delay_end_time_); - } - RasterFinished(); - } - - private: - virtual ~RasterRequiredForActivationFinishedTaskImpl() {} - - base::TimeTicks activation_delay_end_time_; - const size_t tasks_required_for_activation_count_; - - DISALLOW_COPY_AND_ASSIGN(RasterRequiredForActivationFinishedTaskImpl); -}; - } // namespace -// This allows an external rasterize on-demand system to run raster tasks -// with highest priority using the same task graph runner instance. -unsigned RasterWorkerPool::kOnDemandRasterTaskPriority = 0u; // This allows a micro benchmark system to run tasks with highest priority, // since it should finish as quickly as possible. unsigned RasterWorkerPool::kBenchmarkRasterTaskPriority = 0u; // Task priorities that make sure raster finished tasks run before any // remaining raster tasks. -unsigned RasterWorkerPool::kRasterFinishedTaskPriority = 2u; -unsigned RasterWorkerPool::kRasterRequiredForActivationFinishedTaskPriority = - 1u; -unsigned RasterWorkerPool::kRasterTaskPriorityBase = 3u; +unsigned RasterWorkerPool::kRasterFinishedTaskPriority = 1u; +unsigned RasterWorkerPool::kRasterTaskPriorityBase = 2u; RasterWorkerPool::RasterWorkerPool() {} @@ -198,11 +124,6 @@ TaskGraphRunner* RasterWorkerPool::GetTaskGraphRunner() { } // static -size_t RasterWorkerPool::GetPictureCloneIndexForCurrentThread() { - return g_task_graph_runner.Pointer()->GetPictureCloneIndexForCurrentThread(); -} - -// static scoped_refptr<RasterizerTask> RasterWorkerPool::CreateRasterFinishedTask( base::SequencedTaskRunner* task_runner, const base::Closure& on_raster_finished_callback) { @@ -211,18 +132,6 @@ scoped_refptr<RasterizerTask> RasterWorkerPool::CreateRasterFinishedTask( } // static -scoped_refptr<RasterizerTask> -RasterWorkerPool::CreateRasterRequiredForActivationFinishedTask( - size_t tasks_required_for_activation_count, - base::SequencedTaskRunner* task_runner, - const base::Closure& on_raster_finished_callback) { - return make_scoped_refptr(new RasterRequiredForActivationFinishedTaskImpl( - task_runner, - on_raster_finished_callback, - tasks_required_for_activation_count)); -} - -// static void RasterWorkerPool::ScheduleTasksOnOriginThread(RasterizerTaskClient* client, TaskGraph* graph) { TRACE_EVENT0("cc", "Rasterizer::ScheduleTasksOnOriginThread"); @@ -287,4 +196,72 @@ void RasterWorkerPool::InsertNodesForRasterTask( InsertNodeForTask(graph, raster_task, priority, dependencies); } +static bool IsSupportedPlaybackToMemoryFormat(ResourceFormat format) { + switch (format) { + case RGBA_4444: + case RGBA_8888: + case BGRA_8888: + return true; + case ALPHA_8: + case LUMINANCE_8: + case RGB_565: + case ETC1: + return false; + } + NOTREACHED(); + return false; +} + +// static +void RasterWorkerPool::PlaybackToMemory(void* memory, + ResourceFormat format, + const gfx::Size& size, + int stride, + const RasterSource* raster_source, + const gfx::Rect& rect, + float scale) { + DCHECK(IsSupportedPlaybackToMemoryFormat(format)) << format; + + // Uses kPremul_SkAlphaType since the result is not known to be opaque. + SkImageInfo info = + SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType); + SkColorType buffer_color_type = ResourceFormatToSkColorType(format); + bool needs_copy = buffer_color_type != info.colorType(); + + // TODO(danakj): Make a SkSurfaceProps with an SkPixelGeometry to enable or + // disable LCD text. + // TODO(danakj): Disable LCD text on Mac during layout tests: + // https://cs.chromium.org#chromium/src/third_party/WebKit/Source/platform/fonts/mac/FontPlatformDataMac.mm&l=55 + // TODO(danakj): On Windows when LCD text is disabled, ask skia to draw LCD + // text offscreen and downsample it to AA text. + // https://cs.chromium.org#chromium/src/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp&l=86 + SkSurfaceProps* surface_props = nullptr; + + if (!stride) + stride = info.minRowBytes(); + + if (!needs_copy) { + skia::RefPtr<SkSurface> surface = skia::AdoptRef( + SkSurface::NewRasterDirect(info, memory, stride, surface_props)); + skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas()); + raster_source->PlaybackToCanvas(canvas.get(), rect, scale); + return; + } + + skia::RefPtr<SkSurface> surface = + skia::AdoptRef(SkSurface::NewRaster(info, surface_props)); + skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas()); + raster_source->PlaybackToCanvas(canvas.get(), rect, scale); + + SkImageInfo dst_info = info; + dst_info.fColorType = buffer_color_type; + // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the + // bitmap data. There will be no need to call SkAlign4 once crbug.com/293728 + // is fixed. + const size_t dst_row_bytes = SkAlign4(dst_info.minRowBytes()); + DCHECK_EQ(0u, dst_row_bytes % 4); + bool success = canvas->readPixels(dst_info, memory, dst_row_bytes, 0, 0); + DCHECK_EQ(true, success); +} + } // namespace cc diff --git a/chromium/cc/resources/raster_worker_pool.h b/chromium/cc/resources/raster_worker_pool.h index 2c543a0d0c4..5259f835492 100644 --- a/chromium/cc/resources/raster_worker_pool.h +++ b/chromium/cc/resources/raster_worker_pool.h @@ -6,19 +6,21 @@ #define CC_RESOURCES_RASTER_WORKER_POOL_H_ #include "cc/resources/rasterizer.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" namespace base { class SequencedTaskRunner; } namespace cc { +class RasterSource; +class RenderingStatsInstrumentation; class CC_EXPORT RasterWorkerPool { public: - static unsigned kOnDemandRasterTaskPriority; static unsigned kBenchmarkRasterTaskPriority; static unsigned kRasterFinishedTaskPriority; - static unsigned kRasterRequiredForActivationFinishedTaskPriority; static unsigned kRasterTaskPriorityBase; RasterWorkerPool(); @@ -35,24 +37,12 @@ class CC_EXPORT RasterWorkerPool { // Returns a pointer to the global TaskGraphRunner instance. static TaskGraphRunner* GetTaskGraphRunner(); - // Returns a unique clone index for the current thread. Guaranteed to be a - // value between 0 and GetNumRasterThreads() - 1. - static size_t GetPictureCloneIndexForCurrentThread(); - // Utility function that can be used to create a "raster finished" task that // posts |callback| to |task_runner| when run. static scoped_refptr<RasterizerTask> CreateRasterFinishedTask( base::SequencedTaskRunner* task_runner, const base::Closure& callback); - // Utility function that can be used to create a "raster required for - // activation finished" task that posts |callback| to |task_runner| when run. - static scoped_refptr<RasterizerTask> - CreateRasterRequiredForActivationFinishedTask( - size_t tasks_required_for_activation_count, - base::SequencedTaskRunner* task_runner, - const base::Closure& callback); - // Utility function that can be used to call ::ScheduleOnOriginThread() for // each task in |graph|. static void ScheduleTasksOnOriginThread(RasterizerTaskClient* client, @@ -74,6 +64,16 @@ class CC_EXPORT RasterWorkerPool { const ImageDecodeTask::Vector& decode_tasks, unsigned priority); + // Utility function that will create a temporary bitmap and copy pixels to + // |memory| when necessary. + static void PlaybackToMemory(void* memory, + ResourceFormat format, + const gfx::Size& size, + int stride, + const RasterSource* raster_source, + const gfx::Rect& rect, + float scale); + // Type-checking downcast routine. virtual Rasterizer* AsRasterizer() = 0; }; diff --git a/chromium/cc/resources/raster_worker_pool_perftest.cc b/chromium/cc/resources/raster_worker_pool_perftest.cc index a0b63efaf61..0f7a845e8a0 100644 --- a/chromium/cc/resources/raster_worker_pool_perftest.cc +++ b/chromium/cc/resources/raster_worker_pool_perftest.cc @@ -4,20 +4,24 @@ #include "cc/resources/raster_worker_pool.h" +#include "base/test/test_simple_task_runner.h" #include "base/time/time.h" #include "cc/debug/lap_timer.h" #include "cc/output/context_provider.h" -#include "cc/resources/direct_raster_worker_pool.h" -#include "cc/resources/image_copy_raster_worker_pool.h" -#include "cc/resources/image_raster_worker_pool.h" +#include "cc/resources/bitmap_raster_worker_pool.h" +#include "cc/resources/gpu_raster_worker_pool.h" +#include "cc/resources/one_copy_raster_worker_pool.h" #include "cc/resources/pixel_buffer_raster_worker_pool.h" +#include "cc/resources/raster_buffer.h" #include "cc/resources/rasterizer.h" #include "cc/resources/resource_pool.h" #include "cc/resources/resource_provider.h" #include "cc/resources/scoped_resource.h" +#include "cc/resources/zero_copy_raster_worker_pool.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/test_context_support.h" +#include "cc/test/test_gpu_memory_buffer_manager.h" #include "cc/test/test_shared_bitmap_manager.h" #include "cc/test/test_web_graphics_context_3d.h" #include "testing/gtest/include/gtest/gtest.h" @@ -29,47 +33,62 @@ namespace { class PerfGLES2Interface : public gpu::gles2::GLES2InterfaceStub { // Overridden from gpu::gles2::GLES2Interface: - virtual GLuint CreateImageCHROMIUM(GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) OVERRIDE { + GLuint CreateImageCHROMIUM(ClientBuffer buffer, + GLsizei width, + GLsizei height, + GLenum internalformat) override { return 1u; } - virtual void GenBuffers(GLsizei n, GLuint* buffers) OVERRIDE { + void GenBuffers(GLsizei n, GLuint* buffers) override { for (GLsizei i = 0; i < n; ++i) buffers[i] = 1u; } - virtual void GenTextures(GLsizei n, GLuint* textures) OVERRIDE { + void GenTextures(GLsizei n, GLuint* textures) override { for (GLsizei i = 0; i < n; ++i) textures[i] = 1u; } - virtual void GetIntegerv(GLenum pname, GLint* params) OVERRIDE { + void GetIntegerv(GLenum pname, GLint* params) override { if (pname == GL_MAX_TEXTURE_SIZE) *params = INT_MAX; } + void GenQueriesEXT(GLsizei n, GLuint* queries) override { + for (GLsizei i = 0; i < n; ++i) + queries[i] = 1u; + } + void GetQueryObjectuivEXT(GLuint query, + GLenum pname, + GLuint* params) override { + if (pname == GL_QUERY_RESULT_AVAILABLE_EXT) + *params = 1; + } }; class PerfContextProvider : public ContextProvider { public: PerfContextProvider() : context_gl_(new PerfGLES2Interface) {} - virtual bool BindToCurrentThread() OVERRIDE { return true; } - virtual Capabilities ContextCapabilities() OVERRIDE { return Capabilities(); } - virtual gpu::gles2::GLES2Interface* ContextGL() OVERRIDE { - return context_gl_.get(); + bool BindToCurrentThread() override { return true; } + Capabilities ContextCapabilities() override { + Capabilities capabilities; + capabilities.gpu.image = true; + capabilities.gpu.sync_query = true; + return capabilities; } - virtual gpu::ContextSupport* ContextSupport() OVERRIDE { return &support_; } - virtual class GrContext* GrContext() OVERRIDE { return NULL; } - virtual bool IsContextLost() OVERRIDE { return false; } - virtual void VerifyContexts() OVERRIDE {} - virtual void DeleteCachedResources() OVERRIDE {} - virtual bool DestroyedOnMainThread() OVERRIDE { return false; } - virtual void SetLostContextCallback(const LostContextCallback& cb) OVERRIDE {} - virtual void SetMemoryPolicyChangedCallback( - const MemoryPolicyChangedCallback& cb) OVERRIDE {} + gpu::gles2::GLES2Interface* ContextGL() override { return context_gl_.get(); } + gpu::ContextSupport* ContextSupport() override { return &support_; } + class GrContext* GrContext() override { + return NULL; + } + bool IsContextLost() override { return false; } + void VerifyContexts() override {} + void DeleteCachedResources() override {} + bool DestroyedOnMainThread() override { return false; } + void SetLostContextCallback(const LostContextCallback& cb) override {} + void SetMemoryPolicyChangedCallback( + const MemoryPolicyChangedCallback& cb) override {} private: - virtual ~PerfContextProvider() {} + ~PerfContextProvider() override {} scoped_ptr<PerfGLES2Interface> context_gl_; TestContextSupport support_; @@ -77,9 +96,10 @@ class PerfContextProvider : public ContextProvider { enum RasterWorkerPoolType { RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER, - RASTER_WORKER_POOL_TYPE_IMAGE, - RASTER_WORKER_POOL_TYPE_IMAGE_COPY, - RASTER_WORKER_POOL_TYPE_DIRECT + RASTER_WORKER_POOL_TYPE_ZERO_COPY, + RASTER_WORKER_POOL_TYPE_ONE_COPY, + RASTER_WORKER_POOL_TYPE_GPU, + RASTER_WORKER_POOL_TYPE_BITMAP }; static const int kTimeLimitMillis = 2000; @@ -91,12 +111,12 @@ class PerfImageDecodeTaskImpl : public ImageDecodeTask { PerfImageDecodeTaskImpl() {} // Overridden from Task: - virtual void RunOnWorkerThread() OVERRIDE {} + void RunOnWorkerThread() override {} // Overridden from RasterizerTask: - virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {} - virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {} - virtual void RunReplyOnOriginThread() OVERRIDE { Reset(); } + void ScheduleOnOriginThread(RasterizerTaskClient* client) override {} + void CompleteOnOriginThread(RasterizerTaskClient* client) override {} + void RunReplyOnOriginThread() override { Reset(); } void Reset() { did_run_ = false; @@ -104,7 +124,7 @@ class PerfImageDecodeTaskImpl : public ImageDecodeTask { } protected: - virtual ~PerfImageDecodeTaskImpl() {} + ~PerfImageDecodeTaskImpl() override {} private: DISALLOW_COPY_AND_ASSIGN(PerfImageDecodeTaskImpl); @@ -117,16 +137,16 @@ class PerfRasterTaskImpl : public RasterTask { : RasterTask(resource.get(), dependencies), resource_(resource.Pass()) {} // Overridden from Task: - virtual void RunOnWorkerThread() OVERRIDE {} + void RunOnWorkerThread() override {} // Overridden from RasterizerTask: - virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE { - client->AcquireCanvasForRaster(this); + void ScheduleOnOriginThread(RasterizerTaskClient* client) override { + raster_buffer_ = client->AcquireBufferForRaster(resource()); } - virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE { - client->ReleaseCanvasForRaster(this); + void CompleteOnOriginThread(RasterizerTaskClient* client) override { + client->ReleaseBufferForRaster(raster_buffer_.Pass()); } - virtual void RunReplyOnOriginThread() OVERRIDE { Reset(); } + void RunReplyOnOriginThread() override { Reset(); } void Reset() { did_run_ = false; @@ -134,35 +154,28 @@ class PerfRasterTaskImpl : public RasterTask { } protected: - virtual ~PerfRasterTaskImpl() {} + ~PerfRasterTaskImpl() override {} private: scoped_ptr<ScopedResource> resource_; + scoped_ptr<RasterBuffer> raster_buffer_; DISALLOW_COPY_AND_ASSIGN(PerfRasterTaskImpl); }; class RasterWorkerPoolPerfTestBase { public: - typedef std::vector<scoped_refptr<RasterTask> > RasterTaskVector; + typedef std::vector<scoped_refptr<RasterTask>> RasterTaskVector; + + enum NamedTaskSet { REQUIRED_FOR_ACTIVATION = 0, ALL = 1 }; RasterWorkerPoolPerfTestBase() : context_provider_(make_scoped_refptr(new PerfContextProvider)), + task_runner_(new base::TestSimpleTaskRunner), task_graph_runner_(new TaskGraphRunner), timer_(kWarmupRuns, base::TimeDelta::FromMilliseconds(kTimeLimitMillis), - kTimeCheckInterval) { - output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass(); - CHECK(output_surface_->BindToClient(&output_surface_client_)); - - shared_bitmap_manager_.reset(new TestSharedBitmapManager()); - resource_provider_ = - ResourceProvider::Create( - output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, - false).Pass(); - staging_resource_pool_ = ResourcePool::Create( - resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888); - } + kTimeCheckInterval) {} void CreateImageDecodeTasks(unsigned num_image_decode_tasks, ImageDecodeTask::Vector* image_decode_tasks) { @@ -178,7 +191,8 @@ class RasterWorkerPoolPerfTestBase { for (unsigned i = 0; i < num_raster_tasks; ++i) { scoped_ptr<ScopedResource> resource( ScopedResource::Create(resource_provider_.get())); - resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888); + resource->Allocate( + size, ResourceProvider::TextureHintImmutable, RGBA_8888); ImageDecodeTask::Vector dependencies = image_decode_tasks; raster_tasks->push_back( @@ -190,9 +204,11 @@ class RasterWorkerPoolPerfTestBase { const RasterTaskVector& raster_tasks) { for (size_t i = 0u; i < raster_tasks.size(); ++i) { bool required_for_activation = (i % 2) == 0; - queue->items.push_back(RasterTaskQueue::Item(raster_tasks[i].get(), - required_for_activation)); - queue->required_for_activation_count += required_for_activation; + TaskSetCollection task_set_collection; + task_set_collection[ALL] = true; + task_set_collection[REQUIRED_FOR_ACTIVATION] = required_for_activation; + queue->items.push_back( + RasterTaskQueue::Item(raster_tasks[i].get(), task_set_collection)); } } @@ -200,9 +216,8 @@ class RasterWorkerPoolPerfTestBase { scoped_refptr<ContextProvider> context_provider_; FakeOutputSurfaceClient output_surface_client_; scoped_ptr<FakeOutputSurface> output_surface_; - scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; scoped_ptr<ResourceProvider> resource_provider_; - scoped_ptr<ResourcePool> staging_resource_pool_; + scoped_refptr<base::TestSimpleTaskRunner> task_runner_; scoped_ptr<TaskGraphRunner> task_graph_runner_; LapTimer timer_; }; @@ -212,60 +227,72 @@ class RasterWorkerPoolPerfTest public testing::TestWithParam<RasterWorkerPoolType>, public RasterizerClient { public: - RasterWorkerPoolPerfTest() { + // Overridden from testing::Test: + virtual void SetUp() override { switch (GetParam()) { case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER: + Create3dOutputSurfaceAndResourceProvider(); raster_worker_pool_ = PixelBufferRasterWorkerPool::Create( - base::MessageLoopProxy::current().get(), + task_runner_.get(), task_graph_runner_.get(), + context_provider_.get(), resource_provider_.get(), std::numeric_limits<size_t>::max()); break; - case RASTER_WORKER_POOL_TYPE_IMAGE: - raster_worker_pool_ = ImageRasterWorkerPool::Create( - base::MessageLoopProxy::current().get(), - task_graph_runner_.get(), - resource_provider_.get()); + case RASTER_WORKER_POOL_TYPE_ZERO_COPY: + Create3dOutputSurfaceAndResourceProvider(); + raster_worker_pool_ = + ZeroCopyRasterWorkerPool::Create(task_runner_.get(), + task_graph_runner_.get(), + resource_provider_.get()); break; - case RASTER_WORKER_POOL_TYPE_IMAGE_COPY: - raster_worker_pool_ = ImageCopyRasterWorkerPool::Create( - base::MessageLoopProxy::current().get(), - task_graph_runner_.get(), - resource_provider_.get(), - staging_resource_pool_.get()); + case RASTER_WORKER_POOL_TYPE_ONE_COPY: + Create3dOutputSurfaceAndResourceProvider(); + staging_resource_pool_ = ResourcePool::Create( + resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888); + raster_worker_pool_ = + OneCopyRasterWorkerPool::Create(task_runner_.get(), + task_graph_runner_.get(), + context_provider_.get(), + resource_provider_.get(), + staging_resource_pool_.get()); break; - case RASTER_WORKER_POOL_TYPE_DIRECT: - raster_worker_pool_ = DirectRasterWorkerPool::Create( - base::MessageLoopProxy::current().get(), - resource_provider_.get(), - context_provider_.get()); + case RASTER_WORKER_POOL_TYPE_GPU: + Create3dOutputSurfaceAndResourceProvider(); + raster_worker_pool_ = + GpuRasterWorkerPool::Create(task_runner_.get(), + context_provider_.get(), + resource_provider_.get(), + false); + break; + case RASTER_WORKER_POOL_TYPE_BITMAP: + CreateSoftwareOutputSurfaceAndResourceProvider(); + raster_worker_pool_ = + BitmapRasterWorkerPool::Create(task_runner_.get(), + task_graph_runner_.get(), + resource_provider_.get()); break; } DCHECK(raster_worker_pool_); raster_worker_pool_->AsRasterizer()->SetClient(this); } - - // Overridden from testing::Test: - virtual void TearDown() OVERRIDE { + virtual void TearDown() override { raster_worker_pool_->AsRasterizer()->Shutdown(); raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks(); } // Overriden from RasterizerClient: - virtual bool ShouldForceTasksRequiredForActivationToComplete() const - OVERRIDE { - return false; - } - virtual void DidFinishRunningTasks() OVERRIDE { + void DidFinishRunningTasks(TaskSet task_set) override { raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks(); - base::MessageLoop::current()->Quit(); } - virtual void DidFinishRunningTasksRequiredForActivation() OVERRIDE {} + TaskSetCollection TasksThatShouldBeForcedToComplete() const override { + return TaskSetCollection(); + } void RunMessageLoopUntilAllTasksHaveCompleted() { task_graph_runner_->RunUntilIdle(); - base::MessageLoop::current()->Run(); + task_runner_->RunUntilIdle(); } void RunScheduleTasksTest(const std::string& test_name, @@ -371,22 +398,52 @@ class RasterWorkerPoolPerfTest } private: + void Create3dOutputSurfaceAndResourceProvider() { + output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass(); + CHECK(output_surface_->BindToClient(&output_surface_client_)); + resource_provider_ = ResourceProvider::Create(output_surface_.get(), + NULL, + &gpu_memory_buffer_manager_, + NULL, + 0, + false, + 1).Pass(); + } + + void CreateSoftwareOutputSurfaceAndResourceProvider() { + output_surface_ = FakeOutputSurface::CreateSoftware( + make_scoped_ptr(new SoftwareOutputDevice)); + CHECK(output_surface_->BindToClient(&output_surface_client_)); + resource_provider_ = ResourceProvider::Create(output_surface_.get(), + &shared_bitmap_manager_, + NULL, + NULL, + 0, + false, + 1).Pass(); + } + std::string TestModifierString() const { switch (GetParam()) { case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER: return std::string("_pixel_raster_worker_pool"); - case RASTER_WORKER_POOL_TYPE_IMAGE: - return std::string("_image_raster_worker_pool"); - case RASTER_WORKER_POOL_TYPE_IMAGE_COPY: - return std::string("_image_copy_raster_worker_pool"); - case RASTER_WORKER_POOL_TYPE_DIRECT: - return std::string("_direct_raster_worker_pool"); + case RASTER_WORKER_POOL_TYPE_ZERO_COPY: + return std::string("_zero_copy_raster_worker_pool"); + case RASTER_WORKER_POOL_TYPE_ONE_COPY: + return std::string("_one_copy_raster_worker_pool"); + case RASTER_WORKER_POOL_TYPE_GPU: + return std::string("_gpu_raster_worker_pool"); + case RASTER_WORKER_POOL_TYPE_BITMAP: + return std::string("_bitmap_raster_worker_pool"); } NOTREACHED(); return std::string(); } + scoped_ptr<ResourcePool> staging_resource_pool_; scoped_ptr<RasterWorkerPool> raster_worker_pool_; + TestGpuMemoryBufferManager gpu_memory_buffer_manager_; + TestSharedBitmapManager shared_bitmap_manager_; }; TEST_P(RasterWorkerPoolPerfTest, ScheduleTasks) { @@ -419,13 +476,23 @@ TEST_P(RasterWorkerPoolPerfTest, ScheduleAndExecuteTasks) { INSTANTIATE_TEST_CASE_P(RasterWorkerPoolPerfTests, RasterWorkerPoolPerfTest, ::testing::Values(RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER, - RASTER_WORKER_POOL_TYPE_IMAGE, - RASTER_WORKER_POOL_TYPE_IMAGE_COPY, - RASTER_WORKER_POOL_TYPE_DIRECT)); + RASTER_WORKER_POOL_TYPE_ZERO_COPY, + RASTER_WORKER_POOL_TYPE_ONE_COPY, + RASTER_WORKER_POOL_TYPE_GPU, + RASTER_WORKER_POOL_TYPE_BITMAP)); class RasterWorkerPoolCommonPerfTest : public RasterWorkerPoolPerfTestBase, public testing::Test { public: + // Overridden from testing::Test: + virtual void SetUp() override { + output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass(); + CHECK(output_surface_->BindToClient(&output_surface_client_)); + resource_provider_ = + ResourceProvider::Create( + output_surface_.get(), NULL, NULL, NULL, 0, false, 1).Pass(); + } + void RunBuildRasterTaskQueueTest(const std::string& test_name, unsigned num_raster_tasks, unsigned num_image_decode_tasks) { diff --git a/chromium/cc/resources/raster_worker_pool_unittest.cc b/chromium/cc/resources/raster_worker_pool_unittest.cc index 7a5f324e39f..9aee8e7bc74 100644 --- a/chromium/cc/resources/raster_worker_pool_unittest.cc +++ b/chromium/cc/resources/raster_worker_pool_unittest.cc @@ -8,18 +8,22 @@ #include <vector> #include "base/cancelable_callback.h" -#include "cc/resources/direct_raster_worker_pool.h" -#include "cc/resources/image_copy_raster_worker_pool.h" -#include "cc/resources/image_raster_worker_pool.h" +#include "cc/resources/bitmap_raster_worker_pool.h" +#include "cc/resources/gpu_raster_worker_pool.h" +#include "cc/resources/one_copy_raster_worker_pool.h" #include "cc/resources/picture_pile.h" #include "cc/resources/picture_pile_impl.h" #include "cc/resources/pixel_buffer_raster_worker_pool.h" +#include "cc/resources/raster_buffer.h" #include "cc/resources/rasterizer.h" #include "cc/resources/resource_pool.h" #include "cc/resources/resource_provider.h" #include "cc/resources/scoped_resource.h" +#include "cc/resources/zero_copy_raster_worker_pool.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" +#include "cc/test/fake_picture_pile_impl.h" +#include "cc/test/test_gpu_memory_buffer_manager.h" #include "cc/test/test_shared_bitmap_manager.h" #include "cc/test/test_web_graphics_context_3d.h" #include "testing/gtest/include/gtest/gtest.h" @@ -27,42 +31,55 @@ namespace cc { namespace { +const size_t kMaxTransferBufferUsageBytes = 10000U; +// A resource of this dimension^2 * 4 must be greater than the above transfer +// buffer constant. +const size_t kLargeResourceDimension = 1000U; + enum RasterWorkerPoolType { RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER, - RASTER_WORKER_POOL_TYPE_IMAGE, - RASTER_WORKER_POOL_TYPE_IMAGE_COPY, - RASTER_WORKER_POOL_TYPE_DIRECT + RASTER_WORKER_POOL_TYPE_ZERO_COPY, + RASTER_WORKER_POOL_TYPE_ONE_COPY, + RASTER_WORKER_POOL_TYPE_GPU, + RASTER_WORKER_POOL_TYPE_BITMAP }; class TestRasterTaskImpl : public RasterTask { public: - typedef base::Callback< - void(const PicturePileImpl::Analysis& analysis, bool was_canceled)> Reply; + typedef base::Callback<void(const RasterSource::SolidColorAnalysis& analysis, + bool was_canceled)> Reply; TestRasterTaskImpl(const Resource* resource, const Reply& reply, ImageDecodeTask::Vector* dependencies) - : RasterTask(resource, dependencies), reply_(reply) {} + : RasterTask(resource, dependencies), + reply_(reply), + picture_pile_(FakePicturePileImpl::CreateEmptyPile(gfx::Size(1, 1), + gfx::Size(1, 1))) {} // Overridden from Task: - virtual void RunOnWorkerThread() OVERRIDE {} + void RunOnWorkerThread() override { + raster_buffer_->Playback(picture_pile_.get(), gfx::Rect(0, 0, 1, 1), 1.0); + } // Overridden from RasterizerTask: - virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE { - client->AcquireCanvasForRaster(this); + void ScheduleOnOriginThread(RasterizerTaskClient* client) override { + raster_buffer_ = client->AcquireBufferForRaster(resource()); } - virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE { - client->ReleaseCanvasForRaster(this); + void CompleteOnOriginThread(RasterizerTaskClient* client) override { + client->ReleaseBufferForRaster(raster_buffer_.Pass()); } - virtual void RunReplyOnOriginThread() OVERRIDE { - reply_.Run(PicturePileImpl::Analysis(), !HasFinishedRunning()); + void RunReplyOnOriginThread() override { + reply_.Run(RasterSource::SolidColorAnalysis(), !HasFinishedRunning()); } protected: - virtual ~TestRasterTaskImpl() {} + ~TestRasterTaskImpl() override {} private: const Reply reply_; + scoped_ptr<RasterBuffer> raster_buffer_; + scoped_refptr<PicturePileImpl> picture_pile_; DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl); }; @@ -76,16 +93,16 @@ class BlockingTestRasterTaskImpl : public TestRasterTaskImpl { : TestRasterTaskImpl(resource, reply, dependencies), lock_(lock) {} // Overridden from Task: - virtual void RunOnWorkerThread() OVERRIDE { + void RunOnWorkerThread() override { base::AutoLock lock(*lock_); TestRasterTaskImpl::RunOnWorkerThread(); } // Overridden from RasterizerTask: - virtual void RunReplyOnOriginThread() OVERRIDE {} + void RunReplyOnOriginThread() override {} protected: - virtual ~BlockingTestRasterTaskImpl() {} + ~BlockingTestRasterTaskImpl() override {} private: base::Lock* lock_; @@ -102,76 +119,81 @@ class RasterWorkerPoolTest bool canceled; }; - typedef std::vector<scoped_refptr<RasterTask> > RasterTaskVector; + typedef std::vector<scoped_refptr<RasterTask>> RasterTaskVector; + + enum NamedTaskSet { REQUIRED_FOR_ACTIVATION = 0, ALL = 1 }; RasterWorkerPoolTest() : context_provider_(TestContextProvider::Create()), timeout_seconds_(5), - timed_out_(false) { - output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass(); - CHECK(output_surface_->BindToClient(&output_surface_client_)); - - shared_bitmap_manager_.reset(new TestSharedBitmapManager()); - resource_provider_ = - ResourceProvider::Create( - output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, - false).Pass(); - staging_resource_pool_ = ResourcePool::Create( - resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888); + timed_out_(false) {} + // Overridden from testing::Test: + virtual void SetUp() override { switch (GetParam()) { case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER: + Create3dOutputSurfaceAndResourceProvider(); raster_worker_pool_ = PixelBufferRasterWorkerPool::Create( base::MessageLoopProxy::current().get(), RasterWorkerPool::GetTaskGraphRunner(), + context_provider_.get(), resource_provider_.get(), - std::numeric_limits<size_t>::max()); + kMaxTransferBufferUsageBytes); break; - case RASTER_WORKER_POOL_TYPE_IMAGE: - raster_worker_pool_ = ImageRasterWorkerPool::Create( + case RASTER_WORKER_POOL_TYPE_ZERO_COPY: + Create3dOutputSurfaceAndResourceProvider(); + raster_worker_pool_ = ZeroCopyRasterWorkerPool::Create( base::MessageLoopProxy::current().get(), RasterWorkerPool::GetTaskGraphRunner(), resource_provider_.get()); break; - case RASTER_WORKER_POOL_TYPE_IMAGE_COPY: - raster_worker_pool_ = ImageCopyRasterWorkerPool::Create( + case RASTER_WORKER_POOL_TYPE_ONE_COPY: + Create3dOutputSurfaceAndResourceProvider(); + staging_resource_pool_ = ResourcePool::Create( + resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888); + raster_worker_pool_ = OneCopyRasterWorkerPool::Create( base::MessageLoopProxy::current().get(), RasterWorkerPool::GetTaskGraphRunner(), + context_provider_.get(), resource_provider_.get(), staging_resource_pool_.get()); break; - case RASTER_WORKER_POOL_TYPE_DIRECT: - raster_worker_pool_ = DirectRasterWorkerPool::Create( + case RASTER_WORKER_POOL_TYPE_GPU: + Create3dOutputSurfaceAndResourceProvider(); + raster_worker_pool_ = + GpuRasterWorkerPool::Create(base::MessageLoopProxy::current().get(), + context_provider_.get(), + resource_provider_.get(), + false); + break; + case RASTER_WORKER_POOL_TYPE_BITMAP: + CreateSoftwareOutputSurfaceAndResourceProvider(); + raster_worker_pool_ = BitmapRasterWorkerPool::Create( base::MessageLoopProxy::current().get(), - resource_provider_.get(), - context_provider_.get()); + RasterWorkerPool::GetTaskGraphRunner(), + resource_provider_.get()); break; } DCHECK(raster_worker_pool_); raster_worker_pool_->AsRasterizer()->SetClient(this); } - virtual ~RasterWorkerPoolTest() { - staging_resource_pool_.reset(); - resource_provider_.reset(); - } - // Overridden from testing::Test: - virtual void TearDown() OVERRIDE { + virtual void TearDown() override { raster_worker_pool_->AsRasterizer()->Shutdown(); raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks(); } // Overriden from RasterWorkerPoolClient: - virtual bool ShouldForceTasksRequiredForActivationToComplete() const - OVERRIDE { - return false; + void DidFinishRunningTasks(TaskSet task_set) override { + if (task_set == ALL) { + raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks(); + base::MessageLoop::current()->Quit(); + } } - virtual void DidFinishRunningTasks() OVERRIDE { - raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks(); - base::MessageLoop::current()->Quit(); + TaskSetCollection TasksThatShouldBeForcedToComplete() const override { + return TaskSetCollection(); } - virtual void DidFinishRunningTasksRequiredForActivation() OVERRIDE {} void RunMessageLoopUntilAllTasksHaveCompleted() { if (timeout_seconds_) { @@ -195,18 +217,19 @@ class RasterWorkerPoolTest for (RasterTaskVector::const_iterator it = tasks_.begin(); it != tasks_.end(); - ++it) - queue.items.push_back(RasterTaskQueue::Item(*it, false)); + ++it) { + TaskSetCollection task_sets; + task_sets[ALL] = true; + queue.items.push_back(RasterTaskQueue::Item(it->get(), task_sets)); + } raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue); } - void AppendTask(unsigned id) { - const gfx::Size size(1, 1); - + void AppendTask(unsigned id, const gfx::Size& size) { scoped_ptr<ScopedResource> resource( ScopedResource::Create(resource_provider_.get())); - resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888); + resource->Allocate(size, ResourceProvider::TextureHintImmutable, RGBA_8888); const Resource* const_resource = resource.get(); ImageDecodeTask::Vector empty; @@ -219,12 +242,14 @@ class RasterWorkerPoolTest &empty)); } + void AppendTask(unsigned id) { AppendTask(id, gfx::Size(1, 1)); } + void AppendBlockingTask(unsigned id, base::Lock* lock) { const gfx::Size size(1, 1); scoped_ptr<ScopedResource> resource( ScopedResource::Create(resource_provider_.get())); - resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888); + resource->Allocate(size, ResourceProvider::TextureHintImmutable, RGBA_8888); const Resource* const_resource = resource.get(); ImageDecodeTask::Vector empty; @@ -243,9 +268,36 @@ class RasterWorkerPoolTest } private: + void Create3dOutputSurfaceAndResourceProvider() { + output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass(); + CHECK(output_surface_->BindToClient(&output_surface_client_)); + TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d(); + context3d->set_support_sync_query(true); + resource_provider_ = ResourceProvider::Create(output_surface_.get(), + NULL, + &gpu_memory_buffer_manager_, + NULL, + 0, + false, + 1).Pass(); + } + + void CreateSoftwareOutputSurfaceAndResourceProvider() { + output_surface_ = FakeOutputSurface::CreateSoftware( + make_scoped_ptr(new SoftwareOutputDevice)); + CHECK(output_surface_->BindToClient(&output_surface_client_)); + resource_provider_ = ResourceProvider::Create(output_surface_.get(), + &shared_bitmap_manager_, + NULL, + NULL, + 0, + false, + 1).Pass(); + } + void OnTaskCompleted(scoped_ptr<ScopedResource> resource, unsigned id, - const PicturePileImpl::Analysis& analysis, + const RasterSource::SolidColorAnalysis& analysis, bool was_canceled) { RasterTaskResult result; result.id = id; @@ -262,10 +314,11 @@ class RasterWorkerPoolTest scoped_refptr<TestContextProvider> context_provider_; FakeOutputSurfaceClient output_surface_client_; scoped_ptr<FakeOutputSurface> output_surface_; - scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; scoped_ptr<ResourceProvider> resource_provider_; scoped_ptr<ResourcePool> staging_resource_pool_; scoped_ptr<RasterWorkerPool> raster_worker_pool_; + TestGpuMemoryBufferManager gpu_memory_buffer_manager_; + TestSharedBitmapManager shared_bitmap_manager_; base::CancelableClosure timeout_; int timeout_seconds_; bool timed_out_; @@ -286,8 +339,10 @@ TEST_P(RasterWorkerPoolTest, Basic) { } TEST_P(RasterWorkerPoolTest, FailedMapResource) { + if (GetParam() == RASTER_WORKER_POOL_TYPE_BITMAP) + return; + TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d(); - context3d->set_times_map_image_chromium_succeeds(0); context3d->set_times_map_buffer_chromium_succeeds(0); AppendTask(0u); ScheduleTasks(); @@ -322,12 +377,34 @@ TEST_P(RasterWorkerPoolTest, FalseThrottling) { RunMessageLoopUntilAllTasksHaveCompleted(); } +TEST_P(RasterWorkerPoolTest, LargeResources) { + gfx::Size size(kLargeResourceDimension, kLargeResourceDimension); + + { + // Verify a resource of this size is larger than the transfer buffer. + scoped_ptr<ScopedResource> resource( + ScopedResource::Create(resource_provider_.get())); + resource->Allocate(size, ResourceProvider::TextureHintImmutable, RGBA_8888); + EXPECT_GE(resource->bytes(), kMaxTransferBufferUsageBytes); + } + + AppendTask(0u, size); + AppendTask(1u, size); + AppendTask(2u, size); + ScheduleTasks(); + + // This will time out if a resource that is larger than the throttle limit + // never gets scheduled. + RunMessageLoopUntilAllTasksHaveCompleted(); +} + INSTANTIATE_TEST_CASE_P(RasterWorkerPoolTests, RasterWorkerPoolTest, ::testing::Values(RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER, - RASTER_WORKER_POOL_TYPE_IMAGE, - RASTER_WORKER_POOL_TYPE_IMAGE_COPY, - RASTER_WORKER_POOL_TYPE_DIRECT)); + RASTER_WORKER_POOL_TYPE_ZERO_COPY, + RASTER_WORKER_POOL_TYPE_ONE_COPY, + RASTER_WORKER_POOL_TYPE_GPU, + RASTER_WORKER_POOL_TYPE_BITMAP)); } // namespace } // namespace cc diff --git a/chromium/cc/resources/rasterizer.cc b/chromium/cc/resources/rasterizer.cc index df7e27ecebc..4ce8987e8ca 100644 --- a/chromium/cc/resources/rasterizer.cc +++ b/chromium/cc/resources/rasterizer.cc @@ -56,23 +56,24 @@ RasterTask::~RasterTask() {} RasterTask* RasterTask::AsRasterTask() { return this; } -RasterTaskQueue::Item::Item(RasterTask* task, bool required_for_activation) - : task(task), required_for_activation(required_for_activation) {} +RasterTaskQueue::Item::Item(RasterTask* task, + const TaskSetCollection& task_sets) + : task(task), task_sets(task_sets) { + DCHECK(task_sets.any()); +} RasterTaskQueue::Item::~Item() {} -RasterTaskQueue::RasterTaskQueue() : required_for_activation_count(0u) {} +RasterTaskQueue::RasterTaskQueue() { +} RasterTaskQueue::~RasterTaskQueue() {} void RasterTaskQueue::Swap(RasterTaskQueue* other) { items.swap(other->items); - std::swap(required_for_activation_count, - other->required_for_activation_count); } void RasterTaskQueue::Reset() { - required_for_activation_count = 0u; items.clear(); } diff --git a/chromium/cc/resources/rasterizer.h b/chromium/cc/resources/rasterizer.h index 17cc94ed6fa..526058c338d 100644 --- a/chromium/cc/resources/rasterizer.h +++ b/chromium/cc/resources/rasterizer.h @@ -5,23 +5,24 @@ #ifndef CC_RESOURCES_RASTERIZER_H_ #define CC_RESOURCES_RASTERIZER_H_ +#include <bitset> #include <vector> #include "base/callback.h" #include "cc/resources/resource_format.h" #include "cc/resources/task_graph_runner.h" -class SkCanvas; - namespace cc { class ImageDecodeTask; class RasterTask; class Resource; +class RasterBuffer; class CC_EXPORT RasterizerTaskClient { public: - virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) = 0; - virtual void ReleaseCanvasForRaster(RasterTask* task) = 0; + virtual scoped_ptr<RasterBuffer> AcquireBufferForRaster( + const Resource* resource) = 0; + virtual void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) = 0; protected: virtual ~RasterizerTaskClient() {} @@ -29,7 +30,7 @@ class CC_EXPORT RasterizerTaskClient { class CC_EXPORT RasterizerTask : public Task { public: - typedef std::vector<scoped_refptr<RasterizerTask> > Vector; + typedef std::vector<scoped_refptr<RasterizerTask>> Vector; virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) = 0; virtual void CompleteOnOriginThread(RasterizerTaskClient* client) = 0; @@ -49,7 +50,7 @@ class CC_EXPORT RasterizerTask : public Task { protected: RasterizerTask(); - virtual ~RasterizerTask(); + ~RasterizerTask() override; bool did_schedule_; bool did_complete_; @@ -57,40 +58,43 @@ class CC_EXPORT RasterizerTask : public Task { class CC_EXPORT ImageDecodeTask : public RasterizerTask { public: - typedef std::vector<scoped_refptr<ImageDecodeTask> > Vector; + typedef std::vector<scoped_refptr<ImageDecodeTask>> Vector; // Overridden from RasterizerTask: - virtual ImageDecodeTask* AsImageDecodeTask() OVERRIDE; + ImageDecodeTask* AsImageDecodeTask() override; protected: ImageDecodeTask(); - virtual ~ImageDecodeTask(); + ~ImageDecodeTask() override; }; class CC_EXPORT RasterTask : public RasterizerTask { public: - typedef std::vector<scoped_refptr<RasterTask> > Vector; + typedef std::vector<scoped_refptr<RasterTask>> Vector; // Overridden from RasterizerTask: - virtual RasterTask* AsRasterTask() OVERRIDE; + RasterTask* AsRasterTask() override; const Resource* resource() const { return resource_; } const ImageDecodeTask::Vector& dependencies() const { return dependencies_; } protected: RasterTask(const Resource* resource, ImageDecodeTask::Vector* dependencies); - virtual ~RasterTask(); + ~RasterTask() override; private: const Resource* resource_; ImageDecodeTask::Vector dependencies_; }; +static const size_t kNumberOfTaskSets = 2; +typedef size_t TaskSet; +typedef std::bitset<kNumberOfTaskSets> TaskSetCollection; + class CC_EXPORT RasterizerClient { public: - virtual bool ShouldForceTasksRequiredForActivationToComplete() const = 0; - virtual void DidFinishRunningTasks() = 0; - virtual void DidFinishRunningTasksRequiredForActivation() = 0; + virtual void DidFinishRunningTasks(TaskSet task_set) = 0; + virtual TaskSetCollection TasksThatShouldBeForcedToComplete() const = 0; protected: virtual ~RasterizerClient() {} @@ -110,15 +114,11 @@ struct CC_EXPORT RasterTaskQueue { typedef std::vector<Item> Vector; - Item(RasterTask* task, bool required_for_activation); + Item(RasterTask* task, const TaskSetCollection& task_sets); ~Item(); - static bool IsRequiredForActivation(const Item& item) { - return item.required_for_activation; - } - RasterTask* task; - bool required_for_activation; + TaskSetCollection task_sets; }; RasterTaskQueue(); @@ -128,7 +128,6 @@ struct CC_EXPORT RasterTaskQueue { void Reset(); Item::Vector items; - size_t required_for_activation_count; }; // This interface can be used to schedule and run raster tasks. The client will diff --git a/chromium/cc/resources/release_callback_impl.h b/chromium/cc/resources/release_callback_impl.h new file mode 100644 index 00000000000..89f22b66976 --- /dev/null +++ b/chromium/cc/resources/release_callback_impl.h @@ -0,0 +1,20 @@ +// 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_RELEASE_CALLBACK_IMPL_H_ +#define CC_RESOURCES_RELEASE_CALLBACK_IMPL_H_ + +#include "base/callback.h" + +namespace cc { +class BlockingTaskRunner; + +typedef base::Callback<void(uint32 sync_point, + bool is_lost, + BlockingTaskRunner* main_thread_task_runner)> + ReleaseCallbackImpl; + +} // namespace cc + +#endif // CC_RESOURCES_RELEASE_CALLBACK_IMPL_H_ diff --git a/chromium/cc/resources/resource.h b/chromium/cc/resources/resource.h index 24cb88a9f84..707d77e20bf 100644 --- a/chromium/cc/resources/resource.h +++ b/chromium/cc/resources/resource.h @@ -8,7 +8,7 @@ #include "cc/base/cc_export.h" #include "cc/resources/resource_provider.h" #include "third_party/khronos/GLES2/gl2.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" namespace cc { diff --git a/chromium/cc/resources/resource_format.cc b/chromium/cc/resources/resource_format.cc index 273085604a4..6cd0a93e921 100644 --- a/chromium/cc/resources/resource_format.cc +++ b/chromium/cc/resources/resource_format.cc @@ -12,15 +12,16 @@ SkColorType ResourceFormatToSkColorType(ResourceFormat format) { return kARGB_4444_SkColorType; case RGBA_8888: case BGRA_8888: - return kPMColor_SkColorType; + return kN32_SkColorType; case ETC1: + case ALPHA_8: case LUMINANCE_8: case RGB_565: NOTREACHED(); break; } NOTREACHED(); - return kPMColor_SkColorType; + return kN32_SkColorType; } } // namespace cc diff --git a/chromium/cc/resources/resource_format.h b/chromium/cc/resources/resource_format.h index 816c2857913..b51ac7cfe72 100644 --- a/chromium/cc/resources/resource_format.h +++ b/chromium/cc/resources/resource_format.h @@ -15,6 +15,7 @@ enum ResourceFormat { RGBA_8888, RGBA_4444, BGRA_8888, + ALPHA_8, LUMINANCE_8, RGB_565, ETC1, diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc index 31b9b272013..45f36e27816 100644 --- a/chromium/cc/resources/resource_pool.cc +++ b/chromium/cc/resources/resource_pool.cc @@ -105,12 +105,15 @@ bool ResourcePool::ResourceUsageTooHigh() { return false; } -void ResourcePool::CheckBusyResources() { +void ResourcePool::CheckBusyResources(bool wait_if_needed) { ResourceList::iterator it = busy_resources_.begin(); while (it != busy_resources_.end()) { ScopedResource* resource = *it; + if (wait_if_needed) + resource_provider_->WaitReadLockIfNeeded(resource->id()); + if (resource_provider_->CanLockForWrite(resource->id())) { DidFinishUsingResource(resource); it = busy_resources_.erase(it); diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h index 5f481e986a1..e1ee35aa72c 100644 --- a/chromium/cc/resources/resource_pool.h +++ b/chromium/cc/resources/resource_pool.h @@ -34,7 +34,10 @@ class CC_EXPORT ResourcePool { size_t max_resource_count); void ReduceResourceUsage(); - void CheckBusyResources(); + // This might block if |wait_if_needed| is true and one of the currently + // busy resources has a read lock fence that needs to be waited upon before + // it can be locked for write again. + void CheckBusyResources(bool wait_if_needed); size_t total_memory_usage_bytes() const { return memory_usage_bytes_; } size_t acquired_memory_usage_bytes() const { @@ -44,6 +47,7 @@ class CC_EXPORT ResourcePool { size_t acquired_resource_count() const { return resource_count_ - unused_resources_.size(); } + size_t busy_resource_count() const { return busy_resources_.size(); } ResourceFormat resource_format() const { return format_; } diff --git a/chromium/cc/resources/resource_provider.cc b/chromium/cc/resources/resource_provider.cc index e3c21ff7c6b..023a1cdbf06 100644 --- a/chromium/cc/resources/resource_provider.cc +++ b/chromium/cc/resources/resource_provider.cc @@ -21,14 +21,15 @@ #include "cc/resources/transferable_resource.h" #include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/gles2_interface.h" +#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/GrContext.h" -#include "third_party/skia/include/gpu/SkGpuDevice.h" #include "ui/gfx/frame_time.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/vector2d.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/gpu_memory_buffer.h" using gpu::gles2::GLES2Interface; @@ -70,6 +71,7 @@ GLenum TextureToStorageFormat(ResourceFormat format) { storage_format = GL_BGRA8_EXT; break; case RGBA_4444: + case ALPHA_8: case LUMINANCE_8: case RGB_565: case ETC1: @@ -80,12 +82,14 @@ GLenum TextureToStorageFormat(ResourceFormat format) { return storage_format; } -bool IsFormatSupportedForStorage(ResourceFormat format) { +bool IsFormatSupportedForStorage(ResourceFormat format, bool use_bgra) { switch (format) { case RGBA_8888: - case BGRA_8888: return true; + case BGRA_8888: + return use_bgra; case RGBA_4444: + case ALPHA_8: case LUMINANCE_8: case RGB_565: case ETC1: @@ -109,25 +113,21 @@ GrPixelConfig ToGrPixelConfig(ResourceFormat format) { return kSkia8888_GrPixelConfig; } -class IdentityAllocator : public SkBitmap::Allocator { - public: - explicit IdentityAllocator(void* buffer) : buffer_(buffer) {} - virtual bool allocPixelRef(SkBitmap* dst, SkColorTable*) OVERRIDE { - dst->setPixels(buffer_); - return true; +gfx::GpuMemoryBuffer::Format ToGpuMemoryBufferFormat(ResourceFormat format) { + switch (format) { + case RGBA_8888: + return gfx::GpuMemoryBuffer::Format::RGBA_8888; + case BGRA_8888: + return gfx::GpuMemoryBuffer::Format::BGRA_8888; + case RGBA_4444: + case ALPHA_8: + case LUMINANCE_8: + case RGB_565: + case ETC1: + break; } - - private: - void* buffer_; -}; - -void CopyBitmap(const SkBitmap& src, uint8_t* dst, SkColorType dst_colorType) { - SkBitmap dst_bitmap; - IdentityAllocator allocator(dst); - src.copyTo(&dst_bitmap, dst_colorType, &allocator); - // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the - // bitmap data. This check will be removed once crbug.com/293728 is fixed. - CHECK_EQ(0u, dst_bitmap.rowBytes() % 4); + NOTREACHED(); + return gfx::GpuMemoryBuffer::Format::RGBA_8888; } class ScopedSetActiveTexture { @@ -156,13 +156,13 @@ class TextureIdAllocator : public IdAllocator { TextureIdAllocator(GLES2Interface* gl, size_t texture_id_allocation_chunk_size) : IdAllocator(gl, texture_id_allocation_chunk_size) {} - virtual ~TextureIdAllocator() { + ~TextureIdAllocator() override { gl_->DeleteTextures(id_allocation_chunk_size_ - next_id_index_, ids_.get() + next_id_index_); } // Overridden from IdAllocator: - virtual GLuint NextId() OVERRIDE { + GLuint NextId() override { if (next_id_index_ == id_allocation_chunk_size_) { gl_->GenTextures(id_allocation_chunk_size_, ids_.get()); next_id_index_ = 0; @@ -179,13 +179,13 @@ class BufferIdAllocator : public IdAllocator { public: BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size) : IdAllocator(gl, buffer_id_allocation_chunk_size) {} - virtual ~BufferIdAllocator() { + ~BufferIdAllocator() override { gl_->DeleteBuffers(id_allocation_chunk_size_ - next_id_index_, ids_.get() + next_id_index_); } // Overridden from IdAllocator: - virtual GLuint NextId() OVERRIDE { + GLuint NextId() override { if (next_id_index_ == id_allocation_chunk_size_) { gl_->GenBuffers(id_allocation_chunk_size_, ids_.get()); next_id_index_ = 0; @@ -206,15 +206,20 @@ class QueryFence : public ResourceProvider::Fence { : gl_(gl), query_id_(query_id) {} // Overridden from ResourceProvider::Fence: - virtual bool HasPassed() OVERRIDE { + void Set() override {} + bool HasPassed() override { unsigned available = 1; gl_->GetQueryObjectuivEXT( query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available); return !!available; } + void Wait() override { + unsigned result = 0; + gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result); + } private: - virtual ~QueryFence() {} + ~QueryFence() override {} gpu::gles2::GLES2Interface* gl_; unsigned query_id_; @@ -241,7 +246,7 @@ ResourceProvider::Resource::Resource() pending_set_pixels(false), set_pixels_completion_forced(false), allocated(false), - enable_read_lock_fences(false), + read_lock_fences_enabled(false), has_shared_bitmap_id(false), allow_overlay(false), read_lock_fence(NULL), @@ -254,10 +259,12 @@ ResourceProvider::Resource::Resource() bound_image_id(0), texture_pool(0), wrap_mode(0), - hint(TextureUsageAny), + hint(TextureHintImmutable), type(InvalidType), format(RGBA_8888), - shared_bitmap(NULL) {} + shared_bitmap(NULL), + gpu_memory_buffer(NULL) { +} ResourceProvider::Resource::~Resource() {} @@ -268,7 +275,7 @@ ResourceProvider::Resource::Resource(GLuint texture_id, GLenum filter, GLenum texture_pool, GLint wrap_mode, - TextureUsageHint hint, + TextureHint hint, ResourceFormat format) : child_id(0), gl_id(texture_id), @@ -286,7 +293,7 @@ ResourceProvider::Resource::Resource(GLuint texture_id, pending_set_pixels(false), set_pixels_completion_forced(false), allocated(false), - enable_read_lock_fences(false), + read_lock_fences_enabled(false), has_shared_bitmap_id(false), allow_overlay(false), read_lock_fence(NULL), @@ -302,7 +309,8 @@ ResourceProvider::Resource::Resource(GLuint texture_id, hint(hint), type(GLTexture), format(format), - shared_bitmap(NULL) { + shared_bitmap(NULL), + gpu_memory_buffer(NULL) { DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); DCHECK_EQ(origin == Internal, !!texture_pool); } @@ -329,7 +337,7 @@ ResourceProvider::Resource::Resource(uint8_t* pixels, pending_set_pixels(false), set_pixels_completion_forced(false), allocated(false), - enable_read_lock_fences(false), + read_lock_fences_enabled(false), has_shared_bitmap_id(!!bitmap), allow_overlay(false), read_lock_fence(NULL), @@ -342,10 +350,11 @@ ResourceProvider::Resource::Resource(uint8_t* pixels, bound_image_id(0), texture_pool(0), wrap_mode(wrap_mode), - hint(TextureUsageAny), + hint(TextureHintImmutable), type(Bitmap), format(RGBA_8888), - shared_bitmap(bitmap) { + shared_bitmap(bitmap), + gpu_memory_buffer(NULL) { DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); DCHECK(origin == Delegated || pixels); if (bitmap) @@ -373,7 +382,7 @@ ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id, pending_set_pixels(false), set_pixels_completion_forced(false), allocated(false), - enable_read_lock_fences(false), + read_lock_fences_enabled(false), has_shared_bitmap_id(true), allow_overlay(false), read_lock_fence(NULL), @@ -386,209 +395,15 @@ ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id, bound_image_id(0), texture_pool(0), wrap_mode(wrap_mode), - hint(TextureUsageAny), + hint(TextureHintImmutable), type(Bitmap), format(RGBA_8888), shared_bitmap_id(bitmap_id), - shared_bitmap(NULL) { + shared_bitmap(NULL), + gpu_memory_buffer(NULL) { DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); } -ResourceProvider::RasterBuffer::RasterBuffer( - const Resource* resource, - ResourceProvider* resource_provider) - : resource_(resource), - resource_provider_(resource_provider), - locked_canvas_(NULL), - canvas_save_count_(0) { - DCHECK(resource_); - DCHECK(resource_provider_); -} - -ResourceProvider::RasterBuffer::~RasterBuffer() {} - -SkCanvas* ResourceProvider::RasterBuffer::LockForWrite() { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "ResourceProvider::RasterBuffer::LockForWrite"); - - DCHECK(!locked_canvas_); - - locked_canvas_ = DoLockForWrite(); - canvas_save_count_ = locked_canvas_ ? locked_canvas_->save() : 0; - return locked_canvas_; -} - -bool ResourceProvider::RasterBuffer::UnlockForWrite() { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "ResourceProvider::RasterBuffer::UnlockForWrite"); - - if (locked_canvas_) { - locked_canvas_->restoreToCount(canvas_save_count_); - locked_canvas_ = NULL; - } - return DoUnlockForWrite(); -} - -ResourceProvider::DirectRasterBuffer::DirectRasterBuffer( - const Resource* resource, - ResourceProvider* resource_provider, - bool use_distance_field_text ) - : RasterBuffer(resource, resource_provider), - surface_generation_id_(0u), - use_distance_field_text_(use_distance_field_text) {} - -ResourceProvider::DirectRasterBuffer::~DirectRasterBuffer() {} - -SkCanvas* ResourceProvider::DirectRasterBuffer::DoLockForWrite() { - if (!surface_) - surface_ = CreateSurface(); - surface_generation_id_ = surface_ ? surface_->generationID() : 0u; - return surface_ ? surface_->getCanvas() : NULL; -} - -bool ResourceProvider::DirectRasterBuffer::DoUnlockForWrite() { - // generationID returns a non-zero, unique value corresponding to the content - // of surface. Hence, a change since DoLockForWrite was called means the - // surface has changed. - return surface_ ? surface_generation_id_ != surface_->generationID() : false; -} - -skia::RefPtr<SkSurface> ResourceProvider::DirectRasterBuffer::CreateSurface() { - skia::RefPtr<SkSurface> surface; - switch (resource()->type) { - case GLTexture: { - DCHECK(resource()->gl_id); - class GrContext* gr_context = resource_provider()->GrContext(); - if (gr_context) { - GrBackendTextureDesc desc; - desc.fFlags = kRenderTarget_GrBackendTextureFlag; - desc.fWidth = resource()->size.width(); - desc.fHeight = resource()->size.height(); - desc.fConfig = ToGrPixelConfig(resource()->format); - desc.fOrigin = kTopLeft_GrSurfaceOrigin; - desc.fTextureHandle = resource()->gl_id; - skia::RefPtr<GrTexture> gr_texture = - skia::AdoptRef(gr_context->wrapBackendTexture(desc)); - SkSurface::TextRenderMode text_render_mode = - use_distance_field_text_ ? SkSurface::kDistanceField_TextRenderMode - : SkSurface::kStandard_TextRenderMode; - surface = skia::AdoptRef(SkSurface::NewRenderTargetDirect( - gr_texture->asRenderTarget(), text_render_mode)); - } - break; - } - case Bitmap: { - DCHECK(resource()->pixels); - DCHECK_EQ(RGBA_8888, resource()->format); - SkImageInfo image_info = SkImageInfo::MakeN32Premul( - resource()->size.width(), resource()->size.height()); - surface = skia::AdoptRef(SkSurface::NewRasterDirect( - image_info, resource()->pixels, image_info.minRowBytes())); - break; - } - default: - NOTREACHED(); - } - return surface; -} - -ResourceProvider::BitmapRasterBuffer::BitmapRasterBuffer( - const Resource* resource, - ResourceProvider* resource_provider) - : RasterBuffer(resource, resource_provider), - mapped_buffer_(NULL), - raster_bitmap_generation_id_(0u) {} - -ResourceProvider::BitmapRasterBuffer::~BitmapRasterBuffer() {} - -SkCanvas* ResourceProvider::BitmapRasterBuffer::DoLockForWrite() { - DCHECK(!mapped_buffer_); - DCHECK(!raster_canvas_); - - int stride = 0; - mapped_buffer_ = MapBuffer(&stride); - if (!mapped_buffer_) - return NULL; - - switch (resource()->format) { - case RGBA_4444: - // Use the default stride if we will eventually convert this - // bitmap to 4444. - raster_bitmap_.allocN32Pixels(resource()->size.width(), - resource()->size.height()); - break; - case RGBA_8888: - case BGRA_8888: { - SkImageInfo info = SkImageInfo::MakeN32Premul(resource()->size.width(), - resource()->size.height()); - if (0 == stride) - stride = info.minRowBytes(); - raster_bitmap_.installPixels(info, mapped_buffer_, stride); - break; - } - case LUMINANCE_8: - case RGB_565: - case ETC1: - NOTREACHED(); - break; - } - raster_canvas_ = skia::AdoptRef(new SkCanvas(raster_bitmap_)); - raster_bitmap_generation_id_ = raster_bitmap_.getGenerationID(); - return raster_canvas_.get(); -} - -bool ResourceProvider::BitmapRasterBuffer::DoUnlockForWrite() { - raster_canvas_.clear(); - - // getGenerationID returns a non-zero, unique value corresponding to the - // pixels in bitmap. Hence, a change since DoLockForWrite was called means the - // bitmap has changed. - bool raster_bitmap_changed = - raster_bitmap_generation_id_ != raster_bitmap_.getGenerationID(); - - if (raster_bitmap_changed) { - SkColorType buffer_colorType = - ResourceFormatToSkColorType(resource()->format); - if (mapped_buffer_ && (buffer_colorType != raster_bitmap_.colorType())) - CopyBitmap(raster_bitmap_, mapped_buffer_, buffer_colorType); - } - raster_bitmap_.reset(); - - UnmapBuffer(); - mapped_buffer_ = NULL; - return raster_bitmap_changed; -} - -ResourceProvider::ImageRasterBuffer::ImageRasterBuffer( - const Resource* resource, - ResourceProvider* resource_provider) - : BitmapRasterBuffer(resource, resource_provider) {} - -ResourceProvider::ImageRasterBuffer::~ImageRasterBuffer() {} - -uint8_t* ResourceProvider::ImageRasterBuffer::MapBuffer(int* stride) { - return resource_provider()->MapImage(resource(), stride); -} - -void ResourceProvider::ImageRasterBuffer::UnmapBuffer() { - resource_provider()->UnmapImage(resource()); -} - -ResourceProvider::PixelRasterBuffer::PixelRasterBuffer( - const Resource* resource, - ResourceProvider* resource_provider) - : BitmapRasterBuffer(resource, resource_provider) {} - -ResourceProvider::PixelRasterBuffer::~PixelRasterBuffer() {} - -uint8_t* ResourceProvider::PixelRasterBuffer::MapBuffer(int* stride) { - return resource_provider()->MapPixelBuffer(resource(), stride); -} - -void ResourceProvider::PixelRasterBuffer::UnmapBuffer() { - resource_provider()->UnmapPixelBuffer(resource()); -} - ResourceProvider::Child::Child() : marked_for_deletion(false) {} ResourceProvider::Child::~Child() {} @@ -596,17 +411,19 @@ ResourceProvider::Child::~Child() {} scoped_ptr<ResourceProvider> ResourceProvider::Create( OutputSurface* output_surface, SharedBitmapManager* shared_bitmap_manager, + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, + BlockingTaskRunner* blocking_main_thread_task_runner, int highp_threshold_min, bool use_rgba_4444_texture_format, - size_t id_allocation_chunk_size, - bool use_distance_field_text) { + size_t id_allocation_chunk_size) { scoped_ptr<ResourceProvider> resource_provider( new ResourceProvider(output_surface, shared_bitmap_manager, + gpu_memory_buffer_manager, + blocking_main_thread_task_runner, highp_threshold_min, use_rgba_4444_texture_format, - id_allocation_chunk_size, - use_distance_field_text)); + id_allocation_chunk_size)); if (resource_provider->ContextGL()) resource_provider->InitializeGL(); @@ -645,7 +462,7 @@ bool ResourceProvider::AllowOverlay(ResourceId id) { ResourceProvider::ResourceId ResourceProvider::CreateResource( const gfx::Size& size, GLint wrap_mode, - TextureUsageHint hint, + TextureHint hint, ResourceFormat format) { DCHECK(!size.IsEmpty()); switch (default_resource_type_) { @@ -671,7 +488,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateManagedResource( const gfx::Size& size, GLenum target, GLint wrap_mode, - TextureUsageHint hint, + TextureHint hint, ResourceFormat format) { DCHECK(!size.IsEmpty()); switch (default_resource_type_) { @@ -698,7 +515,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateGLTexture( GLenum target, GLenum texture_pool, GLint wrap_mode, - TextureUsageHint hint, + TextureHint hint, ResourceFormat format) { DCHECK_LE(size.width(), max_texture_size_); DCHECK_LE(size.height(), max_texture_size_); @@ -757,7 +574,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface( GL_LINEAR, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, GL_CLAMP_TO_EDGE, - TextureUsageAny, + TextureHintImmutable, RGBA_8888); LazyCreate(&resource); GLES2Interface* gl = ContextGL(); @@ -772,7 +589,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface( ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( const TextureMailbox& mailbox, - scoped_ptr<SingleReleaseCallback> release_callback) { + scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) { DCHECK(thread_checker_.CalledOnValidThread()); // Just store the information. Mailbox will be consumed in LockForRead(). ResourceId id = next_id_++; @@ -786,7 +603,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( GL_LINEAR, 0, GL_CLAMP_TO_EDGE, - TextureUsageAny, + TextureHintImmutable, RGBA_8888); } else { DCHECK(mailbox.IsSharedMemory()); @@ -808,9 +625,9 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( } resource.allocated = true; resource.mailbox = mailbox; - resource.release_callback = - base::Bind(&SingleReleaseCallback::Run, - base::Owned(release_callback.release())); + resource.release_callback_impl = + base::Bind(&SingleReleaseCallbackImpl::Run, + base::Owned(release_callback_impl.release())); resource.allow_overlay = mailbox.allow_overlay(); return id; } @@ -842,10 +659,6 @@ void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it, if (style == ForShutdown && resource->exported_count > 0) lost_resource = true; - resource->direct_raster_buffer.reset(); - resource->image_raster_buffer.reset(); - resource->pixel_raster_buffer.reset(); - if (resource->image_id) { DCHECK(resource->origin == Resource::Internal); GLES2Interface* gl = ContextGL(); @@ -894,7 +707,8 @@ void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it, resource->shared_bitmap = NULL; } } - resource->release_callback.Run(sync_point, lost_resource); + resource->release_callback_impl.Run( + sync_point, lost_resource, blocking_main_thread_task_runner_); } if (resource->gl_id) { GLES2Interface* gl = ContextGL(); @@ -911,6 +725,12 @@ void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it, if (resource->pixels) { DCHECK(resource->origin == Resource::Internal); delete[] resource->pixels; + resource->pixels = NULL; + } + if (resource->gpu_memory_buffer) { + DCHECK(resource->origin == Resource::Internal); + delete resource->gpu_memory_buffer; + resource->gpu_memory_buffer = NULL; } resources_.erase(it); } @@ -1027,30 +847,6 @@ base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime( return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads; } -void ResourceProvider::Flush() { - DCHECK(thread_checker_.CalledOnValidThread()); - GLES2Interface* gl = ContextGL(); - if (gl) - gl->Flush(); -} - -void ResourceProvider::Finish() { - DCHECK(thread_checker_.CalledOnValidThread()); - GLES2Interface* gl = ContextGL(); - if (gl) - gl->Finish(); -} - -bool ResourceProvider::ShallowFlushIfSupported() { - DCHECK(thread_checker_.CalledOnValidThread()); - GLES2Interface* gl = ContextGL(); - if (!gl) - return false; - - gl->ShallowFlushCHROMIUM(); - return true; -} - ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) { DCHECK(thread_checker_.CalledOnValidThread()); ResourceMap::iterator it = resources_.find(id); @@ -1073,12 +869,13 @@ const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) { if (resource->type == GLTexture && !resource->gl_id) { DCHECK(resource->origin != Resource::Internal); DCHECK(resource->mailbox.IsTexture()); + + // Mailbox sync_points must be processed by a call to + // WaitSyncPointIfNeeded() prior to calling LockForRead(). + DCHECK(!resource->mailbox.sync_point()); + GLES2Interface* gl = ContextGL(); DCHECK(gl); - if (resource->mailbox.sync_point()) { - GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point())); - resource->mailbox.set_sync_point(0); - } resource->gl_id = texture_id_allocator_->NextId(); GLC(gl, gl->BindTexture(resource->target, resource->gl_id)); GLC(gl, @@ -1098,8 +895,11 @@ const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) { } resource->lock_for_read_count++; - if (resource->enable_read_lock_fences) + if (resource->read_lock_fences_enabled) { + if (current_read_lock_fence_.get()) + current_read_lock_fence_->Set(); resource->read_lock_fence = current_read_lock_fence_; + } return resource; } @@ -1126,16 +926,9 @@ void ResourceProvider::UnlockForRead(ResourceId id) { } } -const ResourceProvider::Resource* ResourceProvider::LockForWrite( - ResourceId id) { +ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) { Resource* resource = GetResource(id); - DCHECK(!resource->locked_for_write); - DCHECK(!resource->lock_for_read_count); - DCHECK_EQ(resource->exported_count, 0); - DCHECK(resource->origin == Resource::Internal); - DCHECK(!resource->lost); - DCHECK(ReadLockFenceHasPassed(resource)); - LazyAllocate(resource); + DCHECK(CanLockForWrite(id)); resource->locked_for_write = true; return resource; @@ -1148,8 +941,7 @@ bool ResourceProvider::CanLockForWrite(ResourceId id) { !resource->lost && ReadLockFenceHasPassed(resource); } -void ResourceProvider::UnlockForWrite(ResourceId id) { - Resource* resource = GetResource(id); +void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) { DCHECK(resource->locked_for_write); DCHECK_EQ(resource->exported_count, 0); DCHECK(resource->origin == Resource::Internal); @@ -1195,13 +987,14 @@ ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL( ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id) : resource_provider_(resource_provider), - resource_id_(resource_id), - texture_id_(resource_provider->LockForWrite(resource_id)->gl_id) { + resource_(resource_provider->LockForWrite(resource_id)) { + resource_provider_->LazyAllocate(resource_); + texture_id_ = resource_->gl_id; DCHECK(texture_id_); } ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() { - resource_provider_->UnlockForWrite(resource_id_); + resource_provider_->UnlockForWrite(resource_); } void ResourceProvider::PopulateSkBitmapWithResource( @@ -1230,39 +1023,174 @@ ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware( ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id) : resource_provider_(resource_provider), - resource_id_(resource_id) { - ResourceProvider::PopulateSkBitmapWithResource( - &sk_bitmap_, resource_provider->LockForWrite(resource_id)); + resource_(resource_provider->LockForWrite(resource_id)) { + ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_); DCHECK(valid()); sk_canvas_.reset(new SkCanvas(sk_bitmap_)); } ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() { - resource_provider_->UnlockForWrite(resource_id_); + DCHECK(thread_checker_.CalledOnValidThread()); + resource_provider_->UnlockForWrite(resource_); +} + +ResourceProvider::ScopedWriteLockGpuMemoryBuffer:: + ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider, + ResourceProvider::ResourceId resource_id) + : resource_provider_(resource_provider), + resource_(resource_provider->LockForWrite(resource_id)), + gpu_memory_buffer_manager_(resource_provider->gpu_memory_buffer_manager_), + gpu_memory_buffer_(nullptr), + size_(resource_->size), + format_(resource_->format) { + DCHECK_EQ(GLTexture, resource_->type); + std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer); +} + +ResourceProvider::ScopedWriteLockGpuMemoryBuffer:: + ~ScopedWriteLockGpuMemoryBuffer() { + DCHECK(thread_checker_.CalledOnValidThread()); + resource_provider_->UnlockForWrite(resource_); + if (!gpu_memory_buffer_) + return; + + if (!resource_->image_id) { + GLES2Interface* gl = resource_provider_->ContextGL(); + DCHECK(gl); + + resource_->image_id = + gl->CreateImageCHROMIUM(gpu_memory_buffer_->AsClientBuffer(), + size_.width(), + size_.height(), + GL_RGBA); + } + + std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_); + resource_->allocated = true; + resource_->dirty_image = true; + + // GpuMemoryBuffer provides direct access to the memory used by the GPU. + // Read lock fences are required to ensure that we're not trying to map a + // buffer that is currently in-use by the GPU. + resource_->read_lock_fences_enabled = true; +} + +gfx::GpuMemoryBuffer* +ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() { + if (!gpu_memory_buffer_) { + scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer = + gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer( + size_, ToGpuMemoryBufferFormat(format_), gfx::GpuMemoryBuffer::MAP); + gpu_memory_buffer_ = gpu_memory_buffer.release(); + } + + return gpu_memory_buffer_; +} + +ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr( + ResourceProvider* resource_provider, + ResourceProvider::ResourceId resource_id) + : resource_provider_(resource_provider), + resource_(resource_provider->LockForWrite(resource_id)) { +} + +ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() { + DCHECK(thread_checker_.CalledOnValidThread()); + resource_provider_->UnlockForWrite(resource_); } -ResourceProvider::ResourceProvider(OutputSurface* output_surface, - SharedBitmapManager* shared_bitmap_manager, - int highp_threshold_min, - bool use_rgba_4444_texture_format, - size_t id_allocation_chunk_size, - bool use_distance_field_text) +SkSurface* ResourceProvider::ScopedWriteLockGr::GetSkSurface( + bool use_distance_field_text) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(resource_->locked_for_write); + + // If the surface doesn't exist, or doesn't have the correct dff setting, + // recreate the surface within the resource. + if (!resource_->sk_surface || + use_distance_field_text != + resource_->sk_surface->props().isUseDistanceFieldFonts()) { + class GrContext* gr_context = resource_provider_->GrContext(); + // TODO(alokp): Implement TestContextProvider::GrContext(). + if (!gr_context) + return nullptr; + + resource_provider_->LazyAllocate(resource_); + + GrBackendTextureDesc desc; + desc.fFlags = kRenderTarget_GrBackendTextureFlag; + desc.fWidth = resource_->size.width(); + desc.fHeight = resource_->size.height(); + desc.fConfig = ToGrPixelConfig(resource_->format); + desc.fOrigin = kTopLeft_GrSurfaceOrigin; + desc.fTextureHandle = resource_->gl_id; + skia::RefPtr<GrTexture> gr_texture = + skia::AdoptRef(gr_context->wrapBackendTexture(desc)); + if (!gr_texture) + return nullptr; + SkSurface::TextRenderMode text_render_mode = + use_distance_field_text ? SkSurface::kDistanceField_TextRenderMode + : SkSurface::kStandard_TextRenderMode; + resource_->sk_surface = skia::AdoptRef(SkSurface::NewRenderTargetDirect( + gr_texture->asRenderTarget(), text_render_mode)); + } + return resource_->sk_surface.get(); +} + +ResourceProvider::SynchronousFence::SynchronousFence( + gpu::gles2::GLES2Interface* gl) + : gl_(gl), has_synchronized_(true) { +} + +ResourceProvider::SynchronousFence::~SynchronousFence() { +} + +void ResourceProvider::SynchronousFence::Set() { + has_synchronized_ = false; +} + +bool ResourceProvider::SynchronousFence::HasPassed() { + if (!has_synchronized_) { + has_synchronized_ = true; + Synchronize(); + } + return true; +} + +void ResourceProvider::SynchronousFence::Wait() { + HasPassed(); +} + +void ResourceProvider::SynchronousFence::Synchronize() { + TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize"); + gl_->Finish(); +} + +ResourceProvider::ResourceProvider( + OutputSurface* output_surface, + SharedBitmapManager* shared_bitmap_manager, + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, + BlockingTaskRunner* blocking_main_thread_task_runner, + int highp_threshold_min, + bool use_rgba_4444_texture_format, + size_t id_allocation_chunk_size) : output_surface_(output_surface), shared_bitmap_manager_(shared_bitmap_manager), + gpu_memory_buffer_manager_(gpu_memory_buffer_manager), + blocking_main_thread_task_runner_(blocking_main_thread_task_runner), lost_output_surface_(false), highp_threshold_min_(highp_threshold_min), next_id_(1), next_child_(1), default_resource_type_(InvalidType), use_texture_storage_ext_(false), + use_texture_format_bgra_(false), use_texture_usage_hint_(false), use_compressed_texture_etc1_(false), max_texture_size_(0), best_texture_format_(RGBA_8888), use_rgba_4444_texture_format_(use_rgba_4444_texture_format), id_allocation_chunk_size_(id_allocation_chunk_size), - use_sync_query_(false), - use_distance_field_text_(use_distance_field_text) { + use_sync_query_(false) { DCHECK(output_surface_->HasClient()); DCHECK(id_allocation_chunk_size_); } @@ -1293,6 +1221,7 @@ void ResourceProvider::InitializeGL() { bool use_bgra = caps.gpu.texture_format_bgra8888; use_texture_storage_ext_ = caps.gpu.texture_storage; + 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; use_sync_query_ = caps.gpu.sync_query; @@ -1330,10 +1259,10 @@ void ResourceProvider::CleanUpGLIfNeeded() { } #endif // DCHECK_IS_ON - texture_uploader_.reset(); - texture_id_allocator_.reset(); - buffer_id_allocator_.reset(); - Finish(); + texture_uploader_ = nullptr; + texture_id_allocator_ = nullptr; + buffer_id_allocator_ = nullptr; + gl->Finish(); } int ResourceProvider::CreateChild(const ReturnCallback& return_callback) { @@ -1434,7 +1363,8 @@ void ResourceProvider::ReceiveFromChild( TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid"); ReturnedResourceArray to_return; to_return.push_back(it->ToReturnedResource()); - child_info.return_callback.Run(to_return); + child_info.return_callback.Run(to_return, + blocking_main_thread_task_runner_); continue; } @@ -1454,7 +1384,7 @@ void ResourceProvider::ReceiveFromChild( it->filter, 0, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE, - TextureUsageAny, + TextureHintImmutable, it->format); resource.mailbox = TextureMailbox(it->mailbox_holder.mailbox, it->mailbox_holder.texture_target, @@ -1464,6 +1394,7 @@ void ResourceProvider::ReceiveFromChild( // Don't allocate a texture for a child. resource.allocated = true; resource.imported_count = 1; + resource.allow_overlay = it->allow_overlay; child_info.parent_to_child_map[local_id] = it->id; child_info.child_to_parent_map[it->id] = local_id; } @@ -1521,7 +1452,7 @@ void ResourceProvider::ReceiveReturnsFromParent( int child_id = 0; ResourceIdArray resources_for_child; - std::vector<std::pair<ReturnedResource, ResourceMap::iterator> > + std::vector<std::pair<ReturnedResource, ResourceMap::iterator>> sorted_resources; for (ReturnedResourceArray::const_iterator it = resources.begin(); @@ -1558,8 +1489,11 @@ void ResourceProvider::ReceiveReturnsFromParent( // Need to wait for the current read lock fence to pass before we can // recycle this resource. - if (resource->enable_read_lock_fences) + if (resource->read_lock_fences_enabled) { + if (current_read_lock_fence_.get()) + current_read_lock_fence_->Set(); resource->read_lock_fence = current_read_lock_fence_; + } if (returned.sync_point) { DCHECK(!resource->has_shared_bitmap_id); @@ -1621,6 +1555,7 @@ void ResourceProvider::TransferResource(GLES2Interface* gl, resource->filter = source->filter; resource->size = source->size; resource->is_repeated = (source->wrap_mode == GL_REPEAT); + resource->allow_overlay = source->allow_overlay; if (source->type == Bitmap) { resource->mailbox_holder.mailbox = source->shared_bitmap_id; @@ -1744,7 +1679,8 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( } if (!to_return.empty()) - child_info->return_callback.Run(to_return); + child_info->return_callback.Run(to_return, + blocking_main_thread_task_runner_); if (child_info->marked_for_deletion && child_info->parent_to_child_map.empty()) { @@ -1753,67 +1689,11 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( } } -SkCanvas* ResourceProvider::MapDirectRasterBuffer(ResourceId id) { - // Resource needs to be locked for write since DirectRasterBuffer writes - // directly to it. - LockForWrite(id); - Resource* resource = GetResource(id); - if (!resource->direct_raster_buffer.get()) { - resource->direct_raster_buffer.reset( - new DirectRasterBuffer(resource, this, use_distance_field_text_)); - } - return resource->direct_raster_buffer->LockForWrite(); -} - -void ResourceProvider::UnmapDirectRasterBuffer(ResourceId id) { - Resource* resource = GetResource(id); - DCHECK(resource->direct_raster_buffer.get()); - resource->direct_raster_buffer->UnlockForWrite(); - UnlockForWrite(id); -} - -SkCanvas* ResourceProvider::MapImageRasterBuffer(ResourceId id) { - Resource* resource = GetResource(id); - AcquireImage(resource); - if (!resource->image_raster_buffer.get()) - resource->image_raster_buffer.reset(new ImageRasterBuffer(resource, this)); - return resource->image_raster_buffer->LockForWrite(); -} - -bool ResourceProvider::UnmapImageRasterBuffer(ResourceId id) { - Resource* resource = GetResource(id); - resource->dirty_image = true; - return resource->image_raster_buffer->UnlockForWrite(); -} - -void ResourceProvider::AcquirePixelRasterBuffer(ResourceId id) { - Resource* resource = GetResource(id); - AcquirePixelBuffer(resource); - resource->pixel_raster_buffer.reset(new PixelRasterBuffer(resource, this)); -} - -void ResourceProvider::ReleasePixelRasterBuffer(ResourceId id) { - Resource* resource = GetResource(id); - resource->pixel_raster_buffer.reset(); - ReleasePixelBuffer(resource); -} - -SkCanvas* ResourceProvider::MapPixelRasterBuffer(ResourceId id) { - Resource* resource = GetResource(id); - DCHECK(resource->pixel_raster_buffer.get()); - return resource->pixel_raster_buffer->LockForWrite(); -} - -bool ResourceProvider::UnmapPixelRasterBuffer(ResourceId id) { - Resource* resource = GetResource(id); - DCHECK(resource->pixel_raster_buffer.get()); - return resource->pixel_raster_buffer->UnlockForWrite(); -} - -void ResourceProvider::AcquirePixelBuffer(Resource* resource) { +void ResourceProvider::AcquirePixelBuffer(ResourceId id) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "ResourceProvider::AcquirePixelBuffer"); + Resource* resource = GetResource(id); DCHECK(resource->origin == Resource::Internal); DCHECK_EQ(resource->exported_count, 0); DCHECK(!resource->image_id); @@ -1835,10 +1715,11 @@ void ResourceProvider::AcquirePixelBuffer(Resource* resource) { gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); } -void ResourceProvider::ReleasePixelBuffer(Resource* resource) { +void ResourceProvider::ReleasePixelBuffer(ResourceId id) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "ResourceProvider::ReleasePixelBuffer"); + Resource* resource = GetResource(id); DCHECK(resource->origin == Resource::Internal); DCHECK_EQ(resource->exported_count, 0); DCHECK(!resource->image_id); @@ -1867,11 +1748,11 @@ void ResourceProvider::ReleasePixelBuffer(Resource* resource) { gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); } -uint8_t* ResourceProvider::MapPixelBuffer(const Resource* resource, - int* stride) { +uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "ResourceProvider::MapPixelBuffer"); + Resource* resource = GetResource(id); DCHECK(resource->origin == Resource::Internal); DCHECK_EQ(resource->exported_count, 0); DCHECK(!resource->image_id); @@ -1891,10 +1772,11 @@ uint8_t* ResourceProvider::MapPixelBuffer(const Resource* resource, return image; } -void ResourceProvider::UnmapPixelBuffer(const Resource* resource) { +void ResourceProvider::UnmapPixelBuffer(ResourceId id) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "ResourceProvider::UnmapPixelBuffer"); + Resource* resource = GetResource(id); DCHECK(resource->origin == Resource::Internal); DCHECK_EQ(resource->exported_count, 0); DCHECK(!resource->image_id); @@ -1909,10 +1791,9 @@ void ResourceProvider::UnmapPixelBuffer(const Resource* resource) { gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); } -GLenum ResourceProvider::BindForSampling( - ResourceProvider::ResourceId resource_id, - GLenum unit, - GLenum filter) { +GLenum ResourceProvider::BindForSampling(ResourceId resource_id, + GLenum unit, + GLenum filter) { DCHECK(thread_checker_.CalledOnValidThread()); GLES2Interface* gl = ContextGL(); ResourceMap::iterator it = resources_.find(resource_id); @@ -1999,6 +1880,7 @@ void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) { "ResourceProvider::ForceSetPixelsToComplete"); Resource* resource = GetResource(id); + DCHECK(resource->locked_for_write); DCHECK(resource->pending_set_pixels); DCHECK(!resource->set_pixels_completion_forced); @@ -2018,6 +1900,7 @@ bool ResourceProvider::DidSetPixelsComplete(ResourceId id) { "ResourceProvider::DidSetPixelsComplete"); Resource* resource = GetResource(id); + DCHECK(resource->locked_for_write); DCHECK(resource->pending_set_pixels); @@ -2033,7 +1916,12 @@ bool ResourceProvider::DidSetPixelsComplete(ResourceId id) { } resource->pending_set_pixels = false; - UnlockForWrite(id); + UnlockForWrite(resource); + + // Async set pixels commands are not necessarily processed in-sequence with + // drawing commands. Read lock fences are required to ensure that async + // commands don't access the resource while used for drawing. + resource->read_lock_fences_enabled = true; return true; } @@ -2065,9 +1953,11 @@ void ResourceProvider::LazyCreate(Resource* resource) { // Create and set texture properties. Allocation is delayed until needed. GLC(gl, gl->BindTexture(resource->target, resource->gl_id)); GLC(gl, - gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + gl->TexParameteri( + resource->target, GL_TEXTURE_MIN_FILTER, resource->original_filter)); GLC(gl, - gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + gl->TexParameteri( + resource->target, GL_TEXTURE_MAG_FILTER, resource->original_filter)); GLC(gl, gl->TexParameteri( resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode)); @@ -2077,7 +1967,7 @@ void ResourceProvider::LazyCreate(Resource* resource) { GLC(gl, gl->TexParameteri( resource->target, GL_TEXTURE_POOL_CHROMIUM, resource->texture_pool)); - if (use_texture_usage_hint_ && resource->hint == TextureUsageFramebuffer) { + if (use_texture_usage_hint_ && (resource->hint & TextureHintFramebuffer)) { GLC(gl, gl->TexParameteri(resource->target, GL_TEXTURE_USAGE_ANGLE, @@ -2091,10 +1981,10 @@ void ResourceProvider::AllocateForTesting(ResourceId id) { void ResourceProvider::LazyAllocate(Resource* resource) { DCHECK(resource); + if (resource->allocated) + return; LazyCreate(resource); - - DCHECK(resource->gl_id || resource->allocated); - if (resource->allocated || !resource->gl_id) + if (!resource->gl_id) return; resource->allocated = true; GLES2Interface* gl = ContextGL(); @@ -2102,8 +1992,9 @@ void ResourceProvider::LazyAllocate(Resource* resource) { DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); ResourceFormat format = resource->format; GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id)); - if (use_texture_storage_ext_ && IsFormatSupportedForStorage(format) && - resource->hint != TextureUsageFramebuffer) { + if (use_texture_storage_ext_ && + IsFormatSupportedForStorage(format, use_texture_format_bgra_) && + (resource->hint & TextureHintImmutable)) { GLenum storage_format = TextureToStorageFormat(format); GLC(gl, gl->TexStorage2DEXT( @@ -2138,81 +2029,6 @@ void ResourceProvider::BindImageForSampling(Resource* resource) { resource->dirty_image = false; } -void ResourceProvider::EnableReadLockFences(ResourceProvider::ResourceId id, - bool enable) { - Resource* resource = GetResource(id); - resource->enable_read_lock_fences = enable; -} - -void ResourceProvider::AcquireImage(Resource* resource) { - DCHECK(resource->origin == Resource::Internal); - DCHECK_EQ(resource->exported_count, 0); - - if (resource->type != GLTexture) - return; - - if (resource->image_id) - return; - - resource->allocated = true; - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - resource->image_id = - gl->CreateImageCHROMIUM(resource->size.width(), - resource->size.height(), - TextureToStorageFormat(resource->format), - GL_IMAGE_MAP_CHROMIUM); - DCHECK(resource->image_id); -} - -void ResourceProvider::ReleaseImage(Resource* resource) { - DCHECK(resource->origin == Resource::Internal); - DCHECK_EQ(resource->exported_count, 0); - - if (!resource->image_id) - return; - - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - gl->DestroyImageCHROMIUM(resource->image_id); - resource->image_id = 0; - resource->bound_image_id = 0; - resource->dirty_image = false; - resource->allocated = false; -} - -uint8_t* ResourceProvider::MapImage(const Resource* resource, int* stride) { - DCHECK(ReadLockFenceHasPassed(resource)); - DCHECK(resource->origin == Resource::Internal); - DCHECK_EQ(resource->exported_count, 0); - - if (resource->type == GLTexture) { - DCHECK(resource->image_id); - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - // MapImageCHROMIUM should be called prior to GetImageParameterivCHROMIUM. - uint8_t* pixels = - static_cast<uint8_t*>(gl->MapImageCHROMIUM(resource->image_id)); - gl->GetImageParameterivCHROMIUM( - resource->image_id, GL_IMAGE_ROWBYTES_CHROMIUM, stride); - return pixels; - } - DCHECK_EQ(Bitmap, resource->type); - *stride = 0; - return resource->pixels; -} - -void ResourceProvider::UnmapImage(const Resource* resource) { - DCHECK(resource->origin == Resource::Internal); - DCHECK_EQ(resource->exported_count, 0); - - if (resource->image_id) { - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - gl->UnmapImageCHROMIUM(resource->image_id); - } -} - void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) { TRACE_EVENT0("cc", "ResourceProvider::CopyResource"); @@ -2220,6 +2036,7 @@ void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) { DCHECK(!source_resource->lock_for_read_count); DCHECK(source_resource->origin == Resource::Internal); DCHECK_EQ(source_resource->exported_count, 0); + DCHECK_EQ(GLTexture, source_resource->type); DCHECK(source_resource->allocated); LazyCreate(source_resource); @@ -2228,47 +2045,75 @@ void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) { DCHECK(!dest_resource->lock_for_read_count); DCHECK(dest_resource->origin == Resource::Internal); DCHECK_EQ(dest_resource->exported_count, 0); + DCHECK_EQ(GLTexture, dest_resource->type); LazyCreate(dest_resource); DCHECK_EQ(source_resource->type, dest_resource->type); DCHECK_EQ(source_resource->format, dest_resource->format); DCHECK(source_resource->size == dest_resource->size); - if (source_resource->type == GLTexture) { - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - if (source_resource->image_id && source_resource->dirty_image) { - gl->BindTexture(source_resource->target, source_resource->gl_id); - BindImageForSampling(source_resource); - } - DCHECK(use_sync_query_) << "CHROMIUM_sync_query extension missing"; + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + if (source_resource->image_id && source_resource->dirty_image) { + gl->BindTexture(source_resource->target, source_resource->gl_id); + BindImageForSampling(source_resource); + } + if (use_sync_query_) { if (!source_resource->gl_read_lock_query_id) gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id); gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, source_resource->gl_read_lock_query_id); - DCHECK(!dest_resource->image_id); - dest_resource->allocated = true; - gl->CopyTextureCHROMIUM(dest_resource->target, - source_resource->gl_id, - dest_resource->gl_id, - 0, - GLInternalFormat(dest_resource->format), - GLDataType(dest_resource->format)); + } + DCHECK(!dest_resource->image_id); + dest_resource->allocated = true; + gl->CopyTextureCHROMIUM(dest_resource->target, + source_resource->gl_id, + dest_resource->gl_id, + 0, + GLInternalFormat(dest_resource->format), + GLDataType(dest_resource->format)); + if (source_resource->gl_read_lock_query_id) { // End query and create a read lock fence that will prevent access to // source resource until CopyTextureCHROMIUM command has completed. gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM); source_resource->read_lock_fence = make_scoped_refptr( new QueryFence(gl, source_resource->gl_read_lock_query_id)); } else { - DCHECK_EQ(Bitmap, source_resource->type); - DCHECK_EQ(RGBA_8888, source_resource->format); - LazyAllocate(dest_resource); - - size_t bytes = SharedBitmap::CheckedSizeInBytes(source_resource->size); - memcpy(dest_resource->pixels, source_resource->pixels, bytes); + // Create a SynchronousFence when CHROMIUM_sync_query extension is missing. + // Try to use one synchronous fence for as many CopyResource operations as + // possible as that reduce the number of times we have to synchronize with + // the GL. + if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized()) + synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl)); + source_resource->read_lock_fence = synchronous_fence_; + source_resource->read_lock_fence->Set(); } } +void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) { + Resource* resource = GetResource(id); + DCHECK_EQ(resource->exported_count, 0); + DCHECK(resource->allocated); + if (resource->type != GLTexture || resource->gl_id) + return; + if (!resource->mailbox.sync_point()) + return; + DCHECK(resource->mailbox.IsValid()); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point())); + resource->mailbox.set_sync_point(0); +} + +void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) { + Resource* resource = GetResource(id); + DCHECK_EQ(resource->exported_count, 0); + if (!resource->read_lock_fence.get()) + return; + + resource->read_lock_fence->Wait(); +} + GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) { GLint active_unit = 0; gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit); diff --git a/chromium/cc/resources/resource_provider.h b/chromium/cc/resources/resource_provider.h index 1d991e2b144..40103f6b3e3 100644 --- a/chromium/cc/resources/resource_provider.h +++ b/chromium/cc/resources/resource_provider.h @@ -20,33 +20,36 @@ #include "cc/base/cc_export.h" #include "cc/output/context_provider.h" #include "cc/output/output_surface.h" -#include "cc/resources/release_callback.h" +#include "cc/resources/release_callback_impl.h" #include "cc/resources/resource_format.h" #include "cc/resources/return_callback.h" #include "cc/resources/shared_bitmap.h" -#include "cc/resources/single_release_callback.h" +#include "cc/resources/single_release_callback_impl.h" #include "cc/resources/texture_mailbox.h" #include "cc/resources/transferable_resource.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" class GrContext; namespace gpu { +class GpuMemoryBufferManager; namespace gles { class GLES2Interface; } } namespace gfx { +class GpuMemoryBuffer; class Rect; class Vector2d; } namespace cc { +class BlockingTaskRunner; class IdAllocator; class SharedBitmap; class SharedBitmapManager; @@ -55,14 +58,20 @@ class TextureUploader; // This class is not thread-safe and can only be called from the thread it was // created on (in practice, the impl thread). class CC_EXPORT ResourceProvider { + private: + struct Resource; + public: typedef unsigned ResourceId; typedef std::vector<ResourceId> ResourceIdArray; typedef std::set<ResourceId> ResourceIdSet; typedef base::hash_map<ResourceId, ResourceId> ResourceIdMap; - enum TextureUsageHint { - TextureUsageAny, - TextureUsageFramebuffer, + enum TextureHint { + TextureHintDefault = 0x0, + TextureHintImmutable = 0x1, + TextureHintFramebuffer = 0x2, + TextureHintImmutableFramebuffer = + TextureHintImmutable | TextureHintFramebuffer }; enum ResourceType { InvalidType = 0, @@ -73,10 +82,11 @@ class CC_EXPORT ResourceProvider { static scoped_ptr<ResourceProvider> Create( OutputSurface* output_surface, SharedBitmapManager* shared_bitmap_manager, + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, + BlockingTaskRunner* blocking_main_thread_task_runner, int highp_threshold_min, bool use_rgba_4444_texture_format, - size_t id_allocation_chunk_size, - bool use_distance_field_text); + size_t id_allocation_chunk_size); virtual ~ResourceProvider(); void InitializeSoftware(); @@ -106,7 +116,7 @@ class CC_EXPORT ResourceProvider { // Creates a resource of the default resource type. ResourceId CreateResource(const gfx::Size& size, GLint wrap_mode, - TextureUsageHint hint, + TextureHint hint, ResourceFormat format); // Creates a resource which is tagged as being managed for GPU memory @@ -114,7 +124,7 @@ class CC_EXPORT ResourceProvider { ResourceId CreateManagedResource(const gfx::Size& size, GLenum target, GLint wrap_mode, - TextureUsageHint hint, + TextureHint hint, ResourceFormat format); // You can also explicitly create a specific resource type. @@ -122,7 +132,7 @@ class CC_EXPORT ResourceProvider { GLenum target, GLenum texture_pool, GLint wrap_mode, - TextureUsageHint hint, + TextureHint hint, ResourceFormat format); ResourceId CreateBitmap(const gfx::Size& size, GLint wrap_mode); @@ -133,7 +143,7 @@ class CC_EXPORT ResourceProvider { // Wraps an external texture mailbox into a GL resource. ResourceId CreateResourceFromTextureMailbox( const TextureMailbox& mailbox, - scoped_ptr<SingleReleaseCallback> release_callback); + scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl); void DeleteResource(ResourceId id); @@ -153,14 +163,6 @@ class CC_EXPORT ResourceProvider { void ReleaseCachedData(); base::TimeTicks EstimatedUploadCompletionTime(size_t uploads_per_tick); - // Flush all context operations, kicking uploads and ensuring ordering with - // respect to other contexts. - void Flush(); - - // Finish all context operations, causing any pending callbacks to be - // scheduled. - void Finish(); - // Only flush the command buffer if supported. // Returns true if the shallow flush occurred, false otherwise. bool ShallowFlushIfSupported(); @@ -238,7 +240,7 @@ class CC_EXPORT ResourceProvider { ResourceProvider::ResourceId resource_id, GLenum unit, GLenum filter); - virtual ~ScopedSamplerGL(); + ~ScopedSamplerGL() override; GLenum target() const { return target_; } @@ -259,7 +261,7 @@ class CC_EXPORT ResourceProvider { private: ResourceProvider* resource_provider_; - ResourceProvider::ResourceId resource_id_; + ResourceProvider::Resource* resource_; unsigned texture_id_; DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockGL); @@ -299,17 +301,57 @@ class CC_EXPORT ResourceProvider { private: ResourceProvider* resource_provider_; - ResourceProvider::ResourceId resource_id_; + ResourceProvider::Resource* resource_; SkBitmap sk_bitmap_; scoped_ptr<SkCanvas> sk_canvas_; + base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockSoftware); }; + class CC_EXPORT ScopedWriteLockGpuMemoryBuffer { + public: + ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider, + ResourceProvider::ResourceId resource_id); + ~ScopedWriteLockGpuMemoryBuffer(); + + gfx::GpuMemoryBuffer* GetGpuMemoryBuffer(); + + private: + ResourceProvider* resource_provider_; + ResourceProvider::Resource* resource_; + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_; + gfx::GpuMemoryBuffer* gpu_memory_buffer_; + gfx::Size size_; + ResourceFormat format_; + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockGpuMemoryBuffer); + }; + + class CC_EXPORT ScopedWriteLockGr { + public: + ScopedWriteLockGr(ResourceProvider* resource_provider, + ResourceProvider::ResourceId resource_id); + ~ScopedWriteLockGr(); + + SkSurface* GetSkSurface(bool use_distance_field_text); + + private: + ResourceProvider* resource_provider_; + ResourceProvider::Resource* resource_; + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockGr); + }; + class Fence : public base::RefCounted<Fence> { public: Fence() {} + + virtual void Set() = 0; virtual bool HasPassed() = 0; + virtual void Wait() = 0; protected: friend class base::RefCounted<Fence>; @@ -319,31 +361,36 @@ class CC_EXPORT ResourceProvider { DISALLOW_COPY_AND_ASSIGN(Fence); }; - // Returns a canvas for direct rasterization. - // Call Unmap before the resource can be read or used for compositing. - // It is used for direct gpu rasterization. - SkCanvas* MapDirectRasterBuffer(ResourceId id); - void UnmapDirectRasterBuffer(ResourceId id); - - // Returns a canvas backed by an image buffer. UnmapImageRasterBuffer - // returns true if canvas was written to while mapped. - // Rasterizing to the canvas writes the content into the image buffer, - // which is internally bound to the underlying resource when read. - // Call Unmap before the resource can be read or used for compositing. - // It is used by ImageRasterWorkerPool. - SkCanvas* MapImageRasterBuffer(ResourceId id); - bool UnmapImageRasterBuffer(ResourceId id); - - // Returns a canvas backed by pixel buffer. UnmapPixelRasterBuffer - // returns true if canvas was written to while mapped. - // The pixel buffer needs to be uploaded to the underlying resource - // using BeginSetPixels before the resouce can be used for compositing. - // It is used by PixelRasterWorkerPool. - void AcquirePixelRasterBuffer(ResourceId id); - void ReleasePixelRasterBuffer(ResourceId id); - SkCanvas* MapPixelRasterBuffer(ResourceId id); - bool UnmapPixelRasterBuffer(ResourceId id); + class SynchronousFence : public ResourceProvider::Fence { + public: + explicit SynchronousFence(gpu::gles2::GLES2Interface* gl); + + // Overridden from Fence: + void Set() override; + bool HasPassed() override; + void Wait() override; + + // Returns true if fence has been set but not yet synchornized. + bool has_synchronized() const { return has_synchronized_; } + + private: + ~SynchronousFence() override; + void Synchronize(); + + gpu::gles2::GLES2Interface* gl_; + bool has_synchronized_; + + DISALLOW_COPY_AND_ASSIGN(SynchronousFence); + }; + + // Acquire pixel buffer for resource. The pixel buffer can be used to + // set resource pixels without performing unnecessary copying. + void AcquirePixelBuffer(ResourceId resource); + void ReleasePixelBuffer(ResourceId resource); + // Map/unmap the acquired pixel buffer. + uint8_t* MapPixelBuffer(ResourceId id, int* stride); + void UnmapPixelBuffer(ResourceId id); // Asynchronously update pixels from acquired pixel buffer. void BeginSetPixels(ResourceId id); void ForceSetPixelsToComplete(ResourceId id); @@ -363,22 +410,19 @@ class CC_EXPORT ResourceProvider { // until this fence has passed. void SetReadLockFence(Fence* fence) { current_read_lock_fence_ = fence; } - // Enable read lock fences for a specific resource. - void EnableReadLockFences(ResourceProvider::ResourceId id, bool enable); - // Indicates if we can currently lock this resource for write. bool CanLockForWrite(ResourceId id); // Copy pixels from source to destination. void CopyResource(ResourceId source_id, ResourceId dest_id); + void WaitSyncPointIfNeeded(ResourceId id); + + void WaitReadLockIfNeeded(ResourceId id); + static GLint GetActiveTextureUnit(gpu::gles2::GLES2Interface* gl); private: - class DirectRasterBuffer; - class ImageRasterBuffer; - class PixelRasterBuffer; - struct Resource { enum Origin { Internal, External, Delegated }; @@ -391,7 +435,7 @@ class CC_EXPORT ResourceProvider { GLenum filter, GLenum texture_pool, GLint wrap_mode, - TextureUsageHint hint, + TextureHint hint, ResourceFormat format); Resource(uint8_t* pixels, SharedBitmap* bitmap, @@ -414,7 +458,7 @@ class CC_EXPORT ResourceProvider { // Query used to determine when read lock fence has passed. unsigned gl_read_lock_query_id; TextureMailbox mailbox; - ReleaseCallback release_callback; + ReleaseCallbackImpl release_callback_impl; uint8_t* pixels; int lock_for_read_count; int imported_count; @@ -426,7 +470,7 @@ class CC_EXPORT ResourceProvider { bool pending_set_pixels : 1; bool set_pixels_completion_forced : 1; bool allocated : 1; - bool enable_read_lock_fences : 1; + bool read_lock_fences_enabled : 1; bool has_shared_bitmap_id : 1; bool allow_overlay : 1; scoped_refptr<Fence> read_lock_fence; @@ -440,109 +484,16 @@ class CC_EXPORT ResourceProvider { unsigned bound_image_id; GLenum texture_pool; GLint wrap_mode; - TextureUsageHint hint; + TextureHint hint; ResourceType type; ResourceFormat format; SharedBitmapId shared_bitmap_id; SharedBitmap* shared_bitmap; - linked_ptr<DirectRasterBuffer> direct_raster_buffer; - linked_ptr<ImageRasterBuffer> image_raster_buffer; - linked_ptr<PixelRasterBuffer> pixel_raster_buffer; + gfx::GpuMemoryBuffer* gpu_memory_buffer; + skia::RefPtr<SkSurface> sk_surface; }; typedef base::hash_map<ResourceId, Resource> ResourceMap; - class RasterBuffer { - public: - virtual ~RasterBuffer(); - - SkCanvas* LockForWrite(); - // Returns true if canvas was written to while locked. - bool UnlockForWrite(); - - protected: - RasterBuffer(const Resource* resource, ResourceProvider* resource_provider); - const Resource* resource() const { return resource_; } - ResourceProvider* resource_provider() const { return resource_provider_; } - - virtual SkCanvas* DoLockForWrite() = 0; - virtual bool DoUnlockForWrite() = 0; - - private: - const Resource* resource_; - ResourceProvider* resource_provider_; - SkCanvas* locked_canvas_; - int canvas_save_count_; - }; - - class DirectRasterBuffer : public RasterBuffer { - public: - DirectRasterBuffer(const Resource* resource, - ResourceProvider* resource_provider, - bool use_distance_field_text); - virtual ~DirectRasterBuffer(); - - protected: - virtual SkCanvas* DoLockForWrite() OVERRIDE; - virtual bool DoUnlockForWrite() OVERRIDE; - skia::RefPtr<SkSurface> CreateSurface(); - - private: - skia::RefPtr<SkSurface> surface_; - uint32_t surface_generation_id_; - const bool use_distance_field_text_; - - DISALLOW_COPY_AND_ASSIGN(DirectRasterBuffer); - }; - - class BitmapRasterBuffer : public RasterBuffer { - public: - virtual ~BitmapRasterBuffer(); - - protected: - BitmapRasterBuffer(const Resource* resource, - ResourceProvider* resource_provider); - - virtual SkCanvas* DoLockForWrite() OVERRIDE; - virtual bool DoUnlockForWrite() OVERRIDE; - - virtual uint8_t* MapBuffer(int* stride) = 0; - virtual void UnmapBuffer() = 0; - - private: - uint8_t* mapped_buffer_; - SkBitmap raster_bitmap_; - uint32_t raster_bitmap_generation_id_; - skia::RefPtr<SkCanvas> raster_canvas_; - }; - - class ImageRasterBuffer : public BitmapRasterBuffer { - public: - ImageRasterBuffer(const Resource* resource, - ResourceProvider* resource_provider); - virtual ~ImageRasterBuffer(); - - protected: - virtual uint8_t* MapBuffer(int* stride) OVERRIDE; - virtual void UnmapBuffer() OVERRIDE; - - private: - DISALLOW_COPY_AND_ASSIGN(ImageRasterBuffer); - }; - - class PixelRasterBuffer : public BitmapRasterBuffer { - public: - PixelRasterBuffer(const Resource* resource, - ResourceProvider* resource_provider); - virtual ~PixelRasterBuffer(); - - protected: - virtual uint8_t* MapBuffer(int* stride) OVERRIDE; - virtual void UnmapBuffer() OVERRIDE; - - private: - DISALLOW_COPY_AND_ASSIGN(PixelRasterBuffer); - }; - static bool CompareResourceMapIteratorsByChildId( const std::pair<ReturnedResource, ResourceMap::iterator>& a, const std::pair<ReturnedResource, ResourceMap::iterator>& b); @@ -566,18 +517,20 @@ class CC_EXPORT ResourceProvider { ResourceProvider(OutputSurface* output_surface, SharedBitmapManager* shared_bitmap_manager, + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, + BlockingTaskRunner* blocking_main_thread_task_runner, int highp_threshold_min, bool use_rgba_4444_texture_format, - size_t id_allocation_chunk_size, - bool use_distance_field_text); + size_t id_allocation_chunk_size); void CleanUpGLIfNeeded(); Resource* GetResource(ResourceId id); const Resource* LockForRead(ResourceId id); void UnlockForRead(ResourceId id); - const Resource* LockForWrite(ResourceId id); - void UnlockForWrite(ResourceId id); + Resource* LockForWrite(ResourceId id); + void UnlockForWrite(Resource* resource); + static void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap, const Resource* resource); @@ -596,32 +549,11 @@ class CC_EXPORT ResourceProvider { void LazyCreate(Resource* resource); void LazyAllocate(Resource* resource); - // TODO(alokp): Move the implementation to PixelRasterBuffer. - // Acquire pixel buffer for resource. The pixel buffer can be used to - // set resource pixels without performing unnecessary copying. - void AcquirePixelBuffer(Resource* resource); - void ReleasePixelBuffer(Resource* resource); - // Map/unmap the acquired pixel buffer. - uint8_t* MapPixelBuffer(const Resource* resource, int* stride); - void UnmapPixelBuffer(const Resource* resource); - - // TODO(alokp): Move the implementation to ImageRasterBuffer. - // Acquire and release an image. The image allows direct - // manipulation of texture memory. - void AcquireImage(Resource* resource); - void ReleaseImage(Resource* resource); - // Maps the acquired image so that its pixels could be modified. - // Unmap is called when all pixels are set. - uint8_t* MapImage(const Resource* resource, int* stride); - void UnmapImage(const Resource* resource); - void BindImageForSampling(Resource* resource); // Binds the given GL resource to a texture target for sampling using the // specified filter for both minification and magnification. Returns the // texture target used. The resource must be locked for reading. - GLenum BindForSampling(ResourceProvider::ResourceId resource_id, - GLenum unit, - GLenum filter); + GLenum BindForSampling(ResourceId resource_id, GLenum unit, GLenum filter); // Returns NULL if the output_surface_ does not have a ContextProvider. gpu::gles2::GLES2Interface* ContextGL() const; @@ -629,6 +561,8 @@ class CC_EXPORT ResourceProvider { OutputSurface* output_surface_; SharedBitmapManager* shared_bitmap_manager_; + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_; + BlockingTaskRunner* blocking_main_thread_task_runner_; bool lost_output_surface_; int highp_threshold_min_; ResourceId next_id_; @@ -638,6 +572,7 @@ class CC_EXPORT ResourceProvider { ResourceType default_resource_type_; bool use_texture_storage_ext_; + bool use_texture_format_bgra_; bool use_texture_usage_hint_; bool use_compressed_texture_etc1_; scoped_ptr<TextureUploader> texture_uploader_; @@ -654,8 +589,8 @@ class CC_EXPORT ResourceProvider { scoped_ptr<IdAllocator> buffer_id_allocator_; bool use_sync_query_; - - bool use_distance_field_text_; + // Fence used for CopyResource if CHROMIUM_sync_query is not supported. + scoped_refptr<SynchronousFence> synchronous_fence_; DISALLOW_COPY_AND_ASSIGN(ResourceProvider); }; @@ -669,6 +604,7 @@ inline unsigned BitsPerPixel(ResourceFormat format) { 32, // RGBA_8888 16, // RGBA_4444 32, // BGRA_8888 + 8, // ALPHA_8 8, // LUMINANCE_8 16, // RGB_565, 4 // ETC1 @@ -682,6 +618,7 @@ inline GLenum GLDataType(ResourceFormat format) { 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 @@ -695,6 +632,7 @@ inline GLenum GLDataFormat(ResourceFormat format) { 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 diff --git a/chromium/cc/resources/resource_provider_unittest.cc b/chromium/cc/resources/resource_provider_unittest.cc index 4bf9ec0565e..e507ad67a93 100644 --- a/chromium/cc/resources/resource_provider_unittest.cc +++ b/chromium/cc/resources/resource_provider_unittest.cc @@ -19,15 +19,18 @@ #include "cc/resources/single_release_callback.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" +#include "cc/test/test_gpu_memory_buffer_manager.h" #include "cc/test/test_shared_bitmap_manager.h" #include "cc/test/test_texture.h" #include "cc/test/test_web_graphics_context_3d.h" +#include "cc/trees/blocking_task_runner.h" #include "gpu/GLES2/gl2extchromium.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" -#include "ui/gfx/rect.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/gpu_memory_buffer.h" using testing::Mock; using testing::NiceMock; @@ -39,18 +42,28 @@ using testing::_; namespace cc { namespace { -static void EmptyReleaseCallback(uint32 sync_point, bool lost_resource) {} - -static void SharedMemoryReleaseCallback(scoped_ptr<base::SharedMemory> memory, - uint32 sync_point, - bool lost_resource) {} +static void EmptyReleaseCallback(uint32 sync_point, + bool lost_resource, + BlockingTaskRunner* main_thread_task_runner) { +} -static void ReleaseTextureMailbox(uint32* release_sync_point, - bool* release_lost_resource, - uint32 sync_point, - bool lost_resource) { +static void ReleaseCallback( + uint32* release_sync_point, + bool* release_lost_resource, + BlockingTaskRunner** release_main_thread_task_runner, + uint32 sync_point, + bool lost_resource, + BlockingTaskRunner* main_thread_task_runner) { *release_sync_point = sync_point; *release_lost_resource = lost_resource; + *release_main_thread_task_runner = main_thread_task_runner; +} + +static void SharedMemoryReleaseCallback( + scoped_ptr<base::SharedMemory> memory, + uint32 sync_point, + bool lost_resource, + BlockingTaskRunner* main_thread_task_runner) { } static void ReleaseSharedMemoryCallback( @@ -59,7 +72,8 @@ static void ReleaseSharedMemoryCallback( uint32* release_sync_point, bool* lost_resource_result, uint32 sync_point, - bool lost_resource) { + bool lost_resource, + BlockingTaskRunner* main_thread_task_runner) { *release_called = true; *release_sync_point = sync_point; *lost_resource_result = lost_resource; @@ -89,11 +103,11 @@ class TextureStateTrackingContext : public TestWebGraphicsContext3D { // Force all textures to be consecutive numbers starting at "1", // so we easily can test for them. - virtual GLuint NextTextureId() OVERRIDE { + virtual GLuint NextTextureId() override { base::AutoLock lock(namespace_->lock); return namespace_->next_texture_id++; } - virtual void RetireTextureId(GLuint) OVERRIDE {} + virtual void RetireTextureId(GLuint) override {} }; // Shared data between multiple ResourceProviderContext. This contains mailbox @@ -144,7 +158,7 @@ class ContextSharedData { uint32 next_sync_point_; unsigned next_mailbox_; - typedef base::hash_map<unsigned, scoped_refptr<TestTexture> > TextureMap; + typedef base::hash_map<unsigned, scoped_refptr<TestTexture>> TextureMap; TextureMap textures_; base::hash_map<unsigned, uint32> sync_point_for_mailbox_; }; @@ -156,7 +170,7 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { return make_scoped_ptr(new ResourceProviderContext(shared_data)); } - virtual GLuint insertSyncPoint() OVERRIDE { + GLuint insertSyncPoint() override { uint32 sync_point = shared_data_->InsertSyncPoint(); // Commit the produceTextureCHROMIUM calls at this point, so that // they're associated with the sync point. @@ -171,17 +185,17 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { return sync_point; } - virtual void waitSyncPoint(GLuint sync_point) OVERRIDE { + void waitSyncPoint(GLuint sync_point) override { last_waited_sync_point_ = std::max(sync_point, last_waited_sync_point_); } unsigned last_waited_sync_point() const { return last_waited_sync_point_; } - virtual void texStorage2DEXT(GLenum target, - GLint levels, - GLuint internalformat, - GLint width, - GLint height) OVERRIDE { + void texStorage2DEXT(GLenum target, + GLint levels, + GLuint internalformat, + GLint width, + GLint height) override { CheckTextureIsBound(target); ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); ASSERT_EQ(1, levels); @@ -198,15 +212,15 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { AllocateTexture(gfx::Size(width, height), format); } - virtual void texImage2D(GLenum target, - GLint level, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLint border, - GLenum format, - GLenum type, - const void* pixels) OVERRIDE { + void texImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void* pixels) override { CheckTextureIsBound(target); ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); ASSERT_FALSE(level); @@ -218,15 +232,15 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { SetPixels(0, 0, width, height, pixels); } - virtual void texSubImage2D(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - const void* pixels) OVERRIDE { + void texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void* pixels) override { CheckTextureIsBound(target); ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); ASSERT_FALSE(level); @@ -239,12 +253,11 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { SetPixels(xoffset, yoffset, width, height, pixels); } - virtual void genMailboxCHROMIUM(GLbyte* mailbox) OVERRIDE { + void genMailboxCHROMIUM(GLbyte* mailbox) override { return shared_data_->GenMailbox(mailbox); } - virtual void produceTextureCHROMIUM(GLenum target, - const GLbyte* mailbox) OVERRIDE { + void produceTextureCHROMIUM(GLenum target, const GLbyte* mailbox) override { CheckTextureIsBound(target); // Delay moving the texture into the mailbox until the next @@ -257,8 +270,7 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { pending_produce_textures_.push_back(pending.Pass()); } - virtual void consumeTextureCHROMIUM(GLenum target, - const GLbyte* mailbox) OVERRIDE { + void consumeTextureCHROMIUM(GLenum target, const GLbyte* mailbox) override { CheckTextureIsBound(target); base::AutoLock lock_for_texture_access(namespace_->lock); scoped_refptr<TestTexture> texture = @@ -339,6 +351,7 @@ void GetResourcePixels(ResourceProvider* resource_provider, const gfx::Size& size, ResourceFormat format, uint8_t* pixels) { + resource_provider->WaitSyncPointIfNeeded(id); switch (resource_provider->default_resource_type()) { case ResourceProvider::GLTexture: { ResourceProvider::ScopedReadLockGL lock_gl(resource_provider, id); @@ -367,7 +380,8 @@ class ResourceProviderTest ResourceProviderTest() : shared_data_(ContextSharedData::Create()), context3d_(NULL), - child_context_(NULL) { + child_context_(NULL), + main_thread_task_runner_(BlockingTaskRunner::Create(NULL)) { switch (GetParam()) { case ResourceProvider::GLTexture: { scoped_ptr<ResourceProviderContext> context3d( @@ -375,16 +389,15 @@ class ResourceProviderTest context3d_ = context3d.get(); scoped_refptr<TestContextProvider> context_provider = - TestContextProvider::Create( - context3d.PassAs<TestWebGraphicsContext3D>()); + TestContextProvider::Create(context3d.Pass()); output_surface_ = FakeOutputSurface::Create3d(context_provider); scoped_ptr<ResourceProviderContext> child_context_owned = ResourceProviderContext::Create(shared_data_.get()); child_context_ = child_context_owned.get(); - child_output_surface_ = FakeOutputSurface::Create3d( - child_context_owned.PassAs<TestWebGraphicsContext3D>()); + child_output_surface_ = + FakeOutputSurface::Create3d(child_context_owned.Pass()); break; } case ResourceProvider::Bitmap: @@ -400,22 +413,30 @@ class ResourceProviderTest CHECK(output_surface_->BindToClient(&output_surface_client_)); CHECK(child_output_surface_->BindToClient(&child_output_surface_client_)); - shared_bitmap_manager_.reset(new TestSharedBitmapManager()); + shared_bitmap_manager_.reset(new TestSharedBitmapManager); + gpu_memory_buffer_manager_.reset(new TestGpuMemoryBufferManager); - resource_provider_ = ResourceProvider::Create( - output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, - false); - child_resource_provider_ = ResourceProvider::Create( - child_output_surface_.get(), - shared_bitmap_manager_.get(), - 0, - false, - 1, - false); + resource_provider_ = + ResourceProvider::Create(output_surface_.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + main_thread_task_runner_.get(), + 0, + false, + 1); + child_resource_provider_ = + ResourceProvider::Create(child_output_surface_.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + main_thread_task_runner_.get(), + 0, + false, + 1); } static void CollectResources(ReturnedResourceArray* array, - const ReturnedResourceArray& returned) { + const ReturnedResourceArray& returned, + BlockingTaskRunner* main_thread_task_runner) { array->insert(array->end(), returned.begin(), returned.end()); } @@ -446,12 +467,13 @@ class ResourceProviderTest EXPECT_LT(0u, *sync_point); scoped_ptr<base::SharedMemory> shared_memory; - scoped_ptr<SingleReleaseCallback> callback = - SingleReleaseCallback::Create(base::Bind(ReleaseSharedMemoryCallback, - base::Passed(&shared_memory), - release_called, - release_sync_point, - lost_resource)); + scoped_ptr<SingleReleaseCallbackImpl> callback = + SingleReleaseCallbackImpl::Create( + base::Bind(ReleaseSharedMemoryCallback, + base::Passed(&shared_memory), + release_called, + release_sync_point, + lost_resource)); return child_resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox(gpu_mailbox, GL_TEXTURE_2D, *sync_point), callback.Pass()); @@ -461,12 +483,13 @@ class ResourceProviderTest CreateAndFillSharedMemory(size, 0)); base::SharedMemory* shared_memory_ptr = shared_memory.get(); - scoped_ptr<SingleReleaseCallback> callback = - SingleReleaseCallback::Create(base::Bind(ReleaseSharedMemoryCallback, - base::Passed(&shared_memory), - release_called, - release_sync_point, - lost_resource)); + scoped_ptr<SingleReleaseCallbackImpl> callback = + SingleReleaseCallbackImpl::Create( + base::Bind(ReleaseSharedMemoryCallback, + base::Passed(&shared_memory), + release_called, + release_sync_point, + lost_resource)); return child_resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox(shared_memory_ptr, size), callback.Pass()); } @@ -480,9 +503,11 @@ class ResourceProviderTest FakeOutputSurfaceClient child_output_surface_client_; scoped_ptr<OutputSurface> output_surface_; scoped_ptr<OutputSurface> child_output_surface_; + scoped_ptr<BlockingTaskRunner> main_thread_task_runner_; scoped_ptr<ResourceProvider> resource_provider_; scoped_ptr<ResourceProvider> child_resource_provider_; scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_; + scoped_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_; }; void CheckCreateResource(ResourceProvider::ResourceType expected_default_type, @@ -496,7 +521,7 @@ void CheckCreateResource(ResourceProvider::ResourceType expected_default_type, ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); EXPECT_EQ(1, static_cast<int>(resource_provider->num_resources())); if (expected_default_type == ResourceProvider::GLTexture) EXPECT_EQ(0u, context->NumTextures()); @@ -528,7 +553,7 @@ TEST_P(ResourceProviderTest, Upload) { ASSERT_EQ(16U, pixel_size); ResourceProvider::ResourceId id = resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t image[16] = { 0 }; gfx::Rect image_rect(size); @@ -597,20 +622,23 @@ TEST_P(ResourceProviderTest, TransferGLResources) { ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data1[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data2[4] = { 5, 5, 5, 5 }; child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); ResourceProvider::ResourceId id3 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - child_resource_provider_->MapImageRasterBuffer(id3); - child_resource_provider_->UnmapImageRasterBuffer(id3); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); + { + ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock( + child_resource_provider_.get(), id3); + EXPECT_TRUE(!!lock.GetGpuMemoryBuffer()); + } GLuint external_texture_id = child_context_->createExternalTexture(); child_context_->bindTexture(GL_TEXTURE_EXTERNAL_OES, external_texture_id); @@ -624,7 +652,7 @@ TEST_P(ResourceProviderTest, TransferGLResources) { child_resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox( external_mailbox, GL_TEXTURE_EXTERNAL_OES, external_sync_point), - SingleReleaseCallback::Create(base::Bind(&EmptyReleaseCallback))); + SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback))); ReturnedResourceArray returned_to_child; int child_id = @@ -664,6 +692,7 @@ TEST_P(ResourceProviderTest, TransferGLResources) { EXPECT_NE(list[0].mailbox_holder.sync_point, context3d_->last_waited_sync_point()); { + resource_provider_->WaitSyncPointIfNeeded(list[0].id); ResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), list[0].id); } @@ -753,6 +782,7 @@ TEST_P(ResourceProviderTest, TransferGLResources) { EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id4)); { + child_resource_provider_->WaitSyncPointIfNeeded(id1); ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(), id1); ASSERT_NE(0U, lock.texture_id()); @@ -761,6 +791,7 @@ TEST_P(ResourceProviderTest, TransferGLResources) { EXPECT_EQ(0, memcmp(data1, result, pixel_size)); } { + child_resource_provider_->WaitSyncPointIfNeeded(id2); ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(), id2); ASSERT_NE(0U, lock.texture_id()); @@ -769,6 +800,7 @@ TEST_P(ResourceProviderTest, TransferGLResources) { EXPECT_EQ(0, memcmp(data2, result, pixel_size)); } { + child_resource_provider_->WaitSyncPointIfNeeded(id3); ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(), id3); ASSERT_NE(0U, lock.texture_id()); @@ -834,7 +866,7 @@ TEST_P(ResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) { ResourceFormat format = RGBA_8888; ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data1[4] = {1, 2, 3, 4}; gfx::Rect rect(size); child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); @@ -854,6 +886,7 @@ TEST_P(ResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) { resource_provider_->ReceiveFromChild(child_id, list); + resource_provider_->WaitSyncPointIfNeeded(list[0].id); ResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), list[0].id); @@ -866,6 +899,7 @@ TEST_P(ResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) { child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); { + child_resource_provider_->WaitSyncPointIfNeeded(id1); ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(), id1); child_resource_provider_->DeleteResource(id1); @@ -877,6 +911,57 @@ TEST_P(ResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) { resource_provider_->DestroyChild(child_id); } +TEST_P(ResourceProviderTest, AllowOverlayTransfersToParent) { + // Overlays only supported on the GL path. + if (GetParam() != ResourceProvider::GLTexture) + return; + + uint32 sync_point = 0; + TextureMailbox mailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point); + mailbox.set_allow_overlay(true); + scoped_ptr<SingleReleaseCallbackImpl> release_callback = + SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback)); + ResourceProvider::ResourceId id1 = + child_resource_provider_->CreateResourceFromTextureMailbox( + mailbox, release_callback.Pass()); + + TextureMailbox mailbox2(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point); + mailbox2.set_allow_overlay(false); + scoped_ptr<SingleReleaseCallbackImpl> release_callback2 = + SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback)); + ResourceProvider::ResourceId id2 = + child_resource_provider_->CreateResourceFromTextureMailbox( + mailbox2, release_callback2.Pass()); + + ReturnedResourceArray returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer some resources to the parent. + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(id1); + resource_ids_to_transfer.push_back(id2); + TransferableResourceArray list; + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, + &list); + ASSERT_EQ(2u, list.size()); + resource_provider_->ReceiveFromChild(child_id, list); + EXPECT_TRUE(resource_provider_->AllowOverlay(list[0].id)); + EXPECT_FALSE(resource_provider_->AllowOverlay(list[1].id)); + + resource_provider_->DeclareUsedResourcesFromChild( + child_id, ResourceProvider::ResourceIdArray()); + + EXPECT_EQ(2u, returned_to_child.size()); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + + child_resource_provider_->DeleteResource(id1); + child_resource_provider_->DeleteResource(id2); + EXPECT_EQ(0u, child_resource_provider_->num_resources()); + + resource_provider_->DestroyChild(child_id); +} + TEST_P(ResourceProviderTest, TransferSoftwareResources) { if (GetParam() != ResourceProvider::Bitmap) return; @@ -887,31 +972,23 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) { ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data1[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data2[4] = { 5, 5, 5, 5 }; child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); - ResourceProvider::ResourceId id3 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - uint8_t data3[4] = { 6, 7, 8, 9 }; - SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height()); - SkCanvas* raster_canvas = child_resource_provider_->MapImageRasterBuffer(id3); - raster_canvas->writePixels(info, data3, info.minRowBytes(), 0, 0); - child_resource_provider_->UnmapImageRasterBuffer(id3); - scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); shared_memory->CreateAndMapAnonymous(1); base::SharedMemory* shared_memory_ptr = shared_memory.get(); - ResourceProvider::ResourceId id4 = + ResourceProvider::ResourceId id3 = child_resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox(shared_memory_ptr, gfx::Size(1, 1)), - SingleReleaseCallback::Create(base::Bind( + SingleReleaseCallbackImpl::Create(base::Bind( &SharedMemoryReleaseCallback, base::Passed(&shared_memory)))); ReturnedResourceArray returned_to_child; @@ -923,39 +1000,33 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) { resource_ids_to_transfer.push_back(id1); resource_ids_to_transfer.push_back(id2); resource_ids_to_transfer.push_back(id3); - resource_ids_to_transfer.push_back(id4); TransferableResourceArray list; child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); - ASSERT_EQ(4u, list.size()); + ASSERT_EQ(3u, list.size()); EXPECT_EQ(0u, list[0].mailbox_holder.sync_point); EXPECT_EQ(0u, list[1].mailbox_holder.sync_point); EXPECT_EQ(0u, list[2].mailbox_holder.sync_point); - EXPECT_EQ(0u, list[3].mailbox_holder.sync_point); EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3)); - EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4)); resource_provider_->ReceiveFromChild(child_id, list); resource_provider_->DeclareUsedResourcesFromChild(child_id, resource_ids_to_transfer); } - EXPECT_EQ(4u, resource_provider_->num_resources()); + EXPECT_EQ(3u, resource_provider_->num_resources()); ResourceProvider::ResourceIdMap resource_map = resource_provider_->GetChildToParentMap(child_id); ResourceProvider::ResourceId mapped_id1 = resource_map[id1]; ResourceProvider::ResourceId mapped_id2 = resource_map[id2]; ResourceProvider::ResourceId mapped_id3 = resource_map[id3]; - ResourceProvider::ResourceId mapped_id4 = resource_map[id4]; EXPECT_NE(0u, mapped_id1); EXPECT_NE(0u, mapped_id2); EXPECT_NE(0u, mapped_id3); - EXPECT_NE(0u, mapped_id4); EXPECT_FALSE(resource_provider_->InUseByConsumer(id1)); EXPECT_FALSE(resource_provider_->InUseByConsumer(id2)); EXPECT_FALSE(resource_provider_->InUseByConsumer(id3)); - EXPECT_FALSE(resource_provider_->InUseByConsumer(id4)); uint8_t result[4] = { 0 }; GetResourcePixels( @@ -966,24 +1037,18 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) { resource_provider_.get(), context(), mapped_id2, size, format, result); EXPECT_EQ(0, memcmp(data2, result, pixel_size)); - GetResourcePixels( - resource_provider_.get(), context(), mapped_id3, size, format, result); - EXPECT_EQ(0, memcmp(data3, result, pixel_size)); - { // Check that transfering again the same resource from the child to the // parent works. ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(id1); resource_ids_to_transfer.push_back(id2); - resource_ids_to_transfer.push_back(id3); TransferableResourceArray list; child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); - EXPECT_EQ(3u, list.size()); + EXPECT_EQ(2u, list.size()); EXPECT_EQ(id1, list[0].id); EXPECT_EQ(id2, list[1].id); - EXPECT_EQ(id3, list[2].id); ReturnedResourceArray returned; TransferableResource::ReturnResources(list, &returned); child_resource_provider_->ReceiveReturnsFromParent(returned); @@ -991,7 +1056,6 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) { // be in-use. EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); - EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3)); } { EXPECT_EQ(0u, returned_to_child.size()); @@ -1001,31 +1065,27 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) { ResourceProvider::ResourceIdArray no_resources; resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); - ASSERT_EQ(4u, returned_to_child.size()); + ASSERT_EQ(3u, returned_to_child.size()); EXPECT_EQ(0u, returned_to_child[0].sync_point); EXPECT_EQ(0u, returned_to_child[1].sync_point); EXPECT_EQ(0u, returned_to_child[2].sync_point); - EXPECT_EQ(0u, returned_to_child[3].sync_point); std::set<ResourceProvider::ResourceId> expected_ids; expected_ids.insert(id1); expected_ids.insert(id2); expected_ids.insert(id3); - expected_ids.insert(id4); std::set<ResourceProvider::ResourceId> returned_ids; - for (unsigned i = 0; i < 4; i++) + for (unsigned i = 0; i < 3; i++) returned_ids.insert(returned_to_child[i].id); EXPECT_EQ(expected_ids, returned_ids); EXPECT_FALSE(returned_to_child[0].lost); EXPECT_FALSE(returned_to_child[1].lost); EXPECT_FALSE(returned_to_child[2].lost); - EXPECT_FALSE(returned_to_child[3].lost); child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); returned_to_child.clear(); } EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id1)); EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id2)); EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id3)); - EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id4)); { ResourceProvider::ScopedReadLockSoftware lock( @@ -1044,32 +1104,21 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) { EXPECT_EQ(0, memcmp(data2, sk_bitmap->getPixels(), pixel_size)); } { - ResourceProvider::ScopedReadLockSoftware lock( - child_resource_provider_.get(), id3); - const SkBitmap* sk_bitmap = lock.sk_bitmap(); - EXPECT_EQ(sk_bitmap->width(), size.width()); - EXPECT_EQ(sk_bitmap->height(), size.height()); - EXPECT_EQ(0, memcmp(data3, sk_bitmap->getPixels(), pixel_size)); - } - { // Transfer resources to the parent again. ResourceProvider::ResourceIdArray resource_ids_to_transfer; resource_ids_to_transfer.push_back(id1); resource_ids_to_transfer.push_back(id2); resource_ids_to_transfer.push_back(id3); - resource_ids_to_transfer.push_back(id4); TransferableResourceArray list; child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); - ASSERT_EQ(4u, list.size()); + ASSERT_EQ(3u, list.size()); EXPECT_EQ(id1, list[0].id); EXPECT_EQ(id2, list[1].id); EXPECT_EQ(id3, list[2].id); - EXPECT_EQ(id4, list[3].id); EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3)); - EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4)); resource_provider_->ReceiveFromChild(child_id, list); resource_provider_->DeclareUsedResourcesFromChild(child_id, resource_ids_to_transfer); @@ -1077,28 +1126,25 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) { EXPECT_EQ(0u, returned_to_child.size()); - EXPECT_EQ(4u, resource_provider_->num_resources()); + EXPECT_EQ(3u, resource_provider_->num_resources()); resource_provider_->DestroyChild(child_id); EXPECT_EQ(0u, resource_provider_->num_resources()); - ASSERT_EQ(4u, returned_to_child.size()); + ASSERT_EQ(3u, returned_to_child.size()); EXPECT_EQ(0u, returned_to_child[0].sync_point); EXPECT_EQ(0u, returned_to_child[1].sync_point); EXPECT_EQ(0u, returned_to_child[2].sync_point); - EXPECT_EQ(0u, returned_to_child[3].sync_point); std::set<ResourceProvider::ResourceId> expected_ids; expected_ids.insert(id1); expected_ids.insert(id2); expected_ids.insert(id3); - expected_ids.insert(id4); std::set<ResourceProvider::ResourceId> returned_ids; - for (unsigned i = 0; i < 4; i++) + for (unsigned i = 0; i < 3; i++) returned_ids.insert(returned_to_child[i].id); EXPECT_EQ(expected_ids, returned_ids); EXPECT_FALSE(returned_to_child[0].lost); EXPECT_FALSE(returned_to_child[1].lost); EXPECT_FALSE(returned_to_child[2].lost); - EXPECT_FALSE(returned_to_child[3].lost); } TEST_P(ResourceProviderTest, TransferGLToSoftware) { @@ -1109,13 +1155,18 @@ TEST_P(ResourceProviderTest, TransferGLToSoftware) { ResourceProviderContext::Create(shared_data_.get())); FakeOutputSurfaceClient child_output_surface_client; - scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( - child_context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> child_output_surface( + FakeOutputSurface::Create3d(child_context_owned.Pass())); CHECK(child_output_surface->BindToClient(&child_output_surface_client)); - scoped_ptr<ResourceProvider> child_resource_provider(ResourceProvider::Create( - child_output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, - false)); + scoped_ptr<ResourceProvider> child_resource_provider( + ResourceProvider::Create(child_output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -1123,7 +1174,7 @@ TEST_P(ResourceProviderTest, TransferGLToSoftware) { ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data1[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); @@ -1170,7 +1221,7 @@ TEST_P(ResourceProviderTest, TransferInvalidSoftware) { ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data1[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); @@ -1218,13 +1269,13 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) { ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data1[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data2[4] = {5, 5, 5, 5}; child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); @@ -1312,13 +1363,13 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) { ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data1[4] = {1, 2, 3, 4}; gfx::Rect rect(size); child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data2[4] = {5, 5, 5, 5}; child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); @@ -1407,7 +1458,7 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) { // Destroy the parent resource provider. The resource that's left should be // lost at this point, and returned. - resource_provider_.reset(); + resource_provider_ = nullptr; ASSERT_EQ(1u, returned_to_child.size()); if (GetParam() == ResourceProvider::GLTexture) { EXPECT_NE(0u, returned_to_child[0].sync_point); @@ -1423,7 +1474,7 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) { ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d()); @@ -1473,7 +1524,7 @@ TEST_P(ResourceProviderTest, UnuseTransferredResources) { ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); uint8_t data[4] = {1, 2, 3, 4}; gfx::Rect rect(size); child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d()); @@ -1584,8 +1635,8 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { TextureStateTrackingContext* child_context = child_context_owned.get(); FakeOutputSurfaceClient child_output_surface_client; - scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( - child_context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> child_output_surface( + FakeOutputSurface::Create3d(child_context_owned.Pass())); CHECK(child_output_surface->BindToClient(&child_output_surface_client)); scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); @@ -1593,27 +1644,29 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { scoped_ptr<ResourceProvider> child_resource_provider( ResourceProvider::Create(child_output_surface.get(), shared_bitmap_manager.get(), + NULL, + NULL, 0, false, - 1, - false)); + 1)); scoped_ptr<TextureStateTrackingContext> parent_context_owned( new TextureStateTrackingContext); TextureStateTrackingContext* parent_context = parent_context_owned.get(); FakeOutputSurfaceClient parent_output_surface_client; - scoped_ptr<OutputSurface> parent_output_surface(FakeOutputSurface::Create3d( - parent_context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> parent_output_surface( + FakeOutputSurface::Create3d(parent_context_owned.Pass())); CHECK(parent_output_surface->BindToClient(&parent_output_surface_client)); scoped_ptr<ResourceProvider> parent_resource_provider( ResourceProvider::Create(parent_output_surface.get(), shared_bitmap_manager.get(), + NULL, + NULL, 0, false, - 1, - false)); + 1)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -1624,7 +1677,7 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { ASSERT_EQ(4U, pixel_size); ResourceProvider::ResourceId id = child_resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); // The new texture is created with GL_LINEAR. EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id)) @@ -1691,6 +1744,7 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { EXPECT_CALL(*parent_context, consumeTextureCHROMIUM(GL_TEXTURE_2D, _)); parent_resource_provider->ReceiveFromChild(child_id, list); { + parent_resource_provider->WaitSyncPointIfNeeded(list[0].id); ResourceProvider::ScopedReadLockGL lock(parent_resource_provider.get(), list[0].id); } @@ -1779,12 +1833,15 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) { uint32 release_sync_point = 0; bool lost_resource = false; - ReleaseCallback callback = - base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource); + BlockingTaskRunner* main_thread_task_runner = NULL; + ReleaseCallbackImpl callback = base::Bind(ReleaseCallback, + &release_sync_point, + &lost_resource, + &main_thread_task_runner); ResourceProvider::ResourceId resource = resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point), - SingleReleaseCallback::Create(callback)); + SingleReleaseCallbackImpl::Create(callback)); EXPECT_EQ(1u, context()->NumTextures()); EXPECT_EQ(0u, release_sync_point); { @@ -1825,6 +1882,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) { resource_provider_->DeleteResource(resource); EXPECT_LE(list[0].mailbox_holder.sync_point, release_sync_point); EXPECT_FALSE(lost_resource); + EXPECT_EQ(main_thread_task_runner_.get(), main_thread_task_runner); } // We're going to do the same thing as above, but testing the case where we @@ -1834,7 +1892,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) { release_sync_point = 0; resource = resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point), - SingleReleaseCallback::Create(callback)); + SingleReleaseCallbackImpl::Create(callback)); EXPECT_EQ(1u, context()->NumTextures()); EXPECT_EQ(0u, release_sync_point); { @@ -1876,6 +1934,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) { resource_provider_->ReceiveReturnsFromParent(returned); EXPECT_LE(list[0].mailbox_holder.sync_point, release_sync_point); EXPECT_FALSE(lost_resource); + EXPECT_EQ(main_thread_task_runner_.get(), main_thread_task_runner); } context()->waitSyncPoint(release_sync_point); @@ -1889,7 +1948,10 @@ TEST_P(ResourceProviderTest, LostResourceInParent) { ResourceFormat format = RGBA_8888; ResourceProvider::ResourceId resource = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, + GL_CLAMP_TO_EDGE, + ResourceProvider::TextureHintImmutable, + format); child_resource_provider_->AllocateForTesting(resource); // Expect a GL resource to be lost. bool should_lose_resource = GetParam() == ResourceProvider::GLTexture; @@ -1942,7 +2004,10 @@ TEST_P(ResourceProviderTest, LostResourceInGrandParent) { ResourceFormat format = RGBA_8888; ResourceProvider::ResourceId resource = child_resource_provider_->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, + GL_CLAMP_TO_EDGE, + ResourceProvider::TextureHintImmutable, + format); child_resource_provider_->AllocateForTesting(resource); ReturnedResourceArray returned_to_child; @@ -2142,7 +2207,7 @@ TEST_P(ResourceProviderTest, Shutdown) { EXPECT_EQ(0u, release_sync_point); EXPECT_FALSE(lost_resource); - child_resource_provider_.reset(); + child_resource_provider_ = nullptr; if (GetParam() == ResourceProvider::GLTexture) { EXPECT_LE(sync_point, release_sync_point); @@ -2169,7 +2234,7 @@ TEST_P(ResourceProviderTest, ShutdownWithExportedResource) { EXPECT_EQ(0u, release_sync_point); EXPECT_FALSE(lost_resource); - child_resource_provider_.reset(); + child_resource_provider_ = nullptr; // Since the resource is in the parent, the child considers it lost. EXPECT_EQ(0u, release_sync_point); @@ -2191,19 +2256,25 @@ TEST_P(ResourceProviderTest, LostContext) { uint32 release_sync_point = 0; bool lost_resource = false; - scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( - base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource)); + BlockingTaskRunner* main_thread_task_runner = NULL; + scoped_ptr<SingleReleaseCallbackImpl> callback = + SingleReleaseCallbackImpl::Create(base::Bind(ReleaseCallback, + &release_sync_point, + &lost_resource, + &main_thread_task_runner)); resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point), callback.Pass()); EXPECT_EQ(0u, release_sync_point); EXPECT_FALSE(lost_resource); + EXPECT_EQ(NULL, main_thread_task_runner); resource_provider_->DidLoseOutputSurface(); - resource_provider_.reset(); + resource_provider_ = nullptr; EXPECT_LE(sync_point, release_sync_point); EXPECT_TRUE(lost_resource); + EXPECT_EQ(main_thread_task_runner_.get(), main_thread_task_runner); } TEST_P(ResourceProviderTest, ScopedSampler) { @@ -2216,19 +2287,25 @@ TEST_P(ResourceProviderTest, ScopedSampler) { TextureStateTrackingContext* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; int texture_id = 1; ResourceProvider::ResourceId id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); // Check that the texture gets created with the right sampler settings. EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)) @@ -2297,12 +2374,18 @@ TEST_P(ResourceProviderTest, ManagedResource) { TextureStateTrackingContext* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -2313,7 +2396,7 @@ TEST_P(ResourceProviderTest, ManagedResource) { size, GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, - ResourceProvider::TextureUsageAny, + ResourceProvider::TextureHintImmutable, format); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)); EXPECT_CALL(*context, @@ -2346,12 +2429,18 @@ TEST_P(ResourceProviderTest, TextureWrapMode) { TextureStateTrackingContext* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -2360,12 +2449,76 @@ TEST_P(ResourceProviderTest, TextureWrapMode) { for (int texture_id = 1; texture_id <= 2; ++texture_id) { GLint wrap_mode = texture_id == 1 ? GL_CLAMP_TO_EDGE : GL_REPEAT; // Check that the texture gets created with the right sampler settings. + ResourceProvider::ResourceId id = resource_provider->CreateGLTexture( + size, + GL_TEXTURE_2D, + texture_pool, + wrap_mode, + ResourceProvider::TextureHintImmutable, + format); + EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)); + EXPECT_CALL(*context, + texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + EXPECT_CALL(*context, + texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + EXPECT_CALL(*context, + texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode)); + EXPECT_CALL(*context, + texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode)); + EXPECT_CALL(*context, + texParameteri(GL_TEXTURE_2D, + GL_TEXTURE_POOL_CHROMIUM, + GL_TEXTURE_POOL_UNMANAGED_CHROMIUM)); + resource_provider->CreateForTesting(id); + EXPECT_NE(0u, id); + + Mock::VerifyAndClearExpectations(context); + } +} + +TEST_P(ResourceProviderTest, TextureHint) { + // Sampling is only supported for GL textures. + if (GetParam() != ResourceProvider::GLTexture) + return; + + scoped_ptr<TextureStateTrackingContext> context_owned( + new TextureStateTrackingContext); + TextureStateTrackingContext* context = context_owned.get(); + context->set_support_texture_storage(true); + context->set_support_texture_usage(true); + + FakeOutputSurfaceClient output_surface_client; + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); + CHECK(output_surface->BindToClient(&output_surface_client)); + + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); + + gfx::Size size(1, 1); + ResourceFormat format = RGBA_8888; + GLenum texture_pool = GL_TEXTURE_POOL_UNMANAGED_CHROMIUM; + + const ResourceProvider::TextureHint hints[4] = { + ResourceProvider::TextureHintDefault, + ResourceProvider::TextureHintImmutable, + ResourceProvider::TextureHintFramebuffer, + ResourceProvider::TextureHintImmutableFramebuffer, + }; + for (GLuint texture_id = 1; texture_id <= arraysize(hints); ++texture_id) { + // Check that the texture gets created with the right sampler settings. ResourceProvider::ResourceId id = resource_provider->CreateGLTexture(size, GL_TEXTURE_2D, texture_pool, - wrap_mode, - ResourceProvider::TextureUsageAny, + GL_CLAMP_TO_EDGE, + hints[texture_id - 1], format); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)); EXPECT_CALL(*context, @@ -2374,14 +2527,22 @@ TEST_P(ResourceProviderTest, TextureWrapMode) { texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); EXPECT_CALL( *context, - texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode)); + texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); EXPECT_CALL( *context, - texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode)); + texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_POOL_CHROMIUM, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM)); + // Check only TextureHintFramebuffer set GL_TEXTURE_USAGE_ANGLE. + bool is_framebuffer_hint = + hints[texture_id - 1] & ResourceProvider::TextureHintFramebuffer; + EXPECT_CALL(*context, + texParameteri(GL_TEXTURE_2D, + GL_TEXTURE_USAGE_ANGLE, + GL_FRAMEBUFFER_ATTACHMENT_ANGLE)) + .Times(is_framebuffer_hint ? 1 : 0); resource_provider->CreateForTesting(id); EXPECT_NE(0u, id); @@ -2404,11 +2565,23 @@ TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) { new SoftwareOutputDevice))); CHECK(output_surface->BindToClient(&output_surface_client)); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + main_thread_task_runner_.get(), + 0, + false, + 1)); - scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( - base::Bind(&EmptyReleaseCallback)); + uint32 release_sync_point = 0; + bool lost_resource = false; + BlockingTaskRunner* main_thread_task_runner = NULL; + scoped_ptr<SingleReleaseCallbackImpl> callback = + SingleReleaseCallbackImpl::Create(base::Bind(&ReleaseCallback, + &release_sync_point, + &lost_resource, + &main_thread_task_runner)); TextureMailbox mailbox(shared_memory.get(), size); ResourceProvider::ResourceId id = @@ -2423,6 +2596,11 @@ TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) { EXPECT_EQ(sk_bitmap->height(), size.height()); EXPECT_EQ(*sk_bitmap->getAddr32(16, 16), kBadBeef); } + + resource_provider->DeleteResource(id); + EXPECT_EQ(0u, release_sync_point); + EXPECT_FALSE(lost_resource); + EXPECT_EQ(main_thread_task_runner_.get(), main_thread_task_runner); } TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) { @@ -2435,12 +2613,18 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) { TextureStateTrackingContext* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + main_thread_task_runner_.get(), + 0, + false, + 1)); unsigned texture_id = 1; uint32 sync_point = 30; @@ -2454,8 +2638,14 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) { gpu::Mailbox gpu_mailbox; memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); - scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( - base::Bind(&EmptyReleaseCallback)); + uint32 release_sync_point = 0; + bool lost_resource = false; + BlockingTaskRunner* main_thread_task_runner = NULL; + scoped_ptr<SingleReleaseCallbackImpl> callback = + SingleReleaseCallbackImpl::Create(base::Bind(&ReleaseCallback, + &release_sync_point, + &lost_resource, + &main_thread_task_runner)); TextureMailbox mailbox(gpu_mailbox, target, sync_point); @@ -2467,9 +2657,13 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) { Mock::VerifyAndClearExpectations(context); { + // Mailbox sync point WaitSyncPoint before using the texture. + EXPECT_CALL(*context, waitSyncPoint(sync_point)); + resource_provider->WaitSyncPointIfNeeded(id); + Mock::VerifyAndClearExpectations(context); + // Using the texture does a consume of the mailbox. EXPECT_CALL(*context, bindTexture(target, texture_id)); - EXPECT_CALL(*context, waitSyncPoint(sync_point)); EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _)); EXPECT_CALL(*context, insertSyncPoint()).Times(0); @@ -2487,6 +2681,11 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) { EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); } + + resource_provider->DeleteResource(id); + EXPECT_EQ(0u, release_sync_point); + EXPECT_FALSE(lost_resource); + EXPECT_EQ(main_thread_task_runner_.get(), main_thread_task_runner); } TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) { @@ -2499,12 +2698,18 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) { TextureStateTrackingContext* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); unsigned texture_id = 1; uint32 sync_point = 30; @@ -2518,8 +2723,8 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) { gpu::Mailbox gpu_mailbox; memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); - scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( - base::Bind(&EmptyReleaseCallback)); + scoped_ptr<SingleReleaseCallbackImpl> callback = + SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback)); TextureMailbox mailbox(gpu_mailbox, target, sync_point); @@ -2531,9 +2736,13 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) { Mock::VerifyAndClearExpectations(context); { + // Mailbox sync point WaitSyncPoint before using the texture. + EXPECT_CALL(*context, waitSyncPoint(sync_point)); + resource_provider->WaitSyncPointIfNeeded(id); + Mock::VerifyAndClearExpectations(context); + // Using the texture does a consume of the mailbox. EXPECT_CALL(*context, bindTexture(target, texture_id)); - EXPECT_CALL(*context, waitSyncPoint(sync_point)); EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _)); EXPECT_CALL(*context, insertSyncPoint()).Times(0); @@ -2553,6 +2762,120 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) { } } +TEST_P(ResourceProviderTest, + TextureMailbox_WaitSyncPointIfNeeded_WithSyncPoint) { + // Mailboxing is only supported for GL textures. + if (GetParam() != ResourceProvider::GLTexture) + return; + + scoped_ptr<TextureStateTrackingContext> context_owned( + new TextureStateTrackingContext); + TextureStateTrackingContext* context = context_owned.get(); + + FakeOutputSurfaceClient output_surface_client; + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); + CHECK(output_surface->BindToClient(&output_surface_client)); + + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); + + uint32 sync_point = 30; + unsigned target = GL_TEXTURE_2D; + + EXPECT_CALL(*context, bindTexture(_, _)).Times(0); + EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); + EXPECT_CALL(*context, insertSyncPoint()).Times(0); + EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); + + gpu::Mailbox gpu_mailbox; + memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); + scoped_ptr<SingleReleaseCallbackImpl> callback = + SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback)); + + TextureMailbox mailbox(gpu_mailbox, target, sync_point); + + ResourceProvider::ResourceId id = + resource_provider->CreateResourceFromTextureMailbox(mailbox, + callback.Pass()); + EXPECT_NE(0u, id); + + Mock::VerifyAndClearExpectations(context); + + { + // First call to WaitSyncPointIfNeeded should call waitSyncPoint. + EXPECT_CALL(*context, waitSyncPoint(sync_point)); + resource_provider->WaitSyncPointIfNeeded(id); + Mock::VerifyAndClearExpectations(context); + + // Subsequent calls to WaitSyncPointIfNeeded shouldn't call waitSyncPoint. + EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); + resource_provider->WaitSyncPointIfNeeded(id); + Mock::VerifyAndClearExpectations(context); + } +} + +TEST_P(ResourceProviderTest, TextureMailbox_WaitSyncPointIfNeeded_NoSyncPoint) { + // Mailboxing is only supported for GL textures. + if (GetParam() != ResourceProvider::GLTexture) + return; + + scoped_ptr<TextureStateTrackingContext> context_owned( + new TextureStateTrackingContext); + TextureStateTrackingContext* context = context_owned.get(); + + FakeOutputSurfaceClient output_surface_client; + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); + CHECK(output_surface->BindToClient(&output_surface_client)); + + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); + + uint32 sync_point = 0; + unsigned target = GL_TEXTURE_2D; + + EXPECT_CALL(*context, bindTexture(_, _)).Times(0); + EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); + EXPECT_CALL(*context, insertSyncPoint()).Times(0); + EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); + + gpu::Mailbox gpu_mailbox; + memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); + scoped_ptr<SingleReleaseCallbackImpl> callback = + SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback)); + + TextureMailbox mailbox(gpu_mailbox, target, sync_point); + + ResourceProvider::ResourceId id = + resource_provider->CreateResourceFromTextureMailbox(mailbox, + callback.Pass()); + EXPECT_NE(0u, id); + + Mock::VerifyAndClearExpectations(context); + + { + // WaitSyncPointIfNeeded with sync_point == 0 shouldn't call waitSyncPoint. + EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); + resource_provider->WaitSyncPointIfNeeded(id); + Mock::VerifyAndClearExpectations(context); + } +} + class AllocationTrackingContext3D : public TestWebGraphicsContext3D { public: MOCK_METHOD0(NextTextureId, GLuint()); @@ -2614,11 +2937,9 @@ class AllocationTrackingContext3D : public TestWebGraphicsContext3D { GLsizei image_size, const void* data)); MOCK_METHOD1(waitAsyncTexImage2DCHROMIUM, void(GLenum)); - MOCK_METHOD4(createImageCHROMIUM, GLuint(GLsizei, GLsizei, GLenum, GLenum)); + MOCK_METHOD4(createImageCHROMIUM, + GLuint(ClientBuffer, GLsizei, GLsizei, GLenum)); MOCK_METHOD1(destroyImageCHROMIUM, void(GLuint)); - MOCK_METHOD1(mapImageCHROMIUM, void*(GLuint)); - MOCK_METHOD3(getImageParameterivCHROMIUM, void(GLuint, GLenum, GLint*)); - MOCK_METHOD1(unmapImageCHROMIUM, void(GLuint)); MOCK_METHOD2(bindTexImage2DCHROMIUM, void(GLenum, GLint)); MOCK_METHOD2(releaseTexImage2DCHROMIUM, void(GLenum, GLint)); @@ -2637,12 +2958,18 @@ TEST_P(ResourceProviderTest, TextureAllocation) { AllocationTrackingContext3D* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); gfx::Size size(2, 2); gfx::Vector2d offset(0, 0); @@ -2654,7 +2981,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) { // Lazy allocation. Don't allocate when creating the resource. id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1); @@ -2667,7 +2994,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) { // Do allocate when we set the pixels. id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3); @@ -2682,8 +3009,8 @@ TEST_P(ResourceProviderTest, TextureAllocation) { // Same for async version. id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - resource_provider->AcquirePixelRasterBuffer(id); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); + resource_provider->AcquirePixelBuffer(id); EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); @@ -2692,7 +3019,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) { resource_provider->BeginSetPixels(id); ASSERT_TRUE(resource_provider->DidSetPixelsComplete(id)); - resource_provider->ReleasePixelRasterBuffer(id); + resource_provider->ReleasePixelBuffer(id); EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); resource_provider->DeleteResource(id); @@ -2700,7 +3027,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) { Mock::VerifyAndClearExpectations(context); } -TEST_P(ResourceProviderTest, TextureAllocationStorageUsageAny) { +TEST_P(ResourceProviderTest, TextureAllocationHint) { // Only for GL textures. if (GetParam() != ResourceProvider::GLTexture) return; @@ -2708,73 +3035,113 @@ TEST_P(ResourceProviderTest, TextureAllocationStorageUsageAny) { new StrictMock<AllocationTrackingContext3D>); AllocationTrackingContext3D* context = context_owned.get(); context->set_support_texture_storage(true); + context->set_support_texture_usage(true); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); gfx::Size size(2, 2); - ResourceFormat format = RGBA_8888; - ResourceProvider::ResourceId id = 0; - int texture_id = 123; - - // Lazy allocation. Don't allocate when creating the resource. - id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - - EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); - EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); - EXPECT_CALL(*context, texStorage2DEXT(_, _, _, 2, 2)).Times(1); - resource_provider->AllocateForTesting(id); - EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); - resource_provider->DeleteResource(id); - - Mock::VerifyAndClearExpectations(context); + const ResourceFormat formats[2] = {RGBA_8888, BGRA_8888}; + const ResourceProvider::TextureHint hints[4] = { + ResourceProvider::TextureHintDefault, + ResourceProvider::TextureHintImmutable, + ResourceProvider::TextureHintFramebuffer, + ResourceProvider::TextureHintImmutableFramebuffer, + }; + for (size_t i = 0; i < arraysize(formats); ++i) { + for (GLuint texture_id = 1; texture_id <= arraysize(hints); ++texture_id) { + // Lazy allocation. Don't allocate when creating the resource. + ResourceProvider::ResourceId id = resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, hints[texture_id - 1], formats[i]); + + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); + bool is_immutable_hint = + hints[texture_id - 1] & ResourceProvider::TextureHintImmutable; + bool support_immutable_texture = + is_immutable_hint && formats[i] == RGBA_8888; + EXPECT_CALL(*context, texStorage2DEXT(_, _, _, 2, 2)) + .Times(support_immutable_texture ? 1 : 0); + EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)) + .Times(support_immutable_texture ? 0 : 1); + resource_provider->AllocateForTesting(id); + + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); + resource_provider->DeleteResource(id); + + Mock::VerifyAndClearExpectations(context); + } + } } -TEST_P(ResourceProviderTest, TextureAllocationStorageUsageFramebuffer) { +TEST_P(ResourceProviderTest, TextureAllocationHint_BGRA) { // Only for GL textures. if (GetParam() != ResourceProvider::GLTexture) return; scoped_ptr<AllocationTrackingContext3D> context_owned( new StrictMock<AllocationTrackingContext3D>); AllocationTrackingContext3D* context = context_owned.get(); + context->set_support_texture_format_bgra8888(true); context->set_support_texture_storage(true); + context->set_support_texture_usage(true); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); gfx::Size size(2, 2); - ResourceFormat format = RGBA_8888; - ResourceProvider::ResourceId id = 0; - int texture_id = 123; - - // Lazy allocation. Don't allocate when creating the resource. - id = resource_provider->CreateResource( - size, - GL_CLAMP_TO_EDGE, - ResourceProvider::TextureUsageFramebuffer, - format); - - EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); - EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); - EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)).Times(1); - resource_provider->AllocateForTesting(id); + const ResourceFormat formats[2] = {RGBA_8888, BGRA_8888}; - EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); - resource_provider->DeleteResource(id); - - Mock::VerifyAndClearExpectations(context); + const ResourceProvider::TextureHint hints[4] = { + ResourceProvider::TextureHintDefault, + ResourceProvider::TextureHintImmutable, + ResourceProvider::TextureHintFramebuffer, + ResourceProvider::TextureHintImmutableFramebuffer, + }; + for (size_t i = 0; i < arraysize(formats); ++i) { + for (GLuint texture_id = 1; texture_id <= arraysize(hints); ++texture_id) { + // Lazy allocation. Don't allocate when creating the resource. + ResourceProvider::ResourceId id = resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, hints[texture_id - 1], formats[i]); + + EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); + EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); + bool is_immutable_hint = + hints[texture_id - 1] & ResourceProvider::TextureHintImmutable; + EXPECT_CALL(*context, texStorage2DEXT(_, _, _, 2, 2)) + .Times(is_immutable_hint ? 1 : 0); + EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)) + .Times(is_immutable_hint ? 0 : 1); + resource_provider->AllocateForTesting(id); + + EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); + resource_provider->DeleteResource(id); + + Mock::VerifyAndClearExpectations(context); + } + } } TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) { @@ -2785,8 +3152,8 @@ TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) { AllocationTrackingContext3D* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); gfx::Size size(2, 2); @@ -2794,12 +3161,18 @@ TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) { ResourceProvider::ResourceId id = 0; int texture_id = 123; - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - resource_provider->AcquirePixelRasterBuffer(id); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); + resource_provider->AcquirePixelBuffer(id); EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); @@ -2809,7 +3182,7 @@ TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) { EXPECT_TRUE(resource_provider->DidSetPixelsComplete(id)); - resource_provider->ReleasePixelRasterBuffer(id); + resource_provider->ReleasePixelBuffer(id); EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); resource_provider->DeleteResource(id); @@ -2826,8 +3199,8 @@ TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) { AllocationTrackingContext3D* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); gfx::Size size(2, 2); @@ -2835,12 +3208,18 @@ TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) { ResourceProvider::ResourceId id = 0; int texture_id = 123; - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - resource_provider->AcquirePixelRasterBuffer(id); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); + resource_provider->AcquirePixelBuffer(id); EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); @@ -2853,7 +3232,7 @@ TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) { EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, 0)).Times(1); resource_provider->ForceSetPixelsToComplete(id); - resource_provider->ReleasePixelRasterBuffer(id); + resource_provider->ReleasePixelBuffer(id); EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); resource_provider->DeleteResource(id); @@ -2867,8 +3246,8 @@ TEST_P(ResourceProviderTest, PixelBufferLostContext) { AllocationTrackingContext3D* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); gfx::Size size(2, 2); @@ -2876,21 +3255,27 @@ TEST_P(ResourceProviderTest, PixelBufferLostContext) { ResourceProvider::ResourceId id = 0; int texture_id = 123; - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); EXPECT_CALL(*context, NextTextureId()).WillRepeatedly(Return(texture_id)); id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); context->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); - resource_provider->AcquirePixelRasterBuffer(id); - SkCanvas* raster_canvas = resource_provider->MapPixelRasterBuffer(id); - EXPECT_TRUE(raster_canvas == NULL); - resource_provider->UnmapPixelRasterBuffer(id); - resource_provider->ReleasePixelRasterBuffer(id); + resource_provider->AcquirePixelBuffer(id); + int stride; + void* buffer = resource_provider->MapPixelBuffer(id, &stride); + EXPECT_FALSE(buffer); + resource_provider->UnmapPixelBuffer(id); Mock::VerifyAndClearExpectations(context); } @@ -2903,8 +3288,8 @@ TEST_P(ResourceProviderTest, Image_GLTexture) { AllocationTrackingContext3D* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); const int kWidth = 2; @@ -2915,33 +3300,26 @@ TEST_P(ResourceProviderTest, Image_GLTexture) { const unsigned kTextureId = 123u; const unsigned kImageId = 234u; - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); - const int kStride = 4; - void* dummy_mapped_buffer_address = NULL; - EXPECT_CALL( - *context, - createImageCHROMIUM(kWidth, kHeight, GL_RGBA8_OES, GL_IMAGE_MAP_CHROMIUM)) + EXPECT_CALL(*context, createImageCHROMIUM(_, kWidth, kHeight, GL_RGBA)) .WillOnce(Return(kImageId)) .RetiresOnSaturation(); - EXPECT_CALL(*context, getImageParameterivCHROMIUM(kImageId, - GL_IMAGE_ROWBYTES_CHROMIUM, - _)) - .WillOnce(SetArgPointee<2>(kStride)) - .RetiresOnSaturation(); - EXPECT_CALL(*context, mapImageCHROMIUM(kImageId)) - .WillOnce(Return(dummy_mapped_buffer_address)) - .RetiresOnSaturation(); - resource_provider->MapImageRasterBuffer(id); - - EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId)) - .Times(1) - .RetiresOnSaturation(); - resource_provider->UnmapImageRasterBuffer(id); + { + ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock( + resource_provider.get(), id); + EXPECT_TRUE(!!lock.GetGpuMemoryBuffer()); + } EXPECT_CALL(*context, NextTextureId()) .WillOnce(Return(kTextureId)) @@ -2958,20 +3336,11 @@ TEST_P(ResourceProviderTest, Image_GLTexture) { EXPECT_EQ(kTextureId, lock_gl.texture_id()); } - EXPECT_CALL( - *context, - getImageParameterivCHROMIUM(kImageId, GL_IMAGE_ROWBYTES_CHROMIUM, _)) - .WillOnce(SetArgPointee<2>(kStride)) - .RetiresOnSaturation(); - EXPECT_CALL(*context, mapImageCHROMIUM(kImageId)) - .WillOnce(Return(dummy_mapped_buffer_address)) - .RetiresOnSaturation(); - resource_provider->MapImageRasterBuffer(id); - - EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId)) - .Times(1) - .RetiresOnSaturation(); - resource_provider->UnmapImageRasterBuffer(id); + { + ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock( + resource_provider.get(), id); + EXPECT_TRUE(!!lock.GetGpuMemoryBuffer()); + } EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(1) .RetiresOnSaturation(); @@ -2995,45 +3364,6 @@ TEST_P(ResourceProviderTest, Image_GLTexture) { .RetiresOnSaturation(); } -TEST_P(ResourceProviderTest, Image_Bitmap) { - if (GetParam() != ResourceProvider::Bitmap) - return; - FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface( - FakeOutputSurface::CreateSoftware(make_scoped_ptr( - new SoftwareOutputDevice))); - CHECK(output_surface->BindToClient(&output_surface_client)); - - gfx::Size size(1, 1); - ResourceFormat format = RGBA_8888; - ResourceProvider::ResourceId id = 0; - const uint32_t kBadBeef = 0xbadbeef; - - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); - - id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - - SkBitmap bitmap; - bitmap.allocN32Pixels(size.width(), size.height()); - *(bitmap.getAddr32(0, 0)) = kBadBeef; - SkCanvas* canvas = resource_provider->MapImageRasterBuffer(id); - ASSERT_TRUE(!!canvas); - canvas->writePixels(bitmap, 0, 0); - resource_provider->UnmapImageRasterBuffer(id); - - { - ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), id); - const SkBitmap* sk_bitmap = lock.sk_bitmap(); - EXPECT_EQ(sk_bitmap->width(), size.width()); - EXPECT_EQ(sk_bitmap->height(), size.height()); - EXPECT_EQ(*sk_bitmap->getAddr32(0, 0), kBadBeef); - } - - resource_provider->DeleteResource(id); -} - TEST_P(ResourceProviderTest, CopyResource_GLTexture) { if (GetParam() != ResourceProvider::GLTexture) return; @@ -3043,8 +3373,8 @@ TEST_P(ResourceProviderTest, CopyResource_GLTexture) { context_owned->set_support_sync_query(true); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); ASSERT_TRUE(output_surface->BindToClient(&output_surface_client)); const int kWidth = 2; @@ -3057,38 +3387,30 @@ TEST_P(ResourceProviderTest, CopyResource_GLTexture) { const unsigned kDestTextureId = 321u; const unsigned kImageId = 234u; - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, + 0, + false, + 1)); source_id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); - const int kStride = 4; - void* dummy_mapped_buffer_address = NULL; - EXPECT_CALL( - *context, - createImageCHROMIUM(kWidth, kHeight, GL_RGBA8_OES, GL_IMAGE_MAP_CHROMIUM)) + EXPECT_CALL(*context, createImageCHROMIUM(_, kWidth, kHeight, GL_RGBA)) .WillOnce(Return(kImageId)) .RetiresOnSaturation(); - EXPECT_CALL( - *context, - getImageParameterivCHROMIUM(kImageId, GL_IMAGE_ROWBYTES_CHROMIUM, _)) - .WillOnce(SetArgPointee<2>(kStride)) - .RetiresOnSaturation(); - EXPECT_CALL(*context, mapImageCHROMIUM(kImageId)) - .WillOnce(Return(dummy_mapped_buffer_address)) - .RetiresOnSaturation(); - resource_provider->MapImageRasterBuffer(source_id); - Mock::VerifyAndClearExpectations(context); - - EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId)) - .Times(1) - .RetiresOnSaturation(); - resource_provider->UnmapImageRasterBuffer(source_id); + { + ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock( + resource_provider.get(), source_id); + EXPECT_TRUE(!!lock.GetGpuMemoryBuffer()); + } Mock::VerifyAndClearExpectations(context); dest_id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); EXPECT_CALL(*context, NextTextureId()) .WillOnce(Return(kDestTextureId)) @@ -3121,52 +3443,6 @@ TEST_P(ResourceProviderTest, CopyResource_GLTexture) { resource_provider->DeleteResource(dest_id); } -TEST_P(ResourceProviderTest, CopyResource_Bitmap) { - if (GetParam() != ResourceProvider::Bitmap) - return; - FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::CreateSoftware( - make_scoped_ptr(new SoftwareOutputDevice))); - CHECK(output_surface->BindToClient(&output_surface_client)); - - gfx::Size size(1, 1); - ResourceFormat format = RGBA_8888; - ResourceProvider::ResourceId source_id = 0; - ResourceProvider::ResourceId dest_id = 0; - const uint32_t kBadBeef = 0xbadbeef; - - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false)); - - source_id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - - SkBitmap bitmap; - bitmap.allocN32Pixels(size.width(), size.height()); - *(bitmap.getAddr32(0, 0)) = kBadBeef; - SkCanvas* canvas = resource_provider->MapImageRasterBuffer(source_id); - ASSERT_TRUE(!!canvas); - canvas->writePixels(bitmap, 0, 0); - resource_provider->UnmapImageRasterBuffer(source_id); - - dest_id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); - - resource_provider->CopyResource(source_id, dest_id); - - { - ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), - dest_id); - const SkBitmap* sk_bitmap = lock.sk_bitmap(); - EXPECT_EQ(sk_bitmap->width(), size.width()); - EXPECT_EQ(sk_bitmap->height(), size.height()); - EXPECT_EQ(*sk_bitmap->getAddr32(0, 0), kBadBeef); - } - - resource_provider->DeleteResource(source_id); - resource_provider->DeleteResource(dest_id); -} - void InitializeGLAndCheck(ContextSharedData* shared_data, ResourceProvider* resource_provider, FakeOutputSurface* output_surface) { @@ -3175,8 +3451,7 @@ void InitializeGLAndCheck(ContextSharedData* shared_data, ResourceProviderContext* context = context_owned.get(); scoped_refptr<TestContextProvider> context_provider = - TestContextProvider::Create( - context_owned.PassAs<TestWebGraphicsContext3D>()); + TestContextProvider::Create(context_owned.Pass()); output_surface->InitializeAndSetContext3d(context_provider); resource_provider->InitializeGL(); @@ -3194,8 +3469,14 @@ TEST(ResourceProviderTest, BasicInitializeGLSoftware) { EXPECT_TRUE(output_surface->BindToClient(&client)); scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager.get(), + NULL, + NULL, + 0, + false, + 1)); CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL); @@ -3222,22 +3503,23 @@ TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) { context_owned->set_support_compressed_texture_etc1(true); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); gfx::Size size(4, 4); scoped_ptr<ResourceProvider> resource_provider( ResourceProvider::Create(output_surface.get(), shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, 0, false, - 1, - false)); + 1)); int texture_id = 123; ResourceProvider::ResourceId id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, ETC1); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, ETC1); EXPECT_NE(0u, id); EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); @@ -3257,23 +3539,24 @@ TEST_P(ResourceProviderTest, CompressedTextureETC1SetPixels) { context_owned->set_support_compressed_texture_etc1(true); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); gfx::Size size(4, 4); scoped_ptr<ResourceProvider> resource_provider( ResourceProvider::Create(output_surface.get(), shared_bitmap_manager_.get(), + gpu_memory_buffer_manager_.get(), + NULL, 0, false, - 1, - false)); + 1)); int texture_id = 123; uint8_t pixels[8]; ResourceProvider::ResourceId id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, ETC1); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, ETC1); EXPECT_NE(0u, id); EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3); @@ -3294,11 +3577,11 @@ INSTANTIATE_TEST_CASE_P( class TextureIdAllocationTrackingContext : public TestWebGraphicsContext3D { public: - virtual GLuint NextTextureId() OVERRIDE { + GLuint NextTextureId() override { base::AutoLock lock(namespace_->lock); return namespace_->next_texture_id++; } - virtual void RetireTextureId(GLuint) OVERRIDE {} + void RetireTextureId(GLuint) override {} GLuint PeekTextureId() { base::AutoLock lock(namespace_->lock); return namespace_->next_texture_id; @@ -3311,8 +3594,8 @@ TEST(ResourceProviderTest, TextureAllocationChunkSize) { TextureIdAllocationTrackingContext* context = context_owned.get(); FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( - context_owned.PassAs<TestWebGraphicsContext3D>())); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(context_owned.Pass())); CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); @@ -3325,13 +3608,14 @@ TEST(ResourceProviderTest, TextureAllocationChunkSize) { scoped_ptr<ResourceProvider> resource_provider( ResourceProvider::Create(output_surface.get(), shared_bitmap_manager.get(), + NULL, + NULL, 0, false, - kTextureAllocationChunkSize, - false)); + kTextureAllocationChunkSize)); ResourceProvider::ResourceId id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); resource_provider->AllocateForTesting(id); Mock::VerifyAndClearExpectations(context); @@ -3344,13 +3628,14 @@ TEST(ResourceProviderTest, TextureAllocationChunkSize) { scoped_ptr<ResourceProvider> resource_provider( ResourceProvider::Create(output_surface.get(), shared_bitmap_manager.get(), + NULL, + NULL, 0, false, - kTextureAllocationChunkSize, - false)); + kTextureAllocationChunkSize)); ResourceProvider::ResourceId id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format); resource_provider->AllocateForTesting(id); Mock::VerifyAndClearExpectations(context); diff --git a/chromium/cc/resources/resource_update.h b/chromium/cc/resources/resource_update.h index 1eddf83c094..d49114171d4 100644 --- a/chromium/cc/resources/resource_update.h +++ b/chromium/cc/resources/resource_update.h @@ -6,8 +6,8 @@ #define CC_RESOURCES_RESOURCE_UPDATE_H_ #include "cc/base/cc_export.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/vector2d.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" class SkBitmap; diff --git a/chromium/cc/resources/resource_update_controller_unittest.cc b/chromium/cc/resources/resource_update_controller_unittest.cc index 0fb899d1461..d6b4f39b40b 100644 --- a/chromium/cc/resources/resource_update_controller_unittest.cc +++ b/chromium/cc/resources/resource_update_controller_unittest.cc @@ -32,20 +32,19 @@ class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D { explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest* test) : test_(test) {} - virtual void flush() OVERRIDE; - virtual void shallowFlushCHROMIUM() OVERRIDE; - virtual void texSubImage2D(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - const void* pixels) OVERRIDE; - - virtual void getQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* value) - OVERRIDE; + void flush() override; + void shallowFlushCHROMIUM() override; + void texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void* pixels) override; + + void getQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* value) override; private: ResourceUpdateControllerTest* test_; @@ -125,9 +124,13 @@ class ResourceUpdateControllerTest : public Test { CHECK(output_surface_->BindToClient(&output_surface_client_)); shared_bitmap_manager_.reset(new TestSharedBitmapManager()); - resource_provider_ = ResourceProvider::Create( - output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, - false); + resource_provider_ = ResourceProvider::Create(output_surface_.get(), + shared_bitmap_manager_.get(), + NULL, + NULL, + 0, + false, + 1); } void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count, @@ -324,7 +327,7 @@ class FakeResourceUpdateControllerClient void Reset() { ready_to_finalize_called_ = false; } bool ReadyToFinalizeCalled() const { return ready_to_finalize_called_; } - virtual void ReadyToFinalizeTextureUpdates() OVERRIDE { + void ReadyToFinalizeTextureUpdates() override { ready_to_finalize_called_ = true; } @@ -348,7 +351,7 @@ class FakeResourceUpdateController : public ResourceUpdateController { void SetUpdateTextureTime(base::TimeDelta time) { update_textures_time_ = time; } - virtual base::TimeTicks UpdateMoreTexturesCompletionTime() OVERRIDE { + base::TimeTicks UpdateMoreTexturesCompletionTime() override { size_t total_updates = resource_provider_->NumBlockingUploads() + update_more_textures_size_; return now_ + total_updates * update_textures_time_; @@ -356,7 +359,7 @@ class FakeResourceUpdateController : public ResourceUpdateController { void SetUpdateMoreTexturesSize(size_t size) { update_more_textures_size_ = size; } - virtual size_t UpdateMoreTexturesSize() const OVERRIDE { + size_t UpdateMoreTexturesSize() const override { return update_more_textures_size_; } diff --git a/chromium/cc/resources/return_callback.h b/chromium/cc/resources/return_callback.h index d12254bd662..abf5aec1d14 100644 --- a/chromium/cc/resources/return_callback.h +++ b/chromium/cc/resources/return_callback.h @@ -9,8 +9,11 @@ #include "cc/resources/returned_resource.h" namespace cc { +class BlockingTaskRunner; -typedef base::Callback<void(const ReturnedResourceArray&)> ReturnCallback; +typedef base::Callback<void(const ReturnedResourceArray&, + BlockingTaskRunner* main_thread_task_runner)> + ReturnCallback; } // namespace cc diff --git a/chromium/cc/resources/scoped_gpu_raster.cc b/chromium/cc/resources/scoped_gpu_raster.cc new file mode 100644 index 00000000000..517c7a7d814 --- /dev/null +++ b/chromium/cc/resources/scoped_gpu_raster.cc @@ -0,0 +1,52 @@ +// 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/scoped_gpu_raster.h" +#include "gpu/command_buffer/client/gles2_interface.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" +#include "third_party/skia/include/gpu/GrContext.h" + +using gpu::gles2::GLES2Interface; + +namespace cc { + +ScopedGpuRaster::ScopedGpuRaster(ContextProvider* context_provider) + : context_provider_(context_provider) { + BeginGpuRaster(); +} + +ScopedGpuRaster::~ScopedGpuRaster() { + EndGpuRaster(); +} + +void ScopedGpuRaster::BeginGpuRaster() { + GLES2Interface* gl = context_provider_->ContextGL(); + + // TODO(alokp): Use a trace macro to push/pop markers. + // Using push/pop functions directly incurs cost to evaluate function + // arguments even when tracing is disabled. + gl->PushGroupMarkerEXT(0, "GpuRasterization"); + + class GrContext* gr_context = context_provider_->GrContext(); + // TODO(sohanjg): Remove when TestContextProvider gives a GrContext. + if (gr_context) + gr_context->resetContext(); +} + +void ScopedGpuRaster::EndGpuRaster() { + GLES2Interface* gl = context_provider_->ContextGL(); + + class GrContext* gr_context = context_provider_->GrContext(); + // TODO(sohanjg): Remove when TestContextProvider gives a GrContext. + if (gr_context) + gr_context->flush(); + + // TODO(alokp): Use a trace macro to push/pop markers. + // Using push/pop functions directly incurs cost to evaluate function + // arguments even when tracing is disabled. + gl->PopGroupMarkerEXT(); +} + +} // namespace cc diff --git a/chromium/cc/resources/scoped_gpu_raster.h b/chromium/cc/resources/scoped_gpu_raster.h new file mode 100644 index 00000000000..a322ccbbe9a --- /dev/null +++ b/chromium/cc/resources/scoped_gpu_raster.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_SCOPED_GPU_RASTER_H_ +#define CC_RESOURCES_SCOPED_GPU_RASTER_H_ + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "cc/output/context_provider.h" + +namespace cc { + +// The following class is needed to modify GL resources using GPU +// raster. The user must ensure that they only use GPU raster on +// GL resources while an instance of this class is alive. +class CC_EXPORT ScopedGpuRaster { + public: + ScopedGpuRaster(ContextProvider* context_provider); + ~ScopedGpuRaster(); + + private: + void BeginGpuRaster(); + void EndGpuRaster(); + + ContextProvider* context_provider_; + + DISALLOW_COPY_AND_ASSIGN(ScopedGpuRaster); +}; + +} // namespace cc + +#endif // CC_RESOURCES_SCOPED_GPU_RASTER_H_ diff --git a/chromium/cc/resources/scoped_resource.cc b/chromium/cc/resources/scoped_resource.cc index 68ae59fc0ba..c83efb59fd9 100644 --- a/chromium/cc/resources/scoped_resource.cc +++ b/chromium/cc/resources/scoped_resource.cc @@ -16,7 +16,7 @@ ScopedResource::~ScopedResource() { } void ScopedResource::Allocate(const gfx::Size& size, - ResourceProvider::TextureUsageHint hint, + ResourceProvider::TextureHint hint, ResourceFormat format) { DCHECK(!id()); DCHECK(!size.IsEmpty()); @@ -41,7 +41,7 @@ void ScopedResource::AllocateManaged(const gfx::Size& size, size, target, GL_CLAMP_TO_EDGE, - ResourceProvider::TextureUsageAny, + ResourceProvider::TextureHintImmutable, format)); #if DCHECK_IS_ON @@ -59,8 +59,4 @@ void ScopedResource::Free() { set_id(0); } -void ScopedResource::Leak() { - set_id(0); -} - } // namespace cc diff --git a/chromium/cc/resources/scoped_resource.h b/chromium/cc/resources/scoped_resource.h index 9f58395a94c..4241b38eae6 100644 --- a/chromium/cc/resources/scoped_resource.h +++ b/chromium/cc/resources/scoped_resource.h @@ -26,13 +26,12 @@ class CC_EXPORT ScopedResource : public Resource { virtual ~ScopedResource(); void Allocate(const gfx::Size& size, - ResourceProvider::TextureUsageHint hint, + ResourceProvider::TextureHint hint, ResourceFormat format); void AllocateManaged(const gfx::Size& size, GLenum target, ResourceFormat format); void Free(); - void Leak(); protected: explicit ScopedResource(ResourceProvider* provider); diff --git a/chromium/cc/resources/scoped_resource_unittest.cc b/chromium/cc/resources/scoped_resource_unittest.cc index 50422213736..a141218a053 100644 --- a/chromium/cc/resources/scoped_resource_unittest.cc +++ b/chromium/cc/resources/scoped_resource_unittest.cc @@ -21,8 +21,14 @@ TEST(ScopedResourceTest, NewScopedResource) { scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager.get(), + NULL, + NULL, + 0, + false, + 1)); scoped_ptr<ScopedResource> texture = ScopedResource::Create(resource_provider.get()); @@ -41,13 +47,18 @@ TEST(ScopedResourceTest, CreateScopedResource) { scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager.get(), + NULL, + NULL, + 0, + false, + 1)); scoped_ptr<ScopedResource> texture = ScopedResource::Create(resource_provider.get()); - texture->Allocate(gfx::Size(30, 30), - ResourceProvider::TextureUsageAny, - RGBA_8888); + texture->Allocate( + gfx::Size(30, 30), ResourceProvider::TextureHintImmutable, RGBA_8888); // The texture has an allocated byte-size now. size_t expected_bytes = 30 * 30 * 4; @@ -65,16 +76,21 @@ TEST(ScopedResourceTest, ScopedResourceIsDeleted) { scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), + shared_bitmap_manager.get(), + NULL, + NULL, + 0, + false, + 1)); { scoped_ptr<ScopedResource> texture = ScopedResource::Create(resource_provider.get()); EXPECT_EQ(0u, resource_provider->num_resources()); - texture->Allocate(gfx::Size(30, 30), - ResourceProvider::TextureUsageAny, - RGBA_8888); + texture->Allocate( + gfx::Size(30, 30), ResourceProvider::TextureHintImmutable, RGBA_8888); EXPECT_LT(0u, texture->id()); EXPECT_EQ(1u, resource_provider->num_resources()); } @@ -84,9 +100,8 @@ TEST(ScopedResourceTest, ScopedResourceIsDeleted) { scoped_ptr<ScopedResource> texture = ScopedResource::Create(resource_provider.get()); EXPECT_EQ(0u, resource_provider->num_resources()); - texture->Allocate(gfx::Size(30, 30), - ResourceProvider::TextureUsageAny, - RGBA_8888); + texture->Allocate( + gfx::Size(30, 30), ResourceProvider::TextureHintImmutable, RGBA_8888); EXPECT_LT(0u, texture->id()); EXPECT_EQ(1u, resource_provider->num_resources()); texture->Free(); @@ -94,37 +109,5 @@ TEST(ScopedResourceTest, ScopedResourceIsDeleted) { } } -TEST(ScopedResourceTest, LeakScopedResource) { - FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d()); - CHECK(output_surface->BindToClient(&output_surface_client)); - - scoped_ptr<SharedBitmapManager> shared_bitmap_manager( - new TestSharedBitmapManager()); - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false)); - { - scoped_ptr<ScopedResource> texture = - ScopedResource::Create(resource_provider.get()); - - EXPECT_EQ(0u, resource_provider->num_resources()); - texture->Allocate(gfx::Size(30, 30), - ResourceProvider::TextureUsageAny, - RGBA_8888); - EXPECT_LT(0u, texture->id()); - EXPECT_EQ(1u, resource_provider->num_resources()); - - texture->Leak(); - EXPECT_EQ(0u, texture->id()); - EXPECT_EQ(1u, resource_provider->num_resources()); - - texture->Free(); - EXPECT_EQ(0u, texture->id()); - EXPECT_EQ(1u, resource_provider->num_resources()); - } - - EXPECT_EQ(1u, resource_provider->num_resources()); -} - } // namespace } // namespace cc diff --git a/chromium/cc/resources/scoped_ui_resource.h b/chromium/cc/resources/scoped_ui_resource.h index c257e1e25dc..0e5a02c7dbb 100644 --- a/chromium/cc/resources/scoped_ui_resource.h +++ b/chromium/cc/resources/scoped_ui_resource.h @@ -9,7 +9,6 @@ #include "cc/base/cc_export.h" #include "cc/resources/ui_resource_bitmap.h" #include "cc/resources/ui_resource_client.h" -#include "ui/gfx/size.h" namespace cc { @@ -25,11 +24,10 @@ class CC_EXPORT ScopedUIResource : public UIResourceClient { public: static scoped_ptr<ScopedUIResource> Create(LayerTreeHost* host, const UIResourceBitmap& bitmap); - virtual ~ScopedUIResource(); + ~ScopedUIResource() override; // UIResourceClient implementation. - virtual UIResourceBitmap GetBitmap(UIResourceId uid, - bool resource_lost) OVERRIDE; + UIResourceBitmap GetBitmap(UIResourceId uid, bool resource_lost) override; UIResourceId id() { return id_; } protected: diff --git a/chromium/cc/resources/shared_bitmap.h b/chromium/cc/resources/shared_bitmap.h index a90e47a084c..ca1271061f0 100644 --- a/chromium/cc/resources/shared_bitmap.h +++ b/chromium/cc/resources/shared_bitmap.h @@ -10,7 +10,7 @@ #include "base/memory/shared_memory.h" #include "cc/base/cc_export.h" #include "gpu/command_buffer/common/mailbox.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" namespace base { class SharedMemory; } diff --git a/chromium/cc/resources/shared_bitmap_manager.h b/chromium/cc/resources/shared_bitmap_manager.h index e6e49aff523..fe61b0998b8 100644 --- a/chromium/cc/resources/shared_bitmap_manager.h +++ b/chromium/cc/resources/shared_bitmap_manager.h @@ -8,7 +8,7 @@ #include "base/basictypes.h" #include "cc/base/cc_export.h" #include "cc/resources/shared_bitmap.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" namespace cc { diff --git a/chromium/cc/resources/single_release_callback_impl.cc b/chromium/cc/resources/single_release_callback_impl.cc new file mode 100644 index 00000000000..6f3c5353819 --- /dev/null +++ b/chromium/cc/resources/single_release_callback_impl.cc @@ -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. + +#include "cc/resources/single_release_callback_impl.h" + +#include "base/callback_helpers.h" +#include "base/logging.h" +#include "cc/trees/blocking_task_runner.h" + +namespace cc { + +SingleReleaseCallbackImpl::SingleReleaseCallbackImpl( + const ReleaseCallbackImpl& callback) + : has_been_run_(false), callback_(callback) { + DCHECK(!callback_.is_null()) + << "Use a NULL SingleReleaseCallbackImpl for an empty callback."; +} + +SingleReleaseCallbackImpl::~SingleReleaseCallbackImpl() { + DCHECK(callback_.is_null() || has_been_run_) + << "SingleReleaseCallbackImpl was never run."; +} + +void SingleReleaseCallbackImpl::Run( + uint32 sync_point, + bool is_lost, + BlockingTaskRunner* main_thread_task_runner) { + DCHECK(!has_been_run_) << "SingleReleaseCallbackImpl was run more than once."; + has_been_run_ = true; + callback_.Run(sync_point, is_lost, main_thread_task_runner); +} + +} // namespace cc diff --git a/chromium/cc/resources/single_release_callback_impl.h b/chromium/cc/resources/single_release_callback_impl.h new file mode 100644 index 00000000000..41220dc29e8 --- /dev/null +++ b/chromium/cc/resources/single_release_callback_impl.h @@ -0,0 +1,36 @@ +// 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_SINGLE_RELEASE_CALLBACK_IMPL_H_ +#define CC_RESOURCES_SINGLE_RELEASE_CALLBACK_IMPL_H_ + +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "cc/resources/release_callback_impl.h" + +namespace cc { + +class CC_EXPORT SingleReleaseCallbackImpl { + public: + static scoped_ptr<SingleReleaseCallbackImpl> Create( + const ReleaseCallbackImpl& cb) { + return make_scoped_ptr(new SingleReleaseCallbackImpl(cb)); + } + + ~SingleReleaseCallbackImpl(); + + void Run(uint32 sync_point, + bool is_lost, + BlockingTaskRunner* main_thread_task_runner); + + private: + explicit SingleReleaseCallbackImpl(const ReleaseCallbackImpl& callback); + + bool has_been_run_; + ReleaseCallbackImpl callback_; +}; + +} // namespace cc + +#endif // CC_RESOURCES_SINGLE_RELEASE_CALLBACK_IMPL_H_ diff --git a/chromium/cc/resources/skpicture_content_layer_updater.cc b/chromium/cc/resources/skpicture_content_layer_updater.cc index eb12385f460..bd524f235f1 100644 --- a/chromium/cc/resources/skpicture_content_layer_updater.cc +++ b/chromium/cc/resources/skpicture_content_layer_updater.cc @@ -23,27 +23,27 @@ SkPictureContentLayerUpdater::SkPictureContentLayerUpdater( SkPictureContentLayerUpdater::~SkPictureContentLayerUpdater() {} void SkPictureContentLayerUpdater::PrepareToUpdate( - const gfx::Rect& content_rect, - const gfx::Size&, + const gfx::Size& content_size, + const gfx::Rect& paint_rect, + const gfx::Size& tile_size, float contents_width_scale, - float contents_height_scale, - gfx::Rect* resulting_opaque_rect) { + float contents_height_scale) { SkPictureRecorder recorder; - SkCanvas* canvas = recorder.beginRecording( - content_rect.width(), content_rect.height(), NULL, 0); - DCHECK_EQ(content_rect.width(), canvas->getBaseLayerSize().width()); - DCHECK_EQ(content_rect.height(), canvas->getBaseLayerSize().height()); + SkCanvas* canvas = + recorder.beginRecording(paint_rect.width(), paint_rect.height(), NULL, 0); + DCHECK_EQ(paint_rect.width(), canvas->getBaseLayerSize().width()); + DCHECK_EQ(paint_rect.height(), canvas->getBaseLayerSize().height()); base::TimeTicks start_time = rendering_stats_instrumentation_->StartRecording(); PaintContents(canvas, - content_rect, + content_size, + paint_rect, contents_width_scale, - contents_height_scale, - resulting_opaque_rect); + contents_height_scale); base::TimeDelta duration = rendering_stats_instrumentation_->EndRecording(start_time); rendering_stats_instrumentation_->AddRecord( - duration, content_rect.width() * content_rect.height()); + duration, paint_rect.width() * paint_rect.height()); picture_ = skia::AdoptRef(recorder.endRecording()); } diff --git a/chromium/cc/resources/skpicture_content_layer_updater.h b/chromium/cc/resources/skpicture_content_layer_updater.h index a567976a2d8..ec49aaecdbb 100644 --- a/chromium/cc/resources/skpicture_content_layer_updater.h +++ b/chromium/cc/resources/skpicture_content_layer_updater.h @@ -23,13 +23,13 @@ class SkPictureContentLayerUpdater : public ContentLayerUpdater { scoped_ptr<LayerPainter> painter, RenderingStatsInstrumentation* stats_instrumentation, int layer_id); - virtual ~SkPictureContentLayerUpdater(); + ~SkPictureContentLayerUpdater() override; - virtual void PrepareToUpdate(const gfx::Rect& content_rect, - const gfx::Size& tile_size, - float contents_width_scale, - float contents_height_scale, - gfx::Rect* resulting_opaque_rect) OVERRIDE; + void PrepareToUpdate(const gfx::Size& content_size, + const gfx::Rect& paint_rect, + const gfx::Size& tile_size, + float contents_width_scale, + float contents_height_scale) override; void DrawPicture(SkCanvas* canvas); private: diff --git a/chromium/cc/resources/task_graph_runner.cc b/chromium/cc/resources/task_graph_runner.cc index 913c06d9b28..bcbc0dd351c 100644 --- a/chromium/cc/resources/task_graph_runner.cc +++ b/chromium/cc/resources/task_graph_runner.cc @@ -17,7 +17,10 @@ namespace { class DependentIterator { public: DependentIterator(TaskGraph* graph, const Task* task) - : graph_(graph), task_(task), current_index_(-1), current_node_(NULL) { + : graph_(graph), + task_(task), + current_index_(static_cast<size_t>(-1)), + current_node_(NULL) { ++(*this); } diff --git a/chromium/cc/resources/task_graph_runner.h b/chromium/cc/resources/task_graph_runner.h index 0ed714097ad..2ff085d76cb 100644 --- a/chromium/cc/resources/task_graph_runner.h +++ b/chromium/cc/resources/task_graph_runner.h @@ -17,7 +17,7 @@ namespace cc { class CC_EXPORT Task : public base::RefCountedThreadSafe<Task> { public: - typedef std::vector<scoped_refptr<Task> > Vector; + typedef std::vector<scoped_refptr<Task>> Vector; virtual void RunOnWorkerThread() = 0; diff --git a/chromium/cc/resources/task_graph_runner_perftest.cc b/chromium/cc/resources/task_graph_runner_perftest.cc index bfa4ebe8ac3..7809e587975 100644 --- a/chromium/cc/resources/task_graph_runner_perftest.cc +++ b/chromium/cc/resources/task_graph_runner_perftest.cc @@ -22,17 +22,17 @@ static const int kTimeCheckInterval = 10; class PerfTaskImpl : public Task { public: - typedef std::vector<scoped_refptr<PerfTaskImpl> > Vector; + typedef std::vector<scoped_refptr<PerfTaskImpl>> Vector; PerfTaskImpl() {} // Overridden from Task: - virtual void RunOnWorkerThread() OVERRIDE {} + void RunOnWorkerThread() override {} void Reset() { did_run_ = false; } private: - virtual ~PerfTaskImpl() {} + ~PerfTaskImpl() override {} DISALLOW_COPY_AND_ASSIGN(PerfTaskImpl); }; @@ -45,11 +45,11 @@ class TaskGraphRunnerPerfTest : public testing::Test { kTimeCheckInterval) {} // Overridden from testing::Test: - virtual void SetUp() OVERRIDE { + virtual void SetUp() override { task_graph_runner_ = make_scoped_ptr(new TaskGraphRunner); namespace_token_ = task_graph_runner_->GetNamespaceToken(); } - virtual void TearDown() OVERRIDE { task_graph_runner_.reset(); } + virtual void TearDown() override { task_graph_runner_ = nullptr; } void AfterTest(const std::string& test_name) { // Format matches chrome/test/perf/perf_test.h:PrintResult diff --git a/chromium/cc/resources/task_graph_runner_unittest.cc b/chromium/cc/resources/task_graph_runner_unittest.cc index 1a6256c5835..ad23b66087a 100644 --- a/chromium/cc/resources/task_graph_runner_unittest.cc +++ b/chromium/cc/resources/task_graph_runner_unittest.cc @@ -118,7 +118,7 @@ class TaskGraphRunnerTestBase { : test_(test), namespace_index_(namespace_index), id_(id) {} // Overridden from Task: - virtual void RunOnWorkerThread() OVERRIDE { + void RunOnWorkerThread() override { test_->RunTaskOnWorkerThread(namespace_index_, id_); } @@ -127,7 +127,7 @@ class TaskGraphRunnerTestBase { } protected: - virtual ~FakeTaskImpl() {} + ~FakeTaskImpl() override {} private: TaskGraphRunnerTestBase* test_; @@ -145,10 +145,10 @@ class TaskGraphRunnerTestBase { : FakeTaskImpl(test, namespace_index, id) {} // Overridden from FakeTaskImpl: - virtual void CompleteOnOriginThread() OVERRIDE {} + void CompleteOnOriginThread() override {} private: - virtual ~FakeDependentTaskImpl() {} + ~FakeDependentTaskImpl() override {} DISALLOW_COPY_AND_ASSIGN(FakeDependentTaskImpl); }; @@ -167,7 +167,7 @@ class TaskGraphRunnerTest : public TaskGraphRunnerTestBase, public base::DelegateSimpleThread::Delegate { public: // Overridden from testing::Test: - virtual void SetUp() OVERRIDE { + virtual void SetUp() override { const size_t num_threads = GetParam(); while (workers_.size() < num_threads) { scoped_ptr<base::DelegateSimpleThread> worker = @@ -179,7 +179,7 @@ class TaskGraphRunnerTest : public TaskGraphRunnerTestBase, for (int i = 0; i < kNamespaceCount; ++i) namespace_token_[i] = task_graph_runner_->GetNamespaceToken(); } - virtual void TearDown() OVERRIDE { + virtual void TearDown() override { task_graph_runner_->Shutdown(); while (workers_.size()) { scoped_ptr<base::DelegateSimpleThread> worker = workers_.take_front(); @@ -189,7 +189,7 @@ class TaskGraphRunnerTest : public TaskGraphRunnerTestBase, private: // Overridden from base::DelegateSimpleThread::Delegate: - virtual void Run() OVERRIDE { task_graph_runner_->Run(); } + void Run() override { task_graph_runner_->Run(); } ScopedPtrDeque<base::DelegateSimpleThread> workers_; }; @@ -285,21 +285,21 @@ class TaskGraphRunnerSingleThreadTest public base::DelegateSimpleThread::Delegate { public: // Overridden from testing::Test: - virtual void SetUp() OVERRIDE { + virtual void SetUp() override { worker_.reset(new base::DelegateSimpleThread(this, "TestWorker")); worker_->Start(); for (int i = 0; i < kNamespaceCount; ++i) namespace_token_[i] = task_graph_runner_->GetNamespaceToken(); } - virtual void TearDown() OVERRIDE { + virtual void TearDown() override { task_graph_runner_->Shutdown(); worker_->Join(); } private: // Overridden from base::DelegateSimpleThread::Delegate: - virtual void Run() OVERRIDE { task_graph_runner_->Run(); } + void Run() override { task_graph_runner_->Run(); } scoped_ptr<base::DelegateSimpleThread> worker_; }; diff --git a/chromium/cc/resources/texture_mailbox.cc b/chromium/cc/resources/texture_mailbox.cc index 90ce6be79c7..92736f41fe7 100644 --- a/chromium/cc/resources/texture_mailbox.cc +++ b/chromium/cc/resources/texture_mailbox.cc @@ -6,7 +6,6 @@ #include "base/logging.h" #include "cc/resources/shared_bitmap.h" -#include "third_party/khronos/GLES2/gl2.h" namespace cc { diff --git a/chromium/cc/resources/texture_mailbox.h b/chromium/cc/resources/texture_mailbox.h index 4626dd36698..4a0b76afea0 100644 --- a/chromium/cc/resources/texture_mailbox.h +++ b/chromium/cc/resources/texture_mailbox.h @@ -7,11 +7,10 @@ #include <string> -#include "base/callback.h" #include "base/memory/shared_memory.h" #include "cc/base/cc_export.h" #include "gpu/command_buffer/common/mailbox_holder.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" namespace cc { diff --git a/chromium/cc/resources/texture_mailbox_deleter_unittest.cc b/chromium/cc/resources/texture_mailbox_deleter_unittest.cc index 0d04c9917f0..05e33a313aa 100644 --- a/chromium/cc/resources/texture_mailbox_deleter_unittest.cc +++ b/chromium/cc/resources/texture_mailbox_deleter_unittest.cc @@ -34,7 +34,7 @@ TEST(TextureMailboxDeleterTest, Destroy) { // When the deleter is destroyed, it immediately drops its ref on the // ContextProvider, and deletes the texture. - deleter.reset(); + deleter = nullptr; EXPECT_TRUE(context_provider->HasOneRef()); EXPECT_EQ(0u, context_provider->TestContext3d()->NumTextures()); diff --git a/chromium/cc/resources/texture_uploader.cc b/chromium/cc/resources/texture_uploader.cc index eb4e6c097a4..9526fcb9238 100644 --- a/chromium/cc/resources/texture_uploader.cc +++ b/chromium/cc/resources/texture_uploader.cc @@ -10,14 +10,13 @@ #include "base/debug/trace_event.h" #include "base/metrics/histogram.h" #include "cc/base/util.h" -#include "cc/resources/prioritized_resource.h" #include "cc/resources/resource.h" #include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/vector2d.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" using gpu::gles2::GLES2Interface; @@ -116,6 +115,12 @@ double TextureUploader::EstimatedTexturesPerSecond() { } void TextureUploader::BeginQuery() { + // Check to see if any of the pending queries are free before allocating a + // new one. If this is not done, queries may be allocated without bound. + // http://crbug.com/398072 + if (available_queries_.empty()) + ProcessQueries(); + if (available_queries_.empty()) available_queries_.push_back(Query::Create(gl_)); diff --git a/chromium/cc/resources/texture_uploader_unittest.cc b/chromium/cc/resources/texture_uploader_unittest.cc index 8390b28ceef..72491727291 100644 --- a/chromium/cc/resources/texture_uploader_unittest.cc +++ b/chromium/cc/resources/texture_uploader_unittest.cc @@ -19,7 +19,7 @@ class TextureUploadTestContext : public gpu::gles2::GLES2InterfaceStub { public: TextureUploadTestContext() : result_available_(0), unpack_alignment_(4) {} - virtual void PixelStorei(GLenum pname, GLint param) OVERRIDE { + void PixelStorei(GLenum pname, GLint param) override { switch (pname) { case GL_UNPACK_ALIGNMENT: // Param should be a power of two <= 8. @@ -41,9 +41,7 @@ class TextureUploadTestContext : public gpu::gles2::GLES2InterfaceStub { } } - virtual void GetQueryObjectuivEXT(GLuint, - GLenum type, - GLuint* value) OVERRIDE { + void GetQueryObjectuivEXT(GLuint, GLenum type, GLuint* value) override { switch (type) { case GL_QUERY_RESULT_AVAILABLE_EXT: *value = result_available_; @@ -54,15 +52,15 @@ class TextureUploadTestContext : public gpu::gles2::GLES2InterfaceStub { } } - virtual void TexSubImage2D(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - const void* pixels) OVERRIDE { + void TexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void* pixels) override { EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); EXPECT_EQ(0, level); EXPECT_LE(0, width); @@ -217,6 +215,15 @@ TEST(TextureUploaderTest, UploadContentsTest) { } UploadTexture(uploader.get(), RGBA_8888, gfx::Size(41, 43), buffer); + // Upload a tightly packed 41x86 ALPHA 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 * 41] = 0x1; + buffer[(i + 1) * 41 - 1] = 0x2; + } + UploadTexture(uploader.get(), ALPHA_8, gfx::Size(41, 86), buffer); + // Upload a tightly packed 82x86 LUMINANCE texture. memset(buffer, 0, sizeof(buffer)); for (int i = 0; i < 86; ++i) { diff --git a/chromium/cc/resources/tile.cc b/chromium/cc/resources/tile.cc index d59dc029ccc..d6bd3c4b583 100644 --- a/chromium/cc/resources/tile.cc +++ b/chromium/cc/resources/tile.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "base/debug/trace_event_argument.h" #include "cc/base/math_util.h" #include "cc/debug/traced_value.h" #include "cc/resources/tile_manager.h" @@ -16,25 +17,29 @@ namespace cc { Tile::Id Tile::s_next_id_ = 0; Tile::Tile(TileManager* tile_manager, - PicturePileImpl* picture_pile, + RasterSource* raster_source, const gfx::Size& tile_size, const gfx::Rect& content_rect, - const gfx::Rect& opaque_rect, float contents_scale, int layer_id, int source_frame_number, int flags) : RefCountedManaged<Tile>(tile_manager), tile_manager_(tile_manager), - tile_size_(tile_size), + size_(tile_size), content_rect_(content_rect), contents_scale_(contents_scale), - opaque_rect_(opaque_rect), layer_id_(layer_id), source_frame_number_(source_frame_number), flags_(flags), + is_shared_(false), + tiling_i_index_(-1), + tiling_j_index_(-1), + required_for_activation_(false), id_(s_next_id_++) { - set_picture_pile(picture_pile); + set_raster_source(raster_source); + for (int i = 0; i < NUM_TREES; i++) + is_occluded_[i] = false; } Tile::~Tile() { @@ -43,60 +48,43 @@ Tile::~Tile() { "cc::Tile", this); } -void Tile::SetPriority(WhichTree tree, const TilePriority& priority) { - if (priority == priority_[tree]) - return; +void Tile::AsValueInto(base::debug::TracedValue* res) const { + TracedValue::MakeDictIntoImplicitSnapshotWithCategory( + TRACE_DISABLED_BY_DEFAULT("cc.debug"), res, "cc::Tile", this); + TracedValue::SetIDRef(raster_source_.get(), res, "picture_pile"); + res->SetDouble("contents_scale", contents_scale_); - priority_[tree] = priority; - tile_manager_->DidChangeTilePriority(this); -} + res->BeginArray("content_rect"); + MathUtil::AddToTracedValue(content_rect_, res); + res->EndArray(); -void Tile::MarkRequiredForActivation() { - if (priority_[PENDING_TREE].required_for_activation) - return; + res->SetInteger("layer_id", layer_id_); - priority_[PENDING_TREE].required_for_activation = true; - tile_manager_->DidChangeTilePriority(this); -} + res->BeginDictionary("active_priority"); + priority_[ACTIVE_TREE].AsValueInto(res); + res->EndDictionary(); -scoped_ptr<base::Value> Tile::AsValue() const { - scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); - TracedValue::MakeDictIntoImplicitSnapshotWithCategory( - TRACE_DISABLED_BY_DEFAULT("cc.debug"), res.get(), "cc::Tile", this); - res->Set("picture_pile", - TracedValue::CreateIDRef(picture_pile_.get()).release()); - res->SetDouble("contents_scale", contents_scale_); - res->Set("content_rect", MathUtil::AsValue(content_rect_).release()); - res->SetInteger("layer_id", layer_id_); - res->Set("active_priority", priority_[ACTIVE_TREE].AsValue().release()); - res->Set("pending_priority", priority_[PENDING_TREE].AsValue().release()); - res->Set("managed_state", managed_state_.AsValue().release()); - res->SetBoolean("use_picture_analysis", use_picture_analysis()); - return res.PassAs<base::Value>(); -} + res->BeginDictionary("pending_priority"); + priority_[PENDING_TREE].AsValueInto(res); + res->EndDictionary(); -size_t Tile::GPUMemoryUsageInBytes() const { - size_t total_size = 0; - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) - total_size += managed_state_.tile_versions[mode].GPUMemoryUsageInBytes(); - return total_size; -} + res->BeginDictionary("managed_state"); + managed_state_.AsValueInto(res); + res->EndDictionary(); -RasterMode Tile::DetermineRasterModeForTree(WhichTree tree) const { - return DetermineRasterModeForResolution(priority(tree).resolution); + res->SetBoolean("use_picture_analysis", use_picture_analysis()); + + res->SetInteger("gpu_memory_usage", GPUMemoryUsageInBytes()); } -RasterMode Tile::DetermineOverallRasterMode() const { - return DetermineRasterModeForResolution(managed_state_.resolution); +size_t Tile::GPUMemoryUsageInBytes() const { + if (managed_state_.draw_info.resource_) + return managed_state_.draw_info.resource_->bytes(); + return 0; } -RasterMode Tile::DetermineRasterModeForResolution( - TileResolution resolution) const { - RasterMode current_mode = managed_state_.raster_mode; - RasterMode raster_mode = resolution == LOW_RESOLUTION - ? LOW_QUALITY_RASTER_MODE - : HIGH_QUALITY_RASTER_MODE; - return std::min(raster_mode, current_mode); +bool Tile::HasRasterTask() const { + return !!managed_state_.raster_task.get(); } } // namespace cc diff --git a/chromium/cc/resources/tile.h b/chromium/cc/resources/tile.h index 69ef56fde8c..c6413677eb9 100644 --- a/chromium/cc/resources/tile.h +++ b/chromium/cc/resources/tile.h @@ -6,15 +6,12 @@ #define CC_RESOURCES_TILE_H_ #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/scoped_vector.h" #include "cc/base/ref_counted_managed.h" #include "cc/resources/managed_tile_state.h" -#include "cc/resources/picture_pile_impl.h" -#include "cc/resources/raster_mode.h" +#include "cc/resources/raster_source.h" #include "cc/resources/tile_priority.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" namespace cc { @@ -28,13 +25,9 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> { return id_; } - PicturePileImpl* picture_pile() { - return picture_pile_.get(); - } + RasterSource* raster_source() { return raster_source_.get(); } - const PicturePileImpl* picture_pile() const { - return picture_pile_.get(); - } + const RasterSource* raster_source() const { return raster_source_.get(); } const TilePriority& priority(WhichTree tree) const { return priority_[tree]; @@ -48,9 +41,10 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> { return priority_[PENDING_TREE]; case SAME_PRIORITY_FOR_BOTH_TREES: return combined_priority(); + default: + NOTREACHED(); + return TilePriority(); } - NOTREACHED(); - return TilePriority(); } TilePriority combined_priority() const { @@ -58,49 +52,63 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> { priority_[PENDING_TREE]); } - void SetPriority(WhichTree tree, const TilePriority& priority); + void SetPriority(WhichTree tree, const TilePriority& priority) { + priority_[tree] = priority; + } + + // TODO(vmpstr): Move this to the iterators. + void set_is_occluded(WhichTree tree, bool is_occluded) { + is_occluded_[tree] = is_occluded; + } + + bool is_occluded(WhichTree tree) const { return is_occluded_[tree]; } - void MarkRequiredForActivation(); + void set_shared(bool is_shared) { is_shared_ = is_shared; } + bool is_shared() const { return is_shared_; } + + bool is_occluded_for_tree_priority(TreePriority tree_priority) const { + switch (tree_priority) { + case SMOOTHNESS_TAKES_PRIORITY: + return is_occluded_[ACTIVE_TREE]; + case NEW_CONTENT_TAKES_PRIORITY: + return is_occluded_[PENDING_TREE]; + case SAME_PRIORITY_FOR_BOTH_TREES: + return is_occluded_[ACTIVE_TREE] && is_occluded_[PENDING_TREE]; + default: + NOTREACHED(); + return false; + } + } - bool required_for_activation() const { - return priority_[PENDING_TREE].required_for_activation; + // TODO(vmpstr): Move this to the iterators. + bool required_for_activation() const { return required_for_activation_; } + void set_required_for_activation(bool is_required) { + required_for_activation_ = is_required; } bool use_picture_analysis() const { return !!(flags_ & USE_PICTURE_ANALYSIS); } - bool NeedsRasterForMode(RasterMode mode) const { - return !managed_state_.tile_versions[mode].IsReadyToDraw(); - } - - bool HasResources() const { - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { - if (managed_state_.tile_versions[mode].has_resource()) - return true; - } - return false; + bool HasResources() const { return managed_state_.draw_info.has_resource(); } + bool NeedsRaster() const { + return managed_state_.draw_info.mode() == + ManagedTileState::DrawInfo::PICTURE_PILE_MODE || + !managed_state_.draw_info.IsReadyToDraw(); } - scoped_ptr<base::Value> AsValue() const; + void AsValueInto(base::debug::TracedValue* dict) const; inline bool IsReadyToDraw() const { - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { - if (managed_state_.tile_versions[mode].IsReadyToDraw()) - return true; - } - return false; + return managed_state_.draw_info.IsReadyToDraw(); } - const ManagedTileState::TileVersion& GetTileVersionForDrawing() const { - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { - if (managed_state_.tile_versions[mode].IsReadyToDraw()) - return managed_state_.tile_versions[mode]; - } - return managed_state_.tile_versions[HIGH_QUALITY_RASTER_MODE]; + const ManagedTileState::DrawInfo& draw_info() const { + return managed_state_.draw_info; } - gfx::Rect opaque_rect() const { return opaque_rect_; } + ManagedTileState::DrawInfo& draw_info() { return managed_state_.draw_info; } + float contents_scale() const { return contents_scale_; } gfx::Rect content_rect() const { return content_rect_; } @@ -108,25 +116,24 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> { int source_frame_number() const { return source_frame_number_; } - void set_picture_pile(scoped_refptr<PicturePileImpl> pile) { - DCHECK(pile->CanRaster(contents_scale_, content_rect_)); - picture_pile_ = pile; + void set_raster_source(scoped_refptr<RasterSource> raster_source) { + DCHECK(raster_source->CoversRect(content_rect_, contents_scale_)) + << "Recording rect: " + << gfx::ScaleToEnclosingRect(content_rect_, 1.f / contents_scale_) + .ToString(); + raster_source_ = raster_source; } size_t GPUMemoryUsageInBytes() const; - gfx::Size size() const { return tile_size_.size(); } - - RasterMode DetermineRasterModeForTree(WhichTree tree) const; - RasterMode DetermineOverallRasterMode() const; + gfx::Size size() const { return size_; } - // Functionality used in tests. - RasterMode GetRasterModeForTesting() const { - return managed_state().raster_mode; - } - ManagedTileState::TileVersion& GetTileVersionForTesting(RasterMode mode) { - return managed_state_.tile_versions[mode]; + void set_tiling_index(int i, int j) { + tiling_i_index_ = i; + tiling_j_index_ = j; } + int tiling_i_index() const { return tiling_i_index_; } + int tiling_j_index() const { return tiling_j_index_; } private: friend class TileManager; @@ -137,10 +144,9 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> { // Methods called by by tile manager. Tile(TileManager* tile_manager, - PicturePileImpl* picture_pile, + RasterSource* raster_source, const gfx::Size& tile_size, const gfx::Rect& content_rect, - const gfx::Rect& opaque_rect, float contents_scale, int layer_id, int source_frame_number, @@ -149,20 +155,25 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> { ManagedTileState& managed_state() { return managed_state_; } const ManagedTileState& managed_state() const { return managed_state_; } - RasterMode DetermineRasterModeForResolution(TileResolution resolution) const; + + bool HasRasterTask() const; TileManager* tile_manager_; - scoped_refptr<PicturePileImpl> picture_pile_; - gfx::Rect tile_size_; + scoped_refptr<RasterSource> raster_source_; + gfx::Size size_; gfx::Rect content_rect_; float contents_scale_; - gfx::Rect opaque_rect_; + bool is_occluded_[NUM_TREES]; TilePriority priority_[NUM_TREES]; ManagedTileState managed_state_; int layer_id_; int source_frame_number_; int flags_; + bool is_shared_; + int tiling_i_index_; + int tiling_j_index_; + bool required_for_activation_; Id id_; static Id s_next_id_; diff --git a/chromium/cc/resources/tile_manager.cc b/chromium/cc/resources/tile_manager.cc index d508f6a0a17..8b6a72afc6f 100644 --- a/chromium/cc/resources/tile_manager.cc +++ b/chromium/cc/resources/tile_manager.cc @@ -9,6 +9,7 @@ #include <string> #include "base/bind.h" +#include "base/debug/trace_event_argument.h" #include "base/json/json_writer.h" #include "base/logging.h" #include "base/metrics/histogram.h" @@ -16,12 +17,10 @@ #include "cc/debug/frame_viewer_instrumentation.h" #include "cc/debug/traced_value.h" #include "cc/layers/picture_layer_impl.h" -#include "cc/resources/raster_worker_pool.h" +#include "cc/resources/raster_buffer.h" +#include "cc/resources/rasterizer.h" #include "cc/resources/tile.h" -#include "skia/ext/paint_simplifier.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkPixelRef.h" -#include "ui/gfx/rect_conversions.h" +#include "ui/gfx/geometry/rect_conversions.h" namespace cc { namespace { @@ -34,82 +33,71 @@ class RasterTaskImpl : public RasterTask { public: RasterTaskImpl( const Resource* resource, - PicturePileImpl* picture_pile, + RasterSource* raster_source, const gfx::Rect& content_rect, float contents_scale, - RasterMode raster_mode, TileResolution tile_resolution, int layer_id, const void* tile_id, int source_frame_number, bool analyze_picture, RenderingStatsInstrumentation* rendering_stats, - const base::Callback<void(const PicturePileImpl::Analysis&, bool)>& reply, + const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>& + reply, ImageDecodeTask::Vector* dependencies) : RasterTask(resource, dependencies), - picture_pile_(picture_pile), + raster_source_(raster_source), content_rect_(content_rect), contents_scale_(contents_scale), - raster_mode_(raster_mode), tile_resolution_(tile_resolution), layer_id_(layer_id), tile_id_(tile_id), source_frame_number_(source_frame_number), analyze_picture_(analyze_picture), rendering_stats_(rendering_stats), - reply_(reply), - canvas_(NULL) {} + reply_(reply) {} // Overridden from Task: - virtual void RunOnWorkerThread() OVERRIDE { + void RunOnWorkerThread() override { TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread"); - DCHECK(picture_pile_); - if (canvas_) { - AnalyzeAndRaster(picture_pile_->GetCloneForDrawingOnThread( - RasterWorkerPool::GetPictureCloneIndexForCurrentThread())); + DCHECK(raster_source_.get()); + DCHECK(raster_buffer_); + + if (analyze_picture_) { + Analyze(raster_source_.get()); + if (analysis_.is_solid_color) + return; } + + Raster(raster_source_.get()); } // Overridden from RasterizerTask: - virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE { - DCHECK(!canvas_); - canvas_ = client->AcquireCanvasForRaster(this); + void ScheduleOnOriginThread(RasterizerTaskClient* client) override { + DCHECK(!raster_buffer_); + raster_buffer_ = client->AcquireBufferForRaster(resource()); } - virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE { - canvas_ = NULL; - client->ReleaseCanvasForRaster(this); + void CompleteOnOriginThread(RasterizerTaskClient* client) override { + client->ReleaseBufferForRaster(raster_buffer_.Pass()); } - virtual void RunReplyOnOriginThread() OVERRIDE { - DCHECK(!canvas_); + void RunReplyOnOriginThread() override { + DCHECK(!raster_buffer_); reply_.Run(analysis_, !HasFinishedRunning()); } protected: - virtual ~RasterTaskImpl() { DCHECK(!canvas_); } + ~RasterTaskImpl() override { DCHECK(!raster_buffer_); } private: - void AnalyzeAndRaster(PicturePileImpl* picture_pile) { - DCHECK(picture_pile); - DCHECK(canvas_); - - if (analyze_picture_) { - Analyze(picture_pile); - if (analysis_.is_solid_color) - return; - } - - Raster(picture_pile); - } - - void Analyze(PicturePileImpl* picture_pile) { + void Analyze(const RasterSource* raster_source) { frame_viewer_instrumentation::ScopedAnalyzeTask analyze_task( tile_id_, tile_resolution_, source_frame_number_, layer_id_); - DCHECK(picture_pile); + DCHECK(raster_source); - picture_pile->AnalyzeInRect( - content_rect_, contents_scale_, &analysis_, rendering_stats_); + raster_source->PerformSolidColorAnalysis(content_rect_, contents_scale_, + &analysis_); // Record the solid color prediction. UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed", @@ -119,67 +107,31 @@ class RasterTaskImpl : public RasterTask { analysis_.is_solid_color &= kUseColorEstimator; } - void Raster(PicturePileImpl* picture_pile) { + void Raster(const RasterSource* raster_source) { frame_viewer_instrumentation::ScopedRasterTask raster_task( - tile_id_, - tile_resolution_, - source_frame_number_, - layer_id_, - raster_mode_); + tile_id_, tile_resolution_, source_frame_number_, layer_id_); devtools_instrumentation::ScopedLayerTask layer_task( devtools_instrumentation::kRasterTask, layer_id_); - skia::RefPtr<SkDrawFilter> draw_filter; - switch (raster_mode_) { - case LOW_QUALITY_RASTER_MODE: - draw_filter = skia::AdoptRef(new skia::PaintSimplifier); - break; - case HIGH_QUALITY_RASTER_MODE: - break; - case NUM_RASTER_MODES: - default: - NOTREACHED(); - } - canvas_->setDrawFilter(draw_filter.get()); - - base::TimeDelta prev_rasterize_time = - rendering_stats_->impl_thread_rendering_stats().rasterize_time; - - // Only record rasterization time for highres tiles, because - // lowres tiles are not required for activation and therefore - // introduce noise in the measurement (sometimes they get rasterized - // before we draw and sometimes they aren't) - RenderingStatsInstrumentation* stats = - tile_resolution_ == HIGH_RESOLUTION ? rendering_stats_ : NULL; - DCHECK(picture_pile); - picture_pile->RasterToBitmap( - canvas_, content_rect_, contents_scale_, stats); - - if (rendering_stats_->record_rendering_stats()) { - base::TimeDelta current_rasterize_time = - rendering_stats_->impl_thread_rendering_stats().rasterize_time; - HISTOGRAM_CUSTOM_COUNTS( - "Renderer4.PictureRasterTimeUS", - (current_rasterize_time - prev_rasterize_time).InMicroseconds(), - 0, - 100000, - 100); - } + DCHECK(raster_source); + + raster_buffer_->Playback(raster_source_.get(), content_rect_, + contents_scale_); } - PicturePileImpl::Analysis analysis_; - scoped_refptr<PicturePileImpl> picture_pile_; + RasterSource::SolidColorAnalysis analysis_; + scoped_refptr<RasterSource> raster_source_; gfx::Rect content_rect_; float contents_scale_; - RasterMode raster_mode_; TileResolution tile_resolution_; int layer_id_; const void* tile_id_; int source_frame_number_; bool analyze_picture_; RenderingStatsInstrumentation* rendering_stats_; - const base::Callback<void(const PicturePileImpl::Analysis&, bool)> reply_; - SkCanvas* canvas_; + const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)> + reply_; + scoped_ptr<RasterBuffer> raster_buffer_; DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl); }; @@ -196,7 +148,7 @@ class ImageDecodeTaskImpl : public ImageDecodeTask { reply_(reply) {} // Overridden from Task: - virtual void RunOnWorkerThread() OVERRIDE { + void RunOnWorkerThread() override { TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread"); devtools_instrumentation::ScopedImageDecodeTask image_decode_task( @@ -207,14 +159,12 @@ class ImageDecodeTaskImpl : public ImageDecodeTask { } // Overridden from RasterizerTask: - virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {} - virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {} - virtual void RunReplyOnOriginThread() OVERRIDE { - reply_.Run(!HasFinishedRunning()); - } + void ScheduleOnOriginThread(RasterizerTaskClient* client) override {} + void CompleteOnOriginThread(RasterizerTaskClient* client) override {} + void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); } protected: - virtual ~ImageDecodeTaskImpl() {} + ~ImageDecodeTaskImpl() override {} private: skia::RefPtr<SkPixelRef> pixel_ref_; @@ -225,123 +175,18 @@ class ImageDecodeTaskImpl : public ImageDecodeTask { DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl); }; -const size_t kScheduledRasterTasksLimit = 32u; - -// Memory limit policy works by mapping some bin states to the NEVER bin. -const ManagedTileBin kBinPolicyMap[NUM_TILE_MEMORY_LIMIT_POLICIES][NUM_BINS] = { - // [ALLOW_NOTHING] - {NEVER_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NEVER_BIN, // [NOW_BIN] - NEVER_BIN, // [SOON_BIN] - NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] - NEVER_BIN, // [EVENTUALLY_BIN] - NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN] - NEVER_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] - }, - // [ALLOW_ABSOLUTE_MINIMUM] - {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NOW_BIN, // [NOW_BIN] - NEVER_BIN, // [SOON_BIN] - NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] - NEVER_BIN, // [EVENTUALLY_BIN] - NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN] - NEVER_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] - }, - // [ALLOW_PREPAINT_ONLY] - {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NOW_BIN, // [NOW_BIN] - SOON_BIN, // [SOON_BIN] - NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] - NEVER_BIN, // [EVENTUALLY_BIN] - NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN] - NEVER_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] - }, - // [ALLOW_ANYTHING] - {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NOW_BIN, // [NOW_BIN] - SOON_BIN, // [SOON_BIN] - EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] - EVENTUALLY_BIN, // [EVENTUALLY_BIN] - AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN] - AT_LAST_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] - }}; - -// Ready to draw works by mapping NOW_BIN to NOW_AND_READY_TO_DRAW_BIN. -const ManagedTileBin kBinReadyToDrawMap[2][NUM_BINS] = { - // Not ready - {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NOW_BIN, // [NOW_BIN] - SOON_BIN, // [SOON_BIN] - EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] - EVENTUALLY_BIN, // [EVENTUALLY_BIN] - AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN] - AT_LAST_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] - }, - // Ready - {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NOW_AND_READY_TO_DRAW_BIN, // [NOW_BIN] - SOON_BIN, // [SOON_BIN] - EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] - EVENTUALLY_BIN, // [EVENTUALLY_BIN] - AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN] - AT_LAST_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] - }}; - -// Active works by mapping some bin stats to equivalent _ACTIVE_BIN state. -const ManagedTileBin kBinIsActiveMap[2][NUM_BINS] = { - // Inactive - {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NOW_BIN, // [NOW_BIN] - SOON_BIN, // [SOON_BIN] - EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] - EVENTUALLY_BIN, // [EVENTUALLY_BIN] - AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN] - AT_LAST_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] - }, - // Active - {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN] - NOW_BIN, // [NOW_BIN] - SOON_BIN, // [SOON_BIN] - EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN] - EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_BIN] - AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN] - AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_BIN] - NEVER_BIN // [NEVER_BIN] - }}; - -// Determine bin based on three categories of tiles: things we need now, -// things we need soon, and eventually. -inline ManagedTileBin BinFromTilePriority(const TilePriority& prio) { - if (prio.priority_bin == TilePriority::NOW) - return NOW_BIN; - - if (prio.priority_bin == TilePriority::SOON) - return SOON_BIN; - - if (prio.distance_to_visible == std::numeric_limits<float>::infinity()) - return NEVER_BIN; - - return EVENTUALLY_BIN; -} - } // namespace RasterTaskCompletionStats::RasterTaskCompletionStats() : completed_count(0u), canceled_count(0u) {} -scoped_ptr<base::Value> RasterTaskCompletionStatsAsValue( - const RasterTaskCompletionStats& stats) { - scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); +scoped_refptr<base::debug::ConvertableToTraceFormat> +RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); state->SetInteger("completed_count", stats.completed_count); state->SetInteger("canceled_count", stats.canceled_count); - return state.PassAs<base::Value>(); + return state; } // static @@ -350,35 +195,35 @@ scoped_ptr<TileManager> TileManager::Create( base::SequencedTaskRunner* task_runner, ResourcePool* resource_pool, Rasterizer* rasterizer, - RenderingStatsInstrumentation* rendering_stats_instrumentation) { + RenderingStatsInstrumentation* rendering_stats_instrumentation, + size_t scheduled_raster_task_limit) { return make_scoped_ptr(new TileManager(client, task_runner, resource_pool, rasterizer, - rendering_stats_instrumentation)); + rendering_stats_instrumentation, + scheduled_raster_task_limit)); } TileManager::TileManager( TileManagerClient* client, - base::SequencedTaskRunner* task_runner, + const scoped_refptr<base::SequencedTaskRunner>& task_runner, ResourcePool* resource_pool, Rasterizer* rasterizer, - RenderingStatsInstrumentation* rendering_stats_instrumentation) + RenderingStatsInstrumentation* rendering_stats_instrumentation, + size_t scheduled_raster_task_limit) : client_(client), task_runner_(task_runner), resource_pool_(resource_pool), rasterizer_(rasterizer), - prioritized_tiles_dirty_(false), - all_tiles_that_need_to_be_rasterized_have_memory_(true), - all_tiles_required_for_activation_have_memory_(true), - bytes_releasable_(0), - resources_releasable_(0), - ever_exceeded_memory_budget_(false), + scheduled_raster_task_limit_(scheduled_raster_task_limit), + all_tiles_that_need_to_be_rasterized_are_scheduled_(true), rendering_stats_instrumentation_(rendering_stats_instrumentation), did_initialize_visible_tile_(false), did_check_for_completed_tasks_since_last_schedule_tasks_(true), + did_oom_on_last_assign_(false), ready_to_activate_check_notifier_( - task_runner_, + task_runner_.get(), base::Bind(&TileManager::CheckIfReadyToActivate, base::Unretained(this))) { rasterizer_->SetClient(this); @@ -389,9 +234,6 @@ TileManager::~TileManager() { // our memory usage to drop to zero. global_state_ = GlobalStateThatImpactsTilePriority(); - CleanUpReleasedTiles(); - DCHECK_EQ(0u, tiles_.size()); - RasterTaskQueue empty; rasterizer_->ScheduleTasks(&empty); orphan_raster_tasks_.clear(); @@ -401,35 +243,41 @@ TileManager::~TileManager() { rasterizer_->Shutdown(); rasterizer_->CheckForCompletedTasks(); - DCHECK_EQ(0u, bytes_releasable_); - DCHECK_EQ(0u, resources_releasable_); + FreeResourcesForReleasedTiles(); + CleanUpReleasedTiles(); } void TileManager::Release(Tile* tile) { - prioritized_tiles_dirty_ = true; released_tiles_.push_back(tile); } -void TileManager::DidChangeTilePriority(Tile* tile) { - prioritized_tiles_dirty_ = true; +TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const { + TaskSetCollection tasks_that_should_be_forced_to_complete; + if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY) + tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true; + return tasks_that_should_be_forced_to_complete; } -bool TileManager::ShouldForceTasksRequiredForActivationToComplete() const { - return global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY; -} - -void TileManager::CleanUpReleasedTiles() { +void TileManager::FreeResourcesForReleasedTiles() { for (std::vector<Tile*>::iterator it = released_tiles_.begin(); it != released_tiles_.end(); ++it) { Tile* tile = *it; - ManagedTileState& mts = tile->managed_state(); + FreeResourcesForTile(tile); + } +} + +void TileManager::CleanUpReleasedTiles() { + std::vector<Tile*>::iterator it = released_tiles_.begin(); + while (it != released_tiles_.end()) { + Tile* tile = *it; - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { - FreeResourceForTile(tile, static_cast<RasterMode>(mode)); - orphan_raster_tasks_.push_back(mts.tile_versions[mode].raster_task_); + if (tile->HasRasterTask()) { + ++it; + continue; } + DCHECK(!tile->HasResources()); DCHECK(tiles_.find(tile->id()) != tiles_.end()); tiles_.erase(tile->id()); @@ -442,208 +290,96 @@ void TileManager::CleanUpReleasedTiles() { } delete tile; + it = released_tiles_.erase(it); } - - released_tiles_.clear(); } -void TileManager::UpdatePrioritizedTileSetIfNeeded() { - if (!prioritized_tiles_dirty_) - return; +void TileManager::DidFinishRunningTasks(TaskSet task_set) { + if (task_set == ALL) { + TRACE_EVENT1("cc", "TileManager::DidFinishRunningTasks", "task_set", "ALL"); - CleanUpReleasedTiles(); + bool memory_usage_above_limit = resource_pool_->total_memory_usage_bytes() > + global_state_.soft_memory_limit_in_bytes; - prioritized_tiles_.Clear(); - GetTilesWithAssignedBins(&prioritized_tiles_); - prioritized_tiles_dirty_ = false; -} - -void TileManager::DidFinishRunningTasks() { - TRACE_EVENT0("cc", "TileManager::DidFinishRunningTasks"); + // When OOM, keep re-assigning memory until we reach a steady state + // where top-priority tiles are initialized. + if (all_tiles_that_need_to_be_rasterized_are_scheduled_ && + !memory_usage_above_limit) + return; - bool memory_usage_above_limit = resource_pool_->total_memory_usage_bytes() > - global_state_.soft_memory_limit_in_bytes; - - // When OOM, keep re-assigning memory until we reach a steady state - // where top-priority tiles are initialized. - if (all_tiles_that_need_to_be_rasterized_have_memory_ && - !memory_usage_above_limit) - return; - - rasterizer_->CheckForCompletedTasks(); - did_check_for_completed_tasks_since_last_schedule_tasks_ = true; - - TileVector tiles_that_need_to_be_rasterized; - AssignGpuMemoryToTiles(&prioritized_tiles_, - &tiles_that_need_to_be_rasterized); - - // |tiles_that_need_to_be_rasterized| will be empty when we reach a - // steady memory state. Keep scheduling tasks until we reach this state. - if (!tiles_that_need_to_be_rasterized.empty()) { - ScheduleTasks(tiles_that_need_to_be_rasterized); - return; - } - - resource_pool_->ReduceResourceUsage(); - - // We don't reserve memory for required-for-activation tiles during - // accelerated gestures, so we just postpone activation when we don't - // have these tiles, and activate after the accelerated gesture. - bool allow_rasterize_on_demand = - global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY; - - // Use on-demand raster for any required-for-activation tiles that have not - // been been assigned memory after reaching a steady memory state. This - // ensures that we activate even when OOM. - for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { - Tile* tile = it->second; - ManagedTileState& mts = tile->managed_state(); - ManagedTileState::TileVersion& tile_version = - mts.tile_versions[mts.raster_mode]; + rasterizer_->CheckForCompletedTasks(); + did_check_for_completed_tasks_since_last_schedule_tasks_ = true; - if (tile->required_for_activation() && !tile_version.IsReadyToDraw()) { - // If we can't raster on demand, give up early (and don't activate). - if (!allow_rasterize_on_demand) - return; + TileVector tiles_that_need_to_be_rasterized; + AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized); - tile_version.set_rasterize_on_demand(); - client_->NotifyTileStateChanged(tile); + // |tiles_that_need_to_be_rasterized| will be empty when we reach a + // steady memory state. Keep scheduling tasks until we reach this state. + if (!tiles_that_need_to_be_rasterized.empty()) { + ScheduleTasks(tiles_that_need_to_be_rasterized); + return; } - } - - DCHECK(IsReadyToActivate()); - ready_to_activate_check_notifier_.Schedule(); -} - -void TileManager::DidFinishRunningTasksRequiredForActivation() { - // This is only a true indication that all tiles required for - // activation are initialized when no tiles are OOM. We need to - // wait for DidFinishRunningTasks() to be called, try to re-assign - // memory and in worst case use on-demand raster when tiles - // required for activation are OOM. - if (!all_tiles_required_for_activation_have_memory_) - return; - - ready_to_activate_check_notifier_.Schedule(); -} - -void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet* tiles) { - TRACE_EVENT0("cc", "TileManager::GetTilesWithAssignedBins"); - - const TileMemoryLimitPolicy memory_policy = global_state_.memory_limit_policy; - const TreePriority tree_priority = global_state_.tree_priority; - // For each tree, bin into different categories of tiles. - for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { - Tile* tile = it->second; - ManagedTileState& mts = tile->managed_state(); - - const ManagedTileState::TileVersion& tile_version = - tile->GetTileVersionForDrawing(); - bool tile_is_ready_to_draw = tile_version.IsReadyToDraw(); - bool tile_is_active = tile_is_ready_to_draw || - mts.tile_versions[mts.raster_mode].raster_task_; - - // Get the active priority and bin. - TilePriority active_priority = tile->priority(ACTIVE_TREE); - ManagedTileBin active_bin = BinFromTilePriority(active_priority); - - // Get the pending priority and bin. - TilePriority pending_priority = tile->priority(PENDING_TREE); - ManagedTileBin pending_bin = BinFromTilePriority(pending_priority); - - bool pending_is_low_res = pending_priority.resolution == LOW_RESOLUTION; - bool pending_is_non_ideal = - pending_priority.resolution == NON_IDEAL_RESOLUTION; - bool active_is_non_ideal = - active_priority.resolution == NON_IDEAL_RESOLUTION; - - // Adjust bin state based on if ready to draw. - active_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][active_bin]; - pending_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][pending_bin]; - - // Adjust bin state based on if active. - active_bin = kBinIsActiveMap[tile_is_active][active_bin]; - pending_bin = kBinIsActiveMap[tile_is_active][pending_bin]; - - // We never want to paint new non-ideal tiles, as we always have - // a high-res tile covering that content (paint that instead). - if (!tile_is_ready_to_draw && active_is_non_ideal) - active_bin = NEVER_BIN; - if (!tile_is_ready_to_draw && pending_is_non_ideal) - pending_bin = NEVER_BIN; - - ManagedTileBin tree_bin[NUM_TREES]; - tree_bin[ACTIVE_TREE] = kBinPolicyMap[memory_policy][active_bin]; - tree_bin[PENDING_TREE] = kBinPolicyMap[memory_policy][pending_bin]; - - // Adjust pending bin state for low res tiles. This prevents pending tree - // low-res tiles from being initialized before high-res tiles. - if (pending_is_low_res) - tree_bin[PENDING_TREE] = std::max(tree_bin[PENDING_TREE], EVENTUALLY_BIN); - - TilePriority tile_priority; - switch (tree_priority) { - case SAME_PRIORITY_FOR_BOTH_TREES: - mts.bin = std::min(tree_bin[ACTIVE_TREE], tree_bin[PENDING_TREE]); - tile_priority = tile->combined_priority(); - break; - case SMOOTHNESS_TAKES_PRIORITY: - mts.bin = tree_bin[ACTIVE_TREE]; - tile_priority = active_priority; - break; - case NEW_CONTENT_TAKES_PRIORITY: - mts.bin = tree_bin[PENDING_TREE]; - tile_priority = pending_priority; - break; + FreeResourcesForReleasedTiles(); + + resource_pool_->ReduceResourceUsage(); + + // We don't reserve memory for required-for-activation tiles during + // accelerated gestures, so we just postpone activation when we don't + // have these tiles, and activate after the accelerated gesture. + // Likewise if we don't allow any tiles (as is the case when we're + // invisible), if we have tiles that aren't ready, then we shouldn't + // activate as activation can cause checkerboards. + bool allow_rasterize_on_demand = + global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY && + global_state_.memory_limit_policy != ALLOW_NOTHING; + + // Use on-demand raster for any required-for-activation tiles that have not + // been been assigned memory after reaching a steady memory state. This + // ensures that we activate even when OOM. Note that we have to rebuilt the + // queue in case the last AssignGpuMemoryToTiles evicted some tiles that + // would otherwise not be picked up by the old raster queue. + client_->BuildRasterQueue(&raster_priority_queue_, + global_state_.tree_priority); + bool ready_to_activate = true; + while (!raster_priority_queue_.IsEmpty()) { + Tile* tile = raster_priority_queue_.Top(); + ManagedTileState& mts = tile->managed_state(); + + if (tile->required_for_activation() && !mts.draw_info.IsReadyToDraw()) { + // If we can't raster on demand, give up early (and don't activate). + if (!allow_rasterize_on_demand) { + ready_to_activate = false; + break; + } + + mts.draw_info.set_rasterize_on_demand(); + client_->NotifyTileStateChanged(tile); + } + raster_priority_queue_.Pop(); } - // Bump up the priority if we determined it's NEVER_BIN on one tree, - // but is still required on the other tree. - bool is_in_never_bin_on_both_trees = tree_bin[ACTIVE_TREE] == NEVER_BIN && - tree_bin[PENDING_TREE] == NEVER_BIN; - - if (mts.bin == NEVER_BIN && !is_in_never_bin_on_both_trees) - mts.bin = tile_is_active ? AT_LAST_AND_ACTIVE_BIN : AT_LAST_BIN; - - mts.resolution = tile_priority.resolution; - mts.priority_bin = tile_priority.priority_bin; - mts.distance_to_visible = tile_priority.distance_to_visible; - mts.required_for_activation = tile_priority.required_for_activation; - - mts.visible_and_ready_to_draw = - tree_bin[ACTIVE_TREE] == NOW_AND_READY_TO_DRAW_BIN; - - // Tiles that are required for activation shouldn't be in NEVER_BIN unless - // smoothness takes priority or memory policy allows nothing to be - // initialized. - DCHECK(!mts.required_for_activation || mts.bin != NEVER_BIN || - tree_priority == SMOOTHNESS_TAKES_PRIORITY || - memory_policy == ALLOW_NOTHING); - - // If the tile is in NEVER_BIN and it does not have an active task, then we - // can release the resources early. If it does have the task however, we - // should keep it in the prioritized tile set to ensure that AssignGpuMemory - // can visit it. - if (mts.bin == NEVER_BIN && - !mts.tile_versions[mts.raster_mode].raster_task_) { - FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); - continue; + if (ready_to_activate) { + DCHECK(IsReadyToActivate()); + ready_to_activate_check_notifier_.Schedule(); } + raster_priority_queue_.Reset(); + return; + } - // Insert the tile into a priority set. - tiles->InsertTile(tile, mts.bin); + if (task_set == REQUIRED_FOR_ACTIVATION) { + TRACE_EVENT1("cc", + "TileManager::DidFinishRunningTasks", + "task_set", + "REQUIRED_FOR_ACTIVATION"); + ready_to_activate_check_notifier_.Schedule(); } } void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) { TRACE_EVENT0("cc", "TileManager::ManageTiles"); - // Update internal state. - if (state != global_state_) { - global_state_ = state; - prioritized_tiles_dirty_ = true; - } + global_state_ = state; // We need to call CheckForCompletedTasks() once in-between each call // to ScheduleTasks() to prevent canceled tasks from being scheduled. @@ -652,11 +388,11 @@ void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) { did_check_for_completed_tasks_since_last_schedule_tasks_ = true; } - UpdatePrioritizedTileSetIfNeeded(); + FreeResourcesForReleasedTiles(); + CleanUpReleasedTiles(); TileVector tiles_that_need_to_be_rasterized; - AssignGpuMemoryToTiles(&prioritized_tiles_, - &tiles_that_need_to_be_rasterized); + AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized); // Finally, schedule rasterizer tasks. ScheduleTasks(tiles_that_need_to_be_rasterized); @@ -665,7 +401,7 @@ void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) { "DidManage", TRACE_EVENT_SCOPE_THREAD, "state", - TracedValue::FromValue(BasicStateAsValue().release())); + BasicStateAsValue()); TRACE_COUNTER_ID1("cc", "unused_memory_bytes", @@ -685,8 +421,7 @@ bool TileManager::UpdateVisibleTiles() { "DidUpdateVisibleTiles", TRACE_EVENT_SCOPE_THREAD, "stats", - TracedValue::FromValue(RasterTaskCompletionStatsAsValue( - update_visible_tiles_stats_).release())); + RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_)); update_visible_tiles_stats_ = RasterTaskCompletionStats(); bool did_initialize_visible_tile = did_initialize_visible_tile_; @@ -694,230 +429,210 @@ bool TileManager::UpdateVisibleTiles() { return did_initialize_visible_tile; } -scoped_ptr<base::Value> TileManager::BasicStateAsValue() const { - scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); +scoped_refptr<base::debug::ConvertableToTraceFormat> +TileManager::BasicStateAsValue() const { + scoped_refptr<base::debug::TracedValue> value = + new base::debug::TracedValue(); + BasicStateAsValueInto(value.get()); + return value; +} + +void TileManager::BasicStateAsValueInto(base::debug::TracedValue* state) const { state->SetInteger("tile_count", tiles_.size()); - state->Set("global_state", global_state_.AsValue().release()); - return state.PassAs<base::Value>(); + state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_); + state->BeginDictionary("global_state"); + global_state_.AsValueInto(state); + state->EndDictionary(); +} + +void TileManager::RebuildEvictionQueueIfNeeded() { + TRACE_EVENT1("cc", + "TileManager::RebuildEvictionQueueIfNeeded", + "eviction_priority_queue_is_up_to_date", + eviction_priority_queue_is_up_to_date_); + if (eviction_priority_queue_is_up_to_date_) + return; + + eviction_priority_queue_.Reset(); + client_->BuildEvictionQueue(&eviction_priority_queue_, + global_state_.tree_priority); + eviction_priority_queue_is_up_to_date_ = true; } -scoped_ptr<base::Value> TileManager::AllTilesAsValue() const { - scoped_ptr<base::ListValue> state(new base::ListValue()); - for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) - state->Append(it->second->AsValue().release()); +bool TileManager::FreeTileResourcesUntilUsageIsWithinLimit( + const MemoryUsage& limit, + MemoryUsage* usage) { + while (usage->Exceeds(limit)) { + RebuildEvictionQueueIfNeeded(); + if (eviction_priority_queue_.IsEmpty()) + return false; - return state.PassAs<base::Value>(); + Tile* tile = eviction_priority_queue_.Top(); + *usage -= MemoryUsage::FromTile(tile); + FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); + eviction_priority_queue_.Pop(); + } + return true; +} + +bool TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit( + const MemoryUsage& limit, + const TilePriority& other_priority, + MemoryUsage* usage) { + while (usage->Exceeds(limit)) { + RebuildEvictionQueueIfNeeded(); + if (eviction_priority_queue_.IsEmpty()) + return false; + + Tile* tile = eviction_priority_queue_.Top(); + if (!other_priority.IsHigherPriorityThan(tile->combined_priority())) + return false; + + *usage -= MemoryUsage::FromTile(tile); + FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); + eviction_priority_queue_.Pop(); + } + return true; +} + +bool TileManager::TilePriorityViolatesMemoryPolicy( + const TilePriority& priority) { + switch (global_state_.memory_limit_policy) { + case ALLOW_NOTHING: + return true; + case ALLOW_ABSOLUTE_MINIMUM: + return priority.priority_bin > TilePriority::NOW; + case ALLOW_PREPAINT_ONLY: + return priority.priority_bin > TilePriority::SOON; + case ALLOW_ANYTHING: + return priority.distance_to_visible == + std::numeric_limits<float>::infinity(); + } + NOTREACHED(); + return true; } void TileManager::AssignGpuMemoryToTiles( - PrioritizedTileSet* tiles, TileVector* tiles_that_need_to_be_rasterized) { - TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles"); + TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles"); // Maintain the list of released resources that can potentially be re-used // or deleted. // If this operation becomes expensive too, only do this after some // resource(s) was returned. Note that in that case, one also need to // invalidate when releasing some resource from the pool. - resource_pool_->CheckBusyResources(); + resource_pool_->CheckBusyResources(false); // Now give memory out to the tiles until we're out, and build // the needs-to-be-rasterized queue. - all_tiles_that_need_to_be_rasterized_have_memory_ = true; - all_tiles_required_for_activation_have_memory_ = true; - - // Cast to prevent overflow. - int64 soft_bytes_available = - static_cast<int64>(bytes_releasable_) + - static_cast<int64>(global_state_.soft_memory_limit_in_bytes) - - static_cast<int64>(resource_pool_->acquired_memory_usage_bytes()); - int64 hard_bytes_available = - static_cast<int64>(bytes_releasable_) + - static_cast<int64>(global_state_.hard_memory_limit_in_bytes) - - static_cast<int64>(resource_pool_->acquired_memory_usage_bytes()); - int resources_available = resources_releasable_ + - global_state_.num_resources_limit - - resource_pool_->acquired_resource_count(); - size_t soft_bytes_allocatable = - std::max(static_cast<int64>(0), soft_bytes_available); - size_t hard_bytes_allocatable = - std::max(static_cast<int64>(0), hard_bytes_available); - size_t resources_allocatable = std::max(0, resources_available); - - size_t bytes_that_exceeded_memory_budget = 0; - size_t soft_bytes_left = soft_bytes_allocatable; - size_t hard_bytes_left = hard_bytes_allocatable; - - size_t resources_left = resources_allocatable; - bool oomed_soft = false; - bool oomed_hard = false; - bool have_hit_soft_memory = false; // Soft memory comes after hard. - unsigned schedule_priority = 1u; - for (PrioritizedTileSet::Iterator it(tiles, true); it; ++it) { - Tile* tile = *it; - ManagedTileState& mts = tile->managed_state(); - - mts.scheduled_priority = schedule_priority++; - - mts.raster_mode = tile->DetermineOverallRasterMode(); - - ManagedTileState::TileVersion& tile_version = - mts.tile_versions[mts.raster_mode]; - - // If this tile doesn't need a resource, then nothing to do. - if (!tile_version.requires_resource()) - continue; - - // If the tile is not needed, free it up. - if (mts.bin == NEVER_BIN) { - FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); - continue; - } - - const bool tile_uses_hard_limit = mts.bin <= NOW_BIN; - const size_t bytes_if_allocated = BytesConsumedIfAllocated(tile); - const size_t tile_bytes_left = - (tile_uses_hard_limit) ? hard_bytes_left : soft_bytes_left; - - // Hard-limit is reserved for tiles that would cause a calamity - // if they were to go away, so by definition they are the highest - // priority memory, and must be at the front of the list. - DCHECK(!(have_hit_soft_memory && tile_uses_hard_limit)); - have_hit_soft_memory |= !tile_uses_hard_limit; - - size_t tile_bytes = 0; - size_t tile_resources = 0; - - // It costs to maintain a resource. - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { - if (mts.tile_versions[mode].resource_) { - tile_bytes += bytes_if_allocated; - tile_resources++; - } + all_tiles_that_need_to_be_rasterized_are_scheduled_ = true; + bool had_enough_memory_to_schedule_tiles_needed_now = true; + + MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes, + global_state_.num_resources_limit); + MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes, + global_state_.num_resources_limit); + MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(), + resource_pool_->acquired_resource_count()); + + eviction_priority_queue_is_up_to_date_ = false; + client_->BuildRasterQueue(&raster_priority_queue_, + global_state_.tree_priority); + + while (!raster_priority_queue_.IsEmpty()) { + Tile* tile = raster_priority_queue_.Top(); + TilePriority priority = tile->combined_priority(); + + if (TilePriorityViolatesMemoryPolicy(priority)) { + TRACE_EVENT_INSTANT0( + "cc", + "TileManager::AssignGpuMemory tile violates memory policy", + TRACE_EVENT_SCOPE_THREAD); + break; } - // Allow lower priority tiles with initialized resources to keep - // their memory by only assigning memory to new raster tasks if - // they can be scheduled. - bool reached_scheduled_raster_tasks_limit = - tiles_that_need_to_be_rasterized->size() >= kScheduledRasterTasksLimit; - if (!reached_scheduled_raster_tasks_limit) { - // If we don't have the required version, and it's not in flight - // then we'll have to pay to create a new task. - if (!tile_version.resource_ && !tile_version.raster_task_) { - tile_bytes += bytes_if_allocated; - tile_resources++; - } + // We won't be able to schedule this tile, so break out early. + if (tiles_that_need_to_be_rasterized->size() >= + scheduled_raster_task_limit_) { + all_tiles_that_need_to_be_rasterized_are_scheduled_ = false; + break; } - // Tile is OOM. - if (tile_bytes > tile_bytes_left || tile_resources > resources_left) { - bool was_ready_to_draw = tile->IsReadyToDraw(); - - FreeResourcesForTile(tile); - - // This tile was already on screen and now its resources have been - // released. In order to prevent checkerboarding, set this tile as - // rasterize on demand immediately. - if (mts.visible_and_ready_to_draw) - tile_version.set_rasterize_on_demand(); - - if (was_ready_to_draw) - client_->NotifyTileStateChanged(tile); - - oomed_soft = true; - if (tile_uses_hard_limit) { - oomed_hard = true; - bytes_that_exceeded_memory_budget += tile_bytes; - } - } else { - resources_left -= tile_resources; - hard_bytes_left -= tile_bytes; - soft_bytes_left = - (soft_bytes_left > tile_bytes) ? soft_bytes_left - tile_bytes : 0; - if (tile_version.resource_) - continue; + ManagedTileState& mts = tile->managed_state(); + mts.scheduled_priority = schedule_priority++; + mts.resolution = priority.resolution; + + DCHECK(mts.draw_info.mode() == + ManagedTileState::DrawInfo::PICTURE_PILE_MODE || + !mts.draw_info.IsReadyToDraw()); + + // If the tile already has a raster_task, then the memory used by it is + // already accounted for in memory_usage. Otherwise, we'll have to acquire + // more memory to create a raster task. + MemoryUsage memory_required_by_tile_to_be_scheduled; + if (!mts.raster_task.get()) { + memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig( + tile->size(), resource_pool_->resource_format()); } - DCHECK(!tile_version.resource_); - - // Tile shouldn't be rasterized if |tiles_that_need_to_be_rasterized| - // has reached it's limit or we've failed to assign gpu memory to this - // or any higher priority tile. Preventing tiles that fit into memory - // budget to be rasterized when higher priority tile is oom is - // important for two reasons: - // 1. Tile size should not impact raster priority. - // 2. Tiles with existing raster task could otherwise incorrectly - // be added as they are not affected by |bytes_allocatable|. - bool can_schedule_tile = - !oomed_soft && !reached_scheduled_raster_tasks_limit; - - if (!can_schedule_tile) { - all_tiles_that_need_to_be_rasterized_have_memory_ = false; - if (tile->required_for_activation()) - all_tiles_required_for_activation_have_memory_ = false; - it.DisablePriorityOrdering(); - continue; + bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW; + + // This is the memory limit that will be used by this tile. Depending on + // the tile priority, it will be one of hard_memory_limit or + // soft_memory_limit. + MemoryUsage& tile_memory_limit = + tile_is_needed_now ? hard_memory_limit : soft_memory_limit; + + bool memory_usage_is_within_limit = + FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit( + tile_memory_limit - memory_required_by_tile_to_be_scheduled, + priority, + &memory_usage); + + // If we couldn't fit the tile into our current memory limit, then we're + // done. + if (!memory_usage_is_within_limit) { + if (tile_is_needed_now) + had_enough_memory_to_schedule_tiles_needed_now = false; + all_tiles_that_need_to_be_rasterized_are_scheduled_ = false; + break; } + memory_usage += memory_required_by_tile_to_be_scheduled; tiles_that_need_to_be_rasterized->push_back(tile); + raster_priority_queue_.Pop(); } - // OOM reporting uses hard-limit, soft-OOM is normal depending on limit. - ever_exceeded_memory_budget_ |= oomed_hard; - if (ever_exceeded_memory_budget_) { - TRACE_COUNTER_ID2("cc", - "over_memory_budget", - this, - "budget", - global_state_.hard_memory_limit_in_bytes, - "over", - bytes_that_exceeded_memory_budget); - } + // Note that we should try and further reduce memory in case the above loop + // didn't reduce memory. This ensures that we always release as many resources + // as possible to stay within the memory limit. + FreeTileResourcesUntilUsageIsWithinLimit(hard_memory_limit, &memory_usage); + + UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget", + !had_enough_memory_to_schedule_tiles_needed_now); + did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now; + memory_stats_from_last_assign_.total_budget_in_bytes = global_state_.hard_memory_limit_in_bytes; - memory_stats_from_last_assign_.bytes_allocated = - hard_bytes_allocatable - hard_bytes_left; - memory_stats_from_last_assign_.bytes_unreleasable = - resource_pool_->acquired_memory_usage_bytes() - bytes_releasable_; - memory_stats_from_last_assign_.bytes_over = bytes_that_exceeded_memory_budget; -} - -void TileManager::FreeResourceForTile(Tile* tile, RasterMode mode) { - ManagedTileState& mts = tile->managed_state(); - if (mts.tile_versions[mode].resource_) { - resource_pool_->ReleaseResource(mts.tile_versions[mode].resource_.Pass()); + memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes(); + memory_stats_from_last_assign_.had_enough_memory = + had_enough_memory_to_schedule_tiles_needed_now; - DCHECK_GE(bytes_releasable_, BytesConsumedIfAllocated(tile)); - DCHECK_GE(resources_releasable_, 1u); + raster_priority_queue_.Reset(); - bytes_releasable_ -= BytesConsumedIfAllocated(tile); - --resources_releasable_; - } + TRACE_EVENT_END2("cc", + "TileManager::AssignGpuMemoryToTiles", + "all_tiles_that_need_to_be_rasterized_are_scheduled", + all_tiles_that_need_to_be_rasterized_are_scheduled_, + "had_enough_memory_to_schedule_tiles_needed_now", + had_enough_memory_to_schedule_tiles_needed_now); } void TileManager::FreeResourcesForTile(Tile* tile) { - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { - FreeResourceForTile(tile, static_cast<RasterMode>(mode)); - } -} - -void TileManager::FreeUnusedResourcesForTile(Tile* tile) { - DCHECK(tile->IsReadyToDraw()); ManagedTileState& mts = tile->managed_state(); - RasterMode used_mode = LOW_QUALITY_RASTER_MODE; - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { - if (mts.tile_versions[mode].IsReadyToDraw()) { - used_mode = static_cast<RasterMode>(mode); - break; - } - } - - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { - if (mode != used_mode) - FreeResourceForTile(tile, static_cast<RasterMode>(mode)); - } + if (mts.draw_info.resource_) + resource_pool_->ReleaseResource(mts.draw_info.resource_.Pass()); } void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw( @@ -946,28 +661,28 @@ void TileManager::ScheduleTasks( ++it) { Tile* tile = *it; ManagedTileState& mts = tile->managed_state(); - ManagedTileState::TileVersion& tile_version = - mts.tile_versions[mts.raster_mode]; - DCHECK(tile_version.requires_resource()); - DCHECK(!tile_version.resource_); + DCHECK(mts.draw_info.requires_resource()); + DCHECK(!mts.draw_info.resource_); - if (!tile_version.raster_task_) - tile_version.raster_task_ = CreateRasterTask(tile); + if (!mts.raster_task.get()) + mts.raster_task = CreateRasterTask(tile); - raster_queue_.items.push_back(RasterTaskQueue::Item( - tile_version.raster_task_.get(), tile->required_for_activation())); - raster_queue_.required_for_activation_count += - tile->required_for_activation(); + TaskSetCollection task_sets; + if (tile->required_for_activation()) + task_sets.set(REQUIRED_FOR_ACTIVATION); + task_sets.set(ALL); + raster_queue_.items.push_back( + RasterTaskQueue::Item(mts.raster_task.get(), task_sets)); } // We must reduce the amount of unused resoruces before calling // ScheduleTasks to prevent usage from rising above limits. resource_pool_->ReduceResourceUsage(); - // Schedule running of |raster_tasks_|. This replaces any previously + // Schedule running of |raster_queue_|. This replaces any previously // scheduled tasks and effectively cancels all tasks not present - // in |raster_tasks_|. + // in |raster_queue_|. rasterizer_->ScheduleTasks(&raster_queue_); // It's now safe to clean up orphan tasks as raster worker pool is not @@ -995,17 +710,16 @@ scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) { ManagedTileState& mts = tile->managed_state(); scoped_ptr<ScopedResource> resource = - resource_pool_->AcquireResource(tile->tile_size_.size()); + resource_pool_->AcquireResource(tile->size()); const ScopedResource* const_resource = resource.get(); // Create and queue all image decode tasks that this tile depends on. ImageDecodeTask::Vector decode_tasks; PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()]; - for (PicturePileImpl::PixelRefIterator iter( - tile->content_rect(), tile->contents_scale(), tile->picture_pile()); - iter; - ++iter) { - SkPixelRef* pixel_ref = *iter; + std::vector<SkPixelRef*> pixel_refs; + tile->raster_source()->GatherPixelRefs( + tile->content_rect(), tile->contents_scale(), &pixel_refs); + for (SkPixelRef* pixel_ref : pixel_refs) { uint32_t id = pixel_ref->getGenerationID(); // Append existing image decode task if available. @@ -1024,10 +738,9 @@ scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) { return make_scoped_refptr( new RasterTaskImpl(const_resource, - tile->picture_pile(), + tile->raster_source(), tile->content_rect(), tile->contents_scale(), - mts.raster_mode, mts.resolution, tile->layer_id(), static_cast<const void*>(tile), @@ -1037,8 +750,7 @@ scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) { base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this), tile->id(), - base::Passed(&resource), - mts.raster_mode), + base::Passed(&resource)), &decode_tasks)); } @@ -1065,22 +777,15 @@ void TileManager::OnImageDecodeTaskCompleted(int layer_id, void TileManager::OnRasterTaskCompleted( Tile::Id tile_id, scoped_ptr<ScopedResource> resource, - RasterMode raster_mode, - const PicturePileImpl::Analysis& analysis, + const RasterSource::SolidColorAnalysis& analysis, bool was_canceled) { - TileMap::iterator it = tiles_.find(tile_id); - if (it == tiles_.end()) { - ++update_visible_tiles_stats_.canceled_count; - resource_pool_->ReleaseResource(resource.Pass()); - return; - } + DCHECK(tiles_.find(tile_id) != tiles_.end()); - Tile* tile = it->second; + Tile* tile = tiles_[tile_id]; ManagedTileState& mts = tile->managed_state(); - ManagedTileState::TileVersion& tile_version = mts.tile_versions[raster_mode]; - DCHECK(tile_version.raster_task_); - orphan_raster_tasks_.push_back(tile_version.raster_task_); - tile_version.raster_task_ = NULL; + DCHECK(mts.raster_task.get()); + orphan_raster_tasks_.push_back(mts.raster_task); + mts.raster_task = NULL; if (was_canceled) { ++update_visible_tiles_stats_.canceled_count; @@ -1091,495 +796,118 @@ void TileManager::OnRasterTaskCompleted( ++update_visible_tiles_stats_.completed_count; if (analysis.is_solid_color) { - tile_version.set_solid_color(analysis.solid_color); + mts.draw_info.set_solid_color(analysis.solid_color); resource_pool_->ReleaseResource(resource.Pass()); } else { - tile_version.set_use_resource(); - tile_version.resource_ = resource.Pass(); - - bytes_releasable_ += BytesConsumedIfAllocated(tile); - ++resources_releasable_; + mts.draw_info.set_use_resource(); + mts.draw_info.resource_ = resource.Pass(); } - FreeUnusedResourcesForTile(tile); if (tile->priority(ACTIVE_TREE).distance_to_visible == 0.f) did_initialize_visible_tile_ = true; client_->NotifyTileStateChanged(tile); } -scoped_refptr<Tile> TileManager::CreateTile(PicturePileImpl* picture_pile, +scoped_refptr<Tile> TileManager::CreateTile(RasterSource* raster_source, const gfx::Size& tile_size, const gfx::Rect& content_rect, - const gfx::Rect& opaque_rect, float contents_scale, int layer_id, int source_frame_number, int flags) { scoped_refptr<Tile> tile = make_scoped_refptr(new Tile(this, - picture_pile, + raster_source, tile_size, content_rect, - opaque_rect, contents_scale, layer_id, source_frame_number, flags)); DCHECK(tiles_.find(tile->id()) == tiles_.end()); - tiles_[tile->id()] = tile; + tiles_[tile->id()] = tile.get(); used_layer_counts_[tile->layer_id()]++; - prioritized_tiles_dirty_ = true; return tile; } -void TileManager::GetPairedPictureLayers( - std::vector<PairedPictureLayer>* paired_layers) const { - const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers(); +void TileManager::SetRasterizerForTesting(Rasterizer* rasterizer) { + rasterizer_ = rasterizer; + rasterizer_->SetClient(this); +} - paired_layers->clear(); - // Reserve a maximum possible paired layers. - paired_layers->reserve(layers.size()); +bool TileManager::IsReadyToActivate() const { + TRACE_EVENT0("cc", "TileManager::IsReadyToActivate"); + const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers(); for (std::vector<PictureLayerImpl*>::const_iterator it = layers.begin(); it != layers.end(); ++it) { - PictureLayerImpl* layer = *it; - - // TODO(vmpstr): Iterators and should handle this instead. crbug.com/381704 - if (!layer->HasValidTilePriorities()) - continue; - - PictureLayerImpl* twin_layer = layer->GetTwinLayer(); - - // Ignore the twin layer when tile priorities are invalid. - // TODO(vmpstr): Iterators should handle this instead. crbug.com/381704 - if (twin_layer && !twin_layer->HasValidTilePriorities()) - twin_layer = NULL; - - PairedPictureLayer paired_layer; - WhichTree tree = layer->GetTree(); - - // If the current tree is ACTIVE_TREE, then always generate a paired_layer. - // If current tree is PENDING_TREE, then only generate a paired_layer if - // there is no twin layer. - if (tree == ACTIVE_TREE) { - DCHECK(!twin_layer || twin_layer->GetTree() == PENDING_TREE); - paired_layer.active_layer = layer; - paired_layer.pending_layer = twin_layer; - paired_layers->push_back(paired_layer); - } else if (!twin_layer) { - paired_layer.active_layer = NULL; - paired_layer.pending_layer = layer; - paired_layers->push_back(paired_layer); - } - } -} - -TileManager::PairedPictureLayer::PairedPictureLayer() - : active_layer(NULL), pending_layer(NULL) {} - -TileManager::PairedPictureLayer::~PairedPictureLayer() {} - -TileManager::RasterTileIterator::RasterTileIterator(TileManager* tile_manager, - TreePriority tree_priority) - : tree_priority_(tree_priority), comparator_(tree_priority) { - std::vector<TileManager::PairedPictureLayer> paired_layers; - tile_manager->GetPairedPictureLayers(&paired_layers); - bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY; - - paired_iterators_.reserve(paired_layers.size()); - iterator_heap_.reserve(paired_layers.size()); - for (std::vector<TileManager::PairedPictureLayer>::iterator it = - paired_layers.begin(); - it != paired_layers.end(); - ++it) { - PairedPictureLayerIterator paired_iterator; - if (it->active_layer) { - paired_iterator.active_iterator = - PictureLayerImpl::LayerRasterTileIterator(it->active_layer, - prioritize_low_res); - } - - if (it->pending_layer) { - paired_iterator.pending_iterator = - PictureLayerImpl::LayerRasterTileIterator(it->pending_layer, - prioritize_low_res); - } - - if (paired_iterator.PeekTile(tree_priority_) != NULL) { - paired_iterators_.push_back(paired_iterator); - iterator_heap_.push_back(&paired_iterators_.back()); - } - } - - std::make_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_); -} - -TileManager::RasterTileIterator::~RasterTileIterator() {} - -TileManager::RasterTileIterator& TileManager::RasterTileIterator::operator++() { - DCHECK(*this); - - std::pop_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_); - PairedPictureLayerIterator* paired_iterator = iterator_heap_.back(); - iterator_heap_.pop_back(); - - paired_iterator->PopTile(tree_priority_); - if (paired_iterator->PeekTile(tree_priority_) != NULL) { - iterator_heap_.push_back(paired_iterator); - std::push_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_); - } - return *this; -} - -TileManager::RasterTileIterator::operator bool() const { - return !iterator_heap_.empty(); -} - -Tile* TileManager::RasterTileIterator::operator*() { - DCHECK(*this); - return iterator_heap_.front()->PeekTile(tree_priority_); -} - -TileManager::RasterTileIterator::PairedPictureLayerIterator:: - PairedPictureLayerIterator() {} - -TileManager::RasterTileIterator::PairedPictureLayerIterator:: - ~PairedPictureLayerIterator() {} - -Tile* TileManager::RasterTileIterator::PairedPictureLayerIterator::PeekTile( - TreePriority tree_priority) { - PictureLayerImpl::LayerRasterTileIterator* next_iterator = - NextTileIterator(tree_priority).first; - if (!next_iterator) - return NULL; - - DCHECK(*next_iterator); - DCHECK(std::find(returned_shared_tiles.begin(), - returned_shared_tiles.end(), - **next_iterator) == returned_shared_tiles.end()); - return **next_iterator; -} - -void TileManager::RasterTileIterator::PairedPictureLayerIterator::PopTile( - TreePriority tree_priority) { - PictureLayerImpl::LayerRasterTileIterator* next_iterator = - NextTileIterator(tree_priority).first; - DCHECK(next_iterator); - DCHECK(*next_iterator); - returned_shared_tiles.push_back(**next_iterator); - ++(*next_iterator); - - next_iterator = NextTileIterator(tree_priority).first; - while (next_iterator && - std::find(returned_shared_tiles.begin(), - returned_shared_tiles.end(), - **next_iterator) != returned_shared_tiles.end()) { - ++(*next_iterator); - next_iterator = NextTileIterator(tree_priority).first; - } -} - -std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree> -TileManager::RasterTileIterator::PairedPictureLayerIterator::NextTileIterator( - TreePriority tree_priority) { - // If both iterators are out of tiles, return NULL. - if (!active_iterator && !pending_iterator) { - return std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree>( - NULL, ACTIVE_TREE); - } - - // If we only have one iterator with tiles, return it. - if (!active_iterator) - return std::make_pair(&pending_iterator, PENDING_TREE); - if (!pending_iterator) - return std::make_pair(&active_iterator, ACTIVE_TREE); - - // Now both iterators have tiles, so we have to decide based on tree priority. - switch (tree_priority) { - case SMOOTHNESS_TAKES_PRIORITY: - return std::make_pair(&active_iterator, ACTIVE_TREE); - case NEW_CONTENT_TAKES_PRIORITY: - return std::make_pair(&pending_iterator, ACTIVE_TREE); - case SAME_PRIORITY_FOR_BOTH_TREES: { - Tile* active_tile = *active_iterator; - Tile* pending_tile = *pending_iterator; - if (active_tile == pending_tile) - return std::make_pair(&active_iterator, ACTIVE_TREE); - - const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE); - const TilePriority& pending_priority = - pending_tile->priority(PENDING_TREE); - - if (active_priority.IsHigherPriorityThan(pending_priority)) - return std::make_pair(&active_iterator, ACTIVE_TREE); - return std::make_pair(&pending_iterator, PENDING_TREE); - } - } - - NOTREACHED(); - // Keep the compiler happy. - return std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree>( - NULL, ACTIVE_TREE); -} - -TileManager::RasterTileIterator::RasterOrderComparator::RasterOrderComparator( - TreePriority tree_priority) - : tree_priority_(tree_priority) {} - -bool TileManager::RasterTileIterator::RasterOrderComparator::operator()( - PairedPictureLayerIterator* a, - PairedPictureLayerIterator* b) const { - std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree> a_pair = - a->NextTileIterator(tree_priority_); - DCHECK(a_pair.first); - DCHECK(*a_pair.first); - - std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree> b_pair = - b->NextTileIterator(tree_priority_); - DCHECK(b_pair.first); - DCHECK(*b_pair.first); - - Tile* a_tile = **a_pair.first; - Tile* b_tile = **b_pair.first; - - const TilePriority& a_priority = - a_tile->priority_for_tree_priority(tree_priority_); - const TilePriority& b_priority = - b_tile->priority_for_tree_priority(tree_priority_); - bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY; - - // Now we have to return true iff b is higher priority than a. - - // If the bin is the same but the resolution is not, then the order will be - // determined by whether we prioritize low res or not. - // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile - // class but instead produced by the iterators. - if (b_priority.priority_bin == a_priority.priority_bin && - b_priority.resolution != a_priority.resolution) { - // Non ideal resolution should be sorted lower than other resolutions. - if (a_priority.resolution == NON_IDEAL_RESOLUTION) - return true; - - if (b_priority.resolution == NON_IDEAL_RESOLUTION) + if (!(*it)->AllTilesRequiredForActivationAreReadyToDraw()) return false; - - if (prioritize_low_res) - return b_priority.resolution == LOW_RESOLUTION; - - return b_priority.resolution == HIGH_RESOLUTION; } - return b_priority.IsHigherPriorityThan(a_priority); -} - -TileManager::EvictionTileIterator::EvictionTileIterator() - : comparator_(SAME_PRIORITY_FOR_BOTH_TREES) {} - -TileManager::EvictionTileIterator::EvictionTileIterator( - TileManager* tile_manager, - TreePriority tree_priority) - : tree_priority_(tree_priority), comparator_(tree_priority) { - std::vector<TileManager::PairedPictureLayer> paired_layers; - - tile_manager->GetPairedPictureLayers(&paired_layers); - - paired_iterators_.reserve(paired_layers.size()); - iterator_heap_.reserve(paired_layers.size()); - for (std::vector<TileManager::PairedPictureLayer>::iterator it = - paired_layers.begin(); - it != paired_layers.end(); - ++it) { - PairedPictureLayerIterator paired_iterator; - if (it->active_layer) { - paired_iterator.active_iterator = - PictureLayerImpl::LayerEvictionTileIterator(it->active_layer, - tree_priority_); - } - - if (it->pending_layer) { - paired_iterator.pending_iterator = - PictureLayerImpl::LayerEvictionTileIterator(it->pending_layer, - tree_priority_); - } - - if (paired_iterator.PeekTile(tree_priority_) != NULL) { - paired_iterators_.push_back(paired_iterator); - iterator_heap_.push_back(&paired_iterators_.back()); - } - } - - std::make_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_); + return true; } -TileManager::EvictionTileIterator::~EvictionTileIterator() {} +void TileManager::CheckIfReadyToActivate() { + TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate"); -TileManager::EvictionTileIterator& TileManager::EvictionTileIterator:: -operator++() { - std::pop_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_); - PairedPictureLayerIterator* paired_iterator = iterator_heap_.back(); - iterator_heap_.pop_back(); + rasterizer_->CheckForCompletedTasks(); + did_check_for_completed_tasks_since_last_schedule_tasks_ = true; - paired_iterator->PopTile(tree_priority_); - if (paired_iterator->PeekTile(tree_priority_) != NULL) { - iterator_heap_.push_back(paired_iterator); - std::push_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_); - } - return *this; + if (IsReadyToActivate()) + client_->NotifyReadyToActivate(); } -TileManager::EvictionTileIterator::operator bool() const { - return !iterator_heap_.empty(); +TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) { } -Tile* TileManager::EvictionTileIterator::operator*() { - DCHECK(*this); - return iterator_heap_.front()->PeekTile(tree_priority_); +TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes, int resource_count) + : memory_bytes_(memory_bytes), resource_count_(resource_count) { } -TileManager::EvictionTileIterator::PairedPictureLayerIterator:: - PairedPictureLayerIterator() {} - -TileManager::EvictionTileIterator::PairedPictureLayerIterator:: - ~PairedPictureLayerIterator() {} - -Tile* TileManager::EvictionTileIterator::PairedPictureLayerIterator::PeekTile( - TreePriority tree_priority) { - PictureLayerImpl::LayerEvictionTileIterator* next_iterator = - NextTileIterator(tree_priority); - if (!next_iterator) - return NULL; - - DCHECK(*next_iterator); - DCHECK(std::find(returned_shared_tiles.begin(), - returned_shared_tiles.end(), - **next_iterator) == returned_shared_tiles.end()); - return **next_iterator; +// static +TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig( + const gfx::Size& size, + ResourceFormat format) { + return MemoryUsage(Resource::MemorySizeBytes(size, format), 1); } -void TileManager::EvictionTileIterator::PairedPictureLayerIterator::PopTile( - TreePriority tree_priority) { - PictureLayerImpl::LayerEvictionTileIterator* next_iterator = - NextTileIterator(tree_priority); - DCHECK(next_iterator); - DCHECK(*next_iterator); - returned_shared_tiles.push_back(**next_iterator); - ++(*next_iterator); - - next_iterator = NextTileIterator(tree_priority); - while (next_iterator && - std::find(returned_shared_tiles.begin(), - returned_shared_tiles.end(), - **next_iterator) != returned_shared_tiles.end()) { - ++(*next_iterator); - next_iterator = NextTileIterator(tree_priority); +// static +TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) { + const ManagedTileState& mts = tile->managed_state(); + if (mts.draw_info.resource_) { + return MemoryUsage::FromConfig(tile->size(), + mts.draw_info.resource_->format()); } + return MemoryUsage(); } -PictureLayerImpl::LayerEvictionTileIterator* -TileManager::EvictionTileIterator::PairedPictureLayerIterator::NextTileIterator( - TreePriority tree_priority) { - // If both iterators are out of tiles, return NULL. - if (!active_iterator && !pending_iterator) - return NULL; - - // If we only have one iterator with tiles, return it. - if (!active_iterator) - return &pending_iterator; - if (!pending_iterator) - return &active_iterator; - - Tile* active_tile = *active_iterator; - Tile* pending_tile = *pending_iterator; - if (active_tile == pending_tile) - return &active_iterator; - - const TilePriority& active_priority = - active_tile->priority_for_tree_priority(tree_priority); - const TilePriority& pending_priority = - pending_tile->priority_for_tree_priority(tree_priority); - - if (pending_priority.IsHigherPriorityThan(active_priority)) - return &active_iterator; - return &pending_iterator; +TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=( + const MemoryUsage& other) { + memory_bytes_ += other.memory_bytes_; + resource_count_ += other.resource_count_; + return *this; } -TileManager::EvictionTileIterator::EvictionOrderComparator:: - EvictionOrderComparator(TreePriority tree_priority) - : tree_priority_(tree_priority) {} - -bool TileManager::EvictionTileIterator::EvictionOrderComparator::operator()( - PairedPictureLayerIterator* a, - PairedPictureLayerIterator* b) const { - PictureLayerImpl::LayerEvictionTileIterator* a_iterator = - a->NextTileIterator(tree_priority_); - DCHECK(a_iterator); - DCHECK(*a_iterator); - - PictureLayerImpl::LayerEvictionTileIterator* b_iterator = - b->NextTileIterator(tree_priority_); - DCHECK(b_iterator); - DCHECK(*b_iterator); - - Tile* a_tile = **a_iterator; - Tile* b_tile = **b_iterator; - - const TilePriority& a_priority = - a_tile->priority_for_tree_priority(tree_priority_); - const TilePriority& b_priority = - b_tile->priority_for_tree_priority(tree_priority_); - bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY; - - // Now we have to return true iff b is lower priority than a. - - // If the bin is the same but the resolution is not, then the order will be - // determined by whether we prioritize low res or not. - // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile - // class but instead produced by the iterators. - if (b_priority.priority_bin == a_priority.priority_bin && - b_priority.resolution != a_priority.resolution) { - // Non ideal resolution should be sorted higher than other resolutions. - if (a_priority.resolution == NON_IDEAL_RESOLUTION) - return false; - - if (b_priority.resolution == NON_IDEAL_RESOLUTION) - return true; - - if (prioritize_low_res) - return a_priority.resolution == LOW_RESOLUTION; - - return a_priority.resolution == HIGH_RESOLUTION; - } - return a_priority.IsHigherPriorityThan(b_priority); +TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=( + const MemoryUsage& other) { + memory_bytes_ -= other.memory_bytes_; + resource_count_ -= other.resource_count_; + return *this; } -void TileManager::SetRasterizerForTesting(Rasterizer* rasterizer) { - rasterizer_ = rasterizer; - rasterizer_->SetClient(this); +TileManager::MemoryUsage TileManager::MemoryUsage::operator-( + const MemoryUsage& other) { + MemoryUsage result = *this; + result -= other; + return result; } -bool TileManager::IsReadyToActivate() const { - const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers(); - - for (std::vector<PictureLayerImpl*>::const_iterator it = layers.begin(); - it != layers.end(); - ++it) { - if (!(*it)->AllTilesRequiredForActivationAreReadyToDraw()) - return false; - } - - return true; -} - -void TileManager::CheckIfReadyToActivate() { - TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate"); - - rasterizer_->CheckForCompletedTasks(); - did_check_for_completed_tasks_since_last_schedule_tasks_ = true; - - if (IsReadyToActivate()) - client_->NotifyReadyToActivate(); +bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const { + return memory_bytes_ > limit.memory_bytes_ || + resource_count_ > limit.resource_count_; } } // namespace cc diff --git a/chromium/cc/resources/tile_manager.h b/chromium/cc/resources/tile_manager.h index 5ad80910f8e..f5bea383141 100644 --- a/chromium/cc/resources/tile_manager.h +++ b/chromium/cc/resources/tile_manager.h @@ -17,22 +17,32 @@ #include "cc/base/ref_counted_managed.h" #include "cc/base/unique_notifier.h" #include "cc/debug/rendering_stats_instrumentation.h" -#include "cc/layers/picture_layer_impl.h" +#include "cc/resources/eviction_tile_priority_queue.h" #include "cc/resources/managed_tile_state.h" #include "cc/resources/memory_history.h" -#include "cc/resources/picture_pile_impl.h" -#include "cc/resources/prioritized_tile_set.h" +#include "cc/resources/raster_source.h" +#include "cc/resources/raster_tile_priority_queue.h" #include "cc/resources/rasterizer.h" #include "cc/resources/resource_pool.h" #include "cc/resources/tile.h" +namespace base { +namespace debug { +class ConvertableToTraceFormat; +class TracedValue; +} +} + namespace cc { +class PictureLayerImpl; class ResourceProvider; class CC_EXPORT TileManagerClient { public: // Returns the set of layers that the tile manager should consider for raster. - virtual const std::vector<PictureLayerImpl*>& GetPictureLayers() = 0; + // TODO(vmpstr): Change the way we determine if we are ready to activate, so + // that this can be removed. + virtual const std::vector<PictureLayerImpl*>& GetPictureLayers() const = 0; // Called when all tiles marked as required for activation are ready to draw. virtual void NotifyReadyToActivate() = 0; @@ -44,6 +54,18 @@ class CC_EXPORT TileManagerClient { // - Tile marked for on-demand raster. virtual void NotifyTileStateChanged(const Tile* tile) = 0; + // Given an empty raster tile priority queue, this will build a priority queue + // that will return tiles in order in which they should be rasterized. + // Note if the queue was previous built, Reset must be called on it. + virtual void BuildRasterQueue(RasterTilePriorityQueue* queue, + TreePriority tree_priority) = 0; + + // Given an empty eviction tile priority queue, this will build a priority + // queue that will return tiles in order in which they should be evicted. + // Note if the queue was previous built, Reset must be called on it. + virtual void BuildEvictionQueue(EvictionTilePriorityQueue* queue, + TreePriority tree_priority) = 0; + protected: virtual ~TileManagerClient() {} }; @@ -54,8 +76,8 @@ struct RasterTaskCompletionStats { size_t completed_count; size_t canceled_count; }; -scoped_ptr<base::Value> RasterTaskCompletionStatsAsValue( - const RasterTaskCompletionStats& stats); +scoped_refptr<base::debug::ConvertableToTraceFormat> + RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats); // This class manages tiles, deciding which should get rasterized and which // should no longer have any memory assigned to them. Tile objects are "owned" @@ -64,103 +86,11 @@ scoped_ptr<base::Value> RasterTaskCompletionStatsAsValue( class CC_EXPORT TileManager : public RasterizerClient, public RefCountedManager<Tile> { public: - struct CC_EXPORT PairedPictureLayer { - PairedPictureLayer(); - ~PairedPictureLayer(); - - PictureLayerImpl* active_layer; - PictureLayerImpl* pending_layer; - }; - - class CC_EXPORT RasterTileIterator { - public: - RasterTileIterator(TileManager* tile_manager, TreePriority tree_priority); - ~RasterTileIterator(); - - RasterTileIterator& operator++(); - operator bool() const; - Tile* operator*(); - - private: - struct PairedPictureLayerIterator { - PairedPictureLayerIterator(); - ~PairedPictureLayerIterator(); - - Tile* PeekTile(TreePriority tree_priority); - void PopTile(TreePriority tree_priority); - - std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree> - NextTileIterator(TreePriority tree_priority); - - PictureLayerImpl::LayerRasterTileIterator active_iterator; - PictureLayerImpl::LayerRasterTileIterator pending_iterator; - - std::vector<Tile*> returned_shared_tiles; - }; - - class RasterOrderComparator { - public: - explicit RasterOrderComparator(TreePriority tree_priority); - - bool operator()(PairedPictureLayerIterator* a, - PairedPictureLayerIterator* b) const; - - private: - TreePriority tree_priority_; - }; - - std::vector<PairedPictureLayerIterator> paired_iterators_; - std::vector<PairedPictureLayerIterator*> iterator_heap_; - TreePriority tree_priority_; - RasterOrderComparator comparator_; - - DISALLOW_COPY_AND_ASSIGN(RasterTileIterator); - }; - - struct CC_EXPORT EvictionTileIterator { - public: - EvictionTileIterator(); - EvictionTileIterator(TileManager* tile_manager, TreePriority tree_priority); - ~EvictionTileIterator(); - - EvictionTileIterator& operator++(); - operator bool() const; - Tile* operator*(); - - private: - struct PairedPictureLayerIterator { - PairedPictureLayerIterator(); - ~PairedPictureLayerIterator(); - - Tile* PeekTile(TreePriority tree_priority); - void PopTile(TreePriority tree_priority); - - PictureLayerImpl::LayerEvictionTileIterator* NextTileIterator( - TreePriority tree_priority); - - PictureLayerImpl::LayerEvictionTileIterator active_iterator; - PictureLayerImpl::LayerEvictionTileIterator pending_iterator; - - std::vector<Tile*> returned_shared_tiles; - }; - - class EvictionOrderComparator { - public: - explicit EvictionOrderComparator(TreePriority tree_priority); - - bool operator()(PairedPictureLayerIterator* a, - PairedPictureLayerIterator* b) const; - - private: - TreePriority tree_priority_; - }; - - std::vector<PairedPictureLayerIterator> paired_iterators_; - std::vector<PairedPictureLayerIterator*> iterator_heap_; - TreePriority tree_priority_; - EvictionOrderComparator comparator_; - - DISALLOW_COPY_AND_ASSIGN(EvictionTileIterator); + enum NamedTaskSet { + REQUIRED_FOR_ACTIVATION = 0, + ALL = 1, + // Adding additional values requires increasing kNumberOfTaskSets in + // rasterizer.h }; static scoped_ptr<TileManager> Create( @@ -168,87 +98,85 @@ class CC_EXPORT TileManager : public RasterizerClient, base::SequencedTaskRunner* task_runner, ResourcePool* resource_pool, Rasterizer* rasterizer, - RenderingStatsInstrumentation* rendering_stats_instrumentation); - virtual ~TileManager(); + RenderingStatsInstrumentation* rendering_stats_instrumentation, + size_t scheduled_raster_task_limit); + ~TileManager() override; void ManageTiles(const GlobalStateThatImpactsTilePriority& state); // Returns true when visible tiles have been initialized. bool UpdateVisibleTiles(); - scoped_refptr<Tile> CreateTile(PicturePileImpl* picture_pile, + scoped_refptr<Tile> CreateTile(RasterSource* raster_source, const gfx::Size& tile_size, const gfx::Rect& content_rect, - const gfx::Rect& opaque_rect, float contents_scale, int layer_id, int source_frame_number, int flags); - scoped_ptr<base::Value> BasicStateAsValue() const; - scoped_ptr<base::Value> AllTilesAsValue() const; + scoped_refptr<base::debug::ConvertableToTraceFormat> BasicStateAsValue() + const; + void BasicStateAsValueInto(base::debug::TracedValue* dict) const; const MemoryHistory::Entry& memory_stats_from_last_assign() const { return memory_stats_from_last_assign_; } - void GetPairedPictureLayers(std::vector<PairedPictureLayer>* layers) const; - void InitializeTilesWithResourcesForTesting(const std::vector<Tile*>& tiles) { for (size_t i = 0; i < tiles.size(); ++i) { ManagedTileState& mts = tiles[i]->managed_state(); - ManagedTileState::TileVersion& tile_version = - mts.tile_versions[HIGH_QUALITY_RASTER_MODE]; - tile_version.resource_ = resource_pool_->AcquireResource(gfx::Size(1, 1)); - - bytes_releasable_ += BytesConsumedIfAllocated(tiles[i]); - ++resources_releasable_; + mts.draw_info.resource_ = + resource_pool_->AcquireResource(tiles[i]->size()); } } void ReleaseTileResourcesForTesting(const std::vector<Tile*>& tiles) { for (size_t i = 0; i < tiles.size(); ++i) { Tile* tile = tiles[i]; - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) { - FreeResourceForTile(tile, static_cast<RasterMode>(mode)); - } + FreeResourcesForTile(tile); } } void SetGlobalStateForTesting( const GlobalStateThatImpactsTilePriority& state) { - // Soft limit is used for resource pool such that - // memory returns to soft limit after going over. - if (state != global_state_) { - global_state_ = state; - prioritized_tiles_dirty_ = true; - } + global_state_ = state; } void SetRasterizerForTesting(Rasterizer* rasterizer); - void CleanUpReleasedTilesForTesting() { CleanUpReleasedTiles(); } + void FreeResourcesAndCleanUpReleasedTilesForTesting() { + FreeResourcesForReleasedTiles(); + CleanUpReleasedTiles(); + } + + std::vector<Tile*> AllTilesForTesting() const { + std::vector<Tile*> tiles; + for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); + ++it) { + tiles.push_back(it->second); + } + return tiles; + } protected: TileManager(TileManagerClient* client, - base::SequencedTaskRunner* task_runner, + const scoped_refptr<base::SequencedTaskRunner>& task_runner, ResourcePool* resource_pool, Rasterizer* rasterizer, - RenderingStatsInstrumentation* rendering_stats_instrumentation); - - // Methods called by Tile - friend class Tile; - void DidChangeTilePriority(Tile* tile); + RenderingStatsInstrumentation* rendering_stats_instrumentation, + size_t scheduled_raster_task_limit); + void FreeResourcesForReleasedTiles(); void CleanUpReleasedTiles(); // Overriden from RefCountedManager<Tile>: - virtual void Release(Tile* tile) OVERRIDE; + friend class Tile; + void Release(Tile* tile) override; // Overriden from RasterizerClient: - virtual bool ShouldForceTasksRequiredForActivationToComplete() const OVERRIDE; - virtual void DidFinishRunningTasks() OVERRIDE; - virtual void DidFinishRunningTasksRequiredForActivation() OVERRIDE; + void DidFinishRunningTasks(TaskSet task_set) override; + TaskSetCollection TasksThatShouldBeForcedToComplete() const override; typedef std::vector<Tile*> TileVector; typedef std::set<Tile*> TileSet; @@ -257,34 +185,51 @@ class CC_EXPORT TileManager : public RasterizerClient, virtual void ScheduleTasks( const TileVector& tiles_that_need_to_be_rasterized); - void AssignGpuMemoryToTiles(PrioritizedTileSet* tiles, - TileVector* tiles_that_need_to_be_rasterized); - void GetTilesWithAssignedBins(PrioritizedTileSet* tiles); + void AssignGpuMemoryToTiles(TileVector* tiles_that_need_to_be_rasterized); private: + class MemoryUsage { + public: + MemoryUsage(); + MemoryUsage(int64 memory_bytes, int resource_count); + + static MemoryUsage FromConfig(const gfx::Size& size, ResourceFormat format); + static MemoryUsage FromTile(const Tile* tile); + + MemoryUsage& operator+=(const MemoryUsage& other); + MemoryUsage& operator-=(const MemoryUsage& other); + MemoryUsage operator-(const MemoryUsage& other); + + bool Exceeds(const MemoryUsage& limit) const; + int64 memory_bytes() const { return memory_bytes_; } + + private: + int64 memory_bytes_; + int resource_count_; + }; + void OnImageDecodeTaskCompleted(int layer_id, SkPixelRef* pixel_ref, bool was_canceled); void OnRasterTaskCompleted(Tile::Id tile, scoped_ptr<ScopedResource> resource, - RasterMode raster_mode, - const PicturePileImpl::Analysis& analysis, + const RasterSource::SolidColorAnalysis& analysis, bool was_canceled); - inline size_t BytesConsumedIfAllocated(const Tile* tile) const { - return Resource::MemorySizeBytes(tile->size(), - resource_pool_->resource_format()); - } - - void FreeResourceForTile(Tile* tile, RasterMode mode); void FreeResourcesForTile(Tile* tile); - void FreeUnusedResourcesForTile(Tile* tile); void FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(Tile* tile); scoped_refptr<ImageDecodeTask> CreateImageDecodeTask(Tile* tile, SkPixelRef* pixel_ref); scoped_refptr<RasterTask> CreateRasterTask(Tile* tile); - void UpdatePrioritizedTileSetIfNeeded(); + void RebuildEvictionQueueIfNeeded(); + bool FreeTileResourcesUntilUsageIsWithinLimit(const MemoryUsage& limit, + MemoryUsage* usage); + bool FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit( + const MemoryUsage& limit, + const TilePriority& oother_priority, + MemoryUsage* usage); + bool TilePriorityViolatesMemoryPolicy(const TilePriority& priority); bool IsReadyToActivate() const; void CheckIfReadyToActivate(); @@ -293,28 +238,21 @@ class CC_EXPORT TileManager : public RasterizerClient, ResourcePool* resource_pool_; Rasterizer* rasterizer_; GlobalStateThatImpactsTilePriority global_state_; + const size_t scheduled_raster_task_limit_; typedef base::hash_map<Tile::Id, Tile*> TileMap; TileMap tiles_; - PrioritizedTileSet prioritized_tiles_; - bool prioritized_tiles_dirty_; - - bool all_tiles_that_need_to_be_rasterized_have_memory_; - bool all_tiles_required_for_activation_have_memory_; - - size_t bytes_releasable_; - size_t resources_releasable_; - - bool ever_exceeded_memory_budget_; + bool all_tiles_that_need_to_be_rasterized_are_scheduled_; MemoryHistory::Entry memory_stats_from_last_assign_; RenderingStatsInstrumentation* rendering_stats_instrumentation_; bool did_initialize_visible_tile_; bool did_check_for_completed_tasks_since_last_schedule_tasks_; + bool did_oom_on_last_assign_; - typedef base::hash_map<uint32_t, scoped_refptr<ImageDecodeTask> > + typedef base::hash_map<uint32_t, scoped_refptr<ImageDecodeTask>> PixelRefTaskMap; typedef base::hash_map<int, PixelRefTaskMap> LayerPixelRefTaskMap; LayerPixelRefTaskMap image_decode_tasks_; @@ -331,10 +269,14 @@ class CC_EXPORT TileManager : public RasterizerClient, // Queue used when scheduling raster tasks. RasterTaskQueue raster_queue_; - std::vector<scoped_refptr<RasterTask> > orphan_raster_tasks_; + std::vector<scoped_refptr<RasterTask>> orphan_raster_tasks_; UniqueNotifier ready_to_activate_check_notifier_; + RasterTilePriorityQueue raster_priority_queue_; + EvictionTilePriorityQueue eviction_priority_queue_; + bool eviction_priority_queue_is_up_to_date_; + DISALLOW_COPY_AND_ASSIGN(TileManager); }; diff --git a/chromium/cc/resources/tile_manager_perftest.cc b/chromium/cc/resources/tile_manager_perftest.cc index cc54fbb633c..43c10312cfb 100644 --- a/chromium/cc/resources/tile_manager_perftest.cc +++ b/chromium/cc/resources/tile_manager_perftest.cc @@ -4,8 +4,10 @@ #include "base/time/time.h" #include "cc/debug/lap_timer.h" +#include "cc/resources/raster_buffer.h" #include "cc/resources/tile.h" #include "cc/resources/tile_priority.h" +#include "cc/test/begin_frame_args_test.h" #include "cc/test/fake_impl_proxy.h" #include "cc/test/fake_layer_tree_host_impl.h" #include "cc/test/fake_output_surface.h" @@ -22,6 +24,8 @@ #include "testing/gtest/include/gtest/gtest.h" #include "testing/perf/perf_test.h" +#include "ui/gfx/frame_time.h" + namespace cc { namespace { @@ -33,9 +37,9 @@ static const int kTimeCheckInterval = 10; class FakeRasterizerImpl : public Rasterizer, public RasterizerTaskClient { public: // Overridden from Rasterizer: - virtual void SetClient(RasterizerClient* client) OVERRIDE {} - virtual void Shutdown() OVERRIDE {} - virtual void ScheduleTasks(RasterTaskQueue* queue) OVERRIDE { + void SetClient(RasterizerClient* client) override {} + void Shutdown() override {} + void ScheduleTasks(RasterTaskQueue* queue) override { for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); it != queue->items.end(); @@ -49,7 +53,7 @@ class FakeRasterizerImpl : public Rasterizer, public RasterizerTaskClient { completed_tasks_.push_back(task); } } - virtual void CheckForCompletedTasks() OVERRIDE { + void CheckForCompletedTasks() override { for (RasterTask::Vector::iterator it = completed_tasks_.begin(); it != completed_tasks_.end(); ++it) { @@ -65,10 +69,11 @@ class FakeRasterizerImpl : public Rasterizer, public RasterizerTaskClient { } // Overridden from RasterizerTaskClient: - virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) OVERRIDE { - return NULL; + scoped_ptr<RasterBuffer> AcquireBufferForRaster( + const Resource* resource) override { + return nullptr; } - virtual void ReleaseCanvasForRaster(RasterTask* task) OVERRIDE {} + void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override {} private: RasterTask::Vector completed_tasks_; @@ -106,31 +111,27 @@ class TileManagerPerfTest : public testing::Test { host_impl_.tile_manager()->SetGlobalStateForTesting(state); } - virtual void SetUp() OVERRIDE { - picture_pile_ = FakePicturePileImpl::CreateInfiniteFilledPile(); + virtual void SetUp() override { InitializeRenderer(); SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES); } virtual void InitializeRenderer() { - host_impl_.InitializeRenderer( - FakeOutputSurface::Create3d().PassAs<OutputSurface>()); + host_impl_.InitializeRenderer(FakeOutputSurface::Create3d().Pass()); tile_manager()->SetRasterizerForTesting(g_fake_rasterizer.Pointer()); } void SetupDefaultTrees(const gfx::Size& layer_bounds) { - gfx::Size tile_size(100, 100); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + FakePicturePileImpl::CreateFilledPile(kDefaultTileSize, layer_bounds); scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + FakePicturePileImpl::CreateFilledPile(kDefaultTileSize, layer_bounds); SetupTrees(pending_pile, active_pile); } void ActivateTree() { - host_impl_.ActivatePendingTree(); + host_impl_.ActivateSyncTree(); CHECK(!host_impl_.pending_tree()); pending_root_layer_ = NULL; active_root_layer_ = static_cast<FakePictureLayerImpl*>( @@ -160,7 +161,7 @@ class TileManagerPerfTest : public testing::Test { scoped_ptr<FakePictureLayerImpl> pending_layer = FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile); pending_layer->SetDrawsContent(true); - pending_tree->SetRootLayer(pending_layer.PassAs<LayerImpl>()); + pending_tree->SetRootLayer(pending_layer.Pass()); pending_root_layer_ = static_cast<FakePictureLayerImpl*>( host_impl_.pending_tree()->LayerById(id_)); @@ -175,22 +176,100 @@ class TileManagerPerfTest : public testing::Test { pending_root_layer_->SetAllTilesVisible(); } - void RunRasterIteratorTest(const std::string& test_name, - unsigned tile_count) { + void RunRasterQueueConstructTest(const std::string& test_name, + int layer_count) { + TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES, + SMOOTHNESS_TAKES_PRIORITY, + NEW_CONTENT_TAKES_PRIORITY}; + int priority_count = 0; + + std::vector<LayerImpl*> layers = CreateLayers(layer_count, 10); + bool resourceless_software_draw = false; + for (unsigned i = 0; i < layers.size(); ++i) { + layers[i]->UpdateTiles(Occlusion(), resourceless_software_draw); + } + + timer_.Reset(); + do { + RasterTilePriorityQueue queue; + host_impl_.BuildRasterQueue(&queue, priorities[priority_count]); + priority_count = (priority_count + 1) % arraysize(priorities); + timer_.NextLap(); + } while (!timer_.HasTimeLimitExpired()); + + perf_test::PrintResult("tile_manager_raster_tile_queue_construct", + "", + test_name, + timer_.LapsPerSecond(), + "runs/s", + true); + } + + void RunRasterQueueConstructAndIterateTest(const std::string& test_name, + int layer_count, + unsigned tile_count) { + TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES, + SMOOTHNESS_TAKES_PRIORITY, + NEW_CONTENT_TAKES_PRIORITY}; + + std::vector<LayerImpl*> layers = CreateLayers(layer_count, 100); + bool resourceless_software_draw = false; + for (unsigned i = 0; i < layers.size(); ++i) { + layers[i]->UpdateTiles(Occlusion(), resourceless_software_draw); + } + + int priority_count = 0; timer_.Reset(); do { int count = tile_count; - for (TileManager::RasterTileIterator it(tile_manager(), - SAME_PRIORITY_FOR_BOTH_TREES); - it && count; - ++it) { - --count; + RasterTilePriorityQueue queue; + host_impl_.BuildRasterQueue(&queue, priorities[priority_count]); + while (count--) { + ASSERT_FALSE(queue.IsEmpty()); + ASSERT_TRUE(queue.Top() != NULL); + queue.Pop(); + } + priority_count = (priority_count + 1) % arraysize(priorities); + timer_.NextLap(); + } while (!timer_.HasTimeLimitExpired()); + + perf_test::PrintResult( + "tile_manager_raster_tile_queue_construct_and_iterate", + "", + test_name, + timer_.LapsPerSecond(), + "runs/s", + true); + } + + void RunEvictionQueueConstructTest(const std::string& test_name, + int layer_count) { + TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES, + SMOOTHNESS_TAKES_PRIORITY, + NEW_CONTENT_TAKES_PRIORITY}; + int priority_count = 0; + + std::vector<LayerImpl*> layers = CreateLayers(layer_count, 10); + bool resourceless_software_draw = false; + for (unsigned i = 0; i < layers.size(); ++i) { + FakePictureLayerImpl* layer = + static_cast<FakePictureLayerImpl*>(layers[i]); + layer->UpdateTiles(Occlusion(), resourceless_software_draw); + for (size_t j = 0; j < layer->GetTilings()->num_tilings(); ++j) { + tile_manager()->InitializeTilesWithResourcesForTesting( + layer->GetTilings()->tiling_at(j)->AllTilesForTesting()); } - ASSERT_EQ(0, count); + } + + timer_.Reset(); + do { + EvictionTilePriorityQueue queue; + host_impl_.BuildEvictionQueue(&queue, priorities[priority_count]); + priority_count = (priority_count + 1) % arraysize(priorities); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); - perf_test::PrintResult("tile_manager_raster_tile_iterator", + perf_test::PrintResult("tile_manager_eviction_tile_queue_construct", "", test_name, timer_.LapsPerSecond(), @@ -198,6 +277,49 @@ class TileManagerPerfTest : public testing::Test { true); } + void RunEvictionQueueConstructAndIterateTest(const std::string& test_name, + int layer_count, + unsigned tile_count) { + TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES, + SMOOTHNESS_TAKES_PRIORITY, + NEW_CONTENT_TAKES_PRIORITY}; + int priority_count = 0; + + std::vector<LayerImpl*> layers = CreateLayers(layer_count, tile_count); + bool resourceless_software_draw = false; + for (unsigned i = 0; i < layers.size(); ++i) { + FakePictureLayerImpl* layer = + static_cast<FakePictureLayerImpl*>(layers[i]); + layer->UpdateTiles(Occlusion(), resourceless_software_draw); + for (size_t j = 0; j < layer->GetTilings()->num_tilings(); ++j) { + tile_manager()->InitializeTilesWithResourcesForTesting( + layer->GetTilings()->tiling_at(j)->AllTilesForTesting()); + } + } + + timer_.Reset(); + do { + int count = tile_count; + EvictionTilePriorityQueue queue; + host_impl_.BuildEvictionQueue(&queue, priorities[priority_count]); + while (count--) { + ASSERT_FALSE(queue.IsEmpty()); + ASSERT_TRUE(queue.Top() != NULL); + queue.Pop(); + } + priority_count = (priority_count + 1) % arraysize(priorities); + timer_.NextLap(); + } while (!timer_.HasTimeLimitExpired()); + + perf_test::PrintResult( + "tile_manager_eviction_tile_queue_construct_and_iterate", + "", + test_name, + timer_.LapsPerSecond(), + "runs/s", + true); + } + std::vector<LayerImpl*> CreateLayers(int layer_count, int tiles_per_layer_count) { // Compute the width/height required for high res to get @@ -217,7 +339,7 @@ class TileManagerPerfTest : public testing::Test { // Ensure that we start with blank trees and no tiles. host_impl_.ResetTreesForTesting(); - tile_manager()->CleanUpReleasedTilesForTesting(); + tile_manager()->FreeResourcesAndCleanUpReleasedTilesForTesting(); gfx::Size layer_bounds(width, height); gfx::Size viewport(width / 5, height / 5); @@ -235,13 +357,15 @@ class TileManagerPerfTest : public testing::Test { int next_id = id_ + 1; // Create the rest of the layers as children of the root layer. + scoped_refptr<FakePicturePileImpl> pile = + FakePicturePileImpl::CreateFilledPile(kDefaultTileSize, layer_bounds); while (static_cast<int>(layers.size()) < layer_count) { scoped_ptr<FakePictureLayerImpl> layer = - FakePictureLayerImpl::CreateWithPile( - host_impl_.pending_tree(), next_id, picture_pile_); + FakePictureLayerImpl::CreateWithPile(host_impl_.pending_tree(), + next_id, pile); layer->SetBounds(layer_bounds); layers.push_back(layer.get()); - pending_root_layer_->AddChild(layer.PassAs<LayerImpl>()); + pending_root_layer_->AddChild(layer.Pass()); FakePictureLayerImpl* fake_layer = static_cast<FakePictureLayerImpl*>(layers.back()); @@ -274,16 +398,19 @@ class TileManagerPerfTest : public testing::Test { std::vector<LayerImpl*> layers = CreateLayers(layer_count, approximate_tile_count_per_layer); timer_.Reset(); + bool resourceless_software_draw = false; do { - host_impl_.UpdateCurrentFrameTime(); - for (unsigned i = 0; i < layers.size(); ++i) - layers[i]->UpdateTiles(); + BeginFrameArgs args = CreateBeginFrameArgsForTesting(); + host_impl_.UpdateCurrentBeginFrameArgs(args); + for (unsigned i = 0; i < layers.size(); ++i) { + layers[i]->UpdateTiles(Occlusion(), resourceless_software_draw); + } GlobalStateThatImpactsTilePriority global_state(GlobalStateForTest()); tile_manager()->ManageTiles(global_state); tile_manager()->UpdateVisibleTiles(); timer_.NextLap(); - host_impl_.ResetCurrentFrameTimeForNextFrame(); + host_impl_.ResetCurrentBeginFrameArgsForNextFrame(); } while (!timer_.HasTimeLimitExpired()); perf_test::PrintResult( @@ -304,34 +431,65 @@ class TileManagerPerfTest : public testing::Test { FakePictureLayerImpl* pending_root_layer_; FakePictureLayerImpl* active_root_layer_; LapTimer timer_; - scoped_refptr<FakePicturePileImpl> picture_pile_; LayerTreeSettings settings_; + + static const gfx::Size kDefaultTileSize; }; +const gfx::Size TileManagerPerfTest::kDefaultTileSize(100, 100); + TEST_F(TileManagerPerfTest, ManageTiles) { - RunManageTilesTest("1_100", 1, 100); - RunManageTilesTest("1_500", 1, 500); - RunManageTilesTest("1_1000", 1, 1000); - RunManageTilesTest("5_100", 5, 100); - RunManageTilesTest("5_500", 5, 500); - RunManageTilesTest("5_1000", 5, 1000); + RunManageTilesTest("2_100", 2, 100); + RunManageTilesTest("2_500", 2, 500); + RunManageTilesTest("2_1000", 2, 1000); RunManageTilesTest("10_100", 10, 100); RunManageTilesTest("10_500", 10, 500); RunManageTilesTest("10_1000", 10, 1000); - RunManageTilesTest("100_100", 100, 100); - RunManageTilesTest("100_500", 100, 500); - RunManageTilesTest("100_1000", 100, 1000); + RunManageTilesTest("50_100", 100, 100); + RunManageTilesTest("50_500", 100, 500); + RunManageTilesTest("50_1000", 100, 1000); +} + +TEST_F(TileManagerPerfTest, RasterTileQueueConstruct) { + RunRasterQueueConstructTest("2", 2); + RunRasterQueueConstructTest("10", 10); + RunRasterQueueConstructTest("50", 50); } -TEST_F(TileManagerPerfTest, RasterTileIterator) { - SetupDefaultTrees(gfx::Size(10000, 10000)); - active_root_layer_->CreateDefaultTilingsAndTiles(); - pending_root_layer_->CreateDefaultTilingsAndTiles(); +TEST_F(TileManagerPerfTest, RasterTileQueueConstructAndIterate) { + RunRasterQueueConstructAndIterateTest("2_16", 2, 16); + RunRasterQueueConstructAndIterateTest("2_32", 2, 32); + RunRasterQueueConstructAndIterateTest("2_64", 2, 64); + RunRasterQueueConstructAndIterateTest("2_128", 2, 128); + RunRasterQueueConstructAndIterateTest("10_16", 10, 16); + RunRasterQueueConstructAndIterateTest("10_32", 10, 32); + RunRasterQueueConstructAndIterateTest("10_64", 10, 64); + RunRasterQueueConstructAndIterateTest("10_128", 10, 128); + RunRasterQueueConstructAndIterateTest("50_16", 50, 16); + RunRasterQueueConstructAndIterateTest("50_32", 50, 32); + RunRasterQueueConstructAndIterateTest("50_64", 50, 64); + RunRasterQueueConstructAndIterateTest("50_128", 50, 128); +} + +TEST_F(TileManagerPerfTest, EvictionTileQueueConstruct) { + RunEvictionQueueConstructTest("2", 2); + RunEvictionQueueConstructTest("10", 10); + RunEvictionQueueConstructTest("50", 50); +} - RunRasterIteratorTest("2_16", 16); - RunRasterIteratorTest("2_32", 32); - RunRasterIteratorTest("2_64", 64); - RunRasterIteratorTest("2_128", 128); +TEST_F(TileManagerPerfTest, EvictionTileQueueConstructAndIterate) { + RunEvictionQueueConstructAndIterateTest("2_16", 2, 16); + RunEvictionQueueConstructAndIterateTest("2_32", 2, 32); + RunEvictionQueueConstructAndIterateTest("2_64", 2, 64); + RunEvictionQueueConstructAndIterateTest("2_128", 2, 128); + RunEvictionQueueConstructAndIterateTest("10_16", 10, 16); + RunEvictionQueueConstructAndIterateTest("10_32", 10, 32); + RunEvictionQueueConstructAndIterateTest("10_64", 10, 64); + RunEvictionQueueConstructAndIterateTest("10_128", 10, 128); + RunEvictionQueueConstructAndIterateTest("50_16", 50, 16); + RunEvictionQueueConstructAndIterateTest("50_32", 50, 32); + RunEvictionQueueConstructAndIterateTest("50_64", 50, 64); + RunEvictionQueueConstructAndIterateTest("50_128", 50, 128); } } // namespace diff --git a/chromium/cc/resources/tile_manager_unittest.cc b/chromium/cc/resources/tile_manager_unittest.cc index f894c4f9c98..2f0735c33d3 100644 --- a/chromium/cc/resources/tile_manager_unittest.cc +++ b/chromium/cc/resources/tile_manager_unittest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "cc/resources/eviction_tile_priority_queue.h" +#include "cc/resources/raster_tile_priority_queue.h" #include "cc/resources/tile.h" #include "cc/resources/tile_priority.h" #include "cc/test/fake_impl_proxy.h" @@ -20,421 +22,20 @@ namespace cc { namespace { -class TileManagerTest : public testing::TestWithParam<bool>, - public TileManagerClient { +class LowResTilingsSettings : public ImplSidePaintingSettings { public: - typedef std::vector<scoped_refptr<Tile> > TileVector; - - TileManagerTest() - : memory_limit_policy_(ALLOW_ANYTHING), - max_tiles_(0), - ready_to_activate_(false) {} - - void Initialize(int max_tiles, - TileMemoryLimitPolicy memory_limit_policy, - TreePriority tree_priority) { - output_surface_ = FakeOutputSurface::Create3d(); - CHECK(output_surface_->BindToClient(&output_surface_client_)); - - shared_bitmap_manager_.reset(new TestSharedBitmapManager()); - resource_provider_ = ResourceProvider::Create( - output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, - false); - resource_pool_ = ResourcePool::Create( - resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888); - tile_manager_ = - make_scoped_ptr(new FakeTileManager(this, resource_pool_.get())); - - memory_limit_policy_ = memory_limit_policy; - max_tiles_ = max_tiles; - picture_pile_ = FakePicturePileImpl::CreateInfiniteFilledPile(); - - SetTreePriority(tree_priority); - } - - void SetTreePriority(TreePriority tree_priority) { - GlobalStateThatImpactsTilePriority state; - gfx::Size tile_size = settings_.default_tile_size; - - if (UsingMemoryLimit()) { - state.soft_memory_limit_in_bytes = - max_tiles_ * 4 * tile_size.width() * tile_size.height(); - state.num_resources_limit = 100; - } else { - state.soft_memory_limit_in_bytes = 100 * 1000 * 1000; - state.num_resources_limit = max_tiles_; - } - state.hard_memory_limit_in_bytes = state.soft_memory_limit_in_bytes * 2; - state.memory_limit_policy = memory_limit_policy_; - state.tree_priority = tree_priority; - - global_state_ = state; - resource_pool_->SetResourceUsageLimits(state.soft_memory_limit_in_bytes, - state.soft_memory_limit_in_bytes, - state.num_resources_limit); - tile_manager_->SetGlobalStateForTesting(state); - } - - virtual void TearDown() OVERRIDE { - tile_manager_.reset(NULL); - picture_pile_ = NULL; - - testing::Test::TearDown(); - } - - // TileManagerClient implementation. - virtual const std::vector<PictureLayerImpl*>& GetPictureLayers() OVERRIDE { - return picture_layers_; - } - virtual void NotifyReadyToActivate() OVERRIDE { ready_to_activate_ = true; } - virtual void NotifyTileStateChanged(const Tile* tile) OVERRIDE {} - - TileVector CreateTilesWithSize(int count, - TilePriority active_priority, - TilePriority pending_priority, - const gfx::Size& tile_size) { - TileVector tiles; - for (int i = 0; i < count; ++i) { - scoped_refptr<Tile> tile = tile_manager_->CreateTile(picture_pile_.get(), - tile_size, - gfx::Rect(), - gfx::Rect(), - 1.0, - 0, - 0, - 0); - tile->SetPriority(ACTIVE_TREE, active_priority); - tile->SetPriority(PENDING_TREE, pending_priority); - tiles.push_back(tile); - } - return tiles; - } - - TileVector CreateTiles(int count, - TilePriority active_priority, - TilePriority pending_priority) { - return CreateTilesWithSize( - count, active_priority, pending_priority, settings_.default_tile_size); - } - - FakeTileManager* tile_manager() { return tile_manager_.get(); } - - int AssignedMemoryCount(const TileVector& tiles) { - int has_memory_count = 0; - for (TileVector::const_iterator it = tiles.begin(); it != tiles.end(); - ++it) { - if (tile_manager_->HasBeenAssignedMemory(*it)) - ++has_memory_count; - } - return has_memory_count; - } - - bool ready_to_activate() const { return ready_to_activate_; } - - // The parametrization specifies whether the max tile limit should - // be applied to memory or resources. - bool UsingResourceLimit() { return !GetParam(); } - bool UsingMemoryLimit() { return GetParam(); } - - protected: - GlobalStateThatImpactsTilePriority global_state_; - - private: - LayerTreeSettings settings_; - scoped_ptr<FakeTileManager> tile_manager_; - scoped_refptr<FakePicturePileImpl> picture_pile_; - FakeOutputSurfaceClient output_surface_client_; - scoped_ptr<FakeOutputSurface> output_surface_; - scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; - scoped_ptr<ResourceProvider> resource_provider_; - scoped_ptr<ResourcePool> resource_pool_; - TileMemoryLimitPolicy memory_limit_policy_; - int max_tiles_; - bool ready_to_activate_; - std::vector<PictureLayerImpl*> picture_layers_; + LowResTilingsSettings() { create_low_res_tiling = true; } }; -TEST_P(TileManagerTest, EnoughMemoryAllowAnything) { - // A few tiles of each type of priority, with enough memory for all tiles. - - Initialize(10, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY); - TileVector active_now = - CreateTiles(3, TilePriorityForNowBin(), TilePriority()); - TileVector pending_now = - CreateTiles(3, TilePriority(), TilePriorityForNowBin()); - TileVector active_pending_soon = - CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin()); - TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority()); - - tile_manager()->AssignMemoryToTiles(global_state_); - - EXPECT_EQ(3, AssignedMemoryCount(active_now)); - EXPECT_EQ(3, AssignedMemoryCount(pending_now)); - EXPECT_EQ(3, AssignedMemoryCount(active_pending_soon)); - EXPECT_EQ(0, AssignedMemoryCount(never_bin)); -} - -TEST_P(TileManagerTest, EnoughMemoryAllowPrepaintOnly) { - // A few tiles of each type of priority, with enough memory for all tiles, - // with the exception of never bin. - - Initialize(10, ALLOW_PREPAINT_ONLY, SMOOTHNESS_TAKES_PRIORITY); - TileVector active_now = - CreateTiles(3, TilePriorityForNowBin(), TilePriority()); - TileVector pending_now = - CreateTiles(3, TilePriority(), TilePriorityForNowBin()); - TileVector active_pending_soon = - CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin()); - TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority()); - - tile_manager()->AssignMemoryToTiles(global_state_); - - EXPECT_EQ(3, AssignedMemoryCount(active_now)); - EXPECT_EQ(3, AssignedMemoryCount(pending_now)); - EXPECT_EQ(3, AssignedMemoryCount(active_pending_soon)); - EXPECT_EQ(0, AssignedMemoryCount(never_bin)); -} - -TEST_P(TileManagerTest, EnoughMemoryPendingLowResAllowAbsoluteMinimum) { - // A few low-res tiles required for activation, with enough memory for all - // tiles. - - Initialize(5, ALLOW_ABSOLUTE_MINIMUM, SAME_PRIORITY_FOR_BOTH_TREES); - TileVector pending_low_res = - CreateTiles(5, TilePriority(), TilePriorityLowRes()); - - tile_manager()->AssignMemoryToTiles(global_state_); - - EXPECT_EQ(5, AssignedMemoryCount(pending_low_res)); -} - -TEST_P(TileManagerTest, EnoughMemoryAllowAbsoluteMinimum) { - // A few tiles of each type of priority, with enough memory for all tiles, - // with the exception of never and soon bins. - - Initialize(10, ALLOW_ABSOLUTE_MINIMUM, SMOOTHNESS_TAKES_PRIORITY); - TileVector active_now = - CreateTiles(3, TilePriorityForNowBin(), TilePriority()); - TileVector pending_now = - CreateTiles(3, TilePriority(), TilePriorityForNowBin()); - TileVector active_pending_soon = - CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin()); - TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority()); - - tile_manager()->AssignMemoryToTiles(global_state_); - - EXPECT_EQ(3, AssignedMemoryCount(active_now)); - EXPECT_EQ(3, AssignedMemoryCount(pending_now)); - EXPECT_EQ(0, AssignedMemoryCount(active_pending_soon)); - EXPECT_EQ(0, AssignedMemoryCount(never_bin)); -} - -TEST_P(TileManagerTest, EnoughMemoryAllowNothing) { - // A few tiles of each type of priority, with enough memory for all tiles, - // but allow nothing should not assign any memory. - - Initialize(10, ALLOW_NOTHING, SMOOTHNESS_TAKES_PRIORITY); - TileVector active_now = - CreateTiles(3, TilePriorityForNowBin(), TilePriority()); - TileVector pending_now = - CreateTiles(3, TilePriority(), TilePriorityForNowBin()); - TileVector active_pending_soon = - CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin()); - TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority()); - - tile_manager()->AssignMemoryToTiles(global_state_); - - EXPECT_EQ(0, AssignedMemoryCount(active_now)); - EXPECT_EQ(0, AssignedMemoryCount(pending_now)); - EXPECT_EQ(0, AssignedMemoryCount(active_pending_soon)); - EXPECT_EQ(0, AssignedMemoryCount(never_bin)); -} - -TEST_P(TileManagerTest, PartialOOMMemoryToPending) { - // 5 tiles on active tree eventually bin, 5 tiles on pending tree that are - // required for activation, but only enough memory for 8 tiles. The result - // is all pending tree tiles get memory, and 3 of the active tree tiles - // get memory. None of these tiles is needed to avoid calimity (flickering or - // raster-on-demand) so the soft memory limit is used. - - Initialize(8, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY); - TileVector active_tree_tiles = - CreateTiles(5, TilePriorityForEventualBin(), TilePriority()); - TileVector pending_tree_tiles = - CreateTiles(5, TilePriority(), TilePriorityRequiredForActivation()); - tile_manager()->AssignMemoryToTiles(global_state_); - - EXPECT_EQ(5, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(3, AssignedMemoryCount(pending_tree_tiles)); - - SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES); - tile_manager()->AssignMemoryToTiles(global_state_); - - EXPECT_EQ(3, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(5, AssignedMemoryCount(pending_tree_tiles)); -} - -TEST_P(TileManagerTest, PartialOOMMemoryToActive) { - // 5 tiles on active tree eventually bin, 5 tiles on pending tree now bin, - // but only enough memory for 8 tiles. The result is all active tree tiles - // get memory, and 3 of the pending tree tiles get memory. - // The pending tiles are not needed to avoid calimity (flickering or - // raster-on-demand) and the active tiles fit, so the soft limit is used. - - Initialize(8, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY); - TileVector active_tree_tiles = - CreateTiles(5, TilePriorityForNowBin(), TilePriority()); - TileVector pending_tree_tiles = - CreateTiles(5, TilePriority(), TilePriorityForNowBin()); - - tile_manager()->AssignMemoryToTiles(global_state_); - - EXPECT_EQ(5, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(3, AssignedMemoryCount(pending_tree_tiles)); -} - -TEST_P(TileManagerTest, TotalOOMMemoryToPending) { - // 10 tiles on active tree eventually bin, 10 tiles on pending tree that are - // required for activation, but only enough tiles for 4 tiles. The result - // is 4 pending tree tiles get memory, and none of the active tree tiles - // get memory. - - Initialize(4, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY); - TileVector active_tree_tiles = - CreateTiles(10, TilePriorityForEventualBin(), TilePriority()); - TileVector pending_tree_tiles = - CreateTiles(10, TilePriority(), TilePriorityRequiredForActivation()); - - tile_manager()->AssignMemoryToTiles(global_state_); - - EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles)); - - SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES); - tile_manager()->AssignMemoryToTiles(global_state_); - - if (UsingResourceLimit()) { - EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(4, AssignedMemoryCount(pending_tree_tiles)); - } else { - // Pending tiles are now required to avoid calimity (flickering or - // raster-on-demand). Hard-limit is used and double the tiles fit. - EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(8, AssignedMemoryCount(pending_tree_tiles)); - } -} - -TEST_P(TileManagerTest, TotalOOMActiveSoonMemoryToPending) { - // 10 tiles on active tree soon bin, 10 tiles on pending tree that are - // required for activation, but only enough tiles for 4 tiles. The result - // is 4 pending tree tiles get memory, and none of the active tree tiles - // get memory. - - Initialize(4, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY); - TileVector active_tree_tiles = - CreateTiles(10, TilePriorityForSoonBin(), TilePriority()); - TileVector pending_tree_tiles = - CreateTiles(10, TilePriority(), TilePriorityRequiredForActivation()); - - tile_manager()->AssignMemoryToTiles(global_state_); - - EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles)); - - SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES); - tile_manager()->AssignMemoryToTiles(global_state_); - - if (UsingResourceLimit()) { - EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(4, AssignedMemoryCount(pending_tree_tiles)); - } else { - // Pending tiles are now required to avoid calimity (flickering or - // raster-on-demand). Hard-limit is used and double the tiles fit. - EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(8, AssignedMemoryCount(pending_tree_tiles)); - } -} - -TEST_P(TileManagerTest, TotalOOMMemoryToActive) { - // 10 tiles on active tree eventually bin, 10 tiles on pending tree now bin, - // but only enough memory for 4 tiles. The result is 4 active tree tiles - // get memory, and none of the pending tree tiles get memory. - - Initialize(4, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY); - TileVector active_tree_tiles = - CreateTiles(10, TilePriorityForNowBin(), TilePriority()); - TileVector pending_tree_tiles = - CreateTiles(10, TilePriority(), TilePriorityForNowBin()); - - tile_manager()->AssignMemoryToTiles(global_state_); - - if (UsingResourceLimit()) { - EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles)); - } else { - // Active tiles are required to avoid calimity (flickering or - // raster-on-demand). Hard-limit is used and double the tiles fit. - EXPECT_EQ(8, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles)); - } -} - -TEST_P(TileManagerTest, TotalOOMMemoryToNewContent) { - // 10 tiles on active tree now bin, 10 tiles on pending tree now bin, - // but only enough memory for 8 tiles. Any tile missing would cause - // a calamity (flickering or raster-on-demand). Depending on mode, - // we should use varying amounts of the higher hard memory limit. - if (UsingResourceLimit()) - return; - - Initialize(8, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY); - TileVector active_tree_tiles = - CreateTiles(10, TilePriorityForNowBin(), TilePriority()); - TileVector pending_tree_tiles = - CreateTiles(10, TilePriority(), TilePriorityForNowBin()); - - // Active tiles are required to avoid calimity. The hard-limit is used and all - // active-tiles fit. No pending tiles are needed to avoid calamity so only 10 - // tiles total are used. - tile_manager()->AssignMemoryToTiles(global_state_); - EXPECT_EQ(10, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles)); - - // Even the hard-limit won't save us now. All tiles are required to avoid - // a clamity but we only have 16. The tiles will be distribted randomly - // given they are identical, in practice depending on their screen location. - SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES); - tile_manager()->AssignMemoryToTiles(global_state_); - EXPECT_EQ(16, - AssignedMemoryCount(active_tree_tiles) + - AssignedMemoryCount(pending_tree_tiles)); - - // The pending tree is now more important. Active tiles will take higher - // priority if they are ready-to-draw in practice. Importantly though, - // pending tiles also utilize the hard-limit. - SetTreePriority(NEW_CONTENT_TAKES_PRIORITY); - tile_manager()->AssignMemoryToTiles(global_state_); - EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles)); - EXPECT_EQ(10, AssignedMemoryCount(pending_tree_tiles)); -} - -// If true, the max tile limit should be applied as bytes; if false, -// as num_resources_limit. -INSTANTIATE_TEST_CASE_P(TileManagerTests, - TileManagerTest, - ::testing::Values(true, false)); - -class TileManagerTileIteratorTest : public testing::Test { +class TileManagerTilePriorityQueueTest : public testing::Test { public: - TileManagerTileIteratorTest() + TileManagerTilePriorityQueueTest() : memory_limit_policy_(ALLOW_ANYTHING), max_tiles_(10000), ready_to_activate_(false), id_(7), proxy_(base::MessageLoopProxy::current()), - host_impl_(ImplSidePaintingSettings(), - &proxy_, - &shared_bitmap_manager_) {} + host_impl_(LowResTilingsSettings(), &proxy_, &shared_bitmap_manager_) {} void SetTreePriority(TreePriority tree_priority) { GlobalStateThatImpactsTilePriority state; @@ -454,14 +55,13 @@ class TileManagerTileIteratorTest : public testing::Test { host_impl_.tile_manager()->SetGlobalStateForTesting(state); } - virtual void SetUp() OVERRIDE { + virtual void SetUp() override { InitializeRenderer(); SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES); } virtual void InitializeRenderer() { - host_impl_.InitializeRenderer( - FakeOutputSurface::Create3d().PassAs<OutputSurface>()); + host_impl_.InitializeRenderer(FakeOutputSurface::Create3d()); } void SetupDefaultTrees(const gfx::Size& layer_bounds) { @@ -476,7 +76,7 @@ class TileManagerTileIteratorTest : public testing::Test { } void ActivateTree() { - host_impl_.ActivatePendingTree(); + host_impl_.ActivateSyncTree(); CHECK(!host_impl_.pending_tree()); pending_layer_ = NULL; active_layer_ = static_cast<FakePictureLayerImpl*>( @@ -500,13 +100,24 @@ class TileManagerTileIteratorTest : public testing::Test { void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) { host_impl_.CreatePendingTree(); LayerTreeImpl* pending_tree = host_impl_.pending_tree(); - // Clear recycled tree. - pending_tree->DetachLayerTree(); - scoped_ptr<FakePictureLayerImpl> pending_layer = - FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile); - pending_layer->SetDrawsContent(true); - pending_tree->SetRootLayer(pending_layer.PassAs<LayerImpl>()); + // Steal from the recycled tree. + scoped_ptr<LayerImpl> old_pending_root = pending_tree->DetachLayerTree(); + DCHECK_IMPLIES(old_pending_root, old_pending_root->id() == id_); + + scoped_ptr<FakePictureLayerImpl> pending_layer; + if (old_pending_root) { + pending_layer.reset( + static_cast<FakePictureLayerImpl*>(old_pending_root.release())); + pending_layer->SetPile(pile); + } else { + pending_layer = + FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile); + pending_layer->SetDrawsContent(true); + } + // The bounds() just mirror the pile size. + pending_layer->SetBounds(pending_layer->pile()->tiling_size()); + pending_tree->SetRootLayer(pending_layer.Pass()); pending_layer_ = static_cast<FakePictureLayerImpl*>( host_impl_.pending_tree()->LayerById(id_)); @@ -537,121 +148,79 @@ class TileManagerTileIteratorTest : public testing::Test { FakePictureLayerImpl* active_layer_; }; -TEST_F(TileManagerTileIteratorTest, PairedPictureLayers) { - host_impl_.CreatePendingTree(); - host_impl_.ActivatePendingTree(); - host_impl_.CreatePendingTree(); - - LayerTreeImpl* active_tree = host_impl_.active_tree(); - LayerTreeImpl* pending_tree = host_impl_.pending_tree(); - EXPECT_NE(active_tree, pending_tree); - - scoped_ptr<FakePictureLayerImpl> active_layer = - FakePictureLayerImpl::Create(active_tree, 10); - scoped_ptr<FakePictureLayerImpl> pending_layer = - FakePictureLayerImpl::Create(pending_tree, 10); - - TileManager* tile_manager = TileManagerTileIteratorTest::tile_manager(); - EXPECT_TRUE(tile_manager); - - std::vector<TileManager::PairedPictureLayer> paired_layers; - tile_manager->GetPairedPictureLayers(&paired_layers); - - EXPECT_EQ(2u, paired_layers.size()); - if (paired_layers[0].active_layer) { - EXPECT_EQ(active_layer.get(), paired_layers[0].active_layer); - EXPECT_EQ(NULL, paired_layers[0].pending_layer); - } else { - EXPECT_EQ(pending_layer.get(), paired_layers[0].pending_layer); - EXPECT_EQ(NULL, paired_layers[0].active_layer); - } - - if (paired_layers[1].active_layer) { - EXPECT_EQ(active_layer.get(), paired_layers[1].active_layer); - EXPECT_EQ(NULL, paired_layers[1].pending_layer); - } else { - EXPECT_EQ(pending_layer.get(), paired_layers[1].pending_layer); - EXPECT_EQ(NULL, paired_layers[1].active_layer); - } - - active_layer->set_twin_layer(pending_layer.get()); - pending_layer->set_twin_layer(active_layer.get()); - - tile_manager->GetPairedPictureLayers(&paired_layers); - EXPECT_EQ(1u, paired_layers.size()); - - EXPECT_EQ(active_layer.get(), paired_layers[0].active_layer); - EXPECT_EQ(pending_layer.get(), paired_layers[0].pending_layer); -} - -TEST_F(TileManagerTileIteratorTest, RasterTileIterator) { +TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueue) { SetupDefaultTrees(gfx::Size(1000, 1000)); - TileManager* tile_manager = TileManagerTileIteratorTest::tile_manager(); - EXPECT_TRUE(tile_manager); active_layer_->CreateDefaultTilingsAndTiles(); pending_layer_->CreateDefaultTilingsAndTiles(); - std::vector<TileManager::PairedPictureLayer> paired_layers; - tile_manager->GetPairedPictureLayers(&paired_layers); - EXPECT_EQ(1u, paired_layers.size()); - - TileManager::RasterTileIterator it(tile_manager, - SAME_PRIORITY_FOR_BOTH_TREES); - EXPECT_TRUE(it); + RasterTilePriorityQueue queue; + host_impl_.BuildRasterQueue(&queue, SAME_PRIORITY_FOR_BOTH_TREES); + EXPECT_FALSE(queue.IsEmpty()); size_t tile_count = 0; std::set<Tile*> all_tiles; - for (; it; ++it) { - EXPECT_TRUE(*it); - all_tiles.insert(*it); + while (!queue.IsEmpty()) { + EXPECT_TRUE(queue.Top()); + all_tiles.insert(queue.Top()); ++tile_count; + queue.Pop(); } EXPECT_EQ(tile_count, all_tiles.size()); - EXPECT_EQ(17u, tile_count); + EXPECT_EQ(16u, tile_count); // Sanity check, all tiles should be visible. std::set<Tile*> smoothness_tiles; - for (TileManager::RasterTileIterator it(tile_manager, - SMOOTHNESS_TAKES_PRIORITY); - it; - ++it) { - Tile* tile = *it; + queue.Reset(); + host_impl_.BuildRasterQueue(&queue, SMOOTHNESS_TAKES_PRIORITY); + bool had_low_res = false; + while (!queue.IsEmpty()) { + Tile* tile = queue.Top(); EXPECT_TRUE(tile); EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin); EXPECT_EQ(TilePriority::NOW, tile->priority(PENDING_TREE).priority_bin); - smoothness_tiles.insert(tile); + if (tile->priority(ACTIVE_TREE).resolution == LOW_RESOLUTION) + had_low_res = true; + else + smoothness_tiles.insert(tile); + queue.Pop(); } EXPECT_EQ(all_tiles, smoothness_tiles); + EXPECT_TRUE(had_low_res); Region invalidation(gfx::Rect(0, 0, 500, 500)); // Invalidate the pending tree. pending_layer_->set_invalidation(invalidation); - pending_layer_->HighResTiling()->Invalidate(invalidation); - pending_layer_->LowResTiling()->Invalidate(invalidation); + pending_layer_->HighResTiling()->UpdateTilesToCurrentPile( + invalidation, gfx::Size(1000, 1000)); + pending_layer_->LowResTiling()->UpdateTilesToCurrentPile( + invalidation, gfx::Size(1000, 1000)); active_layer_->ResetAllTilesPriorities(); pending_layer_->ResetAllTilesPriorities(); // Renew all of the tile priorities. gfx::Rect viewport(50, 50, 100, 100); - pending_layer_->HighResTiling()->UpdateTilePriorities( - PENDING_TREE, viewport, 1.0f, 1.0); - pending_layer_->LowResTiling()->UpdateTilePriorities( - PENDING_TREE, viewport, 1.0f, 1.0); - active_layer_->HighResTiling()->UpdateTilePriorities( - ACTIVE_TREE, viewport, 1.0f, 1.0); - active_layer_->LowResTiling()->UpdateTilePriorities( - ACTIVE_TREE, viewport, 1.0f, 1.0); + pending_layer_->HighResTiling()->ComputeTilePriorityRects( + PENDING_TREE, viewport, 1.0f, 1.0, Occlusion()); + pending_layer_->LowResTiling()->ComputeTilePriorityRects( + PENDING_TREE, viewport, 1.0f, 1.0, Occlusion()); + active_layer_->HighResTiling()->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion()); + active_layer_->LowResTiling()->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion()); // Populate all tiles directly from the tilings. all_tiles.clear(); + std::set<Tile*> high_res_tiles; std::vector<Tile*> pending_high_res_tiles = pending_layer_->HighResTiling()->AllTilesForTesting(); - for (size_t i = 0; i < pending_high_res_tiles.size(); ++i) + for (size_t i = 0; i < pending_high_res_tiles.size(); ++i) { all_tiles.insert(pending_high_res_tiles[i]); + high_res_tiles.insert(pending_high_res_tiles[i]); + } std::vector<Tile*> pending_low_res_tiles = pending_layer_->LowResTiling()->AllTilesForTesting(); @@ -660,8 +229,10 @@ TEST_F(TileManagerTileIteratorTest, RasterTileIterator) { std::vector<Tile*> active_high_res_tiles = active_layer_->HighResTiling()->AllTilesForTesting(); - for (size_t i = 0; i < active_high_res_tiles.size(); ++i) + for (size_t i = 0; i < active_high_res_tiles.size(); ++i) { all_tiles.insert(active_high_res_tiles[i]); + high_res_tiles.insert(active_high_res_tiles[i]); + } std::vector<Tile*> active_low_res_tiles = active_layer_->LowResTiling()->AllTilesForTesting(); @@ -671,13 +242,12 @@ TEST_F(TileManagerTileIteratorTest, RasterTileIterator) { Tile* last_tile = NULL; smoothness_tiles.clear(); tile_count = 0; - size_t increasing_distance_tiles = 0u; + size_t correct_order_tiles = 0u; // Here we expect to get increasing ACTIVE_TREE priority_bin. - for (TileManager::RasterTileIterator it(tile_manager, - SMOOTHNESS_TAKES_PRIORITY); - it; - ++it) { - Tile* tile = *it; + queue.Reset(); + host_impl_.BuildRasterQueue(&queue, SMOOTHNESS_TAKES_PRIORITY); + while (!queue.IsEmpty()) { + Tile* tile = queue.Top(); EXPECT_TRUE(tile); if (!last_tile) @@ -685,11 +255,19 @@ TEST_F(TileManagerTileIteratorTest, RasterTileIterator) { EXPECT_LE(last_tile->priority(ACTIVE_TREE).priority_bin, tile->priority(ACTIVE_TREE).priority_bin); + bool skip_updating_last_tile = false; if (last_tile->priority(ACTIVE_TREE).priority_bin == tile->priority(ACTIVE_TREE).priority_bin) { - increasing_distance_tiles += + correct_order_tiles += last_tile->priority(ACTIVE_TREE).distance_to_visible <= tile->priority(ACTIVE_TREE).distance_to_visible; + } else if (tile->priority(ACTIVE_TREE).priority_bin == + TilePriority::EVENTUALLY && + tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW) { + // Since we'd return pending tree now tiles before the eventually tiles on + // the active tree, update the value. + ++correct_order_tiles; + skip_updating_last_tile = true; } if (tile->priority(ACTIVE_TREE).priority_bin == TilePriority::NOW && @@ -699,26 +277,28 @@ TEST_F(TileManagerTileIteratorTest, RasterTileIterator) { EXPECT_EQ(LOW_RESOLUTION, last_tile->priority(ACTIVE_TREE).resolution); } - last_tile = tile; + if (!skip_updating_last_tile) + last_tile = tile; ++tile_count; smoothness_tiles.insert(tile); + queue.Pop(); } EXPECT_EQ(tile_count, smoothness_tiles.size()); EXPECT_EQ(all_tiles, smoothness_tiles); // Since we don't guarantee increasing distance due to spiral iterator, we // should check that we're _mostly_ right. - EXPECT_GT(increasing_distance_tiles, 3 * tile_count / 4); + EXPECT_GT(correct_order_tiles, 3 * tile_count / 4); std::set<Tile*> new_content_tiles; last_tile = NULL; - increasing_distance_tiles = 0u; + size_t increasing_distance_tiles = 0u; // Here we expect to get increasing PENDING_TREE priority_bin. - for (TileManager::RasterTileIterator it(tile_manager, - NEW_CONTENT_TAKES_PRIORITY); - it; - ++it) { - Tile* tile = *it; + queue.Reset(); + host_impl_.BuildRasterQueue(&queue, NEW_CONTENT_TAKES_PRIORITY); + tile_count = 0; + while (!queue.IsEmpty()) { + Tile* tile = queue.Top(); EXPECT_TRUE(tile); if (!last_tile) @@ -742,86 +322,143 @@ TEST_F(TileManagerTileIteratorTest, RasterTileIterator) { last_tile = tile; new_content_tiles.insert(tile); + ++tile_count; + queue.Pop(); } EXPECT_EQ(tile_count, new_content_tiles.size()); - EXPECT_EQ(all_tiles, new_content_tiles); + EXPECT_EQ(high_res_tiles, new_content_tiles); // Since we don't guarantee increasing distance due to spiral iterator, we // should check that we're _mostly_ right. - EXPECT_GT(increasing_distance_tiles, 3 * tile_count / 4); + EXPECT_GE(increasing_distance_tiles, 3 * tile_count / 4); } -TEST_F(TileManagerTileIteratorTest, EvictionTileIterator) { +TEST_F(TileManagerTilePriorityQueueTest, ActivationComesBeforeEventually) { SetupDefaultTrees(gfx::Size(1000, 1000)); - TileManager* tile_manager = TileManagerTileIteratorTest::tile_manager(); - EXPECT_TRUE(tile_manager); active_layer_->CreateDefaultTilingsAndTiles(); pending_layer_->CreateDefaultTilingsAndTiles(); - std::vector<TileManager::PairedPictureLayer> paired_layers; - tile_manager->GetPairedPictureLayers(&paired_layers); - EXPECT_EQ(1u, paired_layers.size()); + // Create a pending child layer. + gfx::Size tile_size(256, 256); + scoped_refptr<FakePicturePileImpl> pending_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000)); + scoped_ptr<FakePictureLayerImpl> pending_child = + FakePictureLayerImpl::CreateWithPile( + host_impl_.pending_tree(), id_ + 1, pending_pile); + pending_layer_->AddChild(pending_child.Pass()); + FakePictureLayerImpl* pending_child_raw = static_cast<FakePictureLayerImpl*>( + host_impl_.pending_tree()->LayerById(id_ + 1)); + ASSERT_TRUE(pending_child_raw); + + pending_child_raw->SetDrawsContent(true); + pending_child_raw->DoPostCommitInitializationIfNeeded(); + pending_child_raw->CreateDefaultTilingsAndTiles(); + ASSERT_TRUE(pending_child_raw->HighResTiling()); + + // Set a small viewport, so we have soon and eventually tiles. + gfx::Rect viewport(200, 200); + active_layer_->draw_properties().visible_content_rect = viewport; + active_layer_->UpdateTiles(Occlusion(), false); + pending_layer_->draw_properties().visible_content_rect = viewport; + pending_layer_->UpdateTiles(Occlusion(), false); + pending_child_raw->draw_properties().visible_content_rect = viewport; + pending_child_raw->UpdateTiles(Occlusion(), false); + + RasterTilePriorityQueue queue; + host_impl_.SetRequiresHighResToDraw(); + host_impl_.BuildRasterQueue(&queue, SMOOTHNESS_TAKES_PRIORITY); + EXPECT_FALSE(queue.IsEmpty()); + + // Get all the tiles that are NOW or SOON and make sure they are ready to + // draw. + std::vector<Tile*> all_tiles; + while (!queue.IsEmpty()) { + Tile* tile = queue.Top(); + if (tile->combined_priority().priority_bin >= TilePriority::EVENTUALLY) + break; + + all_tiles.push_back(tile); + queue.Pop(); + } + + tile_manager()->InitializeTilesWithResourcesForTesting( + std::vector<Tile*>(all_tiles.begin(), all_tiles.end())); - TileManager::EvictionTileIterator empty_it(tile_manager, - SAME_PRIORITY_FOR_BOTH_TREES); - EXPECT_FALSE(empty_it); + // Ensure we can activate. + EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw()); + EXPECT_TRUE(pending_child_raw->AllTilesRequiredForActivationAreReadyToDraw()); +} + +TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) { + SetupDefaultTrees(gfx::Size(1000, 1000)); + + active_layer_->CreateDefaultTilingsAndTiles(); + pending_layer_->CreateDefaultTilingsAndTiles(); + + EvictionTilePriorityQueue empty_queue; + host_impl_.BuildEvictionQueue(&empty_queue, SAME_PRIORITY_FOR_BOTH_TREES); + EXPECT_TRUE(empty_queue.IsEmpty()); std::set<Tile*> all_tiles; size_t tile_count = 0; - for (TileManager::RasterTileIterator raster_it(tile_manager, - SAME_PRIORITY_FOR_BOTH_TREES); - raster_it; - ++raster_it) { + RasterTilePriorityQueue raster_queue; + host_impl_.BuildRasterQueue(&raster_queue, SAME_PRIORITY_FOR_BOTH_TREES); + while (!raster_queue.IsEmpty()) { ++tile_count; - EXPECT_TRUE(*raster_it); - all_tiles.insert(*raster_it); + EXPECT_TRUE(raster_queue.Top()); + all_tiles.insert(raster_queue.Top()); + raster_queue.Pop(); } EXPECT_EQ(tile_count, all_tiles.size()); - EXPECT_EQ(17u, tile_count); + EXPECT_EQ(16u, tile_count); - tile_manager->InitializeTilesWithResourcesForTesting( + tile_manager()->InitializeTilesWithResourcesForTesting( std::vector<Tile*>(all_tiles.begin(), all_tiles.end())); - TileManager::EvictionTileIterator it(tile_manager, SMOOTHNESS_TAKES_PRIORITY); - EXPECT_TRUE(it); + EvictionTilePriorityQueue queue; + host_impl_.BuildEvictionQueue(&queue, SMOOTHNESS_TAKES_PRIORITY); + EXPECT_FALSE(queue.IsEmpty()); // Sanity check, all tiles should be visible. std::set<Tile*> smoothness_tiles; - for (; it; ++it) { - Tile* tile = *it; + while (!queue.IsEmpty()) { + Tile* tile = queue.Top(); EXPECT_TRUE(tile); EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin); EXPECT_EQ(TilePriority::NOW, tile->priority(PENDING_TREE).priority_bin); EXPECT_TRUE(tile->HasResources()); smoothness_tiles.insert(tile); + queue.Pop(); } EXPECT_EQ(all_tiles, smoothness_tiles); - tile_manager->ReleaseTileResourcesForTesting( + tile_manager()->ReleaseTileResourcesForTesting( std::vector<Tile*>(all_tiles.begin(), all_tiles.end())); Region invalidation(gfx::Rect(0, 0, 500, 500)); // Invalidate the pending tree. pending_layer_->set_invalidation(invalidation); - pending_layer_->HighResTiling()->Invalidate(invalidation); - pending_layer_->LowResTiling()->Invalidate(invalidation); + pending_layer_->HighResTiling()->UpdateTilesToCurrentPile( + invalidation, gfx::Size(1000, 1000)); + pending_layer_->LowResTiling()->UpdateTilesToCurrentPile( + invalidation, gfx::Size(1000, 1000)); active_layer_->ResetAllTilesPriorities(); pending_layer_->ResetAllTilesPriorities(); // Renew all of the tile priorities. gfx::Rect viewport(50, 50, 100, 100); - pending_layer_->HighResTiling()->UpdateTilePriorities( - PENDING_TREE, viewport, 1.0f, 1.0); - pending_layer_->LowResTiling()->UpdateTilePriorities( - PENDING_TREE, viewport, 1.0f, 1.0); - active_layer_->HighResTiling()->UpdateTilePriorities( - ACTIVE_TREE, viewport, 1.0f, 1.0); - active_layer_->LowResTiling()->UpdateTilePriorities( - ACTIVE_TREE, viewport, 1.0f, 1.0); + pending_layer_->HighResTiling()->ComputeTilePriorityRects( + PENDING_TREE, viewport, 1.0f, 1.0, Occlusion()); + pending_layer_->LowResTiling()->ComputeTilePriorityRects( + PENDING_TREE, viewport, 1.0f, 1.0, Occlusion()); + active_layer_->HighResTiling()->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion()); + active_layer_->LowResTiling()->ComputeTilePriorityRects( + ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion()); // Populate all tiles directly from the tilings. all_tiles.clear(); @@ -845,18 +482,17 @@ TEST_F(TileManagerTileIteratorTest, EvictionTileIterator) { for (size_t i = 0; i < active_low_res_tiles.size(); ++i) all_tiles.insert(active_low_res_tiles[i]); - tile_manager->InitializeTilesWithResourcesForTesting( + tile_manager()->InitializeTilesWithResourcesForTesting( std::vector<Tile*>(all_tiles.begin(), all_tiles.end())); Tile* last_tile = NULL; smoothness_tiles.clear(); tile_count = 0; // Here we expect to get increasing ACTIVE_TREE priority_bin. - for (TileManager::EvictionTileIterator it(tile_manager, - SMOOTHNESS_TAKES_PRIORITY); - it; - ++it) { - Tile* tile = *it; + queue.Reset(); + host_impl_.BuildEvictionQueue(&queue, SMOOTHNESS_TAKES_PRIORITY); + while (!queue.IsEmpty()) { + Tile* tile = queue.Top(); EXPECT_TRUE(tile); EXPECT_TRUE(tile->HasResources()); @@ -867,13 +503,19 @@ TEST_F(TileManagerTileIteratorTest, EvictionTileIterator) { tile->priority(ACTIVE_TREE).priority_bin); if (last_tile->priority(ACTIVE_TREE).priority_bin == tile->priority(ACTIVE_TREE).priority_bin) { - EXPECT_GE(last_tile->priority(ACTIVE_TREE).distance_to_visible, - tile->priority(ACTIVE_TREE).distance_to_visible); + EXPECT_LE(last_tile->required_for_activation(), + tile->required_for_activation()); + if (last_tile->required_for_activation() == + tile->required_for_activation()) { + EXPECT_GE(last_tile->priority(ACTIVE_TREE).distance_to_visible, + tile->priority(ACTIVE_TREE).distance_to_visible); + } } last_tile = tile; ++tile_count; smoothness_tiles.insert(tile); + queue.Pop(); } EXPECT_EQ(tile_count, smoothness_tiles.size()); @@ -882,11 +524,10 @@ TEST_F(TileManagerTileIteratorTest, EvictionTileIterator) { std::set<Tile*> new_content_tiles; last_tile = NULL; // Here we expect to get increasing PENDING_TREE priority_bin. - for (TileManager::EvictionTileIterator it(tile_manager, - NEW_CONTENT_TAKES_PRIORITY); - it; - ++it) { - Tile* tile = *it; + queue.Reset(); + host_impl_.BuildEvictionQueue(&queue, NEW_CONTENT_TAKES_PRIORITY); + while (!queue.IsEmpty()) { + Tile* tile = queue.Top(); EXPECT_TRUE(tile); if (!last_tile) @@ -896,16 +537,233 @@ TEST_F(TileManagerTileIteratorTest, EvictionTileIterator) { tile->priority(PENDING_TREE).priority_bin); if (last_tile->priority(PENDING_TREE).priority_bin == tile->priority(PENDING_TREE).priority_bin) { - EXPECT_GE(last_tile->priority(PENDING_TREE).distance_to_visible, - tile->priority(PENDING_TREE).distance_to_visible); + EXPECT_LE(last_tile->required_for_activation(), + tile->required_for_activation()); + if (last_tile->required_for_activation() == + tile->required_for_activation()) { + EXPECT_GE(last_tile->priority(PENDING_TREE).distance_to_visible, + tile->priority(PENDING_TREE).distance_to_visible); + } } last_tile = tile; new_content_tiles.insert(tile); + queue.Pop(); } EXPECT_EQ(tile_count, new_content_tiles.size()); EXPECT_EQ(all_tiles, new_content_tiles); } + +TEST_F(TileManagerTilePriorityQueueTest, + EvictionTilePriorityQueueWithOcclusion) { + gfx::Size tile_size(102, 102); + gfx::Size layer_bounds(1000, 1000); + + scoped_refptr<FakePicturePileImpl> pending_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + SetupPendingTree(pending_pile); + pending_layer_->CreateDefaultTilingsAndTiles(); + + scoped_ptr<FakePictureLayerImpl> pending_child = + FakePictureLayerImpl::CreateWithPile( + host_impl_.pending_tree(), 2, pending_pile); + pending_layer_->AddChild(pending_child.Pass()); + + FakePictureLayerImpl* pending_child_layer = + static_cast<FakePictureLayerImpl*>(pending_layer_->children()[0]); + pending_child_layer->SetDrawsContent(true); + pending_child_layer->DoPostCommitInitializationIfNeeded(); + pending_child_layer->CreateDefaultTilingsAndTiles(); + + std::set<Tile*> all_tiles; + size_t tile_count = 0; + RasterTilePriorityQueue raster_queue; + host_impl_.BuildRasterQueue(&raster_queue, SAME_PRIORITY_FOR_BOTH_TREES); + while (!raster_queue.IsEmpty()) { + ++tile_count; + EXPECT_TRUE(raster_queue.Top()); + all_tiles.insert(raster_queue.Top()); + raster_queue.Pop(); + } + EXPECT_EQ(tile_count, all_tiles.size()); + EXPECT_EQ(32u, tile_count); + + pending_layer_->ResetAllTilesPriorities(); + + // Renew all of the tile priorities. + gfx::Rect viewport(layer_bounds); + pending_layer_->HighResTiling()->ComputeTilePriorityRects( + PENDING_TREE, viewport, 1.0f, 1.0, Occlusion()); + pending_layer_->LowResTiling()->ComputeTilePriorityRects( + PENDING_TREE, viewport, 1.0f, 1.0, Occlusion()); + pending_child_layer->HighResTiling()->ComputeTilePriorityRects( + PENDING_TREE, viewport, 1.0f, 1.0, Occlusion()); + pending_child_layer->LowResTiling()->ComputeTilePriorityRects( + PENDING_TREE, viewport, 1.0f, 1.0, Occlusion()); + + // Populate all tiles directly from the tilings. + all_tiles.clear(); + std::vector<Tile*> pending_high_res_tiles = + pending_layer_->HighResTiling()->AllTilesForTesting(); + all_tiles.insert(pending_high_res_tiles.begin(), + pending_high_res_tiles.end()); + + std::vector<Tile*> pending_low_res_tiles = + pending_layer_->LowResTiling()->AllTilesForTesting(); + all_tiles.insert(pending_low_res_tiles.begin(), pending_low_res_tiles.end()); + + // Set all tiles on the pending_child_layer as occluded on the pending tree. + std::vector<Tile*> pending_child_high_res_tiles = + pending_child_layer->HighResTiling()->AllTilesForTesting(); + pending_child_layer->HighResTiling()->SetAllTilesOccludedForTesting(); + all_tiles.insert(pending_child_high_res_tiles.begin(), + pending_child_high_res_tiles.end()); + + std::vector<Tile*> pending_child_low_res_tiles = + pending_child_layer->LowResTiling()->AllTilesForTesting(); + pending_child_layer->LowResTiling()->SetAllTilesOccludedForTesting(); + all_tiles.insert(pending_child_low_res_tiles.begin(), + pending_child_low_res_tiles.end()); + + tile_manager()->InitializeTilesWithResourcesForTesting( + std::vector<Tile*>(all_tiles.begin(), all_tiles.end())); + + // Verify occlusion is considered by EvictionTilePriorityQueue. + TreePriority tree_priority = NEW_CONTENT_TAKES_PRIORITY; + size_t occluded_count = 0u; + Tile* last_tile = NULL; + EvictionTilePriorityQueue queue; + host_impl_.BuildEvictionQueue(&queue, tree_priority); + while (!queue.IsEmpty()) { + Tile* tile = queue.Top(); + if (!last_tile) + last_tile = tile; + + bool tile_is_occluded = tile->is_occluded_for_tree_priority(tree_priority); + + // The only way we will encounter an occluded tile after an unoccluded + // tile is if the priorty bin decreased, the tile is required for + // activation, or the scale changed. + if (tile_is_occluded) { + occluded_count++; + + bool last_tile_is_occluded = + last_tile->is_occluded_for_tree_priority(tree_priority); + if (!last_tile_is_occluded) { + TilePriority::PriorityBin tile_priority_bin = + tile->priority_for_tree_priority(tree_priority).priority_bin; + TilePriority::PriorityBin last_tile_priority_bin = + last_tile->priority_for_tree_priority(tree_priority).priority_bin; + + EXPECT_TRUE((tile_priority_bin < last_tile_priority_bin) || + tile->required_for_activation() || + (tile->contents_scale() != last_tile->contents_scale())); + } + } + last_tile = tile; + queue.Pop(); + } + size_t expected_occluded_count = + pending_child_high_res_tiles.size() + pending_child_low_res_tiles.size(); + EXPECT_EQ(expected_occluded_count, occluded_count); +} + +TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueEmptyLayers) { + SetupDefaultTrees(gfx::Size(1000, 1000)); + + active_layer_->CreateDefaultTilingsAndTiles(); + pending_layer_->CreateDefaultTilingsAndTiles(); + + RasterTilePriorityQueue queue; + host_impl_.BuildRasterQueue(&queue, SAME_PRIORITY_FOR_BOTH_TREES); + EXPECT_FALSE(queue.IsEmpty()); + + size_t tile_count = 0; + std::set<Tile*> all_tiles; + while (!queue.IsEmpty()) { + EXPECT_TRUE(queue.Top()); + all_tiles.insert(queue.Top()); + ++tile_count; + queue.Pop(); + } + + EXPECT_EQ(tile_count, all_tiles.size()); + EXPECT_EQ(16u, tile_count); + + queue.Reset(); + for (int i = 1; i < 10; ++i) { + scoped_ptr<FakePictureLayerImpl> pending_layer = + FakePictureLayerImpl::Create(host_impl_.pending_tree(), id_ + i); + pending_layer->SetDrawsContent(true); + pending_layer->DoPostCommitInitializationIfNeeded(); + pending_layer->set_has_valid_tile_priorities(true); + pending_layer_->AddChild(pending_layer.Pass()); + } + + host_impl_.BuildRasterQueue(&queue, SAME_PRIORITY_FOR_BOTH_TREES); + EXPECT_FALSE(queue.IsEmpty()); + + tile_count = 0; + all_tiles.clear(); + while (!queue.IsEmpty()) { + EXPECT_TRUE(queue.Top()); + all_tiles.insert(queue.Top()); + ++tile_count; + queue.Pop(); + } + EXPECT_EQ(tile_count, all_tiles.size()); + EXPECT_EQ(16u, tile_count); +} + +TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueueEmptyLayers) { + SetupDefaultTrees(gfx::Size(1000, 1000)); + + active_layer_->CreateDefaultTilingsAndTiles(); + pending_layer_->CreateDefaultTilingsAndTiles(); + + RasterTilePriorityQueue raster_queue; + host_impl_.BuildRasterQueue(&raster_queue, SAME_PRIORITY_FOR_BOTH_TREES); + EXPECT_FALSE(raster_queue.IsEmpty()); + + size_t tile_count = 0; + std::set<Tile*> all_tiles; + while (!raster_queue.IsEmpty()) { + EXPECT_TRUE(raster_queue.Top()); + all_tiles.insert(raster_queue.Top()); + ++tile_count; + raster_queue.Pop(); + } + EXPECT_EQ(tile_count, all_tiles.size()); + EXPECT_EQ(16u, tile_count); + + std::vector<Tile*> tiles(all_tiles.begin(), all_tiles.end()); + host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles); + + EvictionTilePriorityQueue queue; + for (int i = 1; i < 10; ++i) { + scoped_ptr<FakePictureLayerImpl> pending_layer = + FakePictureLayerImpl::Create(host_impl_.pending_tree(), id_ + i); + pending_layer->SetDrawsContent(true); + pending_layer->DoPostCommitInitializationIfNeeded(); + pending_layer->set_has_valid_tile_priorities(true); + pending_layer_->AddChild(pending_layer.Pass()); + } + + host_impl_.BuildEvictionQueue(&queue, SAME_PRIORITY_FOR_BOTH_TREES); + EXPECT_FALSE(queue.IsEmpty()); + + tile_count = 0; + all_tiles.clear(); + while (!queue.IsEmpty()) { + EXPECT_TRUE(queue.Top()); + all_tiles.insert(queue.Top()); + ++tile_count; + queue.Pop(); + } + EXPECT_EQ(tile_count, all_tiles.size()); + EXPECT_EQ(16u, tile_count); +} + } // namespace } // namespace cc diff --git a/chromium/cc/resources/tile_priority.cc b/chromium/cc/resources/tile_priority.cc index 3bf29680766..26826af450e 100644 --- a/chromium/cc/resources/tile_priority.cc +++ b/chromium/cc/resources/tile_priority.cc @@ -4,111 +4,95 @@ #include "cc/resources/tile_priority.h" +#include "base/debug/trace_event_argument.h" #include "base/values.h" #include "cc/base/math_util.h" namespace cc { -scoped_ptr<base::Value> WhichTreeAsValue(WhichTree tree) { +std::string WhichTreeToString(WhichTree tree) { switch (tree) { case ACTIVE_TREE: - return scoped_ptr<base::Value>(new base::StringValue("ACTIVE_TREE")); + return "ACTIVE_TREE"; case PENDING_TREE: - return scoped_ptr<base::Value>(new base::StringValue("PENDING_TREE")); + return "PENDING_TREE"; default: DCHECK(false) << "Unrecognized WhichTree value " << tree; - return scoped_ptr<base::Value>(new base::StringValue( - "<unknown WhichTree value>")); + return "<unknown WhichTree value>"; } } -scoped_ptr<base::Value> TileResolutionAsValue( - TileResolution resolution) { +std::string TileResolutionToString(TileResolution resolution) { switch (resolution) { case LOW_RESOLUTION: - return scoped_ptr<base::Value>(new base::StringValue("LOW_RESOLUTION")); + return "LOW_RESOLUTION"; case HIGH_RESOLUTION: - return scoped_ptr<base::Value>(new base::StringValue("HIGH_RESOLUTION")); + return "HIGH_RESOLUTION"; case NON_IDEAL_RESOLUTION: - return scoped_ptr<base::Value>(new base::StringValue( - "NON_IDEAL_RESOLUTION")); + return "NON_IDEAL_RESOLUTION"; } DCHECK(false) << "Unrecognized TileResolution value " << resolution; - return scoped_ptr<base::Value>(new base::StringValue( - "<unknown TileResolution value>")); + return "<unknown TileResolution value>"; } -scoped_ptr<base::Value> TilePriorityBinAsValue(TilePriority::PriorityBin bin) { +std::string TilePriorityBinToString(TilePriority::PriorityBin bin) { switch (bin) { case TilePriority::NOW: - return scoped_ptr<base::Value>(base::Value::CreateStringValue("NOW")); + return "NOW"; case TilePriority::SOON: - return scoped_ptr<base::Value>(base::Value::CreateStringValue("SOON")); + return "SOON"; case TilePriority::EVENTUALLY: - return scoped_ptr<base::Value>( - base::Value::CreateStringValue("EVENTUALLY")); + return "EVENTUALLY"; } DCHECK(false) << "Unrecognized TilePriority::PriorityBin value " << bin; - return scoped_ptr<base::Value>(base::Value::CreateStringValue( - "<unknown TilePriority::PriorityBin value>")); + return "<unknown TilePriority::PriorityBin value>"; } -scoped_ptr<base::Value> TilePriority::AsValue() const { - scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); - state->Set("resolution", TileResolutionAsValue(resolution).release()); - state->Set("priority_bin", TilePriorityBinAsValue(priority_bin).release()); - state->Set("distance_to_visible", - MathUtil::AsValueSafely(distance_to_visible).release()); - return state.PassAs<base::Value>(); +void TilePriority::AsValueInto(base::debug::TracedValue* state) const { + state->SetString("resolution", TileResolutionToString(resolution)); + state->SetString("priority_bin", TilePriorityBinToString(priority_bin)); + state->SetDouble("distance_to_visible", + MathUtil::AsDoubleSafely(distance_to_visible)); } -scoped_ptr<base::Value> TileMemoryLimitPolicyAsValue( - TileMemoryLimitPolicy policy) { +std::string TileMemoryLimitPolicyToString(TileMemoryLimitPolicy policy) { switch (policy) { case ALLOW_NOTHING: - return scoped_ptr<base::Value>(new base::StringValue("ALLOW_NOTHING")); + return "ALLOW_NOTHING"; case ALLOW_ABSOLUTE_MINIMUM: - return scoped_ptr<base::Value>(new base::StringValue( - "ALLOW_ABSOLUTE_MINIMUM")); + return "ALLOW_ABSOLUTE_MINIMUM"; case ALLOW_PREPAINT_ONLY: - return scoped_ptr<base::Value>(new base::StringValue( - "ALLOW_PREPAINT_ONLY")); + return "ALLOW_PREPAINT_ONLY"; case ALLOW_ANYTHING: - return scoped_ptr<base::Value>(new base::StringValue( - "ALLOW_ANYTHING")); + return "ALLOW_ANYTHING"; default: DCHECK(false) << "Unrecognized policy value"; - return scoped_ptr<base::Value>(new base::StringValue( - "<unknown>")); + return "<unknown>"; } } -scoped_ptr<base::Value> TreePriorityAsValue(TreePriority prio) { +std::string TreePriorityToString(TreePriority prio) { switch (prio) { case SAME_PRIORITY_FOR_BOTH_TREES: - return scoped_ptr<base::Value>(new base::StringValue( - "SAME_PRIORITY_FOR_BOTH_TREES")); + return "SAME_PRIORITY_FOR_BOTH_TREES"; case SMOOTHNESS_TAKES_PRIORITY: - return scoped_ptr<base::Value>(new base::StringValue( - "SMOOTHNESS_TAKES_PRIORITY")); + return "SMOOTHNESS_TAKES_PRIORITY"; case NEW_CONTENT_TAKES_PRIORITY: - return scoped_ptr<base::Value>(new base::StringValue( - "NEW_CONTENT_TAKES_PRIORITY")); + return "NEW_CONTENT_TAKES_PRIORITY"; + default: + DCHECK(false) << "Unrecognized priority value " << prio; + return "<unknown>"; } - DCHECK(false) << "Unrecognized priority value " << prio; - return scoped_ptr<base::Value>(new base::StringValue( - "<unknown>")); } -scoped_ptr<base::Value> GlobalStateThatImpactsTilePriority::AsValue() const { - scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); - state->Set("memory_limit_policy", - TileMemoryLimitPolicyAsValue(memory_limit_policy).release()); +void GlobalStateThatImpactsTilePriority::AsValueInto( + base::debug::TracedValue* state) const { + state->SetString("memory_limit_policy", + TileMemoryLimitPolicyToString(memory_limit_policy)); state->SetInteger("soft_memory_limit_in_bytes", soft_memory_limit_in_bytes); state->SetInteger("hard_memory_limit_in_bytes", hard_memory_limit_in_bytes); state->SetInteger("num_resources_limit", num_resources_limit); - state->Set("tree_priority", TreePriorityAsValue(tree_priority).release()); - return state.PassAs<base::Value>(); + state->SetString("tree_priority", TreePriorityToString(tree_priority)); } } // namespace cc diff --git a/chromium/cc/resources/tile_priority.h b/chromium/cc/resources/tile_priority.h index f8ac9c6c7b0..d1610571863 100644 --- a/chromium/cc/resources/tile_priority.h +++ b/chromium/cc/resources/tile_priority.h @@ -7,13 +7,11 @@ #include <algorithm> #include <limits> +#include <string> -#include "base/memory/ref_counted.h" +#include "base/debug/trace_event_argument.h" #include "base/memory/scoped_ptr.h" -#include "cc/resources/picture_pile.h" -#include "ui/gfx/quad_f.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/size.h" +#include "cc/base/cc_export.h" namespace base { class Value; @@ -29,23 +27,20 @@ enum WhichTree { NUM_TREES = 2 // Be sure to update WhichTreeAsValue when adding new fields. }; -scoped_ptr<base::Value> WhichTreeAsValue( - WhichTree tree); +scoped_ptr<base::Value> WhichTreeAsValue(WhichTree tree); enum TileResolution { LOW_RESOLUTION = 0 , HIGH_RESOLUTION = 1, NON_IDEAL_RESOLUTION = 2, }; -scoped_ptr<base::Value> TileResolutionAsValue( - TileResolution resolution); +std::string TileResolutionToString(TileResolution resolution); struct CC_EXPORT TilePriority { enum PriorityBin { NOW, SOON, EVENTUALLY }; TilePriority() : resolution(NON_IDEAL_RESOLUTION), - required_for_activation(false), priority_bin(EVENTUALLY), distance_to_visible(std::numeric_limits<float>::infinity()) {} @@ -53,7 +48,6 @@ struct CC_EXPORT TilePriority { PriorityBin bin, float distance_to_visible) : resolution(resolution), - required_for_activation(false), priority_bin(bin), distance_to_visible(distance_to_visible) {} @@ -67,9 +61,6 @@ struct CC_EXPORT TilePriority { else resolution = NON_IDEAL_RESOLUTION; - required_for_activation = - active.required_for_activation || pending.required_for_activation; - if (active.priority_bin < pending.priority_bin) { priority_bin = active.priority_bin; distance_to_visible = active.distance_to_visible; @@ -83,13 +74,12 @@ struct CC_EXPORT TilePriority { } } - scoped_ptr<base::Value> AsValue() const; + void AsValueInto(base::debug::TracedValue* dict) const; bool operator ==(const TilePriority& other) const { return resolution == other.resolution && priority_bin == other.priority_bin && - distance_to_visible == other.distance_to_visible && - required_for_activation == other.required_for_activation; + distance_to_visible == other.distance_to_visible; } bool operator !=(const TilePriority& other) const { @@ -103,15 +93,14 @@ struct CC_EXPORT TilePriority { } TileResolution resolution; - bool required_for_activation; PriorityBin priority_bin; float distance_to_visible; }; -scoped_ptr<base::Value> TilePriorityBinAsValue(TilePriority::PriorityBin bin); +std::string TilePriorityBinToString(TilePriority::PriorityBin bin); enum TileMemoryLimitPolicy { - // Nothing. + // Nothing. This mode is used when visible is set to false. ALLOW_NOTHING = 0, // You might be made visible, but you're not being interacted with. @@ -121,24 +110,18 @@ enum TileMemoryLimitPolicy { ALLOW_PREPAINT_ONLY = 2, // Grande. // You're the only thing in town. Go crazy. - ALLOW_ANYTHING = 3, // Venti. - - NUM_TILE_MEMORY_LIMIT_POLICIES = 4, - - // NOTE: Be sure to update TreePriorityAsValue and kBinPolicyMap when adding - // or reordering fields. + ALLOW_ANYTHING = 3 // Venti. }; -scoped_ptr<base::Value> TileMemoryLimitPolicyAsValue( - TileMemoryLimitPolicy policy); +std::string TileMemoryLimitPolicyToString(TileMemoryLimitPolicy policy); enum TreePriority { SAME_PRIORITY_FOR_BOTH_TREES, SMOOTHNESS_TAKES_PRIORITY, - NEW_CONTENT_TAKES_PRIORITY - + NEW_CONTENT_TAKES_PRIORITY, + NUM_TREE_PRIORITIES // Be sure to update TreePriorityAsValue when adding new fields. }; -scoped_ptr<base::Value> TreePriorityAsValue(TreePriority prio); +std::string TreePriorityToString(TreePriority prio); class GlobalStateThatImpactsTilePriority { public: @@ -168,7 +151,7 @@ class GlobalStateThatImpactsTilePriority { return !(*this == other); } - scoped_ptr<base::Value> AsValue() const; + void AsValueInto(base::debug::TracedValue* dict) const; }; } // namespace cc diff --git a/chromium/cc/resources/transferable_resource.cc b/chromium/cc/resources/transferable_resource.cc index 30fa3169abd..558d6e87728 100644 --- a/chromium/cc/resources/transferable_resource.cc +++ b/chromium/cc/resources/transferable_resource.cc @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/logging.h" #include "cc/resources/returned_resource.h" #include "cc/resources/transferable_resource.h" @@ -13,7 +12,8 @@ TransferableResource::TransferableResource() format(RGBA_8888), filter(0), is_repeated(false), - is_software(false) { + is_software(false), + allow_overlay(false) { } TransferableResource::~TransferableResource() { diff --git a/chromium/cc/resources/transferable_resource.h b/chromium/cc/resources/transferable_resource.h index 11651f2722d..03b47e616c8 100644 --- a/chromium/cc/resources/transferable_resource.h +++ b/chromium/cc/resources/transferable_resource.h @@ -11,7 +11,7 @@ #include "cc/base/cc_export.h" #include "cc/resources/resource_format.h" #include "gpu/command_buffer/common/mailbox_holder.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" namespace cc { @@ -35,6 +35,7 @@ struct CC_EXPORT TransferableResource { gpu::MailboxHolder mailbox_holder; bool is_repeated; bool is_software; + bool allow_overlay; }; } // namespace cc diff --git a/chromium/cc/resources/ui_resource_bitmap.cc b/chromium/cc/resources/ui_resource_bitmap.cc index 58df9d96272..e254cf71614 100644 --- a/chromium/cc/resources/ui_resource_bitmap.cc +++ b/chromium/cc/resources/ui_resource_bitmap.cc @@ -11,6 +11,26 @@ #include "third_party/skia/include/core/SkPixelRef.h" namespace cc { +namespace { + +UIResourceBitmap::UIResourceFormat SkColorTypeToUIResourceFormat( + SkColorType sk_type) { + UIResourceBitmap::UIResourceFormat format = UIResourceBitmap::RGBA8; + switch (sk_type) { + case kN32_SkColorType: + format = UIResourceBitmap::RGBA8; + break; + case kAlpha_8_SkColorType: + format = UIResourceBitmap::ALPHA_8; + break; + default: + NOTREACHED() << "Invalid SkColorType for UIResourceBitmap: " << sk_type; + break; + } + return format; +} + +} // namespace void UIResourceBitmap::Create(const skia::RefPtr<SkPixelRef>& pixel_ref, const gfx::Size& size, @@ -29,14 +49,14 @@ void UIResourceBitmap::Create(const skia::RefPtr<SkPixelRef>& pixel_ref, } UIResourceBitmap::UIResourceBitmap(const SkBitmap& skbitmap) { - DCHECK_EQ(skbitmap.colorType(), kPMColor_SkColorType); DCHECK_EQ(skbitmap.width(), skbitmap.rowBytesAsPixels()); DCHECK(skbitmap.isImmutable()); skia::RefPtr<SkPixelRef> pixel_ref = skia::SharePtr(skbitmap.pixelRef()); const SkImageInfo& info = pixel_ref->info(); - Create( - pixel_ref, gfx::Size(info.fWidth, info.fHeight), UIResourceBitmap::RGBA8); + Create(pixel_ref, + gfx::Size(info.fWidth, info.fHeight), + SkColorTypeToUIResourceFormat(skbitmap.colorType())); SetOpaque(skbitmap.isOpaque()); } diff --git a/chromium/cc/resources/ui_resource_bitmap.h b/chromium/cc/resources/ui_resource_bitmap.h index b8863d8e994..ec6511394d2 100644 --- a/chromium/cc/resources/ui_resource_bitmap.h +++ b/chromium/cc/resources/ui_resource_bitmap.h @@ -10,8 +10,7 @@ #include "cc/base/cc_export.h" #include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkPixelRef.h" -#include "third_party/skia/include/core/SkTypes.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" class SkBitmap; @@ -27,6 +26,7 @@ class CC_EXPORT UIResourceBitmap { public: enum UIResourceFormat { RGBA8, + ALPHA_8, ETC1 }; enum UIResourceWrapMode { @@ -42,7 +42,7 @@ class CC_EXPORT UIResourceBitmap { void SetOpaque(bool opaque) { opaque_ = opaque; } // User must ensure that |skbitmap| is immutable. The SkBitmap Format should - // be 32-bit RGBA. + // be 32-bit RGBA or 8-bit ALPHA. explicit UIResourceBitmap(const SkBitmap& skbitmap); UIResourceBitmap(const gfx::Size& size, bool is_opaque); UIResourceBitmap(const skia::RefPtr<SkPixelRef>& pixel_ref, diff --git a/chromium/cc/resources/ui_resource_request.cc b/chromium/cc/resources/ui_resource_request.cc index 75680369c6d..b8dd50af117 100644 --- a/chromium/cc/resources/ui_resource_request.cc +++ b/chromium/cc/resources/ui_resource_request.cc @@ -26,7 +26,7 @@ UIResourceRequest& UIResourceRequest::operator=( if (request.bitmap_) { bitmap_ = make_scoped_ptr(new UIResourceBitmap(*request.bitmap_.get())); } else { - bitmap_.reset(); + bitmap_ = nullptr; } return *this; diff --git a/chromium/cc/resources/video_resource_updater.cc b/chromium/cc/resources/video_resource_updater.cc index 1d93aebe3cc..01a6042ef3e 100644 --- a/chromium/cc/resources/video_resource_updater.cc +++ b/chromium/cc/resources/video_resource_updater.cc @@ -5,6 +5,7 @@ #include "cc/resources/video_resource_updater.h" #include "base/bind.h" +#include "base/debug/trace_event.h" #include "cc/output/gl_renderer.h" #include "cc/resources/resource_provider.h" #include "gpu/GLES2/gl2extchromium.h" @@ -13,13 +14,32 @@ #include "media/filters/skcanvas_video_renderer.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" -#include "ui/gfx/size_conversions.h" +#include "ui/gfx/geometry/size_conversions.h" namespace cc { +namespace { + const ResourceFormat kYUVResourceFormat = LUMINANCE_8; const ResourceFormat kRGBResourceFormat = RGBA_8888; +class SyncPointClientImpl : public media::VideoFrame::SyncPointClient { + public: + explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} + ~SyncPointClientImpl() override {} + uint32 InsertSyncPoint() override { + return GLC(gl_, gl_->InsertSyncPointCHROMIUM()); + } + void WaitSyncPoint(uint32 sync_point) override { + GLC(gl_, gl_->WaitSyncPointCHROMIUM(sync_point)); + } + + private: + gpu::gles2::GLES2Interface* gl_; +}; + +} // namespace + VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {} VideoFrameExternalResources::~VideoFrameExternalResources() {} @@ -97,6 +117,7 @@ static gfx::Size SoftwarePlaneDimension( VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( const scoped_refptr<media::VideoFrame>& video_frame) { + TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes"); media::VideoFrame::Format input_frame_format = video_frame->format(); #if defined(VIDEO_HOLE) @@ -172,11 +193,11 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( 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::TextureUsageAny, - output_resource_format); + resource_id = resource_provider_->CreateResource( + output_plane_resource_size, + GL_CLAMP_TO_EDGE, + ResourceProvider::TextureHintImmutable, + output_resource_format); DCHECK(mailbox.IsZero()); @@ -188,9 +209,9 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name)); ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id); - GLC(gl, gl->BindTexture(GL_TEXTURE_2D, lock.texture_id())); - GLC(gl, gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name)); - GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0)); + GLC(gl, + gl->ProduceTextureDirectCHROMIUM( + lock.texture_id(), GL_TEXTURE_2D, mailbox.name)); } if (resource_id) @@ -228,10 +249,7 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( { ResourceProvider::ScopedWriteLockSoftware lock( resource_provider_, plane_resources[0].resource_id); - video_renderer_->Paint(video_frame.get(), - lock.sk_canvas(), - video_frame->visible_rect(), - 0xff); + video_renderer_->Copy(video_frame, lock.sk_canvas()); } RecycleResourceData recycle_data = { @@ -283,14 +301,27 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( return external_resources; } -static void ReturnTexture(const scoped_refptr<media::VideoFrame>& frame, - uint32 sync_point, - bool lost_resource) { - frame->AppendReleaseSyncPoint(sync_point); +// static +void VideoResourceUpdater::ReturnTexture( + base::WeakPtr<VideoResourceUpdater> updater, + const scoped_refptr<media::VideoFrame>& video_frame, + uint32 sync_point, + bool lost_resource, + BlockingTaskRunner* main_thread_task_runner) { + // TODO(dshwang) this case should be forwarded to the decoder as lost + // resource. + if (lost_resource || !updater.get()) + return; + // VideoFrame::UpdateReleaseSyncPoint() creates new sync point using the same + // GL context which created the given |sync_point|, so discard the + // |sync_point|. + SyncPointClientImpl client(updater->context_provider_->ContextGL()); + video_frame->UpdateReleaseSyncPoint(&client); } VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( const scoped_refptr<media::VideoFrame>& video_frame) { + TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForHardwarePlanes"); media::VideoFrame::Format frame_format = video_frame->format(); DCHECK_EQ(frame_format, media::VideoFrame::NATIVE_TEXTURE); @@ -323,7 +354,7 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( mailbox_holder->texture_target, mailbox_holder->sync_point)); external_resources.release_callbacks.push_back( - base::Bind(&ReturnTexture, video_frame)); + base::Bind(&ReturnTexture, AsWeakPtr(), video_frame)); return external_resources; } @@ -332,7 +363,8 @@ void VideoResourceUpdater::RecycleResource( base::WeakPtr<VideoResourceUpdater> updater, RecycleResourceData data, uint32 sync_point, - bool lost_resource) { + bool lost_resource, + BlockingTaskRunner* main_thread_task_runner) { if (!updater.get()) { // Resource was already deleted. return; diff --git a/chromium/cc/resources/video_resource_updater.h b/chromium/cc/resources/video_resource_updater.h index eaaa8c10d69..99800b4c878 100644 --- a/chromium/cc/resources/video_resource_updater.h +++ b/chromium/cc/resources/video_resource_updater.h @@ -9,13 +9,12 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "cc/base/cc_export.h" -#include "cc/resources/release_callback.h" +#include "cc/resources/release_callback_impl.h" #include "cc/resources/resource_format.h" #include "cc/resources/texture_mailbox.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" namespace media { class SkCanvasVideoRenderer; @@ -50,11 +49,11 @@ class CC_EXPORT VideoFrameExternalResources { ResourceType type; std::vector<TextureMailbox> mailboxes; - std::vector<ReleaseCallback> release_callbacks; + std::vector<ReleaseCallbackImpl> release_callbacks; // TODO(danakj): Remove these too. std::vector<unsigned> software_resources; - ReleaseCallback software_release_callback; + ReleaseCallbackImpl software_release_callback; VideoFrameExternalResources(); ~VideoFrameExternalResources(); @@ -105,7 +104,13 @@ class CC_EXPORT VideoResourceUpdater static void RecycleResource(base::WeakPtr<VideoResourceUpdater> updater, RecycleResourceData data, uint32 sync_point, - bool lost_resource); + bool lost_resource, + BlockingTaskRunner* main_thread_task_runner); + static void ReturnTexture(base::WeakPtr<VideoResourceUpdater> updater, + const scoped_refptr<media::VideoFrame>& video_frame, + uint32 sync_point, + bool lost_resource, + BlockingTaskRunner* main_thread_task_runner); ContextProvider* context_provider_; ResourceProvider* resource_provider_; diff --git a/chromium/cc/resources/video_resource_updater_unittest.cc b/chromium/cc/resources/video_resource_updater_unittest.cc index 05bcf221b4a..c0a4af402c4 100644 --- a/chromium/cc/resources/video_resource_updater_unittest.cc +++ b/chromium/cc/resources/video_resource_updater_unittest.cc @@ -10,6 +10,7 @@ #include "cc/test/fake_output_surface_client.h" #include "cc/test/test_shared_bitmap_manager.h" #include "cc/test/test_web_graphics_context_3d.h" +#include "cc/trees/blocking_task_runner.h" #include "media/base/video_frame.h" #include "testing/gtest/include/gtest/gtest.h" @@ -27,9 +28,14 @@ class VideoResourceUpdaterTest : public testing::Test { FakeOutputSurface::Create3d(context3d.Pass()); CHECK(output_surface3d_->BindToClient(&client_)); shared_bitmap_manager_.reset(new TestSharedBitmapManager()); - resource_provider3d_ = ResourceProvider::Create( - output_surface3d_.get(), shared_bitmap_manager_.get(), 0, false, 1, - false); + resource_provider3d_ = + ResourceProvider::Create(output_surface3d_.get(), + shared_bitmap_manager_.get(), + NULL, + NULL, + 0, + false, + 1); } scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame() { @@ -62,7 +68,7 @@ class VideoResourceUpdaterTest : public testing::Test { }; TEST_F(VideoResourceUpdaterTest, SoftwareFrame) { - VideoResourceUpdater updater(output_surface3d_->context_provider().get(), + VideoResourceUpdater updater(output_surface3d_->context_provider(), resource_provider3d_.get()); scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame(); diff --git a/chromium/cc/resources/zero_copy_raster_worker_pool.cc b/chromium/cc/resources/zero_copy_raster_worker_pool.cc new file mode 100644 index 00000000000..ca2bc9b01e1 --- /dev/null +++ b/chromium/cc/resources/zero_copy_raster_worker_pool.cc @@ -0,0 +1,211 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/resources/zero_copy_raster_worker_pool.h" + +#include <algorithm> + +#include "base/debug/trace_event.h" +#include "base/debug/trace_event_argument.h" +#include "base/strings/stringprintf.h" +#include "cc/debug/traced_value.h" +#include "cc/resources/raster_buffer.h" +#include "cc/resources/resource.h" +#include "ui/gfx/gpu_memory_buffer.h" + +namespace cc { +namespace { + +class RasterBufferImpl : public RasterBuffer { + public: + RasterBufferImpl(ResourceProvider* resource_provider, + const Resource* resource) + : lock_(resource_provider, resource->id()), resource_(resource) {} + + // Overridden from RasterBuffer: + void Playback(const RasterSource* raster_source, + const gfx::Rect& rect, + float scale) override { + gfx::GpuMemoryBuffer* gpu_memory_buffer = lock_.GetGpuMemoryBuffer(); + if (!gpu_memory_buffer) + return; + + RasterWorkerPool::PlaybackToMemory( + gpu_memory_buffer->Map(), resource_->format(), resource_->size(), + gpu_memory_buffer->GetStride(), raster_source, rect, scale); + gpu_memory_buffer->Unmap(); + } + + private: + ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock_; + const Resource* resource_; + + DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); +}; + +} // namespace + +// static +scoped_ptr<RasterWorkerPool> ZeroCopyRasterWorkerPool::Create( + base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ResourceProvider* resource_provider) { + return make_scoped_ptr<RasterWorkerPool>(new ZeroCopyRasterWorkerPool( + task_runner, task_graph_runner, resource_provider)); +} + +ZeroCopyRasterWorkerPool::ZeroCopyRasterWorkerPool( + base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ResourceProvider* resource_provider) + : task_runner_(task_runner), + task_graph_runner_(task_graph_runner), + namespace_token_(task_graph_runner->GetNamespaceToken()), + resource_provider_(resource_provider), + raster_finished_weak_ptr_factory_(this) { +} + +ZeroCopyRasterWorkerPool::~ZeroCopyRasterWorkerPool() { +} + +Rasterizer* ZeroCopyRasterWorkerPool::AsRasterizer() { + return this; +} + +void ZeroCopyRasterWorkerPool::SetClient(RasterizerClient* client) { + client_ = client; +} + +void ZeroCopyRasterWorkerPool::Shutdown() { + TRACE_EVENT0("cc", "ZeroCopyRasterWorkerPool::Shutdown"); + + TaskGraph empty; + task_graph_runner_->ScheduleTasks(namespace_token_, &empty); + task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); +} + +void ZeroCopyRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) { + TRACE_EVENT0("cc", "ZeroCopyRasterWorkerPool::ScheduleTasks"); + + if (raster_pending_.none()) + TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); + + // Mark all task sets as pending. + raster_pending_.set(); + + unsigned priority = kRasterTaskPriorityBase; + + graph_.Reset(); + + // Cancel existing OnRasterFinished callbacks. + raster_finished_weak_ptr_factory_.InvalidateWeakPtrs(); + + scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets]; + + size_t task_count[kNumberOfTaskSets] = {0}; + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + new_raster_finished_tasks[task_set] = CreateRasterFinishedTask( + task_runner_.get(), + base::Bind(&ZeroCopyRasterWorkerPool::OnRasterFinished, + raster_finished_weak_ptr_factory_.GetWeakPtr(), + task_set)); + } + + for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); + it != queue->items.end(); + ++it) { + const RasterTaskQueue::Item& item = *it; + RasterTask* task = item.task; + DCHECK(!task->HasCompleted()); + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + if (!item.task_sets[task_set]) + continue; + + ++task_count[task_set]; + + graph_.edges.push_back( + TaskGraph::Edge(task, new_raster_finished_tasks[task_set].get())); + } + + InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); + } + + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { + InsertNodeForTask(&graph_, + new_raster_finished_tasks[task_set].get(), + kRasterFinishedTaskPriority, + task_count[task_set]); + } + + ScheduleTasksOnOriginThread(this, &graph_); + task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); + + std::copy(new_raster_finished_tasks, + new_raster_finished_tasks + kNumberOfTaskSets, + raster_finished_tasks_); + + TRACE_EVENT_ASYNC_STEP_INTO1( + "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue()); +} + +void ZeroCopyRasterWorkerPool::CheckForCompletedTasks() { + TRACE_EVENT0("cc", "ZeroCopyRasterWorkerPool::CheckForCompletedTasks"); + + task_graph_runner_->CollectCompletedTasks(namespace_token_, + &completed_tasks_); + for (Task::Vector::const_iterator it = completed_tasks_.begin(); + it != completed_tasks_.end(); + ++it) { + RasterizerTask* task = static_cast<RasterizerTask*>(it->get()); + + task->WillComplete(); + task->CompleteOnOriginThread(this); + task->DidComplete(); + + task->RunReplyOnOriginThread(); + } + completed_tasks_.clear(); +} + +scoped_ptr<RasterBuffer> ZeroCopyRasterWorkerPool::AcquireBufferForRaster( + const Resource* resource) { + return make_scoped_ptr<RasterBuffer>( + new RasterBufferImpl(resource_provider_, resource)); +} + +void ZeroCopyRasterWorkerPool::ReleaseBufferForRaster( + scoped_ptr<RasterBuffer> buffer) { + // Nothing to do here. RasterBufferImpl destructor cleans up after itself. +} + +void ZeroCopyRasterWorkerPool::OnRasterFinished(TaskSet task_set) { + TRACE_EVENT1( + "cc", "ZeroCopyRasterWorkerPool::OnRasterFinished", "task_set", task_set); + + DCHECK(raster_pending_[task_set]); + raster_pending_[task_set] = false; + if (raster_pending_.any()) { + TRACE_EVENT_ASYNC_STEP_INTO1( + "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue()); + } else { + TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); + } + client_->DidFinishRunningTasks(task_set); +} + +scoped_refptr<base::debug::ConvertableToTraceFormat> +ZeroCopyRasterWorkerPool::StateAsValue() const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); + + state->BeginArray("tasks_pending"); + for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) + state->AppendBoolean(raster_pending_[task_set]); + state->EndArray(); + return state; +} + +} // namespace cc diff --git a/chromium/cc/resources/zero_copy_raster_worker_pool.h b/chromium/cc/resources/zero_copy_raster_worker_pool.h new file mode 100644 index 00000000000..d1f583ee164 --- /dev/null +++ b/chromium/cc/resources/zero_copy_raster_worker_pool.h @@ -0,0 +1,79 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_RESOURCES_ZERO_COPY_RASTER_WORKER_POOL_H_ +#define CC_RESOURCES_ZERO_COPY_RASTER_WORKER_POOL_H_ + +#include "base/memory/weak_ptr.h" +#include "base/values.h" +#include "cc/resources/raster_worker_pool.h" +#include "cc/resources/rasterizer.h" + +namespace base { +namespace debug { +class ConvertableToTraceFormat; +} +} + +namespace cc { +class ResourceProvider; + +class CC_EXPORT ZeroCopyRasterWorkerPool : public RasterWorkerPool, + public Rasterizer, + public RasterizerTaskClient { + public: + ~ZeroCopyRasterWorkerPool() override; + + static scoped_ptr<RasterWorkerPool> Create( + base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ResourceProvider* resource_provider); + + // Overridden from RasterWorkerPool: + Rasterizer* AsRasterizer() override; + + // Overridden from Rasterizer: + void SetClient(RasterizerClient* client) override; + void Shutdown() override; + void ScheduleTasks(RasterTaskQueue* queue) override; + void CheckForCompletedTasks() override; + + // Overridden from RasterizerTaskClient: + scoped_ptr<RasterBuffer> AcquireBufferForRaster( + const Resource* resource) override; + void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override; + + protected: + ZeroCopyRasterWorkerPool(base::SequencedTaskRunner* task_runner, + TaskGraphRunner* task_graph_runner, + ResourceProvider* resource_provider); + + private: + void OnRasterFinished(TaskSet task_set); + scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const; + + scoped_refptr<base::SequencedTaskRunner> task_runner_; + TaskGraphRunner* task_graph_runner_; + const NamespaceToken namespace_token_; + RasterizerClient* client_; + ResourceProvider* resource_provider_; + + TaskSetCollection raster_pending_; + + scoped_refptr<RasterizerTask> raster_finished_tasks_[kNumberOfTaskSets]; + + // Task graph used when scheduling tasks and vector used to gather + // completed tasks. + TaskGraph graph_; + Task::Vector completed_tasks_; + + base::WeakPtrFactory<ZeroCopyRasterWorkerPool> + raster_finished_weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ZeroCopyRasterWorkerPool); +}; + +} // namespace cc + +#endif // CC_RESOURCES_ZERO_COPY_RASTER_WORKER_POOL_H_ |