blob: 0d7b46438ad85d849afa786ab4a7f9e92459be65 [file] [log] [blame]
// Copyright 2015 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 <stddef.h>
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "cc/layers/content_layer_client.h"
#include "cc/layers/picture_layer.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_op_buffer.h"
#include "cc/test/layer_tree_pixel_test.h"
#include "cc/test/test_layer_tree_frame_sink.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/test/buildflags.h"
#include "gpu/command_buffer/client/raster_interface.h"
#if !BUILDFLAG(IS_ANDROID)
namespace cc {
namespace {
class LayerTreeHostTilesPixelTest
: public LayerTreePixelTest,
public ::testing::WithParamInterface<RasterTestConfig> {
protected:
LayerTreeHostTilesPixelTest() : LayerTreePixelTest(renderer_type()) {
set_raster_type(GetParam().raster_type);
}
viz::RendererType renderer_type() const { return GetParam().renderer_type; }
void InitializeSettings(LayerTreeSettings* settings) override {
LayerTreePixelTest::InitializeSettings(settings);
settings->use_partial_raster = use_partial_raster_;
}
void BeginTest() override {
// Don't set up a readback target at the start of the test.
PostSetNeedsCommitToMainThread();
}
void DoReadback() {
Layer* target = readback_target_ ? readback_target_.get()
: layer_tree_host()->root_layer();
target->RequestCopyOfOutput(CreateCopyOutputRequest());
}
void WillPrepareTilesOnThread(LayerTreeHostImpl* host_impl) override {
// Issue a GL finish before preparing tiles to ensure resources become
// available for use in a timely manner. Needed for the one-copy path.
viz::RasterContextProvider* context_provider =
host_impl->layer_tree_frame_sink()->worker_context_provider();
if (!context_provider)
return;
viz::RasterContextProvider::ScopedRasterContextLock lock(context_provider);
lock.RasterInterface()->Finish();
}
base::FilePath ref_file_;
std::unique_ptr<SkBitmap> result_bitmap_;
bool use_partial_raster_ = false;
};
class BlueYellowClient : public ContentLayerClient {
public:
explicit BlueYellowClient(const gfx::Size& size)
: size_(size), blue_top_(true) {}
gfx::Rect PaintableRegion() const override { return gfx::Rect(size_); }
scoped_refptr<DisplayItemList> PaintContentsToDisplayList() override {
auto display_list = base::MakeRefCounted<DisplayItemList>();
display_list->StartPaint();
gfx::Rect top(0, 0, size_.width(), size_.height() / 2);
gfx::Rect bottom(0, size_.height() / 2, size_.width(), size_.height() / 2);
gfx::Rect blue_rect = blue_top_ ? top : bottom;
gfx::Rect yellow_rect = blue_top_ ? bottom : top;
PaintFlags flags;
flags.setStyle(PaintFlags::kFill_Style);
// Use custom colors with 0xF2 rather than the default blue/yellow (which
// use 0xFF), as the default won't show dither patterns as it exactly maps
// to a 16-bit color.
flags.setColor(SkColorSetRGB(0x00, 0x00, 0xF2));
display_list->push<DrawRectOp>(gfx::RectToSkRect(blue_rect), flags);
flags.setColor(SkColorSetRGB(0xF2, 0xF2, 0x00));
display_list->push<DrawRectOp>(gfx::RectToSkRect(yellow_rect), flags);
display_list->EndPaintOfUnpaired(PaintableRegion());
display_list->Finalize();
return display_list;
}
bool FillsBoundsCompletely() const override { return true; }
void set_blue_top(bool b) { blue_top_ = b; }
private:
gfx::Size size_;
bool blue_top_;
};
class LayerTreeHostTilesTestPartialInvalidation
: public LayerTreeHostTilesPixelTest {
public:
LayerTreeHostTilesTestPartialInvalidation()
: client_(gfx::Size(200, 200)),
picture_layer_(PictureLayer::Create(&client_)) {
picture_layer_->SetBounds(gfx::Size(200, 200));
picture_layer_->SetIsDrawable(true);
}
void DidCommitAndDrawFrame() override {
switch (layer_tree_host()->SourceFrameNumber()) {
case 1:
// We have done one frame, but the resource may not be available for
// partial raster yet. Force a second frame.
picture_layer_->SetNeedsDisplayRect(gfx::Rect(50, 50, 100, 100));
break;
case 2:
// We have done two frames, so the layer's content has been rastered
// twice and the first frame's resource is available for partial
// raster. Now we change the picture behind it to record something
// completely different, but we give a smaller invalidation rect. The
// layer should only re-raster the stuff in the rect. If it doesn't do
// partial raster it would re-raster the whole thing instead.
client_.set_blue_top(false);
Finish();
picture_layer_->SetNeedsDisplayRect(gfx::Rect(50, 50, 100, 100));
// Add a copy request to see what happened!
DoReadback();
break;
}
}
protected:
BlueYellowClient client_;
scoped_refptr<PictureLayer> picture_layer_;
};
class PrimaryColorClient : public ContentLayerClient {
public:
explicit PrimaryColorClient(const gfx::Size& size) : size_(size) {}
gfx::Rect PaintableRegion() const override { return gfx::Rect(size_); }
scoped_refptr<DisplayItemList> PaintContentsToDisplayList() override {
// When painted, the DisplayItemList should produce blocks of red, green,
// and blue to test primary color reproduction.
auto display_list = base::MakeRefCounted<DisplayItemList>();
display_list->StartPaint();
int w = size_.width() / 3;
gfx::Rect red_rect(0, 0, w, size_.height());
gfx::Rect green_rect(w, 0, w, size_.height());
gfx::Rect blue_rect(w * 2, 0, w, size_.height());
PaintFlags flags;
flags.setStyle(PaintFlags::kFill_Style);
flags.setColor(SK_ColorRED);
display_list->push<DrawRectOp>(gfx::RectToSkRect(red_rect), flags);
flags.setColor(SK_ColorGREEN);
display_list->push<DrawRectOp>(gfx::RectToSkRect(green_rect), flags);
flags.setColor(SK_ColorBLUE);
display_list->push<DrawRectOp>(gfx::RectToSkRect(blue_rect), flags);
display_list->EndPaintOfUnpaired(PaintableRegion());
display_list->Finalize();
return display_list;
}
bool FillsBoundsCompletely() const override { return true; }
private:
gfx::Size size_;
};
class LayerTreeHostTilesTestRasterColorSpace
: public LayerTreeHostTilesPixelTest {
public:
LayerTreeHostTilesTestRasterColorSpace()
: client_(gfx::Size(150, 150)),
picture_layer_(PictureLayer::Create(&client_)) {
picture_layer_->SetBounds(gfx::Size(150, 150));
picture_layer_->SetIsDrawable(true);
}
void SetColorSpace(const gfx::ColorSpace& color_space) {
color_space_ = color_space;
}
void WillBeginTest() override {
LayerTreeHostTilesPixelTest::WillBeginTest();
DCHECK(color_space_.IsValid());
layer_tree_host()->SetDisplayColorSpaces(
gfx::DisplayColorSpaces(color_space_));
}
void DidCommitAndDrawFrame() override {
if (layer_tree_host()->SourceFrameNumber() == 1) {
Finish();
DoReadback();
}
}
protected:
PrimaryColorClient client_;
scoped_refptr<PictureLayer> picture_layer_;
gfx::ColorSpace color_space_;
};
std::vector<RasterTestConfig> const kTestCases = {
{viz::RendererType::kSoftware, TestRasterType::kBitmap},
#if BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
{viz::RendererType::kSkiaGL, TestRasterType::kOneCopy},
{viz::RendererType::kSkiaGL, TestRasterType::kGpu},
#endif // BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
#if BUILDFLAG(ENABLE_VULKAN_BACKEND_TESTS)
{viz::RendererType::kSkiaVk, TestRasterType::kGpu},
#endif // BUILDFLAG(ENABLE_VULKAN_BACKEND_TESTS)
#if BUILDFLAG(ENABLE_DAWN_BACKEND_TESTS)
{viz::RendererType::kSkiaDawn, TestRasterType::kGpu},
#endif // BUILDFLAG(ENABLE_DAWN_BACKEND_TESTS)
};
INSTANTIATE_TEST_SUITE_P(All,
LayerTreeHostTilesTestPartialInvalidation,
::testing::ValuesIn(kTestCases),
::testing::PrintToStringParamName());
#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(MEMORY_SANITIZER) || \
defined(ADDRESS_SANITIZER) || BUILDFLAG(IS_FUCHSIA)
// TODO(crbug.com/1045521): Flakes on all slower bots.
#define MAYBE_PartialRaster DISABLED_PartialRaster
#else
#define MAYBE_PartialRaster PartialRaster
#endif
TEST_P(LayerTreeHostTilesTestPartialInvalidation, MAYBE_PartialRaster) {
use_partial_raster_ = true;
RunSingleThreadedPixelTest(
picture_layer_,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_partial_flipped.png")));
}
#undef MAYBE_PartialRaster
TEST_P(LayerTreeHostTilesTestPartialInvalidation, FullRaster) {
RunSingleThreadedPixelTest(
picture_layer_,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png")));
}
std::vector<RasterTestConfig> const kTestCasesMultiThread = {
#if BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
{viz::RendererType::kSkiaGL, TestRasterType::kOneCopy},
#endif // BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
#if BUILDFLAG(ENABLE_VULKAN_BACKEND_TESTS)
// TODO(rivr): Switch this to one copy raster once is is supported for
// Vulkan in these tests.
{viz::RendererType::kSkiaVk, TestRasterType::kGpu},
#endif // BUILDFLAG(ENABLE_VULKAN_BACKEND_TESTS)
#if BUILDFLAG(ENABLE_DAWN_BACKEND_TESTS)
{viz::RendererType::kSkiaDawn, TestRasterType::kGpu},
#endif // BUILDFLAG(ENABLE_DAWN_BACKEND_TESTS)
};
using LayerTreeHostTilesTestPartialInvalidationMultiThread =
LayerTreeHostTilesTestPartialInvalidation;
INSTANTIATE_TEST_SUITE_P(All,
LayerTreeHostTilesTestPartialInvalidationMultiThread,
::testing::ValuesIn(kTestCasesMultiThread),
::testing::PrintToStringParamName());
// kTestCasesMultiThread is empty on some platforms.
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
LayerTreeHostTilesTestPartialInvalidationMultiThread);
#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(THREAD_SANITIZER)
// Flaky on Linux TSAN. https://crbug.com/707711
#define MAYBE_PartialRaster DISABLED_PartialRaster
#elif BUILDFLAG(IS_CHROMEOS_ASH) || defined(MEMORY_SANITIZER) || \
defined(ADDRESS_SANITIZER) || BUILDFLAG(IS_FUCHSIA)
// TODO(crbug.com/1045521): Flakes on all slower bots.
#define MAYBE_PartialRaster DISABLED_PartialRaster
#else
#define MAYBE_PartialRaster PartialRaster
#endif
TEST_P(LayerTreeHostTilesTestPartialInvalidationMultiThread,
MAYBE_PartialRaster) {
use_partial_raster_ = true;
RunPixelTest(
picture_layer_,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_partial_flipped.png")));
}
#undef MAYBE_PartialRaster
TEST_P(LayerTreeHostTilesTestPartialInvalidationMultiThread, FullRaster) {
RunPixelTest(picture_layer_,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png")));
}
INSTANTIATE_TEST_SUITE_P(All,
LayerTreeHostTilesTestRasterColorSpace,
::testing::ValuesIn(kTestCases),
::testing::PrintToStringParamName());
// These tests verify that no artifacts are introduced when the color space for
// rasterization doesn't contain the primary colors of sRGB.
// See crbug.com/1073962 for more details.
TEST_P(LayerTreeHostTilesTestRasterColorSpace, sRGB) {
SetColorSpace(gfx::ColorSpace::CreateSRGB());
RunPixelTest(picture_layer_,
base::FilePath(FILE_PATH_LITERAL("primary_colors.png")));
}
TEST_P(LayerTreeHostTilesTestRasterColorSpace, GenericRGB) {
SetColorSpace(gfx::ColorSpace(gfx::ColorSpace::PrimaryID::APPLE_GENERIC_RGB,
gfx::ColorSpace::TransferID::GAMMA18));
RunPixelTest(picture_layer_,
base::FilePath(FILE_PATH_LITERAL("primary_colors.png")));
}
TEST_P(LayerTreeHostTilesTestRasterColorSpace, CustomColorSpace) {
// Create a color space with a different blue point.
SkColorSpacePrimaries primaries;
skcms_Matrix3x3 to_XYZD50;
primaries.fRX = 0.640f;
primaries.fRY = 0.330f;
primaries.fGX = 0.300f;
primaries.fGY = 0.600f;
primaries.fBX = 0.130f;
primaries.fBY = 0.080f;
primaries.fWX = 0.3127f;
primaries.fWY = 0.3290f;
primaries.toXYZD50(&to_XYZD50);
SetColorSpace(gfx::ColorSpace::CreateCustom(
to_XYZD50, gfx::ColorSpace::TransferID::SRGB));
RunPixelTest(picture_layer_,
base::FilePath(FILE_PATH_LITERAL("primary_colors.png")));
}
// This test doesn't work on Vulkan because on our hardware we can't render to
// RGBA4444 format using either SwiftShader or native Vulkan. See
// crbug.com/987278 for details.
// TODO(crbug.com/1151490) : Re-enable after this is supported for OOPR.
#if BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
class LayerTreeHostTilesTestPartialInvalidationLowBitDepth
: public LayerTreeHostTilesTestPartialInvalidation {
protected:
void InitializeSettings(LayerTreeSettings* settings) override {
LayerTreeHostTilesPixelTest::InitializeSettings(settings);
settings->use_rgba_4444 = true;
settings->unpremultiply_and_dither_low_bit_depth_tiles = true;
}
};
INSTANTIATE_TEST_SUITE_P(All,
LayerTreeHostTilesTestPartialInvalidationLowBitDepth,
::testing::Values(RasterTestConfig{
viz::RendererType::kSkiaGL, TestRasterType::kGpu}),
::testing::PrintToStringParamName());
TEST_P(LayerTreeHostTilesTestPartialInvalidationLowBitDepth,
DISABLED_PartialRaster) {
use_partial_raster_ = true;
RunSingleThreadedPixelTest(picture_layer_,
base::FilePath(FILE_PATH_LITERAL(
"blue_yellow_partial_flipped_dither.png")));
}
TEST_P(LayerTreeHostTilesTestPartialInvalidationLowBitDepth,
DISABLED_FullRaster) {
RunSingleThreadedPixelTest(
picture_layer_,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped_dither.png")));
}
#endif // BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
} // namespace
} // namespace cc
#endif // !BUILDFLAG(IS_ANDROID)