blob: 3466a633add64b65627c2d24309e71502e911f4e [file] [log] [blame]
// 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 "build/build_config.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/texture_layer.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
#include "cc/test/fake_picture_layer.h"
#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/layer_tree_pixel_test.h"
#include "cc/test/paths.h"
#include "cc/test/solid_color_content_layer_client.h"
#include "cc/trees/layer_tree_impl.h"
#if !defined(OS_ANDROID)
namespace cc {
namespace {
// Can't templatize a class on its own members, so ReadbackType and
// ReadbackTestConfig are declared here, before LayerTreeHostReadbackPixelTest.
enum ReadbackType {
READBACK_INVALID,
READBACK_DEFAULT,
READBACK_BITMAP,
};
struct ReadbackTestConfig {
ReadbackTestConfig(LayerTreePixelTest::PixelTestType pixel_test_type_,
ReadbackType readback_type_)
: pixel_test_type(pixel_test_type_), readback_type(readback_type_) {}
LayerTreePixelTest::PixelTestType pixel_test_type;
ReadbackType readback_type;
};
class LayerTreeHostReadbackPixelTest
: public LayerTreePixelTest,
public testing::WithParamInterface<ReadbackTestConfig> {
protected:
LayerTreeHostReadbackPixelTest()
: readback_type_(READBACK_INVALID),
insert_copy_request_after_frame_count_(0) {}
void RunReadbackTest(PixelTestType test_type,
ReadbackType readback_type,
scoped_refptr<Layer> content_root,
base::FilePath file_name) {
readback_type_ = readback_type;
RunPixelTest(test_type, content_root, file_name);
}
void RunReadbackTestWithReadbackTarget(PixelTestType type,
ReadbackType readback_type,
scoped_refptr<Layer> content_root,
Layer* target,
base::FilePath file_name) {
readback_type_ = readback_type;
RunPixelTestWithReadbackTarget(type, content_root, target, file_name);
}
std::unique_ptr<CopyOutputRequest> CreateCopyOutputRequest() override {
std::unique_ptr<CopyOutputRequest> request;
if (readback_type_ == READBACK_BITMAP) {
request = CopyOutputRequest::CreateBitmapRequest(
base::Bind(&LayerTreeHostReadbackPixelTest::ReadbackResultAsBitmap,
base::Unretained(this)));
} else {
DCHECK_EQ(readback_type_, READBACK_DEFAULT);
if (test_type_ == PIXEL_TEST_SOFTWARE) {
request = CopyOutputRequest::CreateRequest(
base::Bind(&LayerTreeHostReadbackPixelTest::ReadbackResultAsBitmap,
base::Unretained(this)));
} else {
DCHECK_EQ(test_type_, PIXEL_TEST_GL);
request = CopyOutputRequest::CreateRequest(
base::Bind(&LayerTreeHostReadbackPixelTest::ReadbackResultAsTexture,
base::Unretained(this)));
}
}
if (!copy_subrect_.IsEmpty())
request->set_area(copy_subrect_);
return request;
}
void BeginTest() override {
if (insert_copy_request_after_frame_count_ == 0) {
Layer* const target =
readback_target_ ? readback_target_ : layer_tree_host()->root_layer();
target->RequestCopyOfOutput(CreateCopyOutputRequest());
}
PostSetNeedsCommitToMainThread();
}
void DidCommitAndDrawFrame() override {
if (insert_copy_request_after_frame_count_ ==
layer_tree_host()->source_frame_number()) {
Layer* const target =
readback_target_ ? readback_target_ : layer_tree_host()->root_layer();
target->RequestCopyOfOutput(CreateCopyOutputRequest());
}
}
void ReadbackResultAsBitmap(std::unique_ptr<CopyOutputResult> result) {
EXPECT_TRUE(task_runner_provider()->IsMainThread());
EXPECT_TRUE(result->HasBitmap());
result_bitmap_ = result->TakeBitmap();
EndTest();
}
void ReadbackResultAsTexture(std::unique_ptr<CopyOutputResult> result) {
EXPECT_TRUE(task_runner_provider()->IsMainThread());
EXPECT_TRUE(result->HasTexture());
TextureMailbox texture_mailbox;
std::unique_ptr<SingleReleaseCallback> release_callback;
result->TakeTexture(&texture_mailbox, &release_callback);
EXPECT_TRUE(texture_mailbox.IsValid());
EXPECT_TRUE(texture_mailbox.IsTexture());
std::unique_ptr<SkBitmap> bitmap =
CopyTextureMailboxToBitmap(result->size(), texture_mailbox);
release_callback->Run(gpu::SyncToken(), false);
ReadbackResultAsBitmap(
CopyOutputResult::CreateBitmapResult(std::move(bitmap)));
}
ReadbackType readback_type_;
gfx::Rect copy_subrect_;
int insert_copy_request_after_frame_count_;
};
void IgnoreReadbackResult(std::unique_ptr<CopyOutputResult> result) {}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackRootLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> green =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
background->AddChild(green);
RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type,
background, base::FilePath(FILE_PATH_LITERAL("green.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> green =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
background->AddChild(green);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
green->AddChild(blue);
RunReadbackTest(
GetParam().pixel_test_type, GetParam().readback_type, background,
base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> green =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
background->AddChild(green);
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
green.get(), base::FilePath(FILE_PATH_LITERAL("green.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> green =
CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
background->AddChild(green);
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
green.get(), base::FilePath(FILE_PATH_LITERAL("green_small.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayerWithChild) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> green =
CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
background->AddChild(green);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
green->AddChild(blue);
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
green.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubtreeSurroundsTargetLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> target =
CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorRED);
background->AddChild(target);
scoped_refptr<SolidColorLayer> green =
CreateSolidColorLayer(gfx::Rect(-100, -100, 300, 300), SK_ColorGREEN);
target->AddChild(green);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
target->AddChild(blue);
copy_subrect_ = gfx::Rect(0, 0, 100, 100);
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
target.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest,
ReadbackSubtreeExtendsBeyondTargetLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> target =
CreateSolidColorLayer(gfx::Rect(50, 50, 150, 150), SK_ColorRED);
background->AddChild(target);
scoped_refptr<SolidColorLayer> green =
CreateSolidColorLayer(gfx::Rect(50, 50, 200, 200), SK_ColorGREEN);
target->AddChild(green);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(100, 100, 50, 50), SK_ColorBLUE);
target->AddChild(blue);
copy_subrect_ = gfx::Rect(50, 50, 100, 100);
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
target.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
scoped_refptr<SolidColorLayer> hidden_target =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
hidden_target->SetHideLayerAndSubtree(true);
background->AddChild(hidden_target);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
hidden_target->AddChild(blue);
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
hidden_target.get(),
base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest,
HiddenSubtreeNotVisibleWhenDrawnForReadback) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
scoped_refptr<SolidColorLayer> hidden_target =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
hidden_target->SetHideLayerAndSubtree(true);
background->AddChild(hidden_target);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
hidden_target->AddChild(blue);
hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
base::Bind(&IgnoreReadbackResult)));
RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type,
background, base::FilePath(FILE_PATH_LITERAL("black.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubrect) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> green =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
background->AddChild(green);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(100, 100, 50, 50), SK_ColorBLUE);
green->AddChild(blue);
// Grab the middle of the root layer.
copy_subrect_ = gfx::Rect(50, 50, 100, 100);
RunReadbackTest(
GetParam().pixel_test_type, GetParam().readback_type, background,
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> green =
CreateSolidColorLayer(gfx::Rect(25, 25, 150, 150), SK_ColorGREEN);
background->AddChild(green);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(75, 75, 50, 50), SK_ColorBLUE);
green->AddChild(blue);
// Grab the middle of the green layer.
copy_subrect_ = gfx::Rect(25, 25, 100, 100);
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
green.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> parent =
CreateSolidColorLayer(gfx::Rect(0, 0, 150, 150), SK_ColorRED);
background->AddChild(parent);
scoped_refptr<SolidColorLayer> target =
CreateSolidColorLayer(gfx::Rect(0, 0, 100, 100), SK_ColorGREEN);
parent->AddChild(target);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
target->AddChild(blue);
insert_copy_request_after_frame_count_ = 1;
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
target.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackOutsideViewportWhenNoDamage) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> parent =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorRED);
EXPECT_FALSE(parent->masks_to_bounds());
background->AddChild(parent);
scoped_refptr<SolidColorLayer> target =
CreateSolidColorLayer(gfx::Rect(250, 250, 100, 100), SK_ColorGREEN);
parent->AddChild(target);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
target->AddChild(blue);
insert_copy_request_after_frame_count_ = 1;
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
target.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerOutsideViewport) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> green =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
// Only the top left quarter of the layer is inside the viewport, so the
// blue layer is entirely outside.
green->SetPosition(gfx::PointF(100.f, 100.f));
background->AddChild(green);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
green->AddChild(blue);
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
green.get(),
base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootOrFirstLayer) {
// This test has 3 render passes with the copy request on the render pass in
// the middle. This test caught an issue where copy requests on non-root
// non-first render passes were being treated differently from the first
// render pass.
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
scoped_refptr<SolidColorLayer> blue =
CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
blue->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
base::Bind(&IgnoreReadbackResult)));
background->AddChild(blue);
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
background.get(),
base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackPixelTest, MultipleReadbacksOnLayer) {
// This test has 2 copy requests on the background layer. One is added in the
// test body, another is added in RunReadbackTestWithReadbackTarget. For every
// copy request after the first, state must be restored via a call to
// UseRenderPass (see http://crbug.com/99393). This test ensures that the
// renderer correctly handles cases where UseRenderPass is called multiple
// times for a single layer.
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
background->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
base::Bind(&IgnoreReadbackResult)));
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
background.get(), base::FilePath(FILE_PATH_LITERAL("green.png")));
}
INSTANTIATE_TEST_CASE_P(
LayerTreeHostReadbackPixelTests,
LayerTreeHostReadbackPixelTest,
::testing::Values(
ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_SOFTWARE,
READBACK_DEFAULT),
ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
READBACK_DEFAULT),
ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
READBACK_BITMAP)));
class LayerTreeHostReadbackDeviceScalePixelTest
: public LayerTreeHostReadbackPixelTest {
protected:
LayerTreeHostReadbackDeviceScalePixelTest()
: device_scale_factor_(1.f),
white_client_(SK_ColorWHITE, gfx::Size(200, 200)),
green_client_(SK_ColorGREEN, gfx::Size(200, 200)),
blue_client_(SK_ColorBLUE, gfx::Size(200, 200)) {}
void InitializeSettings(LayerTreeSettings* settings) override {
// Cause the device scale factor to be inherited by contents scales.
settings->layer_transforms_should_scale_layer_contents = true;
}
void SetupTree() override {
layer_tree_host()->SetDeviceScaleFactor(device_scale_factor_);
LayerTreePixelTest::SetupTree();
}
void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
EXPECT_EQ(device_scale_factor_,
host_impl->active_tree()->device_scale_factor());
}
float device_scale_factor_;
SolidColorContentLayerClient white_client_;
SolidColorContentLayerClient green_client_;
SolidColorContentLayerClient blue_client_;
};
TEST_P(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackSubrect) {
scoped_refptr<FakePictureLayer> background =
FakePictureLayer::Create(&white_client_);
background->SetBounds(gfx::Size(100, 100));
background->SetIsDrawable(true);
scoped_refptr<FakePictureLayer> green =
FakePictureLayer::Create(&green_client_);
green->SetBounds(gfx::Size(100, 100));
green->SetIsDrawable(true);
background->AddChild(green);
scoped_refptr<FakePictureLayer> blue =
FakePictureLayer::Create(&blue_client_);
blue->SetPosition(gfx::PointF(50.f, 50.f));
blue->SetBounds(gfx::Size(25, 25));
blue->SetIsDrawable(true);
green->AddChild(blue);
// Grab the middle of the root layer.
copy_subrect_ = gfx::Rect(25, 25, 50, 50);
device_scale_factor_ = 2.f;
RunReadbackTest(
GetParam().pixel_test_type, GetParam().readback_type, background,
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
TEST_P(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackNonRootLayerSubrect) {
scoped_refptr<FakePictureLayer> background =
FakePictureLayer::Create(&white_client_);
background->SetBounds(gfx::Size(100, 100));
background->SetIsDrawable(true);
scoped_refptr<FakePictureLayer> green =
FakePictureLayer::Create(&green_client_);
green->SetPosition(gfx::PointF(10.f, 20.f));
green->SetBounds(gfx::Size(90, 80));
green->SetIsDrawable(true);
background->AddChild(green);
scoped_refptr<FakePictureLayer> blue =
FakePictureLayer::Create(&blue_client_);
blue->SetPosition(gfx::PointF(50.f, 50.f));
blue->SetBounds(gfx::Size(25, 25));
blue->SetIsDrawable(true);
green->AddChild(blue);
// Grab the green layer's content with blue in the bottom right.
copy_subrect_ = gfx::Rect(25, 25, 50, 50);
device_scale_factor_ = 2.f;
RunReadbackTestWithReadbackTarget(
GetParam().pixel_test_type, GetParam().readback_type, background,
green.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
INSTANTIATE_TEST_CASE_P(
LayerTreeHostReadbackDeviceScalePixelTests,
LayerTreeHostReadbackDeviceScalePixelTest,
::testing::Values(
ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_SOFTWARE,
READBACK_DEFAULT),
ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
READBACK_DEFAULT),
ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
READBACK_BITMAP)));
} // namespace
} // namespace cc
#endif // OS_ANDROID