Commit c60f5fbb authored by hendrikw's avatar hendrikw Committed by Commit bot

Expose IsSolidColor and write units tests

AnalysisRaster was needed because we must run the analysis on a separate
thread.  My second attempt placed the analysis in the picturepileimpl,
but, as vmpstr predicted, this caused issues when software rasterizing
since it uses yet another thread.  The way around all of this was to
write another raster function without the:
  DCHECK(raster_thread_checker_.CalledOnValidThread());

We're calling the Analysis before any synchronization occures with impl
so it should be safe to call without the check.

BUG=396908

Review URL: https://codereview.chromium.org/494503002

Cr-Commit-Position: refs/heads/master@{#292044}
parent 18047c97
...@@ -203,6 +203,11 @@ bool Picture::IsSuitableForGpuRasterization() const { ...@@ -203,6 +203,11 @@ bool Picture::IsSuitableForGpuRasterization() const {
return picture_->suitableForGpuRasterization(NULL); return picture_->suitableForGpuRasterization(NULL);
} }
int Picture::ApproximateOpCount() const {
DCHECK(picture_);
return picture_->approximateOpCount();
}
bool Picture::HasText() const { bool Picture::HasText() const {
DCHECK(picture_); DCHECK(picture_);
return picture_->hasText(); return picture_->hasText();
......
...@@ -69,6 +69,7 @@ class CC_EXPORT Picture ...@@ -69,6 +69,7 @@ class CC_EXPORT Picture
bool HasRecording() const { return picture_.get() != NULL; } bool HasRecording() const { return picture_.get() != NULL; }
bool IsSuitableForGpuRasterization() const; bool IsSuitableForGpuRasterization() const;
int ApproximateOpCount() const;
bool HasText() const; bool HasText() const;
......
...@@ -19,6 +19,9 @@ namespace { ...@@ -19,6 +19,9 @@ namespace {
// picture that intersects the visible layer rect expanded by this distance // picture that intersects the visible layer rect expanded by this distance
// will be recorded. // will be recorded.
const int kPixelDistanceToRecord = 8000; 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 // 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 // way to set // this from the command line so we can write a benchmark
...@@ -146,7 +149,11 @@ float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, ...@@ -146,7 +149,11 @@ float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles,
namespace cc { namespace cc {
PicturePile::PicturePile() : is_suitable_for_gpu_rasterization_(true) {} PicturePile::PicturePile()
: is_suitable_for_gpu_rasterization_(true),
is_solid_color_(true),
solid_color_(SK_ColorTRANSPARENT) {
}
PicturePile::~PicturePile() { PicturePile::~PicturePile() {
} }
...@@ -501,6 +508,7 @@ bool PicturePile::UpdateAndExpandInvalidation( ...@@ -501,6 +508,7 @@ bool PicturePile::UpdateAndExpandInvalidation(
found_tile_for_recorded_picture = true; found_tile_for_recorded_picture = true;
} }
} }
DetermineIfSolidColor();
DCHECK(found_tile_for_recorded_picture); DCHECK(found_tile_for_recorded_picture);
} }
...@@ -516,4 +524,35 @@ void PicturePile::SetEmptyBounds() { ...@@ -516,4 +524,35 @@ void PicturePile::SetEmptyBounds() {
recorded_viewport_ = gfx::Rect(); recorded_viewport_ = gfx::Rect();
} }
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());
picture->Raster(&canvas, NULL, Region(), 1.0f);
is_solid_color_ = canvas.GetColorIfSolid(&solid_color_);
}
} // namespace cc } // namespace cc
...@@ -51,13 +51,20 @@ class CC_EXPORT PicturePile : public PicturePileBase { ...@@ -51,13 +51,20 @@ class CC_EXPORT PicturePile : public PicturePileBase {
is_suitable_for_gpu_rasterization_ = false; is_suitable_for_gpu_rasterization_ = false;
} }
bool IsSolidColor() const { return is_solid_color_; }
SkColor GetSolidColor() const { return solid_color_; }
protected: protected:
virtual ~PicturePile(); virtual ~PicturePile();
private: private:
friend class PicturePileImpl; friend class PicturePileImpl;
void DetermineIfSolidColor();
bool is_suitable_for_gpu_rasterization_; bool is_suitable_for_gpu_rasterization_;
bool is_solid_color_;
SkColor solid_color_;
DISALLOW_COPY_AND_ASSIGN(PicturePile); DISALLOW_COPY_AND_ASSIGN(PicturePile);
}; };
......
...@@ -39,13 +39,16 @@ class TestPicturePile : public PicturePile { ...@@ -39,13 +39,16 @@ class TestPicturePile : public PicturePile {
class PicturePileTestBase { class PicturePileTestBase {
public: public:
PicturePileTestBase() PicturePileTestBase()
: pile_(new TestPicturePile()), : background_color_(SK_ColorBLUE),
background_color_(SK_ColorBLUE),
min_scale_(0.125), min_scale_(0.125),
frame_number_(0), frame_number_(0),
contents_opaque_(false) { contents_opaque_(false) {}
void InitializeData() {
pile_ = make_scoped_refptr(new TestPicturePile());
pile_->SetTileGridSize(gfx::Size(1000, 1000)); pile_->SetTileGridSize(gfx::Size(1000, 1000));
pile_->SetMinContentsScale(min_scale_); pile_->SetMinContentsScale(min_scale_);
client_ = FakeContentLayerClient();
SetTilingSize(pile_->tiling().max_texture_size()); SetTilingSize(pile_->tiling().max_texture_size());
} }
...@@ -91,7 +94,10 @@ class PicturePileTestBase { ...@@ -91,7 +94,10 @@ class PicturePileTestBase {
bool contents_opaque_; bool contents_opaque_;
}; };
class PicturePileTest : public PicturePileTestBase, public testing::Test {}; class PicturePileTest : public PicturePileTestBase, public testing::Test {
public:
virtual void SetUp() OVERRIDE { InitializeData(); }
};
TEST_F(PicturePileTest, SmallInvalidateInflated) { TEST_F(PicturePileTest, SmallInvalidateInflated) {
// Invalidate something inside a tile. // Invalidate something inside a tile.
...@@ -396,6 +402,8 @@ enum Corner { ...@@ -396,6 +402,8 @@ enum Corner {
class PicturePileResizeCornerTest : public PicturePileTestBase, class PicturePileResizeCornerTest : public PicturePileTestBase,
public testing::TestWithParam<Corner> { public testing::TestWithParam<Corner> {
protected: protected:
virtual void SetUp() OVERRIDE { InitializeData(); }
static gfx::Rect CornerSinglePixelRect(Corner corner, const gfx::Size& s) { static gfx::Rect CornerSinglePixelRect(Corner corner, const gfx::Size& s) {
switch (corner) { switch (corner) {
case TOP_LEFT: case TOP_LEFT:
...@@ -1191,5 +1199,51 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) { ...@@ -1191,5 +1199,51 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) {
invalidation.Clear(); 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_->IsSolidColor());
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), pile_->GetSolidColor());
// 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_->IsSolidColor());
EXPECT_EQ(SK_ColorCYAN, pile_->GetSolidColor());
// 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_->IsSolidColor());
// 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_->IsSolidColor());
EXPECT_EQ(SK_ColorRED, pile_->GetSolidColor());
// 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_->IsSolidColor());
}
} // namespace } // namespace
} // namespace cc } // namespace cc
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment