| // 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 <stddef.h> |
| #include <stdint.h> |
| #include <memory> |
| #include <tuple> |
| |
| #include "base/memory/aligned_memory.h" |
| #include "build/build_config.h" |
| #include "cc/base/math_util.h" |
| #include "cc/paint/paint_flags.h" |
| #include "cc/paint/skia_paint_canvas.h" |
| #include "cc/test/fake_raster_source.h" |
| #include "cc/test/fake_recording_source.h" |
| #include "cc/test/pixel_test.h" |
| #include "cc/test/render_pass_test_utils.h" |
| #include "cc/test/resource_provider_test_utils.h" |
| #include "cc/test/test_in_process_context_provider.h" |
| #include "components/viz/client/client_resource_provider.h" |
| #include "components/viz/common/gpu/texture_allocation.h" |
| #include "components/viz/common/quads/picture_draw_quad.h" |
| #include "components/viz/common/quads/texture_draw_quad.h" |
| #include "components/viz/common/resources/bitmap_allocation.h" |
| #include "components/viz/common/resources/resource_format_utils.h" |
| #include "components/viz/service/display/gl_renderer.h" |
| #include "components/viz/test/test_shared_bitmap_manager.h" |
| #include "gpu/command_buffer/client/gles2_interface.h" |
| #include "media/base/video_frame.h" |
| #include "media/renderers/video_resource_updater.h" |
| #include "media/video/half_float_maker.h" |
| #include "third_party/skia/include/core/SkColorPriv.h" |
| #include "third_party/skia/include/core/SkColorSpaceXform.h" |
| #include "third_party/skia/include/core/SkMatrix.h" |
| #include "third_party/skia/include/core/SkRefCnt.h" |
| #include "third_party/skia/include/core/SkSurface.h" |
| #include "third_party/skia/include/effects/SkColorMatrixFilter.h" |
| #include "ui/gfx/color_transform.h" |
| #include "ui/gfx/geometry/rect_conversions.h" |
| #include "ui/gfx/test/icc_profiles.h" |
| |
| using cc::RendererPixelTest; |
| using cc::GLRendererPixelTest; |
| using cc::SkiaRendererPixelTest; |
| using gpu::gles2::GLES2Interface; |
| |
| namespace viz { |
| namespace { |
| |
| #if !defined(OS_ANDROID) |
| std::unique_ptr<base::SharedMemory> AllocateAndRegisterSharedBitmapMemory( |
| const SharedBitmapId& id, |
| const gfx::Size& size, |
| SharedBitmapManager* shared_bitmap_manager) { |
| std::unique_ptr<base::SharedMemory> shm = |
| bitmap_allocation::AllocateMappedBitmap(size, RGBA_8888); |
| shared_bitmap_manager->ChildAllocatedSharedBitmap( |
| bitmap_allocation::DuplicateAndCloseMappedBitmap(shm.get(), size, |
| RGBA_8888), |
| id); |
| return shm; |
| } |
| |
| void DeleteTexture(scoped_refptr<ContextProvider> context_provider, |
| GLuint texture, |
| const gpu::SyncToken& sync_token, |
| bool is_lost) { |
| DCHECK(context_provider); |
| gpu::gles2::GLES2Interface* gl = context_provider->ContextGL(); |
| DCHECK(gl); |
| gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); |
| gl->DeleteTextures(1, &texture); |
| } |
| |
| ResourceId CreateGpuResource(scoped_refptr<ContextProvider> context_provider, |
| ClientResourceProvider* resource_provider, |
| const gfx::Size& size, |
| ResourceFormat format, |
| gfx::ColorSpace color_space, |
| const void* pixels = nullptr) { |
| DCHECK(context_provider); |
| gpu::gles2::GLES2Interface* gl = context_provider->ContextGL(); |
| DCHECK(gl); |
| const gpu::Capabilities& caps = context_provider->ContextCapabilities(); |
| auto allocation = TextureAllocation::MakeTextureId( |
| gl, caps, format, |
| /*use_gpu_memory_buffer_resources=*/false, |
| /*for_framebuffer_attachment=*/false); |
| if (pixels) { |
| TextureAllocation::UploadStorage(gl, caps, format, size, allocation, |
| color_space, pixels); |
| } else { |
| TextureAllocation::AllocateStorage(gl, caps, format, size, allocation, |
| color_space); |
| } |
| gpu::Mailbox mailbox; |
| gl->ProduceTextureDirectCHROMIUM(allocation.texture_id, mailbox.name); |
| gpu::SyncToken sync_token; |
| gl->GenSyncTokenCHROMIUM(sync_token.GetData()); |
| TransferableResource gl_resource = TransferableResource::MakeGL( |
| mailbox, GL_LINEAR, allocation.texture_target, sync_token); |
| gl_resource.size = size; |
| gl_resource.format = format; |
| // We didn't allocate a GpuMemoryBuffer, but we want to set buffer_format for |
| // consistency with other callsites. |
| // TODO(piman): See if we can remove TransferableResource::buffer_format |
| // altogether, it looks redundant with format. crbug.com/836488 |
| gl_resource.buffer_format = BufferFormat(format); |
| gl_resource.color_space = std::move(color_space); |
| auto release_callback = SingleReleaseCallback::Create(base::BindOnce( |
| &DeleteTexture, std::move(context_provider), allocation.texture_id)); |
| return resource_provider->ImportResource(gl_resource, |
| std::move(release_callback)); |
| } |
| |
| std::unique_ptr<RenderPass> CreateTestRootRenderPass(int id, |
| const gfx::Rect& rect) { |
| std::unique_ptr<RenderPass> pass = RenderPass::Create(); |
| const gfx::Rect output_rect = rect; |
| const gfx::Rect damage_rect = rect; |
| const gfx::Transform transform_to_root_target; |
| pass->SetNew(id, output_rect, damage_rect, transform_to_root_target); |
| return pass; |
| } |
| |
| std::unique_ptr<RenderPass> CreateTestRenderPass( |
| int id, |
| const gfx::Rect& rect, |
| const gfx::Transform& transform_to_root_target) { |
| std::unique_ptr<RenderPass> pass = RenderPass::Create(); |
| const gfx::Rect output_rect = rect; |
| const gfx::Rect damage_rect = rect; |
| pass->SetNew(id, output_rect, damage_rect, transform_to_root_target); |
| return pass; |
| } |
| |
| SharedQuadState* CreateTestSharedQuadState( |
| gfx::Transform quad_to_target_transform, |
| const gfx::Rect& rect, |
| RenderPass* render_pass) { |
| const gfx::Rect layer_rect = rect; |
| const gfx::Rect visible_layer_rect = rect; |
| const gfx::Rect clip_rect = rect; |
| const bool is_clipped = false; |
| const bool are_contents_opaque = false; |
| const float opacity = 1.0f; |
| const SkBlendMode blend_mode = SkBlendMode::kSrcOver; |
| int sorting_context_id = 0; |
| SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState(); |
| shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect, |
| clip_rect, is_clipped, are_contents_opaque, opacity, |
| blend_mode, sorting_context_id); |
| return shared_state; |
| } |
| |
| SharedQuadState* CreateTestSharedQuadStateClipped( |
| gfx::Transform quad_to_target_transform, |
| const gfx::Rect& rect, |
| const gfx::Rect& clip_rect, |
| RenderPass* render_pass) { |
| const gfx::Rect layer_rect = rect; |
| const gfx::Rect visible_layer_rect = clip_rect; |
| const bool is_clipped = true; |
| const bool are_contents_opaque = false; |
| const float opacity = 1.0f; |
| const SkBlendMode blend_mode = SkBlendMode::kSrcOver; |
| int sorting_context_id = 0; |
| SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState(); |
| shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect, |
| clip_rect, is_clipped, are_contents_opaque, opacity, |
| blend_mode, sorting_context_id); |
| return shared_state; |
| } |
| |
| void CreateTestRenderPassDrawQuad(const SharedQuadState* shared_state, |
| const gfx::Rect& rect, |
| int pass_id, |
| RenderPass* render_pass) { |
| auto* quad = render_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); |
| quad->SetNew(shared_state, rect, rect, pass_id, |
| 0, // mask_resource_id |
| gfx::RectF(), // mask_uv_rect |
| gfx::Size(), // mask_texture_size |
| gfx::Vector2dF(), // filters scale |
| gfx::PointF(), // filter origin |
| gfx::RectF(rect), // tex_coord_rect |
| false); // force_anti_aliasing_off |
| } |
| |
| void CreateTestTwoColoredTextureDrawQuad( |
| bool gpu_resource, |
| const gfx::Rect& rect, |
| SkColor texel_color, |
| SkColor texel_stripe_color, |
| SkColor background_color, |
| bool premultiplied_alpha, |
| const SharedQuadState* shared_state, |
| DisplayResourceProvider* resource_provider, |
| ClientResourceProvider* child_resource_provider, |
| SharedBitmapManager* shared_bitmap_manager, |
| scoped_refptr<ContextProvider> child_context_provider, |
| RenderPass* render_pass) { |
| SkPMColor pixel_color = premultiplied_alpha |
| ? SkPreMultiplyColor(texel_color) |
| : SkPackARGB32NoCheck(SkColorGetA(texel_color), |
| SkColorGetR(texel_color), |
| SkColorGetG(texel_color), |
| SkColorGetB(texel_color)); |
| SkPMColor pixel_stripe_color = |
| premultiplied_alpha |
| ? SkPreMultiplyColor(texel_stripe_color) |
| : SkPackARGB32NoCheck(SkColorGetA(texel_stripe_color), |
| SkColorGetR(texel_stripe_color), |
| SkColorGetG(texel_stripe_color), |
| SkColorGetB(texel_stripe_color)); |
| std::vector<uint32_t> pixels(rect.size().GetArea(), pixel_color); |
| for (int i = rect.height() / 4; i < (rect.height() * 3 / 4); ++i) { |
| for (int k = rect.width() / 4; k < (rect.width() * 3 / 4); ++k) { |
| pixels[i * rect.width() + k] = pixel_stripe_color; |
| } |
| } |
| |
| ResourceId resource; |
| if (gpu_resource) { |
| resource = CreateGpuResource(std::move(child_context_provider), |
| child_resource_provider, rect.size(), |
| RGBA_8888, gfx::ColorSpace(), &pixels.front()); |
| } else { |
| SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId(); |
| std::unique_ptr<base::SharedMemory> shm = |
| AllocateAndRegisterSharedBitmapMemory(shared_bitmap_id, rect.size(), |
| shared_bitmap_manager); |
| resource = child_resource_provider->ImportResource( |
| TransferableResource::MakeSoftware(shared_bitmap_id, rect.size(), |
| RGBA_8888), |
| SingleReleaseCallback::Create(base::DoNothing())); |
| |
| for (int i = 0; i < rect.size().GetArea(); ++i) |
| static_cast<uint32_t*>(shm->memory())[i] = pixels[i]; |
| } |
| |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap({resource}, resource_provider, |
| child_resource_provider, |
| child_context_provider.get()); |
| ResourceId mapped_resource = resource_map[resource]; |
| |
| bool needs_blending = true; |
| float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| const gfx::PointF uv_top_left(0.0f, 0.0f); |
| const gfx::PointF uv_bottom_right(1.0f, 1.0f); |
| const bool flipped = false; |
| const bool nearest_neighbor = false; |
| auto* quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); |
| quad->SetNew(shared_state, rect, rect, needs_blending, mapped_resource, |
| premultiplied_alpha, uv_top_left, uv_bottom_right, |
| background_color, vertex_opacity, flipped, nearest_neighbor, |
| false); |
| } |
| |
| void CreateTestTextureDrawQuad( |
| bool gpu_resource, |
| const gfx::Rect& rect, |
| SkColor texel_color, |
| float vertex_opacity[4], |
| SkColor background_color, |
| bool premultiplied_alpha, |
| const SharedQuadState* shared_state, |
| DisplayResourceProvider* resource_provider, |
| ClientResourceProvider* child_resource_provider, |
| SharedBitmapManager* shared_bitmap_manager, |
| scoped_refptr<ContextProvider> child_context_provider, |
| RenderPass* render_pass) { |
| SkPMColor pixel_color = premultiplied_alpha |
| ? SkPreMultiplyColor(texel_color) |
| : SkPackARGB32NoCheck(SkColorGetA(texel_color), |
| SkColorGetR(texel_color), |
| SkColorGetG(texel_color), |
| SkColorGetB(texel_color)); |
| size_t num_pixels = static_cast<size_t>(rect.width()) * rect.height(); |
| std::vector<uint32_t> pixels(num_pixels, pixel_color); |
| |
| ResourceId resource; |
| if (gpu_resource) { |
| resource = CreateGpuResource(std::move(child_context_provider), |
| child_resource_provider, rect.size(), |
| RGBA_8888, gfx::ColorSpace(), &pixels.front()); |
| } else { |
| SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId(); |
| std::unique_ptr<base::SharedMemory> shm = |
| AllocateAndRegisterSharedBitmapMemory(shared_bitmap_id, rect.size(), |
| shared_bitmap_manager); |
| resource = child_resource_provider->ImportResource( |
| TransferableResource::MakeSoftware(shared_bitmap_id, rect.size(), |
| RGBA_8888), |
| SingleReleaseCallback::Create(base::DoNothing())); |
| |
| for (int i = 0; i < rect.size().GetArea(); ++i) |
| static_cast<uint32_t*>(shm->memory())[i] = pixels[i]; |
| } |
| |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap({resource}, resource_provider, |
| child_resource_provider, |
| child_context_provider.get()); |
| ResourceId mapped_resource = resource_map[resource]; |
| |
| bool needs_blending = true; |
| const gfx::PointF uv_top_left(0.0f, 0.0f); |
| const gfx::PointF uv_bottom_right(1.0f, 1.0f); |
| const bool flipped = false; |
| const bool nearest_neighbor = false; |
| auto* quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); |
| quad->SetNew(shared_state, rect, rect, needs_blending, mapped_resource, |
| premultiplied_alpha, uv_top_left, uv_bottom_right, |
| background_color, vertex_opacity, flipped, nearest_neighbor, |
| false); |
| } |
| |
| void CreateTestTextureDrawQuad( |
| bool gpu_resource, |
| const gfx::Rect& rect, |
| SkColor texel_color, |
| SkColor background_color, |
| bool premultiplied_alpha, |
| const SharedQuadState* shared_state, |
| DisplayResourceProvider* resource_provider, |
| ClientResourceProvider* child_resource_provider, |
| SharedBitmapManager* shared_bitmap_manager, |
| scoped_refptr<ContextProvider> child_context_provider, |
| RenderPass* render_pass) { |
| float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| CreateTestTextureDrawQuad(gpu_resource, rect, texel_color, vertex_opacity, |
| background_color, premultiplied_alpha, shared_state, |
| resource_provider, child_resource_provider, |
| shared_bitmap_manager, |
| std::move(child_context_provider), render_pass); |
| } |
| |
| void CreateTestYUVVideoDrawQuad_FromVideoFrame( |
| const SharedQuadState* shared_state, |
| scoped_refptr<media::VideoFrame> video_frame, |
| uint8_t alpha_value, |
| const gfx::RectF& tex_coord_rect, |
| RenderPass* render_pass, |
| media::VideoResourceUpdater* video_resource_updater, |
| const gfx::Rect& rect, |
| const gfx::Rect& visible_rect, |
| DisplayResourceProvider* resource_provider, |
| ClientResourceProvider* child_resource_provider, |
| ContextProvider* child_context_provider) { |
| const bool with_alpha = (video_frame->format() == media::PIXEL_FORMAT_I420A); |
| |
| gfx::ColorSpace video_color_space = video_frame->ColorSpace(); |
| DCHECK(video_color_space.IsValid()); |
| |
| bool needs_blending = true; |
| |
| if (with_alpha) { |
| memset(video_frame->data(media::VideoFrame::kAPlane), alpha_value, |
| video_frame->stride(media::VideoFrame::kAPlane) * |
| video_frame->rows(media::VideoFrame::kAPlane)); |
| } |
| |
| media::VideoFrameExternalResources resources = |
| video_resource_updater->CreateExternalResourcesFromVideoFrame( |
| video_frame); |
| |
| EXPECT_EQ(media::VideoFrameResourceType::YUV, resources.type); |
| EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()), |
| resources.resources.size()); |
| EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()), |
| resources.release_callbacks.size()); |
| |
| ResourceId resource_y = child_resource_provider->ImportResource( |
| resources.resources[media::VideoFrame::kYPlane], |
| SingleReleaseCallback::Create( |
| std::move(resources.release_callbacks[media::VideoFrame::kYPlane]))); |
| ResourceId resource_u = child_resource_provider->ImportResource( |
| resources.resources[media::VideoFrame::kUPlane], |
| SingleReleaseCallback::Create( |
| std::move(resources.release_callbacks[media::VideoFrame::kUPlane]))); |
| ResourceId resource_v = child_resource_provider->ImportResource( |
| resources.resources[media::VideoFrame::kVPlane], |
| SingleReleaseCallback::Create( |
| std::move(resources.release_callbacks[media::VideoFrame::kVPlane]))); |
| ResourceId resource_a = 0; |
| if (with_alpha) { |
| resource_a = child_resource_provider->ImportResource( |
| resources.resources[media::VideoFrame::kAPlane], |
| SingleReleaseCallback::Create(std::move( |
| resources.release_callbacks[media::VideoFrame::kAPlane]))); |
| } |
| |
| std::vector<ResourceId> resource_ids_to_transfer; |
| resource_ids_to_transfer.push_back(resource_y); |
| resource_ids_to_transfer.push_back(resource_u); |
| resource_ids_to_transfer.push_back(resource_v); |
| if (with_alpha) |
| resource_ids_to_transfer.push_back(resource_a); |
| // Transfer resources to the parent, and get the resource map. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| resource_ids_to_transfer, resource_provider, child_resource_provider, |
| child_context_provider); |
| |
| ResourceId mapped_resource_y = resource_map[resource_y]; |
| ResourceId mapped_resource_u = resource_map[resource_u]; |
| ResourceId mapped_resource_v = resource_map[resource_v]; |
| ResourceId mapped_resource_a = 0; |
| if (with_alpha) |
| mapped_resource_a = resource_map[resource_a]; |
| const gfx::Size ya_tex_size = video_frame->coded_size(); |
| const gfx::Size uv_tex_size = media::VideoFrame::PlaneSize( |
| video_frame->format(), media::VideoFrame::kUPlane, |
| video_frame->coded_size()); |
| DCHECK(uv_tex_size == media::VideoFrame::PlaneSize( |
| video_frame->format(), media::VideoFrame::kVPlane, |
| video_frame->coded_size())); |
| if (with_alpha) { |
| DCHECK(ya_tex_size == media::VideoFrame::PlaneSize( |
| video_frame->format(), media::VideoFrame::kAPlane, |
| video_frame->coded_size())); |
| } |
| |
| gfx::RectF ya_tex_coord_rect(tex_coord_rect.x() * ya_tex_size.width(), |
| tex_coord_rect.y() * ya_tex_size.height(), |
| tex_coord_rect.width() * ya_tex_size.width(), |
| tex_coord_rect.height() * ya_tex_size.height()); |
| gfx::RectF uv_tex_coord_rect(tex_coord_rect.x() * uv_tex_size.width(), |
| tex_coord_rect.y() * uv_tex_size.height(), |
| tex_coord_rect.width() * uv_tex_size.width(), |
| tex_coord_rect.height() * uv_tex_size.height()); |
| |
| auto* yuv_quad = render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>(); |
| uint32_t bits_per_channel = 8; |
| if (video_frame->format() == media::PIXEL_FORMAT_YUV420P10 || |
| video_frame->format() == media::PIXEL_FORMAT_YUV422P10 || |
| video_frame->format() == media::PIXEL_FORMAT_YUV444P10) { |
| bits_per_channel = 10; |
| } |
| |
| ResourceFormat yuv_highbit_resource_format = |
| video_resource_updater->YuvResourceFormat(bits_per_channel); |
| |
| float offset = 0.0f; |
| float multiplier = 1.0f; |
| |
| if (yuv_highbit_resource_format == R16_EXT) { |
| multiplier = 65535.0f / ((1 << bits_per_channel) - 1); |
| } else if (yuv_highbit_resource_format == LUMINANCE_F16) { |
| std::unique_ptr<media::HalfFloatMaker> half_float_maker = |
| media::HalfFloatMaker::NewHalfFloatMaker(bits_per_channel); |
| offset = half_float_maker->Offset(); |
| multiplier = half_float_maker->Multiplier(); |
| } else { |
| bits_per_channel = 8; |
| } |
| |
| yuv_quad->SetNew(shared_state, rect, visible_rect, needs_blending, |
| ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size, |
| uv_tex_size, mapped_resource_y, mapped_resource_u, |
| mapped_resource_v, mapped_resource_a, video_color_space, |
| offset, multiplier, bits_per_channel); |
| } |
| |
| void CreateTestY16TextureDrawQuad_FromVideoFrame( |
| const SharedQuadState* shared_state, |
| scoped_refptr<media::VideoFrame> video_frame, |
| const gfx::RectF& tex_coord_rect, |
| RenderPass* render_pass, |
| media::VideoResourceUpdater* video_resource_updater, |
| const gfx::Rect& rect, |
| const gfx::Rect& visible_rect, |
| DisplayResourceProvider* resource_provider, |
| ClientResourceProvider* child_resource_provider, |
| ContextProvider* child_context_provider) { |
| media::VideoFrameExternalResources resources = |
| video_resource_updater->CreateExternalResourcesFromVideoFrame( |
| video_frame); |
| |
| EXPECT_EQ(media::VideoFrameResourceType::RGBA, resources.type); |
| EXPECT_EQ(1u, resources.resources.size()); |
| EXPECT_EQ(1u, resources.release_callbacks.size()); |
| |
| ResourceId resource_y = child_resource_provider->ImportResource( |
| resources.resources[0], |
| SingleReleaseCallback::Create(std::move(resources.release_callbacks[0]))); |
| |
| // Transfer resources to the parent, and get the resource map. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap({resource_y}, resource_provider, |
| child_resource_provider, |
| child_context_provider); |
| ResourceId mapped_resource_y = resource_map[resource_y]; |
| |
| auto* quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); |
| bool needs_blending = true; |
| float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| quad->SetNew(shared_state, rect, rect, needs_blending, mapped_resource_y, |
| false, tex_coord_rect.origin(), tex_coord_rect.bottom_right(), |
| SK_ColorBLACK, vertex_opacity, false, false, false); |
| } |
| |
| // Upshift video frame to 10 bit. |
| scoped_refptr<media::VideoFrame> CreateHighbitVideoFrame( |
| media::VideoFrame* video_frame) { |
| media::VideoPixelFormat format; |
| switch (video_frame->format()) { |
| case media::PIXEL_FORMAT_I420: |
| format = media::PIXEL_FORMAT_YUV420P10; |
| break; |
| case media::PIXEL_FORMAT_I422: |
| format = media::PIXEL_FORMAT_YUV422P10; |
| break; |
| case media::PIXEL_FORMAT_I444: |
| format = media::PIXEL_FORMAT_YUV444P10; |
| break; |
| |
| default: |
| NOTREACHED(); |
| return nullptr; |
| } |
| scoped_refptr<media::VideoFrame> ret = media::VideoFrame::CreateFrame( |
| format, video_frame->coded_size(), video_frame->visible_rect(), |
| video_frame->natural_size(), video_frame->timestamp()); |
| |
| // Copy all metadata. |
| ret->metadata()->MergeMetadataFrom(video_frame->metadata()); |
| |
| for (int plane = media::VideoFrame::kYPlane; |
| plane <= media::VideoFrame::kVPlane; ++plane) { |
| int width = video_frame->row_bytes(plane); |
| const uint8_t* src = video_frame->data(plane); |
| uint16_t* dst = reinterpret_cast<uint16_t*>(ret->data(plane)); |
| for (int row = 0; row < video_frame->rows(plane); row++) { |
| for (int x = 0; x < width; x++) { |
| // Replicate the top bits into the lower bits, this way |
| // 0xFF becomes 0x3FF. |
| dst[x] = (src[x] << 2) | (src[x] >> 6); |
| } |
| src += video_frame->stride(plane); |
| dst += ret->stride(plane) / 2; |
| } |
| } |
| return ret; |
| } |
| |
| void CreateTestYUVVideoDrawQuad_Striped( |
| const SharedQuadState* shared_state, |
| media::VideoPixelFormat format, |
| media::ColorSpace color_space, |
| bool is_transparent, |
| bool highbit, |
| const gfx::RectF& tex_coord_rect, |
| RenderPass* render_pass, |
| media::VideoResourceUpdater* video_resource_updater, |
| const gfx::Rect& rect, |
| const gfx::Rect& visible_rect, |
| DisplayResourceProvider* resource_provider, |
| ClientResourceProvider* child_resource_provider, |
| ContextProvider* child_context_provider) { |
| scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( |
| format, rect.size(), rect, rect.size(), base::TimeDelta()); |
| |
| // YUV values representing a striped pattern, for validating texture |
| // coordinates for sampling. |
| uint8_t y_value = 0; |
| uint8_t u_value = 0; |
| uint8_t v_value = 0; |
| for (int i = 0; i < video_frame->rows(media::VideoFrame::kYPlane); ++i) { |
| uint8_t* y_row = video_frame->data(media::VideoFrame::kYPlane) + |
| video_frame->stride(media::VideoFrame::kYPlane) * i; |
| for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kYPlane); |
| ++j) { |
| y_row[j] = (y_value += 1); |
| } |
| } |
| for (int i = 0; i < video_frame->rows(media::VideoFrame::kUPlane); ++i) { |
| uint8_t* u_row = video_frame->data(media::VideoFrame::kUPlane) + |
| video_frame->stride(media::VideoFrame::kUPlane) * i; |
| uint8_t* v_row = video_frame->data(media::VideoFrame::kVPlane) + |
| video_frame->stride(media::VideoFrame::kVPlane) * i; |
| for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kUPlane); |
| ++j) { |
| u_row[j] = (u_value += 3); |
| v_row[j] = (v_value += 5); |
| } |
| } |
| uint8_t alpha_value = is_transparent ? 0 : 128; |
| |
| if (highbit) |
| video_frame = CreateHighbitVideoFrame(video_frame.get()); |
| video_frame->metadata()->SetInteger(media::VideoFrameMetadata::COLOR_SPACE, |
| color_space); |
| |
| CreateTestYUVVideoDrawQuad_FromVideoFrame( |
| shared_state, video_frame, alpha_value, tex_coord_rect, render_pass, |
| video_resource_updater, rect, visible_rect, resource_provider, |
| child_resource_provider, child_context_provider); |
| } |
| |
| // Creates a video frame of size background_size filled with yuv_background, |
| // and then draws a foreground rectangle in a different color on top of |
| // that. The foreground rectangle must have coordinates that are divisible |
| // by 2 because YUV is a block format. |
| void CreateTestYUVVideoDrawQuad_TwoColor( |
| const SharedQuadState* shared_state, |
| media::VideoPixelFormat format, |
| media::ColorSpace color_space, |
| bool is_transparent, |
| const gfx::RectF& tex_coord_rect, |
| const gfx::Size& background_size, |
| const gfx::Rect& visible_rect, |
| uint8_t y_background, |
| uint8_t u_background, |
| uint8_t v_background, |
| const gfx::Rect& foreground_rect, |
| uint8_t y_foreground, |
| uint8_t u_foreground, |
| uint8_t v_foreground, |
| RenderPass* render_pass, |
| media::VideoResourceUpdater* video_resource_updater, |
| DisplayResourceProvider* resource_provider, |
| ClientResourceProvider* child_resource_provider, |
| ContextProvider* child_context_provider) { |
| const gfx::Rect rect(background_size); |
| |
| scoped_refptr<media::VideoFrame> video_frame = |
| media::VideoFrame::CreateFrame(format, background_size, foreground_rect, |
| foreground_rect.size(), base::TimeDelta()); |
| video_frame->metadata()->SetInteger(media::VideoFrameMetadata::COLOR_SPACE, |
| color_space); |
| |
| int planes[] = {media::VideoFrame::kYPlane, media::VideoFrame::kUPlane, |
| media::VideoFrame::kVPlane}; |
| uint8_t yuv_background[] = {y_background, u_background, v_background}; |
| uint8_t yuv_foreground[] = {y_foreground, u_foreground, v_foreground}; |
| int sample_size[] = {1, 2, 2}; |
| |
| for (int i = 0; i < 3; ++i) { |
| memset(video_frame->data(planes[i]), yuv_background[i], |
| video_frame->stride(planes[i]) * video_frame->rows(planes[i])); |
| } |
| |
| for (int i = 0; i < 3; ++i) { |
| // Since yuv encoding uses block encoding, widths have to be divisible |
| // by the sample size in order for this function to behave properly. |
| DCHECK_EQ(foreground_rect.x() % sample_size[i], 0); |
| DCHECK_EQ(foreground_rect.y() % sample_size[i], 0); |
| DCHECK_EQ(foreground_rect.width() % sample_size[i], 0); |
| DCHECK_EQ(foreground_rect.height() % sample_size[i], 0); |
| |
| gfx::Rect sample_rect(foreground_rect.x() / sample_size[i], |
| foreground_rect.y() / sample_size[i], |
| foreground_rect.width() / sample_size[i], |
| foreground_rect.height() / sample_size[i]); |
| for (int y = sample_rect.y(); y < sample_rect.bottom(); ++y) { |
| for (int x = sample_rect.x(); x < sample_rect.right(); ++x) { |
| size_t offset = y * video_frame->stride(planes[i]) + x; |
| video_frame->data(planes[i])[offset] = yuv_foreground[i]; |
| } |
| } |
| } |
| |
| uint8_t alpha_value = 255; |
| CreateTestYUVVideoDrawQuad_FromVideoFrame( |
| shared_state, video_frame, alpha_value, tex_coord_rect, render_pass, |
| video_resource_updater, rect, visible_rect, resource_provider, |
| child_resource_provider, child_context_provider); |
| } |
| |
| void CreateTestYUVVideoDrawQuad_Solid( |
| const SharedQuadState* shared_state, |
| media::VideoPixelFormat format, |
| media::ColorSpace color_space, |
| bool is_transparent, |
| const gfx::RectF& tex_coord_rect, |
| uint8_t y, |
| uint8_t u, |
| uint8_t v, |
| RenderPass* render_pass, |
| media::VideoResourceUpdater* video_resource_updater, |
| const gfx::Rect& rect, |
| const gfx::Rect& visible_rect, |
| DisplayResourceProvider* resource_provider, |
| ClientResourceProvider* child_resource_provider, |
| ContextProvider* child_context_provider) { |
| scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( |
| format, rect.size(), rect, rect.size(), base::TimeDelta()); |
| video_frame->metadata()->SetInteger(media::VideoFrameMetadata::COLOR_SPACE, |
| color_space); |
| |
| // YUV values of a solid, constant, color. Useful for testing that color |
| // space/color range are being handled properly. |
| memset(video_frame->data(media::VideoFrame::kYPlane), y, |
| video_frame->stride(media::VideoFrame::kYPlane) * |
| video_frame->rows(media::VideoFrame::kYPlane)); |
| memset(video_frame->data(media::VideoFrame::kUPlane), u, |
| video_frame->stride(media::VideoFrame::kUPlane) * |
| video_frame->rows(media::VideoFrame::kUPlane)); |
| memset(video_frame->data(media::VideoFrame::kVPlane), v, |
| video_frame->stride(media::VideoFrame::kVPlane) * |
| video_frame->rows(media::VideoFrame::kVPlane)); |
| |
| uint8_t alpha_value = is_transparent ? 0 : 128; |
| CreateTestYUVVideoDrawQuad_FromVideoFrame( |
| shared_state, video_frame, alpha_value, tex_coord_rect, render_pass, |
| video_resource_updater, rect, visible_rect, resource_provider, |
| child_resource_provider, child_context_provider); |
| } |
| |
| void CreateTestYUVVideoDrawQuad_NV12( |
| const SharedQuadState* shared_state, |
| media::ColorSpace video_frame_color_space, |
| const gfx::ColorSpace& video_color_space, |
| const gfx::RectF& tex_coord_rect, |
| uint8_t y, |
| uint8_t u, |
| uint8_t v, |
| RenderPass* render_pass, |
| media::VideoResourceUpdater* video_resource_updater, |
| const gfx::Rect& rect, |
| const gfx::Rect& visible_rect, |
| DisplayResourceProvider* resource_provider, |
| ClientResourceProvider* child_resource_provider, |
| scoped_refptr<ContextProvider> child_context_provider) { |
| gfx::ColorSpace gfx_color_space = gfx::ColorSpace::CreateREC601(); |
| if (video_frame_color_space == media::COLOR_SPACE_JPEG) { |
| gfx_color_space = gfx::ColorSpace::CreateJpeg(); |
| } |
| |
| bool needs_blending = true; |
| const gfx::Size ya_tex_size = rect.size(); |
| const gfx::Size uv_tex_size = media::VideoFrame::PlaneSize( |
| media::PIXEL_FORMAT_NV12, media::VideoFrame::kUVPlane, rect.size()); |
| |
| std::vector<uint8_t> y_pixels(ya_tex_size.GetArea(), y); |
| ResourceId resource_y = CreateGpuResource( |
| child_context_provider, child_resource_provider, ya_tex_size, |
| video_resource_updater->YuvResourceFormat(8), gfx_color_space, |
| y_pixels.data()); |
| |
| // U goes in the R component and V goes in the G component. |
| uint32_t rgba_pixel = (u << 24) | (v << 16); |
| std::vector<uint32_t> uv_pixels(uv_tex_size.GetArea(), rgba_pixel); |
| ResourceId resource_u = CreateGpuResource( |
| child_context_provider, child_resource_provider, uv_tex_size, RGBA_8888, |
| gfx_color_space, uv_pixels.data()); |
| ResourceId resource_v = resource_u; |
| ResourceId resource_a = 0; |
| |
| // Transfer resources to the parent, and get the resource map. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| {resource_y, resource_u, resource_v}, resource_provider, |
| child_resource_provider, child_context_provider.get()); |
| |
| ResourceId mapped_resource_y = resource_map[resource_y]; |
| ResourceId mapped_resource_u = resource_map[resource_u]; |
| ResourceId mapped_resource_v = resource_map[resource_v]; |
| |
| gfx::RectF ya_tex_coord_rect(tex_coord_rect.x() * ya_tex_size.width(), |
| tex_coord_rect.y() * ya_tex_size.height(), |
| tex_coord_rect.width() * ya_tex_size.width(), |
| tex_coord_rect.height() * ya_tex_size.height()); |
| gfx::RectF uv_tex_coord_rect(tex_coord_rect.x() * uv_tex_size.width(), |
| tex_coord_rect.y() * uv_tex_size.height(), |
| tex_coord_rect.width() * uv_tex_size.width(), |
| tex_coord_rect.height() * uv_tex_size.height()); |
| |
| auto* yuv_quad = render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>(); |
| yuv_quad->SetNew(shared_state, rect, visible_rect, needs_blending, |
| ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size, |
| uv_tex_size, mapped_resource_y, mapped_resource_u, |
| mapped_resource_v, resource_a, video_color_space, 0.0f, 1.0f, |
| 8); |
| } |
| |
| void CreateTestY16TextureDrawQuad_TwoColor( |
| const SharedQuadState* shared_state, |
| const gfx::RectF& tex_coord_rect, |
| uint8_t g_foreground, |
| uint8_t g_background, |
| RenderPass* render_pass, |
| media::VideoResourceUpdater* video_resource_updater, |
| const gfx::Rect& rect, |
| const gfx::Rect& visible_rect, |
| const gfx::Rect& foreground_rect, |
| DisplayResourceProvider* resource_provider, |
| ClientResourceProvider* child_resource_provider, |
| ContextProvider* child_context_provider) { |
| std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory( |
| static_cast<unsigned char*>( |
| base::AlignedAlloc(rect.size().GetArea() * 2, |
| media::VideoFrame::kFrameAddressAlignment))); |
| scoped_refptr<media::VideoFrame> video_frame = |
| media::VideoFrame::WrapExternalData( |
| media::PIXEL_FORMAT_Y16, rect.size(), visible_rect, |
| visible_rect.size(), memory.get(), rect.size().GetArea() * 2, |
| base::TimeDelta()); |
| DCHECK_EQ(video_frame->rows(0) % 2, 0); |
| DCHECK_EQ(video_frame->stride(0) % 2, 0); |
| |
| for (int j = 0; j < video_frame->rows(0); ++j) { |
| uint8_t* row = video_frame->data(0) + j * video_frame->stride(0); |
| if (j < foreground_rect.y() || j >= foreground_rect.bottom()) { |
| for (int i = 0; i < video_frame->stride(0) / 2; ++i) { |
| *row++ = i & 0xFF; // Fill R with anything. It is not rendered. |
| *row++ = g_background; |
| } |
| } else { |
| for (int i = 0; |
| i < std::min(video_frame->stride(0) / 2, foreground_rect.x()); ++i) { |
| *row++ = i & 0xFF; |
| *row++ = g_background; |
| } |
| for (int i = foreground_rect.x(); |
| i < std::min(video_frame->stride(0) / 2, foreground_rect.right()); |
| ++i) { |
| *row++ = i & 0xFF; |
| *row++ = g_foreground; |
| } |
| for (int i = foreground_rect.right(); i < video_frame->stride(0) / 2; |
| ++i) { |
| *row++ = i & 0xFF; |
| *row++ = g_background; |
| } |
| } |
| } |
| |
| CreateTestY16TextureDrawQuad_FromVideoFrame( |
| shared_state, video_frame, tex_coord_rect, render_pass, |
| video_resource_updater, rect, visible_rect, resource_provider, |
| child_resource_provider, child_context_provider); |
| } |
| |
| using RendererTypes = |
| ::testing::Types<GLRenderer, |
| SoftwareRenderer, |
| SkiaRenderer, |
| cc::SkiaRendererDDL, |
| cc::GLRendererWithExpandedViewport, |
| cc::SoftwareRendererWithExpandedViewport>; |
| TYPED_TEST_CASE(RendererPixelTest, RendererTypes); |
| |
| template <typename RendererType> |
| class SoftwareRendererPixelTest : public cc::RendererPixelTest<RendererType> {}; |
| |
| using SoftwareRendererTypes = |
| ::testing::Types<SoftwareRenderer, |
| cc::SoftwareRendererWithExpandedViewport>; |
| TYPED_TEST_CASE(SoftwareRendererPixelTest, SoftwareRendererTypes); |
| |
| // TODO(weiliangc): Move these tests to normal RendererPixelTest as they pass |
| // with SkiaRenderer. Failed test list recorded in crbug.com/821176. |
| template <typename RendererType> |
| class NonSkiaRendererPixelTest : public cc::RendererPixelTest<RendererType> {}; |
| |
| using NonSkiaRendererTypes = |
| ::testing::Types<GLRenderer, |
| SoftwareRenderer, |
| cc::GLRendererWithExpandedViewport, |
| cc::SoftwareRendererWithExpandedViewport>; |
| TYPED_TEST_CASE(NonSkiaRendererPixelTest, NonSkiaRendererTypes); |
| |
| template <typename RendererType> |
| class FuzzyForSoftwareOnlyPixelComparator : public cc::PixelComparator { |
| public: |
| explicit FuzzyForSoftwareOnlyPixelComparator(bool discard_alpha) |
| : fuzzy_(discard_alpha), exact_(discard_alpha) {} |
| |
| bool Compare(const SkBitmap& actual_bmp, |
| const SkBitmap& expected_bmp) const override; |
| |
| private: |
| cc::FuzzyPixelOffByOneComparator fuzzy_; |
| cc::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<SkiaRenderer>::Compare( |
| const SkBitmap& actual_bmp, |
| const SkBitmap& expected_bmp) const { |
| return fuzzy_.Compare(actual_bmp, expected_bmp); |
| } |
| |
| template <> |
| bool FuzzyForSoftwareOnlyPixelComparator<cc::SkiaRendererDDL>::Compare( |
| const SkBitmap& actual_bmp, |
| const SkBitmap& expected_bmp) const { |
| return fuzzy_.Compare(actual_bmp, expected_bmp); |
| } |
| |
| template <> |
| bool FuzzyForSoftwareOnlyPixelComparator< |
| cc::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); |
| } |
| |
| TYPED_TEST(RendererPixelTest, SimpleGreenRect) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, rect, rect, SK_ColorGREEN, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| base::FilePath(FILE_PATH_LITERAL("green.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| TYPED_TEST(RendererPixelTest, SimpleGreenRect_NonRootRenderPass) { |
| gfx::Rect rect(this->device_viewport_size_); |
| gfx::Rect small_rect(100, 100); |
| |
| int child_id = 2; |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_id, small_rect, gfx::Transform()); |
| |
| SharedQuadState* child_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), small_rect, child_pass.get()); |
| |
| auto* color_quad = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(child_shared_state, rect, rect, SK_ColorGREEN, false); |
| |
| int root_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRenderPass(root_id, rect, gfx::Transform()); |
| |
| SharedQuadState* root_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, root_pass.get()); |
| |
| CreateTestRenderPassDrawQuad(root_shared_state, small_rect, child_id, |
| root_pass.get()); |
| |
| RenderPass* child_pass_ptr = child_pass.get(); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| EXPECT_TRUE(this->RunPixelTestWithReadbackTarget( |
| &pass_list, child_pass_ptr, |
| base::FilePath(FILE_PATH_LITERAL("green_small.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| TYPED_TEST(RendererPixelTest, PremultipliedTextureWithoutBackground) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| CreateTestTextureDrawQuad( |
| this->use_gpu(), gfx::Rect(this->device_viewport_size_), |
| SkColorSetARGB(128, 0, 255, 0), // Texel color. |
| SK_ColorTRANSPARENT, // Background color. |
| true, // Premultiplied alpha. |
| shared_state, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), |
| this->child_context_provider_, pass.get()); |
| |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TYPED_TEST(RendererPixelTest, PremultipliedTextureWithBackground) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* texture_quad_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| texture_quad_state->opacity = 0.8f; |
| |
| CreateTestTextureDrawQuad( |
| this->use_gpu(), gfx::Rect(this->device_viewport_size_), |
| SkColorSetARGB(204, 120, 255, 120), // Texel color. |
| SK_ColorGREEN, // Background color. |
| true, // Premultiplied alpha. |
| texture_quad_state, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), |
| this->child_context_provider_, pass.get()); |
| |
| SharedQuadState* color_quad_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(GLRendererPixelTest, SolidColorBlend) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| shared_state->opacity = 1 - 16.0f / 255; |
| shared_state->blend_mode = SkBlendMode::kDstOut; |
| |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, rect, rect, SK_ColorRED, false); |
| |
| SharedQuadState* shared_state_background = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| SkColor background_color = SkColorSetRGB(0xff, 0xff * 14 / 16, 0xff); |
| auto* color_quad_background = |
| pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad_background->SetNew(shared_state_background, rect, rect, |
| background_color, false); |
| // Result should be r=16, g=14, b=16. |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("dark_grey.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(GLRendererPixelTest, SolidColorWithTemperature) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, rect, rect, SK_ColorYELLOW, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| SkMatrix44 color_matrix(SkMatrix44::kIdentity_Constructor); |
| color_matrix.set(0, 0, 0.7f); |
| color_matrix.set(1, 1, 0.4f); |
| color_matrix.set(2, 2, 0.5f); |
| output_surface_->set_color_matrix(color_matrix); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("temperature_brown.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(GLRendererPixelTest, SolidColorWithTemperature_NonRootRenderPass) { |
| // Create a root and a child passes with two different solid color quads. |
| RenderPassList render_passes_in_draw_order; |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| gfx::Rect root_rect(0, 0, viewport_rect.width(), viewport_rect.height() / 2); |
| gfx::Rect child_rect(0, root_rect.bottom(), viewport_rect.width(), |
| root_rect.height()); |
| |
| // Child pass. |
| int child_pass_id = 2; |
| RenderPass* child_pass = cc::AddRenderPass( |
| &render_passes_in_draw_order, child_pass_id, viewport_rect, |
| gfx::Transform(), cc::FilterOperations()); |
| cc::AddQuad(child_pass, child_rect, SK_ColorGREEN); |
| |
| // Root pass. |
| int root_pass_id = 1; |
| RenderPass* root_pass = cc::AddRenderPass( |
| &render_passes_in_draw_order, root_pass_id, viewport_rect, |
| gfx::Transform(), cc::FilterOperations()); |
| cc::AddQuad(root_pass, root_rect, SK_ColorYELLOW); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), viewport_rect, root_pass); |
| CreateTestRenderPassDrawQuad(pass_shared_state, viewport_rect, child_pass_id, |
| root_pass); |
| |
| // Set a non-identity output color matrix on the output surface, and expect |
| // that the colors will be transformed. |
| SkMatrix44 color_matrix(SkMatrix44::kIdentity_Constructor); |
| color_matrix.set(0, 0, 0.7f); |
| color_matrix.set(1, 1, 0.4f); |
| color_matrix.set(2, 2, 0.5f); |
| output_surface_->set_color_matrix(color_matrix); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &render_passes_in_draw_order, |
| base::FilePath(FILE_PATH_LITERAL("temperature_brown_non_root.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(GLRendererPixelTest, |
| PremultipliedTextureWithBackgroundAndVertexOpacity) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* texture_quad_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| texture_quad_state->opacity = 0.8f; |
| |
| float vertex_opacity[4] = {1.f, 1.f, 0.f, 0.f}; |
| CreateTestTextureDrawQuad( |
| this->use_gpu(), gfx::Rect(this->device_viewport_size_), |
| SkColorSetARGB(204, 120, 255, 120), // Texel color. |
| vertex_opacity, |
| SK_ColorGREEN, // Background color. |
| true, // Premultiplied alpha. |
| texture_quad_state, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), |
| this->child_context_provider_, pass.get()); |
| |
| SharedQuadState* color_quad_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("green_alpha_vertex_opacity.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| template <typename TypeParam> |
| class IntersectingQuadPixelTest : public RendererPixelTest<TypeParam> { |
| protected: |
| void SetupQuadStateAndRenderPass() { |
| // This sets up a pair of draw quads. They are both rotated |
| // relative to the root plane, they are also rotated relative to each other. |
| // The intersect in the middle at a non-perpendicular angle so that any |
| // errors are hopefully magnified. |
| // The quads should intersect correctly, as in the front quad should only |
| // be partially in front of the back quad, and partially behind. |
| |
| viewport_rect_ = gfx::Rect(this->device_viewport_size_); |
| quad_rect_ = gfx::Rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2.0); |
| |
| int id = 1; |
| render_pass_ = CreateTestRootRenderPass(id, viewport_rect_); |
| |
| // Create the front quad rotated on the Z and Y axis. |
| gfx::Transform trans; |
| trans.Translate3d(0, 0, 0.707 * this->device_viewport_size_.width() / 2.0); |
| trans.RotateAboutZAxis(45.0); |
| trans.RotateAboutYAxis(45.0); |
| front_quad_state_ = |
| CreateTestSharedQuadState(trans, viewport_rect_, render_pass_.get()); |
| front_quad_state_->clip_rect = quad_rect_; |
| // Make sure they end up in a 3d sorting context. |
| front_quad_state_->sorting_context_id = 1; |
| |
| // Create the back quad, and rotate on just the y axis. This will intersect |
| // the first quad partially. |
| trans = gfx::Transform(); |
| trans.Translate3d(0, 0, -0.707 * this->device_viewport_size_.width() / 2.0); |
| trans.RotateAboutYAxis(-45.0); |
| back_quad_state_ = |
| CreateTestSharedQuadState(trans, viewport_rect_, render_pass_.get()); |
| back_quad_state_->sorting_context_id = 1; |
| back_quad_state_->clip_rect = quad_rect_; |
| } |
| void AppendBackgroundAndRunTest(const cc::PixelComparator& comparator, |
| const base::FilePath::CharType* ref_file) { |
| SharedQuadState* background_quad_state = CreateTestSharedQuadState( |
| gfx::Transform(), viewport_rect_, render_pass_.get()); |
| auto* background_quad = |
| render_pass_->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| background_quad->SetNew(background_quad_state, viewport_rect_, |
| viewport_rect_, SK_ColorWHITE, false); |
| pass_list_.push_back(std::move(render_pass_)); |
| EXPECT_TRUE( |
| this->RunPixelTest(&pass_list_, base::FilePath(ref_file), comparator)); |
| } |
| template <typename T> |
| T* CreateAndAppendDrawQuad() { |
| return render_pass_->CreateAndAppendDrawQuad<T>(); |
| } |
| |
| std::unique_ptr<RenderPass> render_pass_; |
| gfx::Rect viewport_rect_; |
| SharedQuadState* front_quad_state_; |
| SharedQuadState* back_quad_state_; |
| gfx::Rect quad_rect_; |
| RenderPassList pass_list_; |
| }; |
| |
| template <typename TypeParam> |
| class IntersectingQuadGLPixelTest |
| : public IntersectingQuadPixelTest<TypeParam> { |
| public: |
| void SetUp() override { |
| IntersectingQuadPixelTest<TypeParam>::SetUp(); |
| constexpr bool kUseStreamVideoDrawQuad = false; |
| constexpr bool kUseGpuMemoryBufferResources = false; |
| constexpr bool kUseR16Texture = false; |
| constexpr int kMaxResourceSize = 10000; |
| |
| video_resource_updater_ = std::make_unique<media::VideoResourceUpdater>( |
| this->child_context_provider_.get(), nullptr, |
| this->child_resource_provider_.get(), kUseStreamVideoDrawQuad, |
| kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize); |
| video_resource_updater2_ = std::make_unique<media::VideoResourceUpdater>( |
| this->child_context_provider_.get(), nullptr, |
| this->child_resource_provider_.get(), kUseStreamVideoDrawQuad, |
| kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize); |
| } |
| |
| protected: |
| std::unique_ptr<media::VideoResourceUpdater> video_resource_updater_; |
| std::unique_ptr<media::VideoResourceUpdater> video_resource_updater2_; |
| }; |
| |
| template <typename TypeParam> |
| class IntersectingQuadSoftwareTest |
| : public IntersectingQuadPixelTest<TypeParam> {}; |
| |
| using SoftwareRendererTypes = |
| ::testing::Types<SoftwareRenderer, |
| cc::SoftwareRendererWithExpandedViewport>; |
| using GLRendererTypes = |
| ::testing::Types<GLRenderer, cc::GLRendererWithExpandedViewport>; |
| |
| TYPED_TEST_CASE(IntersectingQuadPixelTest, RendererTypes); |
| TYPED_TEST_CASE(IntersectingQuadGLPixelTest, GLRendererTypes); |
| TYPED_TEST_CASE(IntersectingQuadSoftwareTest, SoftwareRendererTypes); |
| |
| TYPED_TEST(IntersectingQuadPixelTest, SolidColorQuads) { |
| this->SetupQuadStateAndRenderPass(); |
| |
| auto* quad = this->template CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| auto* quad2 = this->template CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| |
| quad->SetNew(this->front_quad_state_, this->quad_rect_, this->quad_rect_, |
| SK_ColorBLUE, false); |
| quad2->SetNew(this->back_quad_state_, this->quad_rect_, this->quad_rect_, |
| SK_ColorGREEN, false); |
| SCOPED_TRACE("IntersectingSolidColorQuads"); |
| this->AppendBackgroundAndRunTest( |
| cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f), |
| FILE_PATH_LITERAL("intersecting_blue_green.png")); |
| } |
| |
| static inline uint32_t GetSkiaOrGLColor(const SkColor& color) { |
| return SkColorSetARGB(SkColorGetA(color), SkColorGetB(color), |
| SkColorGetG(color), SkColorGetR(color)); |
| } |
| |
| template <typename TypeParam> |
| uint32_t GetColor(const SkColor& color) { |
| return color; |
| } |
| |
| template <> |
| uint32_t GetColor<GLRenderer>(const SkColor& color) { |
| return GetSkiaOrGLColor(color); |
| } |
| |
| template <> |
| uint32_t GetColor<SkiaRenderer>(const SkColor& color) { |
| return GetSkiaOrGLColor(color); |
| } |
| |
| template <> |
| uint32_t GetColor<cc::SkiaRendererDDL>(const SkColor& color) { |
| return GetSkiaOrGLColor(color); |
| } |
| |
| template <> |
| uint32_t GetColor<cc::GLRendererWithExpandedViewport>(const SkColor& color) { |
| return GetSkiaOrGLColor(color); |
| } |
| |
| TYPED_TEST(IntersectingQuadPixelTest, TexturedQuads) { |
| this->SetupQuadStateAndRenderPass(); |
| CreateTestTwoColoredTextureDrawQuad( |
| this->use_gpu(), this->quad_rect_, |
| GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), |
| GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 255)), SK_ColorTRANSPARENT, |
| true, this->front_quad_state_, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), |
| this->child_context_provider_, this->render_pass_.get()); |
| CreateTestTwoColoredTextureDrawQuad( |
| this->use_gpu(), this->quad_rect_, |
| GetColor<TypeParam>(SkColorSetARGB(255, 0, 255, 0)), |
| GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), SK_ColorTRANSPARENT, |
| true, this->back_quad_state_, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), |
| this->child_context_provider_, this->render_pass_.get()); |
| |
| SCOPED_TRACE("IntersectingTexturedQuads"); |
| this->AppendBackgroundAndRunTest( |
| cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f), |
| FILE_PATH_LITERAL("intersecting_blue_green_squares.png")); |
| } |
| |
| TYPED_TEST(IntersectingQuadSoftwareTest, PictureQuads) { |
| bool needs_blending = true; |
| this->SetupQuadStateAndRenderPass(); |
| gfx::Rect outer_rect(this->quad_rect_); |
| gfx::Rect inner_rect(this->quad_rect_.x() + (this->quad_rect_.width() / 4), |
| this->quad_rect_.y() + (this->quad_rect_.height() / 4), |
| this->quad_rect_.width() / 2, |
| this->quad_rect_.height() / 2); |
| |
| cc::PaintFlags black_flags; |
| black_flags.setColor(SK_ColorBLACK); |
| cc::PaintFlags blue_flags; |
| blue_flags.setColor(SK_ColorBLUE); |
| cc::PaintFlags green_flags; |
| green_flags.setColor(SK_ColorGREEN); |
| |
| std::unique_ptr<cc::FakeRecordingSource> blue_recording = |
| cc::FakeRecordingSource::CreateFilledRecordingSource( |
| this->quad_rect_.size()); |
| blue_recording->add_draw_rect_with_flags(outer_rect, black_flags); |
| blue_recording->add_draw_rect_with_flags(inner_rect, blue_flags); |
| blue_recording->Rerecord(); |
| scoped_refptr<cc::RasterSource> blue_raster_source = |
| blue_recording->CreateRasterSource(); |
| |
| auto* blue_quad = |
| this->render_pass_->template CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| |
| blue_quad->SetNew(this->front_quad_state_, this->quad_rect_, this->quad_rect_, |
| needs_blending, gfx::RectF(this->quad_rect_), |
| this->quad_rect_.size(), false, RGBA_8888, this->quad_rect_, |
| 1.f, {}, blue_raster_source->GetDisplayItemList()); |
| |
| std::unique_ptr<cc::FakeRecordingSource> green_recording = |
| cc::FakeRecordingSource::CreateFilledRecordingSource( |
| this->quad_rect_.size()); |
| green_recording->add_draw_rect_with_flags(outer_rect, green_flags); |
| green_recording->add_draw_rect_with_flags(inner_rect, black_flags); |
| green_recording->Rerecord(); |
| scoped_refptr<cc::RasterSource> green_raster_source = |
| green_recording->CreateRasterSource(); |
| |
| auto* green_quad = |
| this->render_pass_->template CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| green_quad->SetNew(this->back_quad_state_, this->quad_rect_, this->quad_rect_, |
| needs_blending, gfx::RectF(this->quad_rect_), |
| this->quad_rect_.size(), false, RGBA_8888, |
| this->quad_rect_, 1.f, {}, |
| green_raster_source->GetDisplayItemList()); |
| SCOPED_TRACE("IntersectingPictureQuadsPass"); |
| this->AppendBackgroundAndRunTest( |
| cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f), |
| FILE_PATH_LITERAL("intersecting_blue_green_squares.png")); |
| } |
| |
| TYPED_TEST(IntersectingQuadPixelTest, RenderPassQuads) { |
| this->SetupQuadStateAndRenderPass(); |
| int child_pass_id1 = 2; |
| int child_pass_id2 = 3; |
| std::unique_ptr<RenderPass> child_pass1 = |
| CreateTestRenderPass(child_pass_id1, this->quad_rect_, gfx::Transform()); |
| SharedQuadState* child1_quad_state = CreateTestSharedQuadState( |
| gfx::Transform(), this->quad_rect_, child_pass1.get()); |
| std::unique_ptr<RenderPass> child_pass2 = |
| CreateTestRenderPass(child_pass_id2, this->quad_rect_, gfx::Transform()); |
| SharedQuadState* child2_quad_state = CreateTestSharedQuadState( |
| gfx::Transform(), this->quad_rect_, child_pass2.get()); |
| CreateTestTwoColoredTextureDrawQuad( |
| this->use_gpu(), this->quad_rect_, |
| GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), |
| GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 255)), SK_ColorTRANSPARENT, |
| true, child1_quad_state, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), |
| this->child_context_provider_, child_pass1.get()); |
| CreateTestTwoColoredTextureDrawQuad( |
| this->use_gpu(), this->quad_rect_, |
| GetColor<TypeParam>(SkColorSetARGB(255, 0, 255, 0)), |
| GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), SK_ColorTRANSPARENT, |
| true, child2_quad_state, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), |
| this->child_context_provider_, child_pass2.get()); |
| |
| CreateTestRenderPassDrawQuad(this->front_quad_state_, this->quad_rect_, |
| child_pass_id1, this->render_pass_.get()); |
| CreateTestRenderPassDrawQuad(this->back_quad_state_, this->quad_rect_, |
| child_pass_id2, this->render_pass_.get()); |
| |
| this->pass_list_.push_back(std::move(child_pass1)); |
| this->pass_list_.push_back(std::move(child_pass2)); |
| SCOPED_TRACE("IntersectingRenderQuadsPass"); |
| this->AppendBackgroundAndRunTest( |
| cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f), |
| FILE_PATH_LITERAL("intersecting_blue_green_squares.png")); |
| } |
| |
| TYPED_TEST(IntersectingQuadGLPixelTest, YUVVideoQuads) { |
| this->SetupQuadStateAndRenderPass(); |
| gfx::Rect inner_rect( |
| ((this->quad_rect_.x() + (this->quad_rect_.width() / 4)) & ~0xF), |
| ((this->quad_rect_.y() + (this->quad_rect_.height() / 4)) & ~0xF), |
| (this->quad_rect_.width() / 2) & ~0xF, |
| (this->quad_rect_.height() / 2) & ~0xF); |
| |
| CreateTestYUVVideoDrawQuad_TwoColor( |
| this->front_quad_state_, media::PIXEL_FORMAT_I420, |
| media::COLOR_SPACE_JPEG, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), |
| this->quad_rect_.size(), this->quad_rect_, 0, 128, 128, inner_rect, 29, |
| 255, 107, this->render_pass_.get(), this->video_resource_updater_.get(), |
| this->resource_provider_.get(), this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| |
| CreateTestYUVVideoDrawQuad_TwoColor( |
| this->back_quad_state_, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, |
| false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), this->quad_rect_.size(), |
| this->quad_rect_, 149, 43, 21, inner_rect, 0, 128, 128, |
| this->render_pass_.get(), this->video_resource_updater2_.get(), |
| this->resource_provider_.get(), this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| |
| SCOPED_TRACE("IntersectingVideoQuads"); |
| this->AppendBackgroundAndRunTest( |
| cc::FuzzyPixelOffByOneComparator(false), |
| FILE_PATH_LITERAL("intersecting_blue_green_squares_video.png")); |
| } |
| |
| TYPED_TEST(IntersectingQuadGLPixelTest, Y16VideoQuads) { |
| this->SetupQuadStateAndRenderPass(); |
| gfx::Rect inner_rect( |
| ((this->quad_rect_.x() + (this->quad_rect_.width() / 4)) & ~0xF), |
| ((this->quad_rect_.y() + (this->quad_rect_.height() / 4)) & ~0xF), |
| (this->quad_rect_.width() / 2) & ~0xF, |
| (this->quad_rect_.height() / 2) & ~0xF); |
| |
| CreateTestY16TextureDrawQuad_TwoColor( |
| this->front_quad_state_, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 18, 0, |
| this->render_pass_.get(), this->video_resource_updater_.get(), |
| this->quad_rect_, this->quad_rect_, inner_rect, |
| this->resource_provider_.get(), this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| |
| CreateTestY16TextureDrawQuad_TwoColor( |
| this->back_quad_state_, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 0, 182, |
| this->render_pass_.get(), this->video_resource_updater2_.get(), |
| this->quad_rect_, this->quad_rect_, inner_rect, |
| this->resource_provider_.get(), this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| |
| SCOPED_TRACE("IntersectingVideoQuads"); |
| this->AppendBackgroundAndRunTest( |
| cc::FuzzyPixelOffByOneComparator(false), |
| FILE_PATH_LITERAL("intersecting_light_dark_squares_video.png")); |
| } |
| |
| // TODO(skaslev): The software renderer does not support non-premultplied alpha. |
| TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithoutBackground) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| CreateTestTextureDrawQuad( |
| this->use_gpu(), gfx::Rect(this->device_viewport_size_), |
| SkColorSetARGB(128, 0, 255, 0), // Texel color. |
| SK_ColorTRANSPARENT, // Background color. |
| false, // Premultiplied alpha. |
| shared_state, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), |
| this->child_context_provider_, pass.get()); |
| |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| // TODO(skaslev): The software renderer does not support non-premultplied alpha. |
| TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* texture_quad_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| texture_quad_state->opacity = 0.8f; |
| |
| CreateTestTextureDrawQuad( |
| this->use_gpu(), gfx::Rect(this->device_viewport_size_), |
| SkColorSetARGB(204, 120, 255, 120), // Texel color. |
| SK_ColorGREEN, // Background color. |
| false, // Premultiplied alpha. |
| texture_quad_state, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), |
| this->child_context_provider_, pass.get()); |
| |
| SharedQuadState* color_quad_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| class VideoGLRendererPixelTest : public cc::GLRendererPixelTest { |
| protected: |
| void CreateEdgeBleedPass(media::VideoPixelFormat format, |
| media::ColorSpace color_space, |
| RenderPassList* pass_list) { |
| gfx::Rect rect(200, 200); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| // Scale the video up so that bilinear filtering kicks in to sample more |
| // than just nearest neighbor would. |
| gfx::Transform scale_by_2; |
| scale_by_2.Scale(2.f, 2.f); |
| gfx::Rect half_rect(100, 100); |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(scale_by_2, half_rect, pass.get()); |
| |
| gfx::Size background_size(200, 200); |
| gfx::Rect green_rect(16, 20, 100, 100); |
| gfx::RectF tex_coord_rect( |
| static_cast<float>(green_rect.x()) / background_size.width(), |
| static_cast<float>(green_rect.y()) / background_size.height(), |
| static_cast<float>(green_rect.width()) / background_size.width(), |
| static_cast<float>(green_rect.height()) / background_size.height()); |
| |
| // YUV of (149,43,21) should be green (0,255,0) in RGB. |
| // Create a video frame that has a non-green background rect, with a |
| // green sub-rectangle that should be the only thing displayed in |
| // the final image. Bleeding will appear on all four sides of the video |
| // if the tex coords are not clamped. |
| CreateTestYUVVideoDrawQuad_TwoColor( |
| shared_state, format, color_space, false, tex_coord_rect, |
| background_size, gfx::Rect(background_size), 128, 128, 128, green_rect, |
| 149, 43, 21, pass.get(), video_resource_updater_.get(), |
| resource_provider_.get(), child_resource_provider_.get(), |
| child_context_provider_.get()); |
| pass_list->push_back(std::move(pass)); |
| } |
| |
| void SetUp() override { |
| GLRendererPixelTest::SetUp(); |
| constexpr bool kUseStreamVideoDrawQuad = false; |
| constexpr bool kUseGpuMemoryBufferResources = false; |
| constexpr bool kUseR16Texture = false; |
| constexpr int kMaxResourceSize = 10000; |
| video_resource_updater_ = std::make_unique<media::VideoResourceUpdater>( |
| child_context_provider_.get(), nullptr, child_resource_provider_.get(), |
| kUseStreamVideoDrawQuad, kUseGpuMemoryBufferResources, kUseR16Texture, |
| kMaxResourceSize); |
| } |
| |
| void TearDown() override { |
| video_resource_updater_ = nullptr; |
| GLRendererPixelTest::TearDown(); |
| } |
| |
| std::unique_ptr<media::VideoResourceUpdater> video_resource_updater_; |
| }; |
| |
| class VideoGLRendererPixelHiLoTest : public VideoGLRendererPixelTest, |
| public testing::WithParamInterface<bool> { |
| public: |
| bool IsHighbit() const { return GetParam(); } |
| }; |
| |
| TEST_P(VideoGLRendererPixelHiLoTest, SimpleYUVRect) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| // Set the output color space to match the input primaries and transfer. |
| pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M, |
| gfx::ColorSpace::TransferID::SMPTE170M); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| CreateTestYUVVideoDrawQuad_Striped( |
| shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601, |
| false, IsHighbit(), gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), |
| video_resource_updater_.get(), rect, rect, resource_provider_.get(), |
| child_resource_provider_.get(), child_context_provider_.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("yuv_stripes.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_P(VideoGLRendererPixelHiLoTest, ClippedYUVRect) { |
| gfx::Rect viewport(this->device_viewport_size_); |
| gfx::Rect draw_rect(this->device_viewport_size_.width() * 1.5, |
| this->device_viewport_size_.height() * 1.5); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, viewport); |
| // Set the output color space to match the input primaries and transfer. |
| pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M, |
| gfx::ColorSpace::TransferID::SMPTE170M); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), viewport, pass.get()); |
| |
| CreateTestYUVVideoDrawQuad_Striped( |
| shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601, |
| false, IsHighbit(), gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), |
| video_resource_updater_.get(), draw_rect, viewport, |
| resource_provider_.get(), child_resource_provider_.get(), |
| child_context_provider_.get()); |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("yuv_stripes_clipped.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(VideoGLRendererPixelHiLoTest, OffsetYUVRect) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| // Set the output color space to match the input primaries and transfer. |
| pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M, |
| gfx::ColorSpace::TransferID::SMPTE170M); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| // Intentionally sets frame format to I420 for testing coverage. |
| CreateTestYUVVideoDrawQuad_Striped( |
| shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601, |
| false, false, gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f), pass.get(), |
| video_resource_updater_.get(), rect, rect, resource_provider_.get(), |
| child_resource_provider_.get(), child_context_provider_.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("yuv_stripes_offset.png")), |
| cc::FuzzyPixelComparator(true, 100.0f, 1.0f, 1.0f, 1, 0))); |
| } |
| |
| TEST_F(VideoGLRendererPixelTest, SimpleYUVRectBlack) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| // Set the output color space to match the input primaries and transfer. |
| pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M, |
| gfx::ColorSpace::TransferID::SMPTE170M); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| // In MPEG color range YUV values of (15,128,128) should produce black. |
| CreateTestYUVVideoDrawQuad_Solid( |
| shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601, |
| false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(), |
| video_resource_updater_.get(), rect, rect, resource_provider_.get(), |
| child_resource_provider_.get(), child_context_provider_.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // If we didn't get black out of the YUV values above, then we probably have a |
| // color range issue. |
| EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| base::FilePath(FILE_PATH_LITERAL("black.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| // First argument (test case prefix) is intentionally left empty. |
| INSTANTIATE_TEST_CASE_P(, VideoGLRendererPixelHiLoTest, testing::Bool()); |
| |
| TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| // YUV of (149,43,21) should be green (0,255,0) in RGB. |
| CreateTestYUVVideoDrawQuad_Solid( |
| shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, false, |
| gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(), |
| video_resource_updater_.get(), rect, rect, resource_provider_.get(), |
| child_resource_provider_.get(), child_context_provider_.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| base::FilePath(FILE_PATH_LITERAL("green.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(VideoGLRendererPixelTest, SimpleNV12JRect) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| // YUV of (149,43,21) should be green (0,255,0) in RGB. |
| CreateTestYUVVideoDrawQuad_NV12( |
| shared_state, media::COLOR_SPACE_JPEG, gfx::ColorSpace::CreateJpeg(), |
| gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(), |
| video_resource_updater_.get(), rect, rect, resource_provider_.get(), |
| child_resource_provider_.get(), child_context_provider_); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| base::FilePath(FILE_PATH_LITERAL("green.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| // Test that a YUV video doesn't bleed outside of its tex coords when the |
| // tex coord rect is only a partial subrectangle of the coded contents. |
| TEST_F(VideoGLRendererPixelTest, YUVEdgeBleed) { |
| RenderPassList pass_list; |
| CreateEdgeBleedPass(media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, |
| &pass_list); |
| EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| base::FilePath(FILE_PATH_LITERAL("green.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(VideoGLRendererPixelTest, YUVAEdgeBleed) { |
| RenderPassList pass_list; |
| CreateEdgeBleedPass(media::PIXEL_FORMAT_I420A, media::COLOR_SPACE_SD_REC601, |
| &pass_list); |
| // Set the output color space to match the input primaries and transfer. |
| pass_list.back()->color_space = |
| gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M, |
| gfx::ColorSpace::TransferID::SMPTE170M); |
| EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| base::FilePath(FILE_PATH_LITERAL("green.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(VideoGLRendererPixelTest, SimpleYUVJRectGrey) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| // Dark grey in JPEG color range (in MPEG, this is black). |
| CreateTestYUVVideoDrawQuad_Solid( |
| shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, false, |
| gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(), |
| video_resource_updater_.get(), rect, rect, resource_provider_.get(), |
| child_resource_provider_.get(), child_context_provider_.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("dark_grey.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(VideoGLRendererPixelHiLoTest, SimpleYUVARect) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| // Set the output color space to match the input primaries and transfer. |
| pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M, |
| gfx::ColorSpace::TransferID::SMPTE170M); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| CreateTestYUVVideoDrawQuad_Striped( |
| shared_state, media::PIXEL_FORMAT_I420A, media::COLOR_SPACE_SD_REC601, |
| false, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), |
| video_resource_updater_.get(), rect, rect, resource_provider_.get(), |
| child_resource_provider_.get(), child_context_provider_.get()); |
| |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("yuv_stripes_alpha.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| // Set the output color space to match the input primaries and transfer. |
| pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M, |
| gfx::ColorSpace::TransferID::SMPTE170M); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| CreateTestYUVVideoDrawQuad_Striped( |
| shared_state, media::PIXEL_FORMAT_I420A, media::COLOR_SPACE_SD_REC601, |
| true, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), |
| video_resource_updater_.get(), rect, rect, resource_provider_.get(), |
| child_resource_provider_.get(), child_context_provider_.get()); |
| |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| base::FilePath(FILE_PATH_LITERAL("black.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| TEST_F(VideoGLRendererPixelTest, TwoColorY16Rect) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| gfx::Rect upper_rect(rect.x(), rect.y(), rect.width(), rect.height() / 2); |
| CreateTestY16TextureDrawQuad_TwoColor( |
| shared_state, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 68, 123, pass.get(), |
| video_resource_updater_.get(), rect, rect, upper_rect, |
| resource_provider_.get(), child_resource_provider_.get(), |
| child_context_provider_.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("blue_yellow_filter_chain.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) { |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| |
| int child_pass_id = 2; |
| gfx::Rect pass_rect(this->device_viewport_size_); |
| gfx::Transform transform_to_root; |
| 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; |
| cc::FilterOperations filters; |
| filters.Append(cc::FilterOperation::CreateReferenceFilter( |
| sk_make_sp<cc::ColorFilterPaintFilter>( |
| SkColorFilter::MakeMatrixFilterRowMajor255(matrix), nullptr))); |
| |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); |
| child_pass->filters = filters; |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| shared_state->opacity = 0.5f; |
| |
| gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false); |
| gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2, |
| this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false); |
| |
| SharedQuadState* blank_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| |
| auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE, |
| false); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get()); |
| |
| auto* render_pass_quad = |
| root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); |
| render_pass_quad->SetNew(pass_shared_state, pass_rect, pass_rect, |
| child_pass_id, 0, gfx::RectF(), gfx::Size(), |
| gfx::Vector2dF(), gfx::PointF(), |
| gfx::RectF(pass_rect), false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_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, FastPassSaturateFilter) { |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| |
| int child_pass_id = 2; |
| gfx::Rect pass_rect(this->device_viewport_size_); |
| gfx::Transform transform_to_root; |
| cc::FilterOperations filters; |
| filters.Append(cc::FilterOperation::CreateSaturateFilter(0.5f)); |
| |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); |
| child_pass->filters = filters; |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| shared_state->opacity = 0.5f; |
| |
| gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false); |
| gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2, |
| this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false); |
| |
| SharedQuadState* blank_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| |
| auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE, |
| false); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get()); |
| |
| auto* render_pass_quad = |
| root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); |
| render_pass_quad->SetNew(pass_shared_state, pass_rect, pass_rect, |
| child_pass_id, 0, gfx::RectF(), gfx::Size(), |
| gfx::Vector2dF(), gfx::PointF(), |
| gfx::RectF(pass_rect), false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| // This test blends slightly differently with the software renderer vs. 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, FastPassFilterChain) { |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| |
| int child_pass_id = 2; |
| gfx::Rect pass_rect(this->device_viewport_size_); |
| gfx::Transform transform_to_root; |
| cc::FilterOperations filters; |
| filters.Append(cc::FilterOperation::CreateGrayscaleFilter(1.f)); |
| filters.Append(cc::FilterOperation::CreateBrightnessFilter(0.5f)); |
| |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); |
| child_pass->filters = filters; |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| shared_state->opacity = 0.5f; |
| |
| gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false); |
| gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2, |
| this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false); |
| |
| SharedQuadState* blank_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| |
| auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE, |
| false); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get()); |
| |
| auto* render_pass_quad = |
| root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); |
| render_pass_quad->SetNew(pass_shared_state, pass_rect, pass_rect, |
| child_pass_id, 0, gfx::RectF(), gfx::Size(), |
| gfx::Vector2dF(), gfx::PointF(), |
| gfx::RectF(pass_rect), false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| // This test blends slightly differently with the software renderer vs. the gl |
| // renderer so use a fuzzy comparator. |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("blue_yellow_filter_chain.png")), |
| FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false))); |
| } |
| |
| TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) { |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| |
| int child_pass_id = 2; |
| gfx::Rect pass_rect(this->device_viewport_size_); |
| gfx::Transform transform_to_root; |
| 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; |
| cc::FilterOperations filters; |
| filters.Append(cc::FilterOperation::CreateReferenceFilter( |
| sk_make_sp<cc::ColorFilterPaintFilter>( |
| SkColorFilter::MakeMatrixFilterRowMajor255(matrix), nullptr))); |
| |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); |
| child_pass->filters = filters; |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| shared_state->opacity = 0.5f; |
| |
| gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false); |
| gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2, |
| this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false); |
| |
| SharedQuadState* blank_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| |
| auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE, |
| false); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get()); |
| |
| auto* render_pass_quad = |
| root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); |
| render_pass_quad->SetNew(pass_shared_state, pass_rect, pass_rect, |
| child_pass_id, 0, gfx::RectF(), gfx::Size(), |
| gfx::Vector2dF(), gfx::PointF(), |
| gfx::RectF(pass_rect), false); |
| |
| RenderPassList pass_list; |
| |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_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_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| |
| int child_pass_id = 2; |
| gfx::Rect pass_rect(this->device_viewport_size_); |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| |
| gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false); |
| gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2, |
| this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get()); |
| CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id, |
| root_pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| this->renderer_->SetEnlargePassTextureAmountForTesting(gfx::Size(50, 75)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| TYPED_TEST(RendererPixelTest, EnlargedRenderPassTextureWithAntiAliasing) { |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| |
| int child_pass_id = 2; |
| gfx::Rect pass_rect(this->device_viewport_size_); |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| |
| gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false); |
| gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2, |
| this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false); |
| |
| gfx::Transform aa_transform; |
| aa_transform.Translate(0.5, 0.0); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(aa_transform, pass_rect, root_pass.get()); |
| CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id, |
| root_pass.get()); |
| |
| SharedQuadState* root_shared_state = CreateTestSharedQuadState( |
| gfx::Transform(), viewport_rect, root_pass.get()); |
| auto* background = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| background->SetNew(root_shared_state, gfx::Rect(this->device_viewport_size_), |
| gfx::Rect(this->device_viewport_size_), SK_ColorWHITE, |
| false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| this->renderer_->SetEnlargePassTextureAmountForTesting(gfx::Size(50, 75)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("blue_yellow_anti_aliasing.png")), |
| cc::FuzzyPixelComparator(true, 100.f, 0.f, 5.f, 5, 0))); |
| } |
| |
| // This tests the case where we have a RenderPass with a mask, but the quad |
| // for the masked surface does not include the full surface texture. |
| TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad) { |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState( |
| gfx::Transform(), viewport_rect, root_pass.get()); |
| |
| int child_pass_id = 2; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root); |
| SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState( |
| gfx::Transform(), viewport_rect, child_pass.get()); |
| |
| // The child render pass is just a green box. |
| static const SkColor kCSSGreen = 0xff008000; |
| auto* green = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| green->SetNew(child_pass_shared_state, viewport_rect, viewport_rect, |
| kCSSGreen, false); |
| |
| // Make a mask. |
| gfx::Rect mask_rect = viewport_rect; |
| SkBitmap bitmap; |
| bitmap.allocPixels( |
| SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height())); |
| cc::SkiaPaintCanvas canvas(bitmap); |
| cc::PaintFlags flags; |
| flags.setStyle(cc::PaintFlags::kStroke_Style); |
| flags.setStrokeWidth(SkIntToScalar(4)); |
| flags.setColor(SK_ColorWHITE); |
| canvas.clear(SK_ColorTRANSPARENT); |
| gfx::Rect rect = mask_rect; |
| while (!rect.IsEmpty()) { |
| rect.Inset(6, 6, 4, 4); |
| canvas.drawRect( |
| SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()), |
| flags); |
| rect.Inset(6, 6, 4, 4); |
| } |
| |
| ResourceId mask_resource_id; |
| if (this->use_gpu()) { |
| mask_resource_id = CreateGpuResource( |
| this->child_context_provider_, this->child_resource_provider_.get(), |
| mask_rect.size(), RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); |
| } else { |
| mask_resource_id = |
| this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap); |
| } |
| |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| {mask_resource_id}, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| ResourceId mapped_mask_resource_id = resource_map[mask_resource_id]; |
| |
| // This RenderPassDrawQuad does not include the full |viewport_rect| |
| // which is the size of the child render pass. |
| gfx::Rect sub_rect = gfx::Rect(50, 50, 200, 100); |
| EXPECT_NE(sub_rect.x(), child_pass->output_rect.x()); |
| EXPECT_NE(sub_rect.y(), child_pass->output_rect.y()); |
| EXPECT_NE(sub_rect.right(), child_pass->output_rect.right()); |
| EXPECT_NE(sub_rect.bottom(), child_pass->output_rect.bottom()); |
| |
| // Set up a mask on the RenderPassDrawQuad. |
| auto* mask_quad = root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); |
| mask_quad->SetNew( |
| root_pass_shared_state, sub_rect, sub_rect, child_pass_id, |
| mapped_mask_resource_id, |
| gfx::ScaleRect(gfx::RectF(sub_rect), 2.f / mask_rect.width(), |
| 2.f / mask_rect.height()), // mask_uv_rect |
| gfx::Size(mask_rect.size()), // mask_texture_size |
| gfx::Vector2dF(), // filters scale |
| gfx::PointF(), // filter origin |
| gfx::RectF(sub_rect), // tex_coord_rect |
| false); // force_anti_aliasing_off |
| // White background behind the masked render pass. |
| auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| white->SetNew(root_pass_shared_state, viewport_rect, viewport_rect, |
| SK_ColorWHITE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("mask_bottom_right.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| // This tests the case where we have a RenderPass with a mask, but the quad |
| // for the masked surface does not include the full surface texture. |
| TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad2) { |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState( |
| gfx::Transform(), viewport_rect, root_pass.get()); |
| |
| int child_pass_id = 2; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root); |
| SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState( |
| gfx::Transform(), viewport_rect, child_pass.get()); |
| |
| // The child render pass is just a green box. |
| static const SkColor kCSSGreen = 0xff008000; |
| auto* green = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| green->SetNew(child_pass_shared_state, viewport_rect, viewport_rect, |
| kCSSGreen, false); |
| |
| // Make a mask. |
| gfx::Rect mask_rect = viewport_rect; |
| SkBitmap bitmap; |
| bitmap.allocPixels( |
| SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height())); |
| cc::SkiaPaintCanvas canvas(bitmap); |
| cc::PaintFlags flags; |
| flags.setStyle(cc::PaintFlags::kStroke_Style); |
| flags.setStrokeWidth(SkIntToScalar(4)); |
| flags.setColor(SK_ColorWHITE); |
| canvas.clear(SK_ColorTRANSPARENT); |
| gfx::Rect rect = mask_rect; |
| while (!rect.IsEmpty()) { |
| rect.Inset(6, 6, 4, 4); |
| canvas.drawRect( |
| SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()), |
| flags); |
| rect.Inset(6, 6, 4, 4); |
| } |
| |
| ResourceId mask_resource_id; |
| if (this->use_gpu()) { |
| mask_resource_id = CreateGpuResource( |
| this->child_context_provider_, this->child_resource_provider_.get(), |
| mask_rect.size(), RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); |
| } else { |
| mask_resource_id = |
| this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap); |
| } |
| |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| {mask_resource_id}, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| ResourceId mapped_mask_resource_id = resource_map[mask_resource_id]; |
| |
| // This RenderPassDrawQuad does not include the full |viewport_rect| |
| // which is the size of the child render pass. |
| gfx::Rect sub_rect = gfx::Rect(50, 20, 200, 60); |
| EXPECT_NE(sub_rect.x(), child_pass->output_rect.x()); |
| EXPECT_NE(sub_rect.y(), child_pass->output_rect.y()); |
| EXPECT_NE(sub_rect.right(), child_pass->output_rect.right()); |
| EXPECT_NE(sub_rect.bottom(), child_pass->output_rect.bottom()); |
| |
| // Set up a mask on the RenderPassDrawQuad. |
| auto* mask_quad = root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); |
| mask_quad->SetNew( |
| root_pass_shared_state, sub_rect, sub_rect, child_pass_id, |
| mapped_mask_resource_id, |
| gfx::ScaleRect(gfx::RectF(sub_rect), 2.f / mask_rect.width(), |
| 2.f / mask_rect.height()), // mask_uv_rect |
| gfx::Size(mask_rect.size()), // mask_texture_size |
| gfx::Vector2dF(), // filters scale |
| gfx::PointF(), // filter origin |
| gfx::RectF(sub_rect), // tex_coord_rect |
| false); // force_anti_aliasing_off |
| // White background behind the masked render pass. |
| auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| white->SetNew(root_pass_shared_state, viewport_rect, viewport_rect, |
| SK_ColorWHITE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("mask_middle.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| template <typename RendererType> |
| class RendererPixelTestWithBackgroundFilter |
| : public RendererPixelTest<RendererType> { |
| protected: |
| void SetUpRenderPassList() { |
| gfx::Rect device_viewport_rect(this->device_viewport_size_); |
| |
| int root_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_id, device_viewport_rect); |
| root_pass->has_transparent_background = false; |
| |
| gfx::Transform identity_quad_to_target_transform; |
| |
| int filter_pass_id = 2; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> filter_pass = CreateTestRenderPass( |
| filter_pass_id, filter_pass_layer_rect_, transform_to_root); |
| filter_pass->background_filters = this->background_filters_; |
| |
| // A non-visible quad in the filtering render pass. |
| { |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(identity_quad_to_target_transform, |
| filter_pass_layer_rect_, filter_pass.get()); |
| auto* color_quad = |
| filter_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, filter_pass_layer_rect_, |
| filter_pass_layer_rect_, SK_ColorTRANSPARENT, false); |
| } |
| |
| { |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(filter_pass_to_target_transform_, |
| filter_pass_layer_rect_, filter_pass.get()); |
| auto* filter_pass_quad = |
| root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); |
| filter_pass_quad->SetNew(shared_state, filter_pass_layer_rect_, |
| filter_pass_layer_rect_, filter_pass_id, |
| 0, // mask_resource_id |
| gfx::RectF(), // mask_uv_rect |
| gfx::Size(), // mask_texture_size |
| gfx::Vector2dF(1.0f, 1.0f), // filters_scale |
| gfx::PointF(), // filters_origin |
| gfx::RectF(), // tex_coord_rect |
| false); // force_anti_aliasing_off |
| } |
| |
| 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) { |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| identity_quad_to_target_transform, left_rect, root_pass.get()); |
| auto* color_quad = |
| root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, left_rect, left_rect, SK_ColorGREEN, |
| false); |
| 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) { |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| identity_quad_to_target_transform, middle_rect, root_pass.get()); |
| auto* color_quad = |
| root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, middle_rect, middle_rect, SK_ColorRED, |
| false); |
| 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) { |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| identity_quad_to_target_transform, right_rect, root_pass.get()); |
| auto* color_quad = |
| root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, right_rect, right_rect, SK_ColorBLUE, |
| false); |
| right_rect += gfx::Vector2d(0, right_rect.height() + 1); |
| } |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(identity_quad_to_target_transform, |
| device_viewport_rect, root_pass.get()); |
| auto* background_quad = |
| root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| background_quad->SetNew(shared_state, device_viewport_rect, |
| device_viewport_rect, SK_ColorWHITE, false); |
| |
| pass_list_.push_back(std::move(filter_pass)); |
| pass_list_.push_back(std::move(root_pass)); |
| } |
| |
| RenderPassList pass_list_; |
| cc::FilterOperations background_filters_; |
| gfx::Transform filter_pass_to_target_transform_; |
| gfx::Rect filter_pass_layer_rect_; |
| }; |
| |
| // The software renderer does not support background filters yet. |
| using BackgroundFilterRendererTypes = |
| ::testing::Types<GLRenderer, SkiaRenderer, cc::SkiaRendererDDL>; |
| |
| TYPED_TEST_CASE(RendererPixelTestWithBackgroundFilter, |
| BackgroundFilterRendererTypes); |
| |
| TYPED_TEST(RendererPixelTestWithBackgroundFilter, InvertFilter) { |
| this->background_filters_.Append( |
| cc::FilterOperation::CreateInvertFilter(1.f)); |
| |
| this->filter_pass_layer_rect_ = gfx::Rect(this->device_viewport_size_); |
| this->filter_pass_layer_rect_.Inset(12, 14, 16, 18); |
| |
| this->SetUpRenderPassList(); |
| EXPECT_TRUE(this->RunPixelTest( |
| &this->pass_list_, |
| base::FilePath(FILE_PATH_LITERAL("background_filter.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| class ExternalStencilPixelTest : public GLRendererPixelTest { |
| protected: |
| void ClearBackgroundToGreen() { |
| GLES2Interface* gl = output_surface_->context_provider()->ContextGL(); |
| output_surface_->EnsureBackbuffer(); |
| output_surface_->Reshape(device_viewport_size_, 1, gfx::ColorSpace(), true, |
| false); |
| gl->ClearColor(0.f, 1.f, 0.f, 1.f); |
| gl->Clear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| void PopulateStencilBuffer() { |
| // Set two quadrants of the stencil buffer to 1. |
| GLES2Interface* gl = output_surface_->context_provider()->ContextGL(); |
| output_surface_->EnsureBackbuffer(); |
| output_surface_->Reshape(device_viewport_size_, 1, gfx::ColorSpace(), true, |
| false); |
| gl->ClearStencil(0); |
| gl->Clear(GL_STENCIL_BUFFER_BIT); |
| gl->Enable(GL_SCISSOR_TEST); |
| gl->ClearStencil(1); |
| gl->Scissor(0, 0, device_viewport_size_.width() / 2, |
| device_viewport_size_.height() / 2); |
| gl->Clear(GL_STENCIL_BUFFER_BIT); |
| gl->Scissor(device_viewport_size_.width() / 2, |
| device_viewport_size_.height() / 2, |
| device_viewport_size_.width(), device_viewport_size_.height()); |
| gl->Clear(GL_STENCIL_BUFFER_BIT); |
| gl->StencilFunc(GL_EQUAL, 1, 1); |
| } |
| }; |
| |
| 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_); |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| SharedQuadState* blue_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false); |
| pass->has_transparent_background = false; |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), |
| cc::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_); |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| SharedQuadState* green_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| auto* green = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false); |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| base::FilePath(FILE_PATH_LITERAL("green.png")), |
| cc::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_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| root_pass->has_transparent_background = false; |
| |
| int child_pass_id = 2; |
| gfx::Rect pass_rect(this->device_viewport_size_); |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| |
| gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height()); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get()); |
| CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id, |
| root_pass.get()); |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| // Software renderer does not support anti-aliased edges. |
| TEST_F(GLRendererPixelTest, AntiAliasing) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| gfx::Transform red_quad_to_target_transform; |
| red_quad_to_target_transform.Rotate(10); |
| SharedQuadState* red_shared_state = |
| CreateTestSharedQuadState(red_quad_to_target_transform, rect, pass.get()); |
| |
| auto* red = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| red->SetNew(red_shared_state, rect, rect, SK_ColorRED, false); |
| |
| gfx::Transform yellow_quad_to_target_transform; |
| yellow_quad_to_target_transform.Rotate(5); |
| SharedQuadState* yellow_shared_state = CreateTestSharedQuadState( |
| yellow_quad_to_target_transform, rect, pass.get()); |
| |
| auto* yellow = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| yellow->SetNew(yellow_shared_state, rect, rect, SK_ColorYELLOW, false); |
| |
| gfx::Transform blue_quad_to_target_transform; |
| SharedQuadState* blue_shared_state = CreateTestSharedQuadState( |
| blue_quad_to_target_transform, rect, pass.get()); |
| |
| auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("anti_aliasing.png")), |
| cc::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_); |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, rect, transform_to_root); |
| |
| gfx::Transform red_quad_to_target_transform; |
| red_quad_to_target_transform.Translate(50, 50); |
| red_quad_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f), |
| 0.5f + 1.0f / (rect.height() * 2.0f)); |
| SharedQuadState* red_shared_state = |
| CreateTestSharedQuadState(red_quad_to_target_transform, rect, pass.get()); |
| |
| auto* red = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| red->SetNew(red_shared_state, rect, rect, SK_ColorRED, false); |
| |
| gfx::Transform yellow_quad_to_target_transform; |
| yellow_quad_to_target_transform.Translate(25.5f, 25.5f); |
| yellow_quad_to_target_transform.Scale(0.5f, 0.5f); |
| SharedQuadState* yellow_shared_state = CreateTestSharedQuadState( |
| yellow_quad_to_target_transform, rect, pass.get()); |
| |
| auto* yellow = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| yellow->SetNew(yellow_shared_state, rect, rect, SK_ColorYELLOW, false); |
| |
| gfx::Transform blue_quad_to_target_transform; |
| SharedQuadState* blue_shared_state = CreateTestSharedQuadState( |
| blue_quad_to_target_transform, rect, pass.get()); |
| |
| auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("axis_aligned.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| // This test tests that forcing anti-aliasing off works as expected for |
| // solid color draw quads. |
| // Anti-aliasing is only supported in the gl renderer. |
| TEST_F(GLRendererPixelTest, SolidColorDrawQuadForceAntiAliasingOff) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, rect, transform_to_root); |
| |
| gfx::Transform hole_quad_to_target_transform; |
| hole_quad_to_target_transform.Translate(50, 50); |
| hole_quad_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f), |
| 0.5f + 1.0f / (rect.height() * 2.0f)); |
| SharedQuadState* hole_shared_state = CreateTestSharedQuadState( |
| hole_quad_to_target_transform, rect, pass.get()); |
| |
| auto* hole = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| hole->SetAll(hole_shared_state, rect, rect, false, SK_ColorTRANSPARENT, true); |
| |
| gfx::Transform green_quad_to_target_transform; |
| SharedQuadState* green_shared_state = CreateTestSharedQuadState( |
| green_quad_to_target_transform, rect, pass.get()); |
| |
| auto* green = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("force_anti_aliasing_off.png")), |
| cc::ExactPixelComparator(false))); |
| } |
| |
| // This test tests that forcing anti-aliasing off works as expected for |
| // render pass draw quads. |
| // Anti-aliasing is only supported in the gl renderer. |
| TEST_F(GLRendererPixelTest, RenderPassDrawQuadForceAntiAliasingOff) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRenderPass(root_pass_id, rect, transform_to_root); |
| |
| int child_pass_id = 2; |
| gfx::Transform child_pass_transform; |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, rect, child_pass_transform); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* hole_shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, rect, child_pass.get()); |
| SolidColorDrawQuad* hole = |
| child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| hole->SetAll(hole_shared_state, rect, rect, false, SK_ColorTRANSPARENT, |
| false); |
| |
| bool needs_blending = false; |
| bool force_anti_aliasing_off = true; |
| gfx::Transform hole_pass_to_target_transform; |
| hole_pass_to_target_transform.Translate(50, 50); |
| hole_pass_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f), |
| 0.5f + 1.0f / (rect.height() * 2.0f)); |
| SharedQuadState* pass_shared_state = CreateTestSharedQuadState( |
| hole_pass_to_target_transform, rect, root_pass.get()); |
| RenderPassDrawQuad* pass_quad = |
| root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); |
| pass_quad->SetAll(pass_shared_state, rect, rect, needs_blending, |
| child_pass_id, 0, gfx::RectF(), gfx::Size(), |
| gfx::Vector2dF(), gfx::PointF(), gfx::RectF(rect), |
| force_anti_aliasing_off); |
| |
| gfx::Transform green_quad_to_target_transform; |
| SharedQuadState* green_shared_state = CreateTestSharedQuadState( |
| green_quad_to_target_transform, rect, root_pass.get()); |
| |
| SolidColorDrawQuad* green = |
| root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("force_anti_aliasing_off.png")), |
| cc::ExactPixelComparator(false))); |
| } |
| |
| // This test tests that forcing anti-aliasing off works as expected for |
| // tile draw quads. |
| // Anti-aliasing is only supported in the gl renderer. |
| TEST_F(GLRendererPixelTest, TileDrawQuadForceAntiAliasingOff) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| SkBitmap bitmap; |
| bitmap.allocN32Pixels(32, 32); |
| SkCanvas canvas(bitmap); |
| canvas.clear(SK_ColorTRANSPARENT); |
| |
| gfx::Size tile_size(32, 32); |
| ResourceId resource; |
| if (this->use_gpu()) { |
| resource = CreateGpuResource( |
| this->child_context_provider_, this->child_resource_provider_.get(), |
| tile_size, RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); |
| } else { |
| resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap); |
| } |
| |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| {resource}, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| ResourceId mapped_resource = resource_map[resource]; |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, rect, transform_to_root); |
| |
| bool swizzle_contents = true; |
| bool contents_premultiplied = true; |
| bool needs_blending = false; |
| bool nearest_neighbor = true; |
| bool force_anti_aliasing_off = true; |
| gfx::Transform hole_quad_to_target_transform; |
| hole_quad_to_target_transform.Translate(50, 50); |
| hole_quad_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f), |
| 0.5f + 1.0f / (rect.height() * 2.0f)); |
| SharedQuadState* hole_shared_state = CreateTestSharedQuadState( |
| hole_quad_to_target_transform, rect, pass.get()); |
| TileDrawQuad* hole = pass->CreateAndAppendDrawQuad<TileDrawQuad>(); |
| hole->SetNew(hole_shared_state, rect, rect, needs_blending, mapped_resource, |
| gfx::RectF(gfx::Rect(tile_size)), tile_size, swizzle_contents, |
| contents_premultiplied, nearest_neighbor, |
| force_anti_aliasing_off); |
| |
| gfx::Transform green_quad_to_target_transform; |
| SharedQuadState* green_shared_state = CreateTestSharedQuadState( |
| green_quad_to_target_transform, rect, pass.get()); |
| |
| SolidColorDrawQuad* green = |
| pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("force_anti_aliasing_off.png")), |
| cc::ExactPixelComparator(false))); |
| } |
| |
| TEST_F(GLRendererPixelTest, AntiAliasingPerspective) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(1, rect); |
| |
| gfx::Rect red_rect(0, 0, 180, 500); |
| gfx::Transform red_quad_to_target_transform( |
| 1.0f, 2.4520f, 10.6206f, 19.0f, 0.0f, 0.3528f, 5.9737f, 9.5f, 0.0f, |
| -0.2250f, -0.9744f, 0.0f, 0.0f, 0.0225f, 0.0974f, 1.0f); |
| SharedQuadState* red_shared_state = CreateTestSharedQuadState( |
| red_quad_to_target_transform, red_rect, pass.get()); |
| auto* red = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| red->SetNew(red_shared_state, red_rect, red_rect, SK_ColorRED, false); |
| |
| gfx::Rect green_rect(19, 7, 180, 10); |
| SharedQuadState* green_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), green_rect, pass.get()); |
| auto* green = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| green->SetNew(green_shared_state, green_rect, green_rect, SK_ColorGREEN, |
| false); |
| |
| SharedQuadState* blue_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("anti_aliasing_perspective.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| // Trilinear filtering is only supported in the gl renderer. |
| // TODO(reveman): Enable test after updating osmesa to a version where |
| // GL_LINEAR_MIPMAP_LINEAR works correctly. --use-gpu-in-tests can be |
| // used to verify that trilinear filtering works until then. |
| TEST_F(GLRendererPixelTest, DISABLED_TrilinearFiltering) { |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| root_pass->has_transparent_background = false; |
| |
| int child_pass_id = 2; |
| gfx::Transform transform_to_root; |
| gfx::Rect child_pass_rect( |
| ScaleToCeiledSize(this->device_viewport_size_, 4.0f)); |
| bool generate_mipmap = true; |
| std::unique_ptr<RenderPass> child_pass = RenderPass::Create(); |
| child_pass->SetAll(child_pass_id, child_pass_rect, child_pass_rect, |
| transform_to_root, cc::FilterOperations(), |
| cc::FilterOperations(), gfx::ColorSpace::CreateSRGB(), |
| false, false, false, generate_mipmap); |
| |
| gfx::Rect red_rect(child_pass_rect); |
| // Small enough red rect that linear filtering will miss it but large enough |
| // that it makes a meaningful contribution when using trilinear filtering. |
| red_rect.ClampToCenteredSize(gfx::Size(2, child_pass_rect.height())); |
| SharedQuadState* red_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), red_rect, child_pass.get()); |
| auto* red = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| red->SetNew(red_shared_state, red_rect, red_rect, SK_ColorRED, false); |
| |
| SharedQuadState* blue_shared_state = CreateTestSharedQuadState( |
| gfx::Transform(), child_pass_rect, child_pass.get()); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(blue_shared_state, child_pass_rect, child_pass_rect, |
| SK_ColorBLUE, false); |
| |
| gfx::Transform child_to_root_transform(SkMatrix::MakeRectToRect( |
| RectToSkRect(child_pass_rect), RectToSkRect(viewport_rect), |
| SkMatrix::kFill_ScaleToFit)); |
| SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState( |
| child_to_root_transform, child_pass_rect, root_pass.get()); |
| auto* child_pass_quad = |
| root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); |
| child_pass_quad->SetNew(child_pass_shared_state, child_pass_rect, |
| child_pass_rect, child_pass_id, 0, gfx::RectF(), |
| gfx::Size(), gfx::Vector2dF(), gfx::PointF(), |
| gfx::RectF(child_pass_rect), false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("trilinear_filtering.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadIdentityScale) { |
| gfx::Rect viewport(this->device_viewport_size_); |
| // TODO(enne): the renderer should figure this out on its own. |
| ResourceFormat texture_format = RGBA_8888; |
| bool nearest_neighbor = false; |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_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)); |
| |
| std::unique_ptr<cc::FakeRecordingSource> blue_recording = |
| cc::FakeRecordingSource::CreateFilledRecordingSource(blue_rect.size()); |
| cc::PaintFlags red_flags; |
| red_flags.setColor(SK_ColorRED); |
| blue_recording->add_draw_rect_with_flags(blue_rect, red_flags); |
| cc::PaintFlags blue_flags; |
| blue_flags.setColor(SK_ColorBLUE); |
| blue_recording->add_draw_rect_with_flags(blue_clip_rect, blue_flags); |
| blue_recording->Rerecord(); |
| |
| scoped_refptr<cc::RasterSource> blue_raster_source = |
| blue_recording->CreateRasterSource(); |
| |
| gfx::Vector2d offset(viewport.bottom_right() - blue_rect.bottom_right()); |
| bool needs_blending = true; |
| gfx::Transform blue_quad_to_target_transform; |
| blue_quad_to_target_transform.Translate(offset.x(), offset.y()); |
| gfx::Rect blue_target_clip_rect = cc::MathUtil::MapEnclosingClippedRect( |
| blue_quad_to_target_transform, blue_clip_rect); |
| SharedQuadState* blue_shared_state = |
| CreateTestSharedQuadStateClipped(blue_quad_to_target_transform, blue_rect, |
| blue_target_clip_rect, pass.get()); |
| |
| auto* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| |
| blue_quad->SetNew(blue_shared_state, |
| viewport, // Intentionally bigger than clip. |
| viewport, needs_blending, gfx::RectF(viewport), |
| viewport.size(), nearest_neighbor, texture_format, viewport, |
| 1.f, {}, blue_raster_source->GetDisplayItemList()); |
| |
| // One viewport-filling green quad. |
| std::unique_ptr<cc::FakeRecordingSource> green_recording = |
| cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); |
| cc::PaintFlags green_flags; |
| green_flags.setColor(SK_ColorGREEN); |
| green_recording->add_draw_rect_with_flags(viewport, green_flags); |
| green_recording->Rerecord(); |
| scoped_refptr<cc::RasterSource> green_raster_source = |
| green_recording->CreateRasterSource(); |
| |
| gfx::Transform green_quad_to_target_transform; |
| SharedQuadState* green_shared_state = CreateTestSharedQuadState( |
| green_quad_to_target_transform, viewport, pass.get()); |
| |
| auto* green_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| green_quad->SetNew(green_shared_state, viewport, viewport, needs_blending, |
| gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(), |
| nearest_neighbor, texture_format, viewport, 1.f, {}, |
| green_raster_source->GetDisplayItemList()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| // Not WithSkiaGPUBackend since that path currently requires tiles for opacity. |
| TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadOpacity) { |
| gfx::Rect viewport(this->device_viewport_size_); |
| bool needs_blending = true; |
| ResourceFormat texture_format = RGBA_8888; |
| bool nearest_neighbor = false; |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, viewport, transform_to_root); |
| |
| // One viewport-filling 0.5-opacity green quad. |
| std::unique_ptr<cc::FakeRecordingSource> green_recording = |
| cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); |
| cc::PaintFlags green_flags; |
| green_flags.setColor(SK_ColorGREEN); |
| green_recording->add_draw_rect_with_flags(viewport, green_flags); |
| green_recording->Rerecord(); |
| scoped_refptr<cc::RasterSource> green_raster_source = |
| green_recording->CreateRasterSource(); |
| |
| gfx::Transform green_quad_to_target_transform; |
| SharedQuadState* green_shared_state = CreateTestSharedQuadState( |
| green_quad_to_target_transform, viewport, pass.get()); |
| green_shared_state->opacity = 0.5f; |
| |
| auto* green_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| green_quad->SetNew(green_shared_state, viewport, viewport, needs_blending, |
| gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor, |
| texture_format, viewport, 1.f, {}, |
| green_raster_source->GetDisplayItemList()); |
| |
| // One viewport-filling white quad. |
| std::unique_ptr<cc::FakeRecordingSource> white_recording = |
| cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); |
| cc::PaintFlags white_flags; |
| white_flags.setColor(SK_ColorWHITE); |
| white_recording->add_draw_rect_with_flags(viewport, white_flags); |
| white_recording->Rerecord(); |
| scoped_refptr<cc::RasterSource> white_raster_source = |
| white_recording->CreateRasterSource(); |
| |
| gfx::Transform white_quad_to_target_transform; |
| SharedQuadState* white_shared_state = CreateTestSharedQuadState( |
| white_quad_to_target_transform, viewport, pass.get()); |
| |
| auto* white_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| white_quad->SetNew(white_shared_state, viewport, viewport, needs_blending, |
| gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor, |
| texture_format, viewport, 1.f, {}, |
| white_raster_source->GetDisplayItemList()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("green_alpha.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| template <typename TypeParam> |
| bool IsSoftwareRenderer() { |
| return false; |
| } |
| |
| template <> |
| bool IsSoftwareRenderer<SoftwareRenderer>() { |
| return true; |
| } |
| |
| template <> |
| bool IsSoftwareRenderer<cc::SoftwareRendererWithExpandedViewport>() { |
| return true; |
| } |
| |
| void draw_point_color(SkCanvas* canvas, SkScalar x, SkScalar y, SkColor color) { |
| SkPaint paint; |
| paint.setColor(color); |
| canvas->drawPoint(x, y, paint); |
| } |
| |
| // If we disable image filtering, then a 2x2 bitmap should appear as four |
| // huge sharp squares. |
| TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadDisableImageFiltering) { |
| // We only care about this in software mode since bilinear filtering is |
| // cheap in hardware. |
| if (!IsSoftwareRenderer<TypeParam>()) |
| return; |
| |
| gfx::Rect viewport(this->device_viewport_size_); |
| ResourceFormat texture_format = RGBA_8888; |
| bool needs_blending = true; |
| bool nearest_neighbor = false; |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, viewport, transform_to_root); |
| |
| sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(2, 2); |
| ASSERT_NE(surface, nullptr); |
| SkCanvas* canvas = surface->getCanvas(); |
| draw_point_color(canvas, 0, 0, SK_ColorGREEN); |
| draw_point_color(canvas, 0, 1, SK_ColorBLUE); |
| draw_point_color(canvas, 1, 0, SK_ColorBLUE); |
| draw_point_color(canvas, 1, 1, SK_ColorGREEN); |
| |
| std::unique_ptr<cc::FakeRecordingSource> recording = |
| cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); |
| cc::PaintFlags flags; |
| flags.setFilterQuality(kLow_SkFilterQuality); |
| recording->add_draw_image_with_flags(surface->makeImageSnapshot(), |
| gfx::Point(), flags); |
| recording->Rerecord(); |
| scoped_refptr<cc::RasterSource> raster_source = |
| recording->CreateRasterSource(); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(quad_to_target_transform, viewport, pass.get()); |
| |
| auto* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| quad->SetNew(shared_state, viewport, viewport, needs_blending, |
| gfx::RectF(0, 0, 2, 2), viewport.size(), nearest_neighbor, |
| texture_format, viewport, 1.f, {}, |
| raster_source->GetDisplayItemList()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| this->disable_picture_quad_image_filtering_ = true; |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| // This disables filtering by setting |nearest_neighbor| on the |
| // PictureDrawQuad. |
| TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNearestNeighbor) { |
| gfx::Rect viewport(this->device_viewport_size_); |
| ResourceFormat texture_format = RGBA_8888; |
| bool needs_blending = true; |
| bool nearest_neighbor = true; |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, viewport, transform_to_root); |
| |
| sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(2, 2); |
| ASSERT_NE(surface, nullptr); |
| SkCanvas* canvas = surface->getCanvas(); |
| draw_point_color(canvas, 0, 0, SK_ColorGREEN); |
| draw_point_color(canvas, 0, 1, SK_ColorBLUE); |
| draw_point_color(canvas, 1, 0, SK_ColorBLUE); |
| draw_point_color(canvas, 1, 1, SK_ColorGREEN); |
| |
| std::unique_ptr<cc::FakeRecordingSource> recording = |
| cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); |
| cc::PaintFlags flags; |
| flags.setFilterQuality(kLow_SkFilterQuality); |
| recording->add_draw_image_with_flags(surface->makeImageSnapshot(), |
| gfx::Point(), flags); |
| recording->Rerecord(); |
| scoped_refptr<cc::RasterSource> raster_source = |
| recording->CreateRasterSource(); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(quad_to_target_transform, viewport, pass.get()); |
| |
| auto* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| quad->SetNew(shared_state, viewport, viewport, needs_blending, |
| gfx::RectF(0, 0, 2, 2), viewport.size(), nearest_neighbor, |
| texture_format, viewport, 1.f, {}, |
| raster_source->GetDisplayItemList()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| // This disables filtering by setting |nearest_neighbor| on the |
| // TileDrawQuad. |
| TYPED_TEST(NonSkiaRendererPixelTest, TileDrawQuadNearestNeighbor) { |
| gfx::Rect viewport(this->device_viewport_size_); |
| bool swizzle_contents = true; |
| bool contents_premultiplied = true; |
| bool needs_blending = true; |
| bool nearest_neighbor = true; |
| bool force_anti_aliasing_off = false; |
| |
| SkBitmap bitmap; |
| bitmap.allocN32Pixels(2, 2); |
| SkCanvas canvas(bitmap); |
| draw_point_color(&canvas, 0, 0, SK_ColorGREEN); |
| draw_point_color(&canvas, 0, 1, SK_ColorBLUE); |
| draw_point_color(&canvas, 1, 0, SK_ColorBLUE); |
| draw_point_color(&canvas, 1, 1, SK_ColorGREEN); |
| |
| gfx::Size tile_size(2, 2); |
| ResourceId resource; |
| if (this->use_gpu()) { |
| resource = CreateGpuResource( |
| this->child_context_provider_, this->child_resource_provider_.get(), |
| tile_size, RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); |
| } else { |
| resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap); |
| } |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| {resource}, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| ResourceId mapped_resource = resource_map[resource]; |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, viewport, transform_to_root); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(quad_to_target_transform, viewport, pass.get()); |
| |
| auto* quad = pass->CreateAndAppendDrawQuad<TileDrawQuad>(); |
| quad->SetNew(shared_state, viewport, viewport, needs_blending, |
| mapped_resource, gfx::RectF(gfx::Rect(tile_size)), tile_size, |
| swizzle_contents, contents_premultiplied, nearest_neighbor, |
| force_anti_aliasing_off); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| // This disables filtering by setting |nearest_neighbor| to true on the |
| // TextureDrawQuad. |
| TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadNearestNeighbor) { |
| gfx::Rect viewport(this->device_viewport_size_); |
| bool needs_blending = true; |
| bool nearest_neighbor = true; |
| |
| SkBitmap bitmap; |
| bitmap.allocN32Pixels(2, 2); |
| SkCanvas canvas(bitmap); |
| draw_point_color(&canvas, 0, 0, SK_ColorGREEN); |
| draw_point_color(&canvas, 0, 1, SK_ColorBLUE); |
| draw_point_color(&canvas, 1, 0, SK_ColorBLUE); |
| draw_point_color(&canvas, 1, 1, SK_ColorGREEN); |
| |
| gfx::Size tile_size(2, 2); |
| ResourceId resource = |
| this->AllocateAndFillSoftwareResource(tile_size, bitmap); |
| |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| {resource}, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| ResourceId mapped_resource = resource_map[resource]; |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, viewport, transform_to_root); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(quad_to_target_transform, viewport, pass.get()); |
| |
| float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| auto* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); |
| quad->SetNew(shared_state, viewport, viewport, needs_blending, |
| mapped_resource, false, gfx::PointF(0, 0), gfx::PointF(1, 1), |
| SK_ColorBLACK, vertex_opacity, false, nearest_neighbor, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), |
| cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f))); |
| } |
| |
| // This ensures filtering is enabled by setting |nearest_neighbor| to false on |
| // the TextureDrawQuad. |
| TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadLinear) { |
| gfx::Rect viewport(this->device_viewport_size_); |
| bool needs_blending = true; |
| bool nearest_neighbor = false; |
| |
| SkBitmap bitmap; |
| bitmap.allocN32Pixels(2, 2); |
| { |
| SkCanvas canvas(bitmap); |
| draw_point_color(&canvas, 0, 0, SK_ColorGREEN); |
| draw_point_color(&canvas, 0, 1, SK_ColorBLUE); |
| draw_point_color(&canvas, 1, 0, SK_ColorBLUE); |
| draw_point_color(&canvas, 1, 1, SK_ColorGREEN); |
| } |
| |
| gfx::Size tile_size(2, 2); |
| ResourceId resource = |
| this->AllocateAndFillSoftwareResource(tile_size, bitmap); |
| |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| {resource}, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| ResourceId mapped_resource = resource_map[resource]; |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, viewport, transform_to_root); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(quad_to_target_transform, viewport, pass.get()); |
| |
| float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| auto* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); |
| quad->SetNew(shared_state, viewport, viewport, needs_blending, |
| mapped_resource, false, gfx::PointF(0, 0), gfx::PointF(1, 1), |
| SK_ColorBLACK, vertex_opacity, false, nearest_neighbor, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Allow for a small amount of error as the blending alogrithm used by Skia is |
| // affected by the offset in the expanded rect. |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers_linear.png")), |
| cc::FuzzyPixelComparator(false, 100.f, 0.f, 16.f, 16.f, 0.f))); |
| } |
| |
| TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNonIdentityScale) { |
| gfx::Rect viewport(this->device_viewport_size_); |
| // TODO(enne): the renderer should figure this out on its own. |
| ResourceFormat texture_format = RGBA_8888; |
| bool needs_blending = true; |
| bool nearest_neighbor = false; |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_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_quad_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)); |
| |
| std::unique_ptr<cc::FakeRecordingSource> green_recording = |
| cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); |
| |
| cc::PaintFlags red_flags; |
| red_flags.setColor(SK_ColorRED); |
| green_recording->add_draw_rect_with_flags(viewport, red_flags); |
| cc::PaintFlags green_flags; |
| green_flags.setColor(SK_ColorGREEN); |
| green_recording->add_draw_rect_with_flags(green_rect1, green_flags); |
| green_recording->add_draw_rect_with_flags(green_rect2, green_flags); |
| green_recording->Rerecord(); |
| scoped_refptr<cc::RasterSource> green_raster_source = |
| green_recording->CreateRasterSource(); |
| |
| SharedQuadState* top_right_green_shared_quad_state = |
| CreateTestSharedQuadState(green_quad_to_target_transform, viewport, |
| pass.get()); |
| |
| auto* green_quad1 = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| green_quad1->SetNew( |
| top_right_green_shared_quad_state, green_rect1, green_rect1, |
| needs_blending, gfx::RectF(gfx::SizeF(green_rect1.size())), |
| green_rect1.size(), nearest_neighbor, texture_format, green_rect1, 1.f, |
| {}, green_raster_source->GetDisplayItemList()); |
| |
| auto* green_quad2 = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| green_quad2->SetNew( |
| top_right_green_shared_quad_state, green_rect2, green_rect2, |
| needs_blending, gfx::RectF(gfx::SizeF(green_rect2.size())), |
| green_rect2.size(), nearest_neighbor, texture_format, green_rect2, 1.f, |
| {}, green_raster_source->GetDisplayItemList()); |
| |
| // 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)); |
| SharedQuadState* bottom_right_green_shared_state = |
| CreateTestSharedQuadStateClipped(green_quad_to_target_transform, viewport, |
| bottom_right_rect, pass.get()); |
| auto* bottom_right_color_quad = |
| pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| bottom_right_color_quad->SetNew(bottom_right_green_shared_state, viewport, |
| viewport, SK_ColorGREEN, false); |
| |
| // 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); |
| |
| std::unique_ptr<cc::FakeRecordingSource> recording = |
| cc::FakeRecordingSource::CreateFilledRecordingSource(layer_rect.size()); |
| |
| cc::Region outside(layer_rect); |
| outside.Subtract(gfx::ToEnclosingRect(union_layer_rect)); |
| for (gfx::Rect rect : outside) { |
| recording->add_draw_rect_with_flags(rect, red_flags); |
| } |
| |
| cc::PaintFlags blue_flags; |
| blue_flags.setColor(SK_ColorBLUE); |
| recording->add_draw_rectf_with_flags(blue_layer_rect1, blue_flags); |
| recording->add_draw_rectf_with_flags(blue_layer_rect2, blue_flags); |
| recording->Rerecord(); |
| scoped_refptr<cc::RasterSource> raster_source = |
| recording->CreateRasterSource(); |
| |
| 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 quad_to_target_transform; |
| quad_to_target_transform.Scale(10.0, 10.0); |
| gfx::Rect quad_content_rect(gfx::Size(20, 20)); |
| SharedQuadState* blue_shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, quad_content_rect, pass.get()); |
| |
| auto* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); |
| blue_quad->SetNew(blue_shared_state, quad_content_rect, quad_content_rect, |
| needs_blending, gfx::RectF(quad_content_rect), |
| content_union_rect.size(), nearest_neighbor, texture_format, |
| content_union_rect, contents_scale, {}, |
| raster_source->GetDisplayItemList()); |
| |
| // Fill left half of viewport with green. |
| gfx::Transform half_green_quad_to_target_transform; |
| gfx::Rect half_green_rect(gfx::Size(viewport.width() / 2, viewport.height())); |
| SharedQuadState* half_green_shared_state = CreateTestSharedQuadState( |
| half_green_quad_to_target_transform, half_green_rect, pass.get()); |
| auto* half_color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| half_color_quad->SetNew(half_green_shared_state, half_green_rect, |
| half_green_rect, SK_ColorGREEN, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| using GLRendererPixelTestWithFlippedOutputSurface = |
| RendererPixelTest<cc::GLRendererWithFlippedSurface>; |
| |
| TEST_F(GLRendererPixelTestWithFlippedOutputSurface, ExplicitFlipTest) { |
| // This draws a blue rect above a yellow rect with an inverted output surface. |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| |
| int child_pass_id = 2; |
| gfx::Rect pass_rect(this->device_viewport_size_); |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| |
| gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false); |
| gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2, |
| this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get()); |
| CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id, |
| root_pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| // Note: RunPixelTest() will issue a CopyOutputRequest on the root pass. The |
| // implementation should realize the output surface is flipped, and return a |
| // right-side up result regardless (i.e., NOT blue_yellow_flipped.png). |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| TEST_F(GLRendererPixelTestWithFlippedOutputSurface, CheckChildPassUnflipped) { |
| // This draws a blue rect above a yellow rect with an inverted output surface. |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| |
| int child_pass_id = 2; |
| gfx::Rect pass_rect(this->device_viewport_size_); |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| |
| gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false); |
| gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2, |
| this->device_viewport_size_.width(), |
| this->device_viewport_size_.height() / 2); |
| auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get()); |
| CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id, |
| root_pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| // Check that the child pass remains unflipped. |
| EXPECT_TRUE(this->RunPixelTestWithReadbackTarget( |
| &pass_list, pass_list.front().get(), |
| base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| TEST_F(GLRendererPixelTest, CheckReadbackSubset) { |
| gfx::Rect viewport_rect(this->device_viewport_size_); |
| |
| int root_pass_id = 1; |
| std::unique_ptr<RenderPass> root_pass = |
| CreateTestRootRenderPass(root_pass_id, viewport_rect); |
| |
| int child_pass_id = 2; |
| gfx::Rect pass_rect(this->device_viewport_size_); |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> child_pass = |
| CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); |
| |
| gfx::Transform quad_to_target_transform; |
| SharedQuadState* shared_state = CreateTestSharedQuadState( |
| quad_to_target_transform, viewport_rect, child_pass.get()); |
| |
| // Draw a green quad full-size with a blue quad in the lower-right corner. |
| gfx::Rect blue_rect(this->device_viewport_size_.width() * 3 / 4, |
| this->device_viewport_size_.height() * 3 / 4, |
| this->device_viewport_size_.width() * 3 / 4, |
| this->device_viewport_size_.height() * 3 / 4); |
| auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false); |
| gfx::Rect green_rect(0, 0, this->device_viewport_size_.width(), |
| this->device_viewport_size_.height()); |
| auto* green = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| green->SetNew(shared_state, green_rect, green_rect, SK_ColorGREEN, false); |
| |
| SharedQuadState* pass_shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get()); |
| CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id, |
| root_pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(child_pass)); |
| pass_list.push_back(std::move(root_pass)); |
| |
| // Check that the child pass remains unflipped. |
| gfx::Rect capture_rect(this->device_viewport_size_.width() / 2, |
| this->device_viewport_size_.height() / 2, |
| this->device_viewport_size_.width() / 2, |
| this->device_viewport_size_.height() / 2); |
| EXPECT_TRUE(this->RunPixelTestWithReadbackTargetAndArea( |
| &pass_list, pass_list.front().get(), |
| base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")), |
| cc::ExactPixelComparator(true), &capture_rect)); |
| } |
| |
| TEST_F(GLRendererPixelTest, TextureQuadBatching) { |
| // This test verifies that multiple texture quads using the same resource |
| // get drawn correctly. It implicitly is trying to test that the |
| // GLRenderer does the right thing with its draw quad cache. |
| |
| gfx::Rect rect(this->device_viewport_size_); |
| bool needs_blending = false; |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| // Make a mask. |
| gfx::Rect mask_rect = rect; |
| SkBitmap bitmap; |
| bitmap.allocPixels( |
| SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height())); |
| SkCanvas canvas(bitmap); |
| SkPaint paint; |
| paint.setStyle(SkPaint::kStroke_Style); |
| paint.setStrokeWidth(SkIntToScalar(4)); |
| paint.setColor(SK_ColorGREEN); |
| canvas.clear(SK_ColorWHITE); |
| gfx::Rect inset_rect = rect; |
| while (!inset_rect.IsEmpty()) { |
| inset_rect.Inset(6, 6, 4, 4); |
| canvas.drawRect(SkRect::MakeXYWH(inset_rect.x(), inset_rect.y(), |
| inset_rect.width(), inset_rect.height()), |
| paint); |
| inset_rect.Inset(6, 6, 4, 4); |
| } |
| |
| ResourceId resource = CreateGpuResource( |
| this->child_context_provider_, this->child_resource_provider_.get(), |
| mask_rect.size(), RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); |
| |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| {resource}, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| ResourceId mapped_resource = resource_map[resource]; |
| |
| // Arbitrary dividing lengths to divide up the resource into 16 quads. |
| int widths[] = { |
| 0, 60, 50, 40, |
| }; |
| int heights[] = { |
| 0, 10, 80, 50, |
| }; |
| size_t num_quads = 4; |
| for (size_t i = 0; i < num_quads; ++i) { |
| int x_start = widths[i]; |
| int x_end = i == num_quads - 1 ? rect.width() : widths[i + 1]; |
| DCHECK_LE(x_end, rect.width()); |
| for (size_t j = 0; j < num_quads; ++j) { |
| int y_start = heights[j]; |
| int y_end = j == num_quads - 1 ? rect.height() : heights[j + 1]; |
| DCHECK_LE(y_end, rect.height()); |
| |
| float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| gfx::Rect layer_rect(x_start, y_start, x_end - x_start, y_end - y_start); |
| gfx::RectF uv_rect = gfx::ScaleRect( |
| gfx::RectF(layer_rect), 1.f / rect.width(), 1.f / rect.height()); |
| |
| auto* texture_quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); |
| texture_quad->SetNew(shared_state, layer_rect, layer_rect, needs_blending, |
| mapped_resource, true, uv_rect.origin(), |
| uv_rect.bottom_right(), SK_ColorWHITE, |
| vertex_opacity, false, false, false); |
| } |
| } |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, base::FilePath(FILE_PATH_LITERAL("spiral.png")), |
| cc::FuzzyPixelOffByOneComparator(true))); |
| } |
| |
| TEST_F(GLRendererPixelTest, TileQuadClamping) { |
| gfx::Rect viewport(this->device_viewport_size_); |
| bool swizzle_contents = true; |
| bool contents_premultiplied = true; |
| bool needs_blending = true; |
| bool nearest_neighbor = false; |
| bool use_aa = false; |
| |
| gfx::Size layer_size(4, 4); |
| gfx::Size tile_size(20, 20); |
| gfx::Rect quad_rect(layer_size); |
| gfx::RectF tex_coord_rect(quad_rect); |
| |
| // tile sized bitmap, with valid contents green and contents outside the |
| // layer rect red. |
| SkBitmap bitmap; |
| bitmap.allocN32Pixels(tile_size.width(), tile_size.height()); |
| SkCanvas canvas(bitmap); |
| SkPaint red; |
| red.setColor(SK_ColorRED); |
| canvas.drawRect(SkRect::MakeWH(tile_size.width(), tile_size.height()), red); |
| SkPaint green; |
| green.setColor(SK_ColorGREEN); |
| canvas.drawRect(SkRect::MakeWH(layer_size.width(), layer_size.height()), |
| green); |
| |
| ResourceId resource; |
| if (this->use_gpu()) { |
| resource = CreateGpuResource( |
| this->child_context_provider_, this->child_resource_provider_.get(), |
| tile_size, RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); |
| } else { |
| resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap); |
| } |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| {resource}, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| ResourceId mapped_resource = resource_map[resource]; |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, viewport, transform_to_root); |
| |
| // Green quad that should not show any red pixels from outside the |
| // tex coord rect. |
| gfx::Transform transform; |
| transform.Scale(40, 40); |
| SharedQuadState* quad_shared = |
| CreateTestSharedQuadState(transform, gfx::Rect(layer_size), pass.get()); |
| auto* quad = pass->CreateAndAppendDrawQuad<TileDrawQuad>(); |
| quad->SetNew(quad_shared, gfx::Rect(layer_size), gfx::Rect(layer_size), |
| needs_blending, mapped_resource, tex_coord_rect, tile_size, |
| swizzle_contents, contents_premultiplied, nearest_neighbor, |
| use_aa); |
| |
| // Green background. |
| SharedQuadState* background_shared = |
| CreateTestSharedQuadState(gfx::Transform(), viewport, pass.get()); |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(background_shared, viewport, viewport, SK_ColorGREEN, |
| false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest(&pass_list, |
| base::FilePath(FILE_PATH_LITERAL("green.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| class GLRendererPixelTestWithOverdrawFeedback : public GLRendererPixelTest { |
| protected: |
| void SetUp() override { |
| renderer_settings_.show_overdraw_feedback = true; |
| GLRendererPixelTest::SetUp(); |
| } |
| }; |
| |
| TEST_F(GLRendererPixelTestWithOverdrawFeedback, TranslucentRectangles) { |
| gfx::Rect rect(this->device_viewport_size_); |
| |
| int id = 1; |
| gfx::Transform transform_to_root; |
| std::unique_ptr<RenderPass> pass = |
| CreateTestRenderPass(id, rect, transform_to_root); |
| |
| gfx::Transform dark_gray_quad_to_target_transform; |
| dark_gray_quad_to_target_transform.Translate(50, 50); |
| dark_gray_quad_to_target_transform.Scale( |
| 0.5f + 1.0f / (rect.width() * 2.0f), |
| 0.5f + 1.0f / (rect.height() * 2.0f)); |
| SharedQuadState* dark_gray_shared_state = CreateTestSharedQuadState( |
| dark_gray_quad_to_target_transform, rect, pass.get()); |
| |
| auto* dark_gray = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| dark_gray->SetNew(dark_gray_shared_state, rect, rect, 0x10444444, false); |
| |
| gfx::Transform light_gray_quad_to_target_transform; |
| light_gray_quad_to_target_transform.Translate(25.5f, 25.5f); |
| light_gray_quad_to_target_transform.Scale(0.5f, 0.5f); |
| SharedQuadState* light_gray_shared_state = CreateTestSharedQuadState( |
| light_gray_quad_to_target_transform, rect, pass.get()); |
| |
| auto* light_gray = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| light_gray->SetNew(light_gray_shared_state, rect, rect, 0x10CCCCCC, false); |
| |
| gfx::Transform bg_quad_to_target_transform; |
| SharedQuadState* bg_shared_state = |
| CreateTestSharedQuadState(bg_quad_to_target_transform, rect, pass.get()); |
| |
| auto* bg = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| bg->SetNew(bg_shared_state, rect, rect, SK_ColorBLACK, false); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| EXPECT_TRUE(this->RunPixelTest( |
| &pass_list, |
| base::FilePath(FILE_PATH_LITERAL("translucent_rectangles.png")), |
| cc::ExactPixelComparator(true))); |
| } |
| |
| using ColorSpacePair = std::tuple<gfx::ColorSpace, gfx::ColorSpace, bool>; |
| |
| class ColorTransformPixelTest |
| : public GLRendererPixelTest, |
| public testing::WithParamInterface<ColorSpacePair> { |
| public: |
| ColorTransformPixelTest() { |
| // Note that this size of 17 is not random -- it is chosen to match the |
| // size of LUTs that are created. If we did not match the LUT size exactly, |
| // then the error for LUT based transforms is much larger. |
| device_viewport_size_ = gfx::Size(17, 5); |
| src_color_space_ = std::get<0>(GetParam()); |
| dst_color_space_ = std::get<1>(GetParam()); |
| if (!src_color_space_.IsValid()) { |
| src_color_space_ = |
| gfx::ICCProfileForTestingNoAnalyticTrFn().GetColorSpace(); |
| } |
| if (!dst_color_space_.IsValid()) { |
| dst_color_space_ = |
| gfx::ICCProfileForTestingNoAnalyticTrFn().GetColorSpace(); |
| } |
| premultiplied_alpha_ = std::get<2>(GetParam()); |
| } |
| gfx::ColorSpace src_color_space_; |
| gfx::ColorSpace dst_color_space_; |
| bool premultiplied_alpha_ = false; |
| }; |
| |
| TEST_P(ColorTransformPixelTest, Basic) { |
| gfx::Rect rect(this->device_viewport_size_); |
| std::vector<uint8_t> input_colors(4 * rect.width() * rect.height(), 0); |
| std::vector<SkColor> expected_output_colors(rect.width() * rect.height()); |
| |
| // Set the input data to be: |
| // Row 0: Gradient of red from 0 to 255 |
| // Row 1: Gradient of green from 0 to 255 |
| // Row 2: Gradient of blue from 0 to 255 |
| // Row 3: Gradient of grey from 0 to 255 |
| // Row 4: Gradient of alpha from 0 to 255 with mixed colors. |
| for (int x = 0; x < rect.width(); ++x) { |
| int gradient_value = (x * 255) / (rect.width() - 1); |
| for (int y = 0; y < rect.height(); ++y) { |
| uint8_t* pixel = &input_colors[4 * (x + rect.width() * y)]; |
| pixel[3] = 255; |
| if (y < 3) { |
| pixel[y] = gradient_value; |
| } else if (y == 3) { |
| pixel[0] = pixel[1] = pixel[2] = gradient_value; |
| } else { |
| if (premultiplied_alpha_) { |
| pixel[x % 3] = gradient_value; |
| pixel[3] = gradient_value; |
| } else { |
| pixel[x % 3] = 0xFF; |
| pixel[3] = gradient_value; |
| } |
| } |
| } |
| } |
| |
| std::unique_ptr<gfx::ColorTransform> transform = |
| gfx::ColorTransform::NewColorTransform( |
| src_color_space_, dst_color_space_, |
| gfx::ColorTransform::Intent::INTENT_PERCEPTUAL); |
| |
| for (size_t i = 0; i < expected_output_colors.size(); ++i) { |
| gfx::ColorTransform::TriStim color; |
| color.set_x(input_colors[4 * i + 0] / 255.f); |
| color.set_y(input_colors[4 * i + 1] / 255.f); |
| color.set_z(input_colors[4 * i + 2] / 255.f); |
| float alpha = input_colors[4 * i + 3] / 255.f; |
| if (premultiplied_alpha_ && alpha > 0.0) { |
| color.Scale(1.0f / alpha); |
| } |
| transform->Transform(&color, 1); |
| color.Scale(alpha); |
| color.set_x(std::min(std::max(0.f, color.x()), 1.f)); |
| color.set_y(std::min(std::max(0.f, color.y()), 1.f)); |
| color.set_z(std::min(std::max(0.f, color.z()), 1.f)); |
| expected_output_colors[i] = |
| SkColorSetARGB(255, static_cast<size_t>(255.f * color.x() + 0.5f), |
| static_cast<size_t>(255.f * color.y() + 0.5f), |
| static_cast<size_t>(255.f * color.z() + 0.5f)); |
| } |
| |
| int id = 1; |
| std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); |
| pass->color_space = dst_color_space_; |
| |
| // Append a quad to execute the transform. |
| { |
| SharedQuadState* shared_state = |
| CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); |
| |
| ResourceId resource = CreateGpuResource( |
| this->child_context_provider_, this->child_resource_provider_.get(), |
| rect.size(), RGBA_8888, src_color_space_, input_colors.data()); |
| |
| // Return the mapped resource id. |
| std::unordered_map<ResourceId, ResourceId> resource_map = |
| cc::SendResourceAndGetChildToParentMap( |
| {resource}, this->resource_provider_.get(), |
| this->child_resource_provider_.get(), |
| this->child_context_provider_.get()); |
| ResourceId mapped_resource = resource_map[resource]; |
| |
| bool needs_blending = true; |
| const gfx::PointF uv_top_left(0.0f, 0.0f); |
| const gfx::PointF uv_bottom_right(1.0f, 1.0f); |
| const bool flipped = false; |
| const bool nearest_neighbor = false; |
| auto* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); |
| |
| float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| quad->SetNew(shared_state, rect, rect, needs_blending, mapped_resource, |
| premultiplied_alpha_, uv_top_left, uv_bottom_right, |
| SK_ColorBLACK, vertex_opacity, flipped, nearest_neighbor, |
| false); |
| |
| auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false); |
| } |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Allow a difference of 2 bytes in comparison for shader-based transforms, |
| // and 4 bytes for LUT-based transforms (determined empirically). |
| cc::FuzzyPixelComparator comparator(false, 100.f, 0.f, 2.f, 2, 0); |
| if (!transform->CanGetShaderSource()) |
| comparator = cc::FuzzyPixelComparator(false, 100.f, 0.f, 6.f, 6, 0); |
| EXPECT_TRUE(RunPixelTest(&pass_list, &expected_output_colors, comparator)); |
| } |
| |
| using PrimaryID = gfx::ColorSpace::PrimaryID; |
| using TransferID = gfx::ColorSpace::TransferID; |
| using MatrixID = gfx::ColorSpace::MatrixID; |
| using RangeID = gfx::ColorSpace::RangeID; |
| |
| gfx::ColorSpace src_color_spaces[] = { |
| // This will be replaced by an ICC-based space (which can't be initialized |
| // here). |
| gfx::ColorSpace(), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::BT709), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::GAMMA22), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::GAMMA24), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::GAMMA28), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTE170M), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTE240M), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::LOG), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::LOG_SQRT), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_4), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::BT1361_ECG), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::BT2020_10), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::BT2020_12), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTEST2084), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTEST428_1), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::ARIB_STD_B67), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1_HDR), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR), |
| gfx::ColorSpace(PrimaryID::BT709, |
| TransferID::BT2020_10, |
| MatrixID::BT2020_CL, |
| RangeID::FULL), |
| }; |
| |
| gfx::ColorSpace dst_color_spaces[] = { |
| // This will be replaced by an ICC-based space (which can't be initialized |
| // here). |
| gfx::ColorSpace(), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::BT709), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::GAMMA22), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::GAMMA24), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::GAMMA28), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTE170M), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTE240M), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::LOG), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::LOG_SQRT), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_4), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::BT1361_ECG), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::BT2020_10), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::BT2020_12), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTEST2084), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::ARIB_STD_B67), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1_HDR), |
| gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR), |
| }; |
| |
| gfx::ColorSpace intermediate_color_spaces[] = { |
| gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::LINEAR), |
| gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::IEC61966_2_1_HDR), |
| }; |
| |
| bool color_space_premul_values[] = { |
| true, false, |
| }; |
| |
| INSTANTIATE_TEST_CASE_P( |
| FromColorSpace, |
| ColorTransformPixelTest, |
| testing::Combine(testing::ValuesIn(src_color_spaces), |
| testing::ValuesIn(intermediate_color_spaces), |
| testing::ValuesIn(color_space_premul_values))); |
| |
| INSTANTIATE_TEST_CASE_P( |
| ToColorSpace, |
| ColorTransformPixelTest, |
| testing::Combine(testing::ValuesIn(intermediate_color_spaces), |
| testing::ValuesIn(dst_color_spaces), |
| testing::ValuesIn(color_space_premul_values))); |
| |
| #endif // !defined(OS_ANDROID) |
| |
| } // namespace |
| } // namespace viz |