diff options
Diffstat (limited to 'chromium/cc/output/renderer_pixeltest.cc')
-rw-r--r-- | chromium/cc/output/renderer_pixeltest.cc | 1548 |
1 files changed, 1548 insertions, 0 deletions
diff --git a/chromium/cc/output/renderer_pixeltest.cc b/chromium/cc/output/renderer_pixeltest.cc new file mode 100644 index 00000000000..9508aa29166 --- /dev/null +++ b/chromium/cc/output/renderer_pixeltest.cc @@ -0,0 +1,1548 @@ +// Copyright 2012 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 "base/message_loop/message_loop.h" +#include "cc/layers/append_quads_data.h" +#include "cc/output/gl_renderer.h" +#include "cc/quads/draw_quad.h" +#include "cc/quads/picture_draw_quad.h" +#include "cc/quads/texture_draw_quad.h" +#include "cc/resources/platform_color.h" +#include "cc/resources/sync_point_helper.h" +#include "cc/test/fake_picture_pile_impl.h" +#include "cc/test/pixel_test.h" +#include "gpu/GLES2/gl2extchromium.h" +#include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/effects/SkColorFilterImageFilter.h" +#include "third_party/skia/include/effects/SkColorMatrixFilter.h" +#include "ui/gfx/rect_conversions.h" + +namespace cc { +namespace { + +scoped_ptr<RenderPass> CreateTestRootRenderPass(RenderPass::Id id, + gfx::Rect rect) { + scoped_ptr<RenderPass> pass = RenderPass::Create(); + const gfx::Rect output_rect = rect; + const gfx::RectF damage_rect = rect; + const gfx::Transform transform_to_root_target; + pass->SetNew(id, output_rect, damage_rect, transform_to_root_target); + return pass.Pass(); +} + +scoped_ptr<RenderPass> CreateTestRenderPass( + RenderPass::Id id, + gfx::Rect rect, + const gfx::Transform& transform_to_root_target) { + scoped_ptr<RenderPass> pass = RenderPass::Create(); + const gfx::Rect output_rect = rect; + const gfx::RectF damage_rect = rect; + pass->SetNew(id, output_rect, damage_rect, transform_to_root_target); + return pass.Pass(); +} + +scoped_ptr<SharedQuadState> CreateTestSharedQuadState( + gfx::Transform content_to_target_transform, gfx::Rect rect) { + const gfx::Size content_bounds = rect.size(); + const gfx::Rect visible_content_rect = rect; + const gfx::Rect clip_rect = rect; + const bool is_clipped = false; + const float opacity = 1.0f; + scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create(); + shared_state->SetAll(content_to_target_transform, + content_bounds, + visible_content_rect, + clip_rect, + is_clipped, + opacity); + return shared_state.Pass(); +} + +scoped_ptr<SharedQuadState> CreateTestSharedQuadStateClipped( + gfx::Transform content_to_target_transform, + gfx::Rect rect, + gfx::Rect clip_rect) { + const gfx::Size content_bounds = rect.size(); + const gfx::Rect visible_content_rect = clip_rect; + const bool is_clipped = true; + const float opacity = 1.0f; + scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create(); + shared_state->SetAll(content_to_target_transform, + content_bounds, + visible_content_rect, + clip_rect, + is_clipped, + opacity); + return shared_state.Pass(); +} + +scoped_ptr<DrawQuad> CreateTestRenderPassDrawQuad( + SharedQuadState* shared_state, gfx::Rect rect, RenderPass::Id pass_id) { + scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create(); + quad->SetNew(shared_state, + rect, + pass_id, + false, // is_replica + 0, // mask_resource_id + rect, // contents_changed_since_last_frame + gfx::RectF(), // mask_uv_rect + FilterOperations(), // foreground filters + skia::RefPtr<SkImageFilter>(), // foreground filter + FilterOperations()); // background filters + + return quad.PassAs<DrawQuad>(); +} + +scoped_ptr<TextureDrawQuad> CreateTestTextureDrawQuad( + gfx::Rect rect, + SkColor texel_color, + SkColor background_color, + bool premultiplied_alpha, + SharedQuadState* shared_state, + ResourceProvider* resource_provider) { + SkPMColor pixel_color = premultiplied_alpha ? + SkPreMultiplyColor(texel_color) : + SkPackARGB32NoCheck(SkColorGetA(texel_color), + SkColorGetR(texel_color), + SkColorGetG(texel_color), + SkColorGetB(texel_color)); + std::vector<uint32_t> pixels(rect.size().GetArea(), pixel_color); + + ResourceProvider::ResourceId resource = resource_provider->CreateResource( + rect.size(), GL_RGBA, ResourceProvider::TextureUsageAny); + resource_provider->SetPixels( + resource, + reinterpret_cast<uint8_t*>(&pixels.front()), + rect, + rect, + gfx::Vector2d()); + + float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create(); + quad->SetNew(shared_state, + rect, + gfx::Rect(), + resource, + premultiplied_alpha, + gfx::PointF(0.0f, 0.0f), // uv_top_left + gfx::PointF(1.0f, 1.0f), // uv_bottom_right + background_color, + vertex_opacity, + false); // flipped + return quad.Pass(); +} + +typedef ::testing::Types<GLRenderer, + SoftwareRenderer, + GLRendererWithExpandedViewport, + SoftwareRendererWithExpandedViewport> RendererTypes; +TYPED_TEST_CASE(RendererPixelTest, RendererTypes); + +typedef ::testing::Types<GLRenderer, + GLRendererWithSkiaGPUBackend, + SoftwareRenderer> RendererTypesWithSkiaGPUBackend; +template <typename RendererType> +class RendererPixelTestWithSkiaGPUBackend + : public RendererPixelTest<RendererType> { +}; +TYPED_TEST_CASE(RendererPixelTestWithSkiaGPUBackend, + RendererTypesWithSkiaGPUBackend); + +// All pixels can be off by one, but any more than that is an error. +class FuzzyPixelOffByOneComparator : public FuzzyPixelComparator { + public: + explicit FuzzyPixelOffByOneComparator(bool discard_alpha) + : FuzzyPixelComparator(discard_alpha, 100.f, 0.f, 1.f, 1, 0) {} +}; + +template <typename RendererType> +class FuzzyForSoftwareOnlyPixelComparator : public PixelComparator { + public: + explicit FuzzyForSoftwareOnlyPixelComparator(bool discard_alpha) + : fuzzy_(discard_alpha), exact_(discard_alpha) {} + + virtual bool Compare(const SkBitmap& actual_bmp, + const SkBitmap& expected_bmp) const; + + private: + FuzzyPixelOffByOneComparator fuzzy_; + ExactPixelComparator exact_; +}; + +template<> +bool FuzzyForSoftwareOnlyPixelComparator<SoftwareRenderer>::Compare( + const SkBitmap& actual_bmp, + const SkBitmap& expected_bmp) const { + return fuzzy_.Compare(actual_bmp, expected_bmp); +} + +template <> +bool FuzzyForSoftwareOnlyPixelComparator< + SoftwareRendererWithExpandedViewport>::Compare( + const SkBitmap& actual_bmp, + const SkBitmap& expected_bmp) const { + return fuzzy_.Compare(actual_bmp, expected_bmp); +} + +template<typename RendererType> +bool FuzzyForSoftwareOnlyPixelComparator<RendererType>::Compare( + const SkBitmap& actual_bmp, + const SkBitmap& expected_bmp) const { + return exact_.Compare(actual_bmp, expected_bmp); +} + +#if !defined(OS_ANDROID) +TYPED_TEST(RendererPixelTest, SimpleGreenRect) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(shared_state.get(), rect, SK_ColorGREEN, false); + + pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("green.png")), + ExactPixelComparator(true))); +} + +TYPED_TEST(RendererPixelTest, SimpleGreenRect_NonRootRenderPass) { + gfx::Rect rect(this->device_viewport_size_); + gfx::Rect small_rect(100, 100); + + RenderPass::Id child_id(2, 1); + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_id, small_rect, gfx::Transform()); + + scoped_ptr<SharedQuadState> child_shared_state = + CreateTestSharedQuadState(gfx::Transform(), small_rect); + + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(child_shared_state.get(), rect, SK_ColorGREEN, false); + child_pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + + RenderPass::Id root_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRenderPass(root_id, rect, gfx::Transform()); + + scoped_ptr<SharedQuadState> root_shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + + scoped_ptr<DrawQuad> render_pass_quad = + CreateTestRenderPassDrawQuad(root_shared_state.get(), + small_rect, + child_id); + root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); + + RenderPass* child_pass_ptr = child_pass.get(); + + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + EXPECT_TRUE(this->RunPixelTestWithReadbackTarget( + &pass_list, + child_pass_ptr, + base::FilePath(FILE_PATH_LITERAL("green_small.png")), + ExactPixelComparator(true))); +} + +TYPED_TEST(RendererPixelTest, PremultipliedTextureWithoutBackground) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + + scoped_ptr<TextureDrawQuad> texture_quad = CreateTestTextureDrawQuad( + gfx::Rect(this->device_viewport_size_), + SkColorSetARGB(128, 0, 255, 0), // Texel color. + SK_ColorTRANSPARENT, // Background color. + true, // Premultiplied alpha. + shared_state.get(), + this->resource_provider_.get()); + pass->quad_list.push_back(texture_quad.PassAs<DrawQuad>()); + + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(shared_state.get(), rect, SK_ColorWHITE, false); + pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), + FuzzyPixelOffByOneComparator(true))); +} + +TYPED_TEST(RendererPixelTest, PremultipliedTextureWithBackground) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + scoped_ptr<SharedQuadState> texture_quad_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + texture_quad_state->opacity = 0.8f; + + scoped_ptr<TextureDrawQuad> texture_quad = CreateTestTextureDrawQuad( + gfx::Rect(this->device_viewport_size_), + SkColorSetARGB(204, 120, 255, 120), // Texel color. + SK_ColorGREEN, // Background color. + true, // Premultiplied alpha. + texture_quad_state.get(), + this->resource_provider_.get()); + pass->quad_list.push_back(texture_quad.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> color_quad_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(color_quad_state.get(), rect, SK_ColorWHITE, false); + pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), + FuzzyPixelOffByOneComparator(true))); +} + +// TODO(skaslev): The software renderer does not support non-premultplied alpha. +TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithoutBackground) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + + scoped_ptr<TextureDrawQuad> texture_quad = CreateTestTextureDrawQuad( + gfx::Rect(this->device_viewport_size_), + SkColorSetARGB(128, 0, 255, 0), // Texel color. + SK_ColorTRANSPARENT, // Background color. + false, // Premultiplied alpha. + shared_state.get(), + this->resource_provider_.get()); + pass->quad_list.push_back(texture_quad.PassAs<DrawQuad>()); + + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(shared_state.get(), rect, SK_ColorWHITE, false); + pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), + FuzzyPixelOffByOneComparator(true))); +} + +// TODO(skaslev): The software renderer does not support non-premultplied alpha. +TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + scoped_ptr<SharedQuadState> texture_quad_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + texture_quad_state->opacity = 0.8f; + + scoped_ptr<TextureDrawQuad> texture_quad = CreateTestTextureDrawQuad( + gfx::Rect(this->device_viewport_size_), + SkColorSetARGB(204, 120, 255, 120), // Texel color. + SK_ColorGREEN, // Background color. + false, // Premultiplied alpha. + texture_quad_state.get(), + this->resource_provider_.get()); + pass->quad_list.push_back(texture_quad.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> color_quad_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(color_quad_state.get(), rect, SK_ColorWHITE, false); + pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), + FuzzyPixelOffByOneComparator(true))); +} + +class VideoGLRendererPixelTest : public GLRendererPixelTest { + protected: + scoped_ptr<YUVVideoDrawQuad> CreateTestYUVVideoDrawQuad( + SharedQuadState* shared_state, bool with_alpha, bool is_transparent) { + gfx::Rect rect(this->device_viewport_size_); + gfx::Rect opaque_rect(0, 0, 0, 0); + + ResourceProvider::ResourceId y_resource = + resource_provider_->CreateResource( + this->device_viewport_size_, + GL_LUMINANCE, + ResourceProvider::TextureUsageAny); + ResourceProvider::ResourceId u_resource = + resource_provider_->CreateResource( + this->device_viewport_size_, + GL_LUMINANCE, + ResourceProvider::TextureUsageAny); + ResourceProvider::ResourceId v_resource = + resource_provider_->CreateResource( + this->device_viewport_size_, + GL_LUMINANCE, + ResourceProvider::TextureUsageAny); + ResourceProvider::ResourceId a_resource = 0; + if (with_alpha) { + a_resource = resource_provider_->CreateResource( + this->device_viewport_size_, + GL_LUMINANCE, + ResourceProvider::TextureUsageAny); + } + + int w = this->device_viewport_size_.width(); + int h = this->device_viewport_size_.height(); + const int y_plane_size = w * h; + gfx::Rect uv_rect((w + 1) / 2, (h + 1) / 2); + const int uv_plane_size = uv_rect.size().GetArea(); + scoped_ptr<uint8_t[]> y_plane(new uint8_t[y_plane_size]); + scoped_ptr<uint8_t[]> u_plane(new uint8_t[uv_plane_size]); + scoped_ptr<uint8_t[]> v_plane(new uint8_t[uv_plane_size]); + scoped_ptr<uint8_t[]> a_plane; + if (with_alpha) + a_plane.reset(new uint8_t[y_plane_size]); + // YUV values representing Green. + memset(y_plane.get(), 149, y_plane_size); + memset(u_plane.get(), 43, uv_plane_size); + memset(v_plane.get(), 21, uv_plane_size); + if (with_alpha) + memset(a_plane.get(), is_transparent ? 0 : 128, y_plane_size); + + resource_provider_->SetPixels(y_resource, y_plane.get(), rect, rect, + gfx::Vector2d()); + resource_provider_->SetPixels(u_resource, u_plane.get(), uv_rect, uv_rect, + gfx::Vector2d()); + resource_provider_->SetPixels(v_resource, v_plane.get(), uv_rect, uv_rect, + gfx::Vector2d()); + if (with_alpha) { + resource_provider_->SetPixels(a_resource, a_plane.get(), rect, rect, + gfx::Vector2d()); + } + + scoped_ptr<YUVVideoDrawQuad> yuv_quad = cc::YUVVideoDrawQuad::Create(); + yuv_quad->SetNew(shared_state, rect, opaque_rect, gfx::Size(), + y_resource, u_resource, v_resource, a_resource); + return yuv_quad.Pass(); + } +}; + +TEST_F(VideoGLRendererPixelTest, SimpleYUVRect) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + + scoped_ptr<YUVVideoDrawQuad> yuv_quad = + CreateTestYUVVideoDrawQuad(shared_state.get(), false, false); + + pass->quad_list.push_back(yuv_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("green.png")), + ExactPixelComparator(true))); +} + +TEST_F(VideoGLRendererPixelTest, SimpleYUVARect) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + + scoped_ptr<YUVVideoDrawQuad> yuv_quad = + CreateTestYUVVideoDrawQuad(shared_state.get(), true, false); + + pass->quad_list.push_back(yuv_quad.PassAs<DrawQuad>()); + + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(shared_state.get(), rect, SK_ColorWHITE, false); + + pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), + ExactPixelComparator(true))); +} + +TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + + scoped_ptr<YUVVideoDrawQuad> yuv_quad = + CreateTestYUVVideoDrawQuad(shared_state.get(), true, true); + + pass->quad_list.push_back(yuv_quad.PassAs<DrawQuad>()); + + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(shared_state.get(), rect, SK_ColorBLACK, false); + + pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("black.png")), + ExactPixelComparator(true))); +} + +TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) { + gfx::Rect viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(this->device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + shared_state->opacity = 0.5f; + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorBLUE, + false); + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(shared_state.get(), + gfx::Rect(0, + this->device_viewport_size_.height() / 2, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorYELLOW, + false); + + scoped_ptr<SharedQuadState> blank_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create(); + white->SetNew(blank_state.get(), + viewport_rect, + SK_ColorWHITE, + false); + + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(white.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), pass_rect); + + SkScalar matrix[20]; + float amount = 0.5f; + matrix[0] = 0.213f + 0.787f * amount; + matrix[1] = 0.715f - 0.715f * amount; + matrix[2] = 1.f - (matrix[0] + matrix[1]); + matrix[3] = matrix[4] = 0; + matrix[5] = 0.213f - 0.213f * amount; + matrix[6] = 0.715f + 0.285f * amount; + matrix[7] = 1.f - (matrix[5] + matrix[6]); + matrix[8] = matrix[9] = 0; + matrix[10] = 0.213f - 0.213f * amount; + matrix[11] = 0.715f - 0.715f * amount; + matrix[12] = 1.f - (matrix[10] + matrix[11]); + matrix[13] = matrix[14] = 0; + matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0; + matrix[18] = 1; + skia::RefPtr<SkColorFilter> colorFilter(skia::AdoptRef( + new SkColorMatrixFilter(matrix))); + skia::RefPtr<SkImageFilter> filter = + skia::AdoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), NULL)); + + scoped_ptr<RenderPassDrawQuad> render_pass_quad = + RenderPassDrawQuad::Create(); + render_pass_quad->SetNew(pass_shared_state.get(), + pass_rect, + child_pass_id, + false, + 0, + pass_rect, + gfx::RectF(), + FilterOperations(), + filter, + FilterOperations()); + + root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + // This test has alpha=254 for the software renderer vs. alpha=255 for the gl + // renderer so use a fuzzy comparator. + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")), + FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false))); +} + +TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) { + gfx::Rect viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(this->device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + shared_state->opacity = 0.5f; + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorBLUE, + false); + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(shared_state.get(), + gfx::Rect(0, + this->device_viewport_size_.height() / 2, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorYELLOW, + false); + + scoped_ptr<SharedQuadState> blank_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create(); + white->SetNew(blank_state.get(), + viewport_rect, + SK_ColorWHITE, + false); + + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(white.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), pass_rect); + + SkScalar matrix[20]; + float amount = 0.5f; + matrix[0] = 0.213f + 0.787f * amount; + matrix[1] = 0.715f - 0.715f * amount; + matrix[2] = 1.f - (matrix[0] + matrix[1]); + matrix[3] = 0; + matrix[4] = 20.f; + matrix[5] = 0.213f - 0.213f * amount; + matrix[6] = 0.715f + 0.285f * amount; + matrix[7] = 1.f - (matrix[5] + matrix[6]); + matrix[8] = 0; + matrix[9] = 200.f; + matrix[10] = 0.213f - 0.213f * amount; + matrix[11] = 0.715f - 0.715f * amount; + matrix[12] = 1.f - (matrix[10] + matrix[11]); + matrix[13] = 0; + matrix[14] = 1.5f; + matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0; + matrix[18] = 1; + skia::RefPtr<SkColorFilter> colorFilter(skia::AdoptRef( + new SkColorMatrixFilter(matrix))); + skia::RefPtr<SkImageFilter> filter = + skia::AdoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), NULL)); + + scoped_ptr<RenderPassDrawQuad> render_pass_quad = + RenderPassDrawQuad::Create(); + render_pass_quad->SetNew(pass_shared_state.get(), + pass_rect, + child_pass_id, + false, + 0, + pass_rect, + gfx::RectF(), + FilterOperations(), + filter, + FilterOperations()); + + root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); + RenderPassList pass_list; + + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + // This test has alpha=254 for the software renderer vs. alpha=255 for the gl + // renderer so use a fuzzy comparator. + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha_translate.png")), + FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false))); +} + +TYPED_TEST(RendererPixelTest, EnlargedRenderPassTexture) { + gfx::Rect viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(this->device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorBLUE, + false); + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(shared_state.get(), + gfx::Rect(0, + this->device_viewport_size_.height() / 2, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorYELLOW, + false); + + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), pass_rect); + root_pass->quad_list.push_back( + CreateTestRenderPassDrawQuad(pass_shared_state.get(), + pass_rect, + child_pass_id)); + + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + this->renderer_->SetEnlargePassTextureAmountForTesting(gfx::Vector2d(50, 75)); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")), + ExactPixelComparator(true))); +} + +TYPED_TEST(RendererPixelTest, EnlargedRenderPassTextureWithAntiAliasing) { + gfx::Rect viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(this->device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorBLUE, + false); + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(shared_state.get(), + gfx::Rect(0, + this->device_viewport_size_.height() / 2, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorYELLOW, + false); + + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + + gfx::Transform aa_transform; + aa_transform.Translate(0.5, 0.0); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(aa_transform, pass_rect); + root_pass->quad_list.push_back( + CreateTestRenderPassDrawQuad(pass_shared_state.get(), + pass_rect, + child_pass_id)); + + scoped_ptr<SharedQuadState> root_shared_state = + CreateTestSharedQuadState(gfx::Transform(), viewport_rect); + scoped_ptr<SolidColorDrawQuad> background = SolidColorDrawQuad::Create(); + background->SetNew(root_shared_state.get(), + gfx::Rect(this->device_viewport_size_), + SK_ColorWHITE, + false); + root_pass->quad_list.push_back(background.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + this->renderer_->SetEnlargePassTextureAmountForTesting(gfx::Vector2d(50, 75)); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("blue_yellow_anti_aliasing.png")), + FuzzyPixelOffByOneComparator(true))); +} + +template <typename RendererType> +class RendererPixelTestWithBackgroundFilter + : public RendererPixelTest<RendererType> { + protected: + void SetUpRenderPassList() { + gfx::Rect device_viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_id, device_viewport_rect); + root_pass->has_transparent_background = false; + + gfx::Transform identity_content_to_target_transform; + + RenderPass::Id filter_pass_id(2, 1); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> filter_pass = + CreateTestRenderPass(filter_pass_id, + filter_pass_content_rect_, + transform_to_root); + + // A non-visible quad in the filtering render pass. + { + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(identity_content_to_target_transform, + filter_pass_content_rect_); + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(shared_state.get(), + filter_pass_content_rect_, + SK_ColorTRANSPARENT, + false); + filter_pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + filter_pass->shared_quad_state_list.push_back(shared_state.Pass()); + } + + { + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(filter_pass_to_target_transform_, + filter_pass_content_rect_); + scoped_ptr<RenderPassDrawQuad> filter_pass_quad = + RenderPassDrawQuad::Create(); + filter_pass_quad->SetNew( + shared_state.get(), + filter_pass_content_rect_, + filter_pass_id, + false, // is_replica + 0, // mask_resource_id + filter_pass_content_rect_, // contents_changed_since_last_frame + gfx::RectF(), // mask_uv_rect + FilterOperations(), // filters + skia::RefPtr<SkImageFilter>(), // filter + this->background_filters_); + root_pass->quad_list.push_back(filter_pass_quad.PassAs<DrawQuad>()); + root_pass->shared_quad_state_list.push_back(shared_state.Pass()); + } + + const int kColumnWidth = device_viewport_rect.width() / 3; + + gfx::Rect left_rect = gfx::Rect(0, 0, kColumnWidth, 20); + for (int i = 0; left_rect.y() < device_viewport_rect.height(); ++i) { + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(identity_content_to_target_transform, + left_rect); + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(shared_state.get(), left_rect, SK_ColorGREEN, false); + root_pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + root_pass->shared_quad_state_list.push_back(shared_state.Pass()); + left_rect += gfx::Vector2d(0, left_rect.height() + 1); + } + + gfx::Rect middle_rect = gfx::Rect(kColumnWidth+1, 0, kColumnWidth, 20); + for (int i = 0; middle_rect.y() < device_viewport_rect.height(); ++i) { + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(identity_content_to_target_transform, + middle_rect); + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(shared_state.get(), middle_rect, SK_ColorRED, false); + root_pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + root_pass->shared_quad_state_list.push_back(shared_state.Pass()); + middle_rect += gfx::Vector2d(0, middle_rect.height() + 1); + } + + gfx::Rect right_rect = gfx::Rect((kColumnWidth+1)*2, 0, kColumnWidth, 20); + for (int i = 0; right_rect.y() < device_viewport_rect.height(); ++i) { + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(identity_content_to_target_transform, + right_rect); + scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); + color_quad->SetNew(shared_state.get(), right_rect, SK_ColorBLUE, false); + root_pass->quad_list.push_back(color_quad.PassAs<DrawQuad>()); + root_pass->shared_quad_state_list.push_back(shared_state.Pass()); + right_rect += gfx::Vector2d(0, right_rect.height() + 1); + } + + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(identity_content_to_target_transform, + device_viewport_rect); + scoped_ptr<SolidColorDrawQuad> background_quad = + SolidColorDrawQuad::Create(); + background_quad->SetNew(shared_state.get(), + device_viewport_rect, + SK_ColorWHITE, + false); + root_pass->quad_list.push_back(background_quad.PassAs<DrawQuad>()); + root_pass->shared_quad_state_list.push_back(shared_state.Pass()); + + pass_list_.push_back(filter_pass.Pass()); + pass_list_.push_back(root_pass.Pass()); + } + + RenderPassList pass_list_; + FilterOperations background_filters_; + gfx::Transform filter_pass_to_target_transform_; + gfx::Rect filter_pass_content_rect_; +}; + +typedef ::testing::Types<GLRenderer, SoftwareRenderer> + BackgroundFilterRendererTypes; +TYPED_TEST_CASE(RendererPixelTestWithBackgroundFilter, + BackgroundFilterRendererTypes); + +typedef RendererPixelTestWithBackgroundFilter<GLRenderer> +GLRendererPixelTestWithBackgroundFilter; + +// TODO(skaslev): The software renderer does not support filters yet. +TEST_F(GLRendererPixelTestWithBackgroundFilter, InvertFilter) { + this->background_filters_.Append( + FilterOperation::CreateInvertFilter(1.f)); + + this->filter_pass_content_rect_ = gfx::Rect(this->device_viewport_size_); + this->filter_pass_content_rect_.Inset(12, 14, 16, 18); + + this->SetUpRenderPassList(); + EXPECT_TRUE(this->RunPixelTest( + &this->pass_list_, + base::FilePath(FILE_PATH_LITERAL("background_filter.png")), + ExactPixelComparator(true))); +} + +class ExternalStencilPixelTest : public GLRendererPixelTest { + protected: + void ClearBackgroundToGreen() { + WebKit::WebGraphicsContext3D* context3d = output_surface_->context3d(); + output_surface_->EnsureBackbuffer(); + output_surface_->Reshape(device_viewport_size_, 1); + context3d->clearColor(0.f, 1.f, 0.f, 1.f); + context3d->clear(GL_COLOR_BUFFER_BIT); + } + + void PopulateStencilBuffer() { + // Set two quadrants of the stencil buffer to 1. + WebKit::WebGraphicsContext3D* context3d = output_surface_->context3d(); + ASSERT_TRUE(context3d->getContextAttributes().stencil); + output_surface_->EnsureBackbuffer(); + output_surface_->Reshape(device_viewport_size_, 1); + context3d->clearStencil(0); + context3d->clear(GL_STENCIL_BUFFER_BIT); + context3d->enable(GL_SCISSOR_TEST); + context3d->clearStencil(1); + context3d->scissor(0, + 0, + device_viewport_size_.width() / 2, + device_viewport_size_.height() / 2); + context3d->clear(GL_STENCIL_BUFFER_BIT); + context3d->scissor(device_viewport_size_.width() / 2, + device_viewport_size_.height() / 2, + device_viewport_size_.width(), + device_viewport_size_.height()); + context3d->clear(GL_STENCIL_BUFFER_BIT); + } +}; + +TEST_F(ExternalStencilPixelTest, StencilTestEnabled) { + ClearBackgroundToGreen(); + PopulateStencilBuffer(); + this->EnableExternalStencilTest(); + + // Draw a blue quad that covers the entire device viewport. It should be + // clipped to the bottom left and top right corners by the external stencil. + gfx::Rect rect(this->device_viewport_size_); + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + scoped_ptr<SharedQuadState> blue_shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE, false); + pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + pass->has_transparent_background = false; + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), + ExactPixelComparator(true))); +} + +TEST_F(ExternalStencilPixelTest, StencilTestDisabled) { + PopulateStencilBuffer(); + + // Draw a green quad that covers the entire device viewport. The stencil + // buffer should be ignored. + gfx::Rect rect(this->device_viewport_size_); + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + scoped_ptr<SharedQuadState> green_shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + scoped_ptr<SolidColorDrawQuad> green = SolidColorDrawQuad::Create(); + green->SetNew(green_shared_state.get(), rect, SK_ColorGREEN, false); + pass->quad_list.push_back(green.PassAs<DrawQuad>()); + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("green.png")), + ExactPixelComparator(true))); +} + +TEST_F(ExternalStencilPixelTest, RenderSurfacesIgnoreStencil) { + // The stencil test should apply only to the final render pass. + ClearBackgroundToGreen(); + PopulateStencilBuffer(); + this->EnableExternalStencilTest(); + + gfx::Rect viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + root_pass->has_transparent_background = false; + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(this->device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + this->device_viewport_size_.width(), + this->device_viewport_size_.height()), + SK_ColorBLUE, + false); + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), pass_rect); + root_pass->quad_list.push_back( + CreateTestRenderPassDrawQuad(pass_shared_state.get(), + pass_rect, + child_pass_id)); + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), + ExactPixelComparator(true))); +} + +// Software renderer does not support anti-aliased edges. +TEST_F(GLRendererPixelTest, AntiAliasing) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); + + gfx::Transform red_content_to_target_transform; + red_content_to_target_transform.Rotate(10); + scoped_ptr<SharedQuadState> red_shared_state = + CreateTestSharedQuadState(red_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> red = SolidColorDrawQuad::Create(); + red->SetNew(red_shared_state.get(), rect, SK_ColorRED, false); + + pass->quad_list.push_back(red.PassAs<DrawQuad>()); + + gfx::Transform yellow_content_to_target_transform; + yellow_content_to_target_transform.Rotate(5); + scoped_ptr<SharedQuadState> yellow_shared_state = + CreateTestSharedQuadState(yellow_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(yellow_shared_state.get(), rect, SK_ColorYELLOW, false); + + pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + + gfx::Transform blue_content_to_target_transform; + scoped_ptr<SharedQuadState> blue_shared_state = + CreateTestSharedQuadState(blue_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE, false); + + pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("anti_aliasing.png")), + FuzzyPixelOffByOneComparator(true))); +} + +// This test tests that anti-aliasing works for axis aligned quads. +// Anti-aliasing is only supported in the gl renderer. +TEST_F(GLRendererPixelTest, AxisAligned) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> pass = + CreateTestRenderPass(id, rect, transform_to_root); + + gfx::Transform red_content_to_target_transform; + red_content_to_target_transform.Translate(50, 50); + red_content_to_target_transform.Scale( + 0.5f + 1.0f / (rect.width() * 2.0f), + 0.5f + 1.0f / (rect.height() * 2.0f)); + scoped_ptr<SharedQuadState> red_shared_state = + CreateTestSharedQuadState(red_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> red = SolidColorDrawQuad::Create(); + red->SetNew(red_shared_state.get(), rect, SK_ColorRED, false); + + pass->quad_list.push_back(red.PassAs<DrawQuad>()); + + gfx::Transform yellow_content_to_target_transform; + yellow_content_to_target_transform.Translate(25.5f, 25.5f); + yellow_content_to_target_transform.Scale(0.5f, 0.5f); + scoped_ptr<SharedQuadState> yellow_shared_state = + CreateTestSharedQuadState(yellow_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(yellow_shared_state.get(), rect, SK_ColorYELLOW, false); + + pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + + gfx::Transform blue_content_to_target_transform; + scoped_ptr<SharedQuadState> blue_shared_state = + CreateTestSharedQuadState(blue_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE, false); + + pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("axis_aligned.png")), + ExactPixelComparator(true))); +} + +// This test tests that forcing anti-aliasing off works as expected. +// Anti-aliasing is only supported in the gl renderer. +TEST_F(GLRendererPixelTest, ForceAntiAliasingOff) { + gfx::Rect rect(this->device_viewport_size_); + + RenderPass::Id id(1, 1); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> pass = + CreateTestRenderPass(id, rect, transform_to_root); + + gfx::Transform hole_content_to_target_transform; + hole_content_to_target_transform.Translate(50, 50); + hole_content_to_target_transform.Scale( + 0.5f + 1.0f / (rect.width() * 2.0f), + 0.5f + 1.0f / (rect.height() * 2.0f)); + scoped_ptr<SharedQuadState> hole_shared_state = + CreateTestSharedQuadState(hole_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> hole = SolidColorDrawQuad::Create(); + hole->SetAll(hole_shared_state.get(), rect, rect, rect, false, + SK_ColorTRANSPARENT, true); + pass->quad_list.push_back(hole.PassAs<DrawQuad>()); + + gfx::Transform green_content_to_target_transform; + scoped_ptr<SharedQuadState> green_shared_state = + CreateTestSharedQuadState(green_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> green = SolidColorDrawQuad::Create(); + green->SetNew(green_shared_state.get(), rect, SK_ColorGREEN, false); + + pass->quad_list.push_back(green.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("force_anti_aliasing_off.png")), + ExactPixelComparator(false))); +} + +TEST_F(GLRendererPixelTest, AntiAliasingPerspective) { + gfx::Rect rect(this->device_viewport_size_); + + scoped_ptr<RenderPass> pass = + CreateTestRootRenderPass(RenderPass::Id(1, 1), rect); + + gfx::Rect red_rect(0, 0, 180, 500); + gfx::Transform red_content_to_target_transform( + 1.0, 2.4520, 10.6206, 19.0, + 0.0, 0.3528, 5.9737, 9.5, + 0.0, -0.2250, -0.9744, 0.0, + 0.0, 0.0225, 0.0974, 1.0); + scoped_ptr<SharedQuadState> red_shared_state = + CreateTestSharedQuadState(red_content_to_target_transform, red_rect); + scoped_ptr<SolidColorDrawQuad> red = SolidColorDrawQuad::Create(); + red->SetNew(red_shared_state.get(), red_rect, SK_ColorRED, false); + pass->quad_list.push_back(red.PassAs<DrawQuad>()); + + gfx::Rect green_rect(19, 7, 180, 10); + scoped_ptr<SharedQuadState> green_shared_state = + CreateTestSharedQuadState(gfx::Transform(), green_rect); + scoped_ptr<SolidColorDrawQuad> green = SolidColorDrawQuad::Create(); + green->SetNew(green_shared_state.get(), green_rect, SK_ColorGREEN, false); + pass->quad_list.push_back(green.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> blue_shared_state = + CreateTestSharedQuadState(gfx::Transform(), rect); + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE, false); + pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("anti_aliasing_perspective.png")), + FuzzyPixelOffByOneComparator(true))); +} + +TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, PictureDrawQuadIdentityScale) { + gfx::Size pile_tile_size(1000, 1000); + gfx::Rect viewport(this->device_viewport_size_); + bool use_skia_gpu_backend = this->UseSkiaGPUBackend(); + // TODO(enne): the renderer should figure this out on its own. + bool contents_swizzled = !PlatformColor::SameComponentOrder(GL_RGBA); + + RenderPass::Id id(1, 1); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> pass = + CreateTestRenderPass(id, viewport, transform_to_root); + + // One clipped blue quad in the lower right corner. Outside the clip + // is red, which should not appear. + gfx::Rect blue_rect(gfx::Size(100, 100)); + gfx::Rect blue_clip_rect(gfx::Point(50, 50), gfx::Size(50, 50)); + scoped_refptr<FakePicturePileImpl> blue_pile = + FakePicturePileImpl::CreateFilledPile(pile_tile_size, blue_rect.size()); + SkPaint red_paint; + red_paint.setColor(SK_ColorRED); + blue_pile->add_draw_rect_with_paint(blue_rect, red_paint); + SkPaint blue_paint; + blue_paint.setColor(SK_ColorBLUE); + blue_pile->add_draw_rect_with_paint(blue_clip_rect, blue_paint); + blue_pile->RerecordPile(); + + gfx::Transform blue_content_to_target_transform; + gfx::Vector2d offset(viewport.bottom_right() - blue_rect.bottom_right()); + blue_content_to_target_transform.Translate(offset.x(), offset.y()); + gfx::RectF blue_scissor_rect = blue_clip_rect; + blue_content_to_target_transform.TransformRect(&blue_scissor_rect); + scoped_ptr<SharedQuadState> blue_shared_state = + CreateTestSharedQuadStateClipped(blue_content_to_target_transform, + blue_rect, + gfx::ToEnclosingRect(blue_scissor_rect)); + + scoped_ptr<PictureDrawQuad> blue_quad = PictureDrawQuad::Create(); + + blue_quad->SetNew(blue_shared_state.get(), + viewport, // Intentionally bigger than clip. + gfx::Rect(), + viewport, + viewport.size(), + contents_swizzled, + viewport, + 1.f, + use_skia_gpu_backend, + blue_pile); + pass->quad_list.push_back(blue_quad.PassAs<DrawQuad>()); + + // One viewport-filling green quad. + scoped_refptr<FakePicturePileImpl> green_pile = + FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size()); + SkPaint green_paint; + green_paint.setColor(SK_ColorGREEN); + green_pile->add_draw_rect_with_paint(viewport, green_paint); + green_pile->RerecordPile(); + + gfx::Transform green_content_to_target_transform; + scoped_ptr<SharedQuadState> green_shared_state = + CreateTestSharedQuadState(green_content_to_target_transform, viewport); + + scoped_ptr<PictureDrawQuad> green_quad = PictureDrawQuad::Create(); + green_quad->SetNew(green_shared_state.get(), + viewport, + gfx::Rect(), + gfx::RectF(0.f, 0.f, 1.f, 1.f), + viewport.size(), + contents_swizzled, + viewport, + 1.f, + use_skia_gpu_backend, + green_pile); + pass->quad_list.push_back(green_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")), + ExactPixelComparator(true))); +} + +TYPED_TEST(RendererPixelTestWithSkiaGPUBackend, + PictureDrawQuadNonIdentityScale) { + gfx::Size pile_tile_size(1000, 1000); + gfx::Rect viewport(this->device_viewport_size_); + bool use_skia_gpu_backend = this->UseSkiaGPUBackend(); + // TODO(enne): the renderer should figure this out on its own. + bool contents_swizzled = !PlatformColor::SameComponentOrder(GL_RGBA); + + RenderPass::Id id(1, 1); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> pass = + CreateTestRenderPass(id, viewport, transform_to_root); + + // As scaling up the blue checkerboards will cause sampling on the GPU, + // a few extra "cleanup rects" need to be added to clobber the blending + // to make the output image more clean. This will also test subrects + // of the layer. + gfx::Transform green_content_to_target_transform; + gfx::Rect green_rect1(gfx::Point(80, 0), gfx::Size(20, 100)); + gfx::Rect green_rect2(gfx::Point(0, 80), gfx::Size(100, 20)); + scoped_refptr<FakePicturePileImpl> green_pile = + FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size()); + SkPaint red_paint; + red_paint.setColor(SK_ColorRED); + green_pile->add_draw_rect_with_paint(viewport, red_paint); + SkPaint green_paint; + green_paint.setColor(SK_ColorGREEN); + green_pile->add_draw_rect_with_paint(green_rect1, green_paint); + green_pile->add_draw_rect_with_paint(green_rect2, green_paint); + green_pile->RerecordPile(); + + scoped_ptr<SharedQuadState> top_right_green_shared_quad_state = + CreateTestSharedQuadState(green_content_to_target_transform, viewport); + + scoped_ptr<PictureDrawQuad> green_quad1 = PictureDrawQuad::Create(); + green_quad1->SetNew(top_right_green_shared_quad_state.get(), + green_rect1, + gfx::Rect(), + gfx::RectF(green_rect1.size()), + green_rect1.size(), + contents_swizzled, + green_rect1, + 1.f, + use_skia_gpu_backend, + green_pile); + pass->quad_list.push_back(green_quad1.PassAs<DrawQuad>()); + + scoped_ptr<PictureDrawQuad> green_quad2 = PictureDrawQuad::Create(); + green_quad2->SetNew(top_right_green_shared_quad_state.get(), + green_rect2, + gfx::Rect(), + gfx::RectF(green_rect2.size()), + green_rect2.size(), + contents_swizzled, + green_rect2, + 1.f, + use_skia_gpu_backend, + green_pile); + pass->quad_list.push_back(green_quad2.PassAs<DrawQuad>()); + + // Add a green clipped checkerboard in the bottom right to help test + // interleaving picture quad content and solid color content. + gfx::Rect bottom_right_rect( + gfx::Point(viewport.width() / 2, viewport.height() / 2), + gfx::Size(viewport.width() / 2, viewport.height() / 2)); + scoped_ptr<SharedQuadState> bottom_right_green_shared_state = + CreateTestSharedQuadStateClipped( + green_content_to_target_transform, viewport, bottom_right_rect); + scoped_ptr<SolidColorDrawQuad> bottom_right_color_quad = + SolidColorDrawQuad::Create(); + bottom_right_color_quad->SetNew( + bottom_right_green_shared_state.get(), viewport, SK_ColorGREEN, false); + pass->quad_list.push_back(bottom_right_color_quad.PassAs<DrawQuad>()); + + // Add two blue checkerboards taking up the bottom left and top right, + // but use content scales as content rects to make this happen. + // The content is at a 4x content scale. + gfx::Rect layer_rect(gfx::Size(20, 30)); + float contents_scale = 4.f; + // Two rects that touch at their corners, arbitrarily placed in the layer. + gfx::RectF blue_layer_rect1(gfx::PointF(5.5f, 9.0f), gfx::SizeF(2.5f, 2.5f)); + gfx::RectF blue_layer_rect2(gfx::PointF(8.0f, 6.5f), gfx::SizeF(2.5f, 2.5f)); + gfx::RectF union_layer_rect = blue_layer_rect1; + union_layer_rect.Union(blue_layer_rect2); + + // Because scaling up will cause sampling outside the rects, add one extra + // pixel of buffer at the final content scale. + float inset = -1.f / contents_scale; + blue_layer_rect1.Inset(inset, inset, inset, inset); + blue_layer_rect2.Inset(inset, inset, inset, inset); + + scoped_refptr<FakePicturePileImpl> pile = + FakePicturePileImpl::CreateFilledPile(pile_tile_size, layer_rect.size()); + + Region outside(layer_rect); + outside.Subtract(gfx::ToEnclosingRect(union_layer_rect)); + for (Region::Iterator iter(outside); iter.has_rect(); iter.next()) { + pile->add_draw_rect_with_paint(iter.rect(), red_paint); + } + + SkPaint blue_paint; + blue_paint.setColor(SK_ColorBLUE); + pile->add_draw_rect_with_paint(blue_layer_rect1, blue_paint); + pile->add_draw_rect_with_paint(blue_layer_rect2, blue_paint); + pile->RerecordPile(); + + gfx::Rect content_rect( + gfx::ScaleToEnclosingRect(layer_rect, contents_scale)); + gfx::Rect content_union_rect( + gfx::ToEnclosingRect(gfx::ScaleRect(union_layer_rect, contents_scale))); + + // At a scale of 4x the rectangles with a width of 2.5 will take up 10 pixels, + // so scale an additional 10x to make them 100x100. + gfx::Transform content_to_target_transform; + content_to_target_transform.Scale(10.0, 10.0); + gfx::Rect quad_content_rect(gfx::Size(20, 20)); + scoped_ptr<SharedQuadState> blue_shared_state = + CreateTestSharedQuadState(content_to_target_transform, quad_content_rect); + + scoped_ptr<PictureDrawQuad> blue_quad = PictureDrawQuad::Create(); + blue_quad->SetNew(blue_shared_state.get(), + quad_content_rect, + gfx::Rect(), + quad_content_rect, + content_union_rect.size(), + contents_swizzled, + content_union_rect, + contents_scale, + use_skia_gpu_backend, + pile); + pass->quad_list.push_back(blue_quad.PassAs<DrawQuad>()); + + // Fill left half of viewport with green. + gfx::Transform half_green_content_to_target_transform; + gfx::Rect half_green_rect(gfx::Size(viewport.width() / 2, viewport.height())); + scoped_ptr<SharedQuadState> half_green_shared_state = + CreateTestSharedQuadState(half_green_content_to_target_transform, + half_green_rect); + scoped_ptr<SolidColorDrawQuad> half_color_quad = SolidColorDrawQuad::Create(); + half_color_quad->SetNew( + half_green_shared_state.get(), half_green_rect, SK_ColorGREEN, false); + pass->quad_list.push_back(half_color_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), + ExactPixelComparator(true))); +} +#endif // !defined(OS_ANDROID) + +} // namespace +} // namespace cc |