blob: 99a1ded4b990cab7d1028f6b7c3d40314688a5ee [file] [log] [blame]
// Copyright 2014 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 <utility>
#include <vector>
#include "base/bind.h"
#include "base/containers/flat_map.h"
#include "base/test/scoped_feature_list.h"
#include "base/unguessable_token.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/resource_provider_test_utils.h"
#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/quads/render_pass.h"
#include "components/viz/common/quads/render_pass_draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/stream_video_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/quads/video_hole_draw_quad.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/service/display/ca_layer_overlay.h"
#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/gl_renderer.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display/overlay_candidate_validator.h"
#include "components/viz/service/display/overlay_processor.h"
#include "components/viz/service/display/overlay_strategy_fullscreen.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
#include "components/viz/service/display/overlay_strategy_underlay.h"
#include "components/viz/service/display/overlay_strategy_underlay_cast.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_gles2_interface.h"
#include "components/viz/test/test_shared_bitmap_manager.h"
#include "gpu/config/gpu_finch_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gl/gl_switches.h"
#include "ui/latency/latency_info.h"
using testing::_;
using testing::Mock;
namespace viz {
namespace {
const gfx::Size kDisplaySize(256, 256);
const gfx::Rect kOverlayRect(0, 0, 256, 256);
const gfx::Rect kOverlayTopLeftRect(0, 0, 128, 128);
const gfx::Rect kOverlayBottomRightRect(128, 128, 128, 128);
const gfx::Rect kOverlayClipRect(0, 0, 128, 128);
const gfx::PointF kUVTopLeft(0.1f, 0.2f);
const gfx::PointF kUVBottomRight(1.0f, 1.0f);
const gfx::Transform kNormalTransform =
gfx::Transform(0.9f, 0, 0, 0.8f, 0.1f, 0.2f); // x,y -> x,y.
const gfx::Transform kXMirrorTransform =
gfx::Transform(-0.9f, 0, 0, 0.8f, 1.0f, 0.2f); // x,y -> 1-x,y.
const gfx::Transform kYMirrorTransform =
gfx::Transform(0.9f, 0, 0, -0.8f, 0.1f, 1.0f); // x,y -> x,1-y.
const gfx::Transform kBothMirrorTransform =
gfx::Transform(-0.9f, 0, 0, -0.8f, 1.0f, 1.0f); // x,y -> 1-x,1-y.
const gfx::Transform kSwapTransform =
gfx::Transform(0, 1, 1, 0, 0, 0); // x,y -> y,x.
class FullscreenOverlayValidator : public OverlayCandidateValidator {
public:
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {
strategies->push_back(std::make_unique<OverlayStrategyFullscreen>(this));
}
bool AllowCALayerOverlays() override { return false; }
bool AllowDCLayerOverlays() override { return false; }
bool NeedsSurfaceOccludingDamageRect() override { return true; }
void CheckOverlaySupport(OverlayCandidateList* surfaces) override {
surfaces->back().overlay_handled = true;
}
};
class SingleOverlayValidator : public OverlayCandidateValidator {
public:
SingleOverlayValidator() : expected_rects_(1, gfx::RectF(kOverlayRect)) {}
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {
strategies->push_back(std::make_unique<OverlayStrategySingleOnTop>(this));
strategies->push_back(std::make_unique<OverlayStrategyUnderlay>(this));
}
bool AllowCALayerOverlays() override { return false; }
bool AllowDCLayerOverlays() override { return false; }
bool NeedsSurfaceOccludingDamageRect() override { return true; }
void CheckOverlaySupport(OverlayCandidateList* surfaces) override {
// We may have 1 or 2 surfaces depending on whether this ran through the
// full renderer and picked up the output surface, or not.
ASSERT_LE(1U, surfaces->size());
ASSERT_GE(2U, surfaces->size());
OverlayCandidate& candidate = surfaces->back();
EXPECT_TRUE(!candidate.use_output_surface_for_resource);
for (const auto& r : expected_rects_) {
const float kAbsoluteError = 0.01f;
if (std::abs(r.x() - candidate.display_rect.x()) <= kAbsoluteError &&
std::abs(r.y() - candidate.display_rect.y()) <= kAbsoluteError &&
std::abs(r.width() - candidate.display_rect.width()) <=
kAbsoluteError &&
std::abs(r.height() - candidate.display_rect.height()) <=
kAbsoluteError) {
EXPECT_FLOAT_RECT_EQ(BoundingRect(kUVTopLeft, kUVBottomRight),
candidate.uv_rect);
if (!candidate.clip_rect.IsEmpty()) {
EXPECT_EQ(true, candidate.is_clipped);
EXPECT_EQ(kOverlayClipRect, candidate.clip_rect);
}
candidate.overlay_handled = true;
return;
}
}
// We should find one rect in expected_rects_that matches candidate.
EXPECT_TRUE(false);
}
void AddExpectedRect(const gfx::RectF& rect) {
expected_rects_.push_back(rect);
}
private:
std::vector<gfx::RectF> expected_rects_;
};
class CALayerValidator : public OverlayCandidateValidator {
public:
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {}
bool AllowCALayerOverlays() override { return true; }
bool AllowDCLayerOverlays() override { return false; }
bool NeedsSurfaceOccludingDamageRect() override { return false; }
void CheckOverlaySupport(OverlayCandidateList* surfaces) override {}
};
class DCLayerValidator : public OverlayCandidateValidator {
public:
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {}
bool AllowCALayerOverlays() override { return false; }
bool AllowDCLayerOverlays() override { return true; }
bool NeedsSurfaceOccludingDamageRect() override { return true; }
void CheckOverlaySupport(OverlayCandidateList* surfaces) override {}
};
class SingleOnTopOverlayValidator : public SingleOverlayValidator {
public:
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {
strategies->push_back(std::make_unique<OverlayStrategySingleOnTop>(this));
}
};
class UnderlayOverlayValidator : public SingleOverlayValidator {
public:
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {
strategies->push_back(std::make_unique<OverlayStrategyUnderlay>(this));
}
};
class TransparentUnderlayOverlayValidator : public SingleOverlayValidator {
public:
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {
strategies->push_back(std::make_unique<OverlayStrategyUnderlay>(
this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates));
}
};
class UnderlayCastOverlayValidator : public SingleOverlayValidator {
public:
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {
strategies->push_back(std::make_unique<OverlayStrategyUnderlayCast>(this));
}
};
class DefaultOverlayProcessor : public OverlayProcessor {
public:
DefaultOverlayProcessor(OverlayCandidateValidator* overlay_validator,
ContextProvider* context_provider);
size_t GetStrategyCount();
};
DefaultOverlayProcessor::DefaultOverlayProcessor(
OverlayCandidateValidator* overlay_validator,
ContextProvider* context_provider)
: OverlayProcessor(overlay_validator, context_provider) {}
size_t DefaultOverlayProcessor::GetStrategyCount() {
return strategies_.size();
}
template <typename OverlayCandidateValidatorType>
class OverlayOutputSurface : public OutputSurface {
public:
explicit OverlayOutputSurface(
scoped_refptr<TestContextProvider> context_provider)
: OutputSurface(std::move(context_provider)) {
is_displayed_as_overlay_plane_ = true;
}
// OutputSurface implementation.
void BindToClient(OutputSurfaceClient* client) override {}
void EnsureBackbuffer() override {}
void DiscardBackbuffer() override {}
void BindFramebuffer() override { bind_framebuffer_count_ += 1; }
void SetDrawRectangle(const gfx::Rect& rect) override {}
void Reshape(const gfx::Size& size,
float device_scale_factor,
const gfx::ColorSpace& color_space,
bool has_alpha,
bool use_stencil) override {}
void SwapBuffers(OutputSurfaceFrame frame) override {}
uint32_t GetFramebufferCopyTextureFormat() override {
// TestContextProvider has no real framebuffer, just use RGB.
return GL_RGB;
}
bool HasExternalStencilTest() const override { return false; }
void ApplyExternalStencil() override {}
OverlayCandidateValidatorType* GetOverlayCandidateValidator() const override {
return overlay_candidate_validator_.get();
}
bool IsDisplayedAsOverlayPlane() const override {
return is_displayed_as_overlay_plane_;
}
unsigned GetOverlayTextureId() const override { return 10000; }
gfx::BufferFormat GetOverlayBufferFormat() const override {
return gfx::BufferFormat::RGBX_8888;
}
unsigned UpdateGpuFence() override { return 0; }
void SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback) override {}
void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
gfx::OverlayTransform GetDisplayTransform() override {
return gfx::OVERLAY_TRANSFORM_NONE;
}
void set_is_displayed_as_overlay_plane(bool value) {
is_displayed_as_overlay_plane_ = value;
}
void SetOverlayCandidateValidator(OverlayCandidateValidatorType* validator) {
overlay_candidate_validator_.reset(validator);
}
unsigned bind_framebuffer_count() const { return bind_framebuffer_count_; }
private:
std::unique_ptr<OverlayCandidateValidatorType> overlay_candidate_validator_;
bool is_displayed_as_overlay_plane_;
unsigned bind_framebuffer_count_ = 0;
};
template <typename OverlayCandidateValidatorType>
class TypedOverlayProcessor : public OverlayProcessor {
public:
TypedOverlayProcessor(OverlayCandidateValidatorType* validator,
const ContextProvider* context_provider)
: OverlayProcessor(validator, context_provider), validator_(validator) {}
OverlayCandidateValidatorType* GetTypedOverlayCandidateValidator() {
return validator_;
}
private:
OverlayCandidateValidatorType* validator_;
};
std::unique_ptr<RenderPass> CreateRenderPass() {
int render_pass_id = 1;
gfx::Rect output_rect(0, 0, 256, 256);
std::unique_ptr<RenderPass> pass = RenderPass::Create();
pass->SetNew(render_pass_id, output_rect, output_rect, gfx::Transform());
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
return pass;
}
std::unique_ptr<RenderPass> CreateRenderPassWithTransform(
const gfx::Transform& transform) {
int render_pass_id = 1;
gfx::Rect output_rect(0, 0, 256, 256);
std::unique_ptr<RenderPass> pass = RenderPass::Create();
pass->SetNew(render_pass_id, output_rect, output_rect, gfx::Transform());
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
shared_state->quad_to_target_transform = transform;
return pass;
}
static ResourceId CreateResourceInLayerTree(
ClientResourceProvider* child_resource_provider,
const gfx::Size& size,
bool is_overlay_candidate) {
auto resource = TransferableResource::MakeGL(
gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(),
size, is_overlay_candidate);
auto release_callback = SingleReleaseCallback::Create(
base::BindRepeating([](const gpu::SyncToken&, bool) {}));
ResourceId resource_id = child_resource_provider->ImportResource(
resource, std::move(release_callback));
return resource_id;
}
ResourceId CreateResource(DisplayResourceProvider* parent_resource_provider,
ClientResourceProvider* child_resource_provider,
ContextProvider* child_context_provider,
const gfx::Size& size,
bool is_overlay_candidate) {
ResourceId resource_id = CreateResourceInLayerTree(
child_resource_provider, size, is_overlay_candidate);
int child_id = parent_resource_provider->CreateChild(
base::BindRepeating([](const std::vector<ReturnedResource>&) {}), true);
// Transfer resource to the parent.
std::vector<ResourceId> resource_ids_to_transfer;
resource_ids_to_transfer.push_back(resource_id);
std::vector<TransferableResource> list;
child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list,
child_context_provider);
parent_resource_provider->ReceiveFromChild(child_id, list);
// Delete it in the child so it won't be leaked, and will be released once
// returned from the parent.
child_resource_provider->RemoveImportedResource(resource_id);
// In DisplayResourceProvider's namespace, use the mapped resource id.
std::unordered_map<ResourceId, ResourceId> resource_map =
parent_resource_provider->GetChildToParentMap(child_id);
return resource_map[list[0].id];
}
SolidColorDrawQuad* CreateSolidColorQuadAt(
const SharedQuadState* shared_quad_state,
SkColor color,
RenderPass* render_pass,
const gfx::Rect& rect) {
SolidColorDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
quad->SetNew(shared_quad_state, rect, rect, color, false);
return quad;
}
TextureDrawQuad* CreateCandidateQuadAt(
DisplayResourceProvider* parent_resource_provider,
ClientResourceProvider* child_resource_provider,
ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect,
ui::ProtectedVideoType protected_video_type) {
bool needs_blending = false;
bool premultiplied_alpha = false;
bool flipped = false;
bool nearest_neighbor = false;
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
gfx::Size resource_size_in_pixels = rect.size();
bool is_overlay_candidate = true;
ResourceId resource_id = CreateResource(
parent_resource_provider, child_resource_provider, child_context_provider,
resource_size_in_pixels, is_overlay_candidate);
auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
overlay_quad->SetNew(shared_quad_state, rect, rect, needs_blending,
resource_id, premultiplied_alpha, kUVTopLeft,
kUVBottomRight, SK_ColorTRANSPARENT, vertex_opacity,
flipped, nearest_neighbor, /*secure_output_only=*/false,
protected_video_type);
overlay_quad->set_resource_size_in_pixels(resource_size_in_pixels);
return overlay_quad;
}
TextureDrawQuad* CreateCandidateQuadAt(
DisplayResourceProvider* parent_resource_provider,
ClientResourceProvider* child_resource_provider,
ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect) {
return CreateCandidateQuadAt(
parent_resource_provider, child_resource_provider, child_context_provider,
shared_quad_state, render_pass, rect, ui::ProtectedVideoType::kClear);
}
// For Cast we use VideoHoleDrawQuad, and that's what overlay_processor_
// expects.
VideoHoleDrawQuad* CreateVideoHoleDrawQuadAt(
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect) {
base::UnguessableToken overlay_plane_id = base::UnguessableToken::Create();
auto* overlay_quad =
render_pass->CreateAndAppendDrawQuad<VideoHoleDrawQuad>();
overlay_quad->SetNew(shared_quad_state, rect, rect, overlay_plane_id);
return overlay_quad;
}
TextureDrawQuad* CreateTransparentCandidateQuadAt(
DisplayResourceProvider* parent_resource_provider,
ClientResourceProvider* child_resource_provider,
ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect) {
bool needs_blending = true;
bool premultiplied_alpha = false;
bool flipped = false;
bool nearest_neighbor = false;
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
gfx::Size resource_size_in_pixels = rect.size();
bool is_overlay_candidate = true;
ResourceId resource_id = CreateResource(
parent_resource_provider, child_resource_provider, child_context_provider,
resource_size_in_pixels, is_overlay_candidate);
auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
overlay_quad->SetNew(shared_quad_state, rect, rect, needs_blending,
resource_id, premultiplied_alpha, kUVTopLeft,
kUVBottomRight, SK_ColorTRANSPARENT, vertex_opacity,
flipped, nearest_neighbor, /*secure_output_only=*/false,
ui::ProtectedVideoType::kClear);
overlay_quad->set_resource_size_in_pixels(resource_size_in_pixels);
return overlay_quad;
}
TextureDrawQuad* CreateFullscreenCandidateQuad(
DisplayResourceProvider* parent_resource_provider,
ClientResourceProvider* child_resource_provider,
ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass) {
return CreateCandidateQuadAt(
parent_resource_provider, child_resource_provider, child_context_provider,
shared_quad_state, render_pass, render_pass->output_rect);
}
YUVVideoDrawQuad* CreateFullscreenCandidateYUVVideoQuad(
DisplayResourceProvider* parent_resource_provider,
ClientResourceProvider* child_resource_provider,
ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass) {
bool needs_blending = false;
gfx::RectF tex_coord_rect(0, 0, 1, 1);
gfx::Rect rect = render_pass->output_rect;
gfx::Size resource_size_in_pixels = rect.size();
bool is_overlay_candidate = true;
ResourceId resource_id = CreateResource(
parent_resource_provider, child_resource_provider, child_context_provider,
resource_size_in_pixels, is_overlay_candidate);
auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
overlay_quad->SetNew(shared_quad_state, rect, rect, needs_blending,
tex_coord_rect, tex_coord_rect, resource_size_in_pixels,
resource_size_in_pixels, resource_id, resource_id,
resource_id, resource_id,
gfx::ColorSpace::CreateREC601(), 0, 1.0, 8);
return overlay_quad;
}
void CreateOpaqueQuadAt(DisplayResourceProvider* resource_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect) {
auto* color_quad = render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
color_quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
}
void CreateOpaqueQuadAt(DisplayResourceProvider* resource_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect,
SkColor color) {
DCHECK_EQ(255u, SkColorGetA(color));
auto* color_quad = render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
color_quad->SetNew(shared_quad_state, rect, rect, color, false);
}
void CreateFullscreenOpaqueQuad(DisplayResourceProvider* resource_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass) {
CreateOpaqueQuadAt(resource_provider, shared_quad_state, render_pass,
render_pass->output_rect);
}
static void CompareRenderPassLists(const RenderPassList& expected_list,
const RenderPassList& actual_list) {
EXPECT_EQ(expected_list.size(), actual_list.size());
for (size_t i = 0; i < actual_list.size(); ++i) {
RenderPass* expected = expected_list[i].get();
RenderPass* actual = actual_list[i].get();
EXPECT_EQ(expected->id, actual->id);
EXPECT_EQ(expected->output_rect, actual->output_rect);
EXPECT_EQ(expected->transform_to_root_target,
actual->transform_to_root_target);
EXPECT_EQ(expected->damage_rect, actual->damage_rect);
EXPECT_EQ(expected->has_transparent_background,
actual->has_transparent_background);
EXPECT_EQ(expected->shared_quad_state_list.size(),
actual->shared_quad_state_list.size());
EXPECT_EQ(expected->quad_list.size(), actual->quad_list.size());
for (auto exp_iter = expected->quad_list.cbegin(),
act_iter = actual->quad_list.cbegin();
exp_iter != expected->quad_list.cend(); ++exp_iter, ++act_iter) {
EXPECT_EQ(exp_iter->rect.ToString(), act_iter->rect.ToString());
EXPECT_EQ(exp_iter->shared_quad_state->quad_layer_rect.ToString(),
act_iter->shared_quad_state->quad_layer_rect.ToString());
}
}
}
SkMatrix44 GetIdentityColorMatrix() {
return SkMatrix44(SkMatrix44::kIdentity_Constructor);
}
SkMatrix GetNonIdentityColorMatrix() {
SkMatrix44 matrix = GetIdentityColorMatrix();
matrix.set(1, 1, 0.5f);
matrix.set(2, 2, 0.5f);
return matrix;
}
template <typename OverlayCandidateValidatorType>
class OverlayTest : public testing::Test {
using OutputSurfaceType = OverlayOutputSurface<OverlayCandidateValidatorType>;
using OverlayProcessorType =
TypedOverlayProcessor<OverlayCandidateValidatorType>;
protected:
void SetUp() override {
provider_ = TestContextProvider::Create();
provider_->BindToCurrentThread();
output_surface_ = std::make_unique<OutputSurfaceType>(provider_);
output_surface_->BindToClient(&client_);
output_surface_->SetOverlayCandidateValidator(
new OverlayCandidateValidatorType);
shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>();
resource_provider_ = std::make_unique<DisplayResourceProvider>(
DisplayResourceProvider::kGpu, provider_.get(),
shared_bitmap_manager_.get());
child_provider_ = TestContextProvider::Create();
child_provider_->BindToCurrentThread();
child_resource_provider_ = std::make_unique<ClientResourceProvider>(true);
overlay_processor_ = std::make_unique<OverlayProcessorType>(
output_surface_->GetOverlayCandidateValidator(),
output_surface_->context_provider());
overlay_processor_->Initialize();
overlay_processor_->SetDCHasHwOverlaySupportForTesting();
}
void TearDown() override {
overlay_processor_ = nullptr;
child_resource_provider_->ShutdownAndReleaseAllResources();
child_resource_provider_ = nullptr;
child_provider_ = nullptr;
resource_provider_ = nullptr;
shared_bitmap_manager_ = nullptr;
output_surface_ = nullptr;
provider_ = nullptr;
}
void AddExpectedRectToOverlayValidator(const gfx::RectF& rect) {
overlay_processor_->GetTypedOverlayCandidateValidator()->AddExpectedRect(
rect);
}
scoped_refptr<TestContextProvider> provider_;
std::unique_ptr<OutputSurfaceType> output_surface_;
cc::FakeOutputSurfaceClient client_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
std::unique_ptr<DisplayResourceProvider> resource_provider_;
scoped_refptr<TestContextProvider> child_provider_;
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
std::unique_ptr<OverlayProcessorType> overlay_processor_;
gfx::Rect damage_rect_;
std::vector<gfx::Rect> content_bounds_;
};
using FullscreenOverlayTest = OverlayTest<FullscreenOverlayValidator>;
using SingleOverlayOnTopTest = OverlayTest<SingleOnTopOverlayValidator>;
using UnderlayTest = OverlayTest<UnderlayOverlayValidator>;
using TransparentUnderlayTest =
OverlayTest<TransparentUnderlayOverlayValidator>;
using UnderlayCastTest = OverlayTest<UnderlayCastOverlayValidator>;
using CALayerOverlayTest = OverlayTest<CALayerValidator>;
TEST(OverlayTest, NoOverlaysByDefault) {
scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
OverlayOutputSurface<OverlayCandidateValidator> output_surface(provider);
EXPECT_EQ(nullptr, output_surface.GetOverlayCandidateValidator());
output_surface.SetOverlayCandidateValidator(new SingleOverlayValidator);
EXPECT_TRUE(output_surface.GetOverlayCandidateValidator() != nullptr);
}
TEST(OverlayTest, OverlaysProcessorHasStrategy) {
scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
provider->BindToCurrentThread();
OverlayOutputSurface<OverlayCandidateValidator> output_surface(provider);
cc::FakeOutputSurfaceClient client;
output_surface.BindToClient(&client);
output_surface.SetOverlayCandidateValidator(new SingleOverlayValidator);
auto shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>();
std::unique_ptr<DisplayResourceProvider> resource_provider =
std::make_unique<DisplayResourceProvider>(DisplayResourceProvider::kGpu,
provider.get(),
shared_bitmap_manager.get());
auto overlay_processor = std::make_unique<DefaultOverlayProcessor>(
output_surface.GetOverlayCandidateValidator(),
output_surface.context_provider());
overlay_processor->Initialize();
EXPECT_GE(2U, overlay_processor->GetStrategyCount());
}
TEST_F(FullscreenOverlayTest, SuccessfulOverlay) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
gfx::Rect output_rect = pass->output_rect;
TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
unsigned original_resource_id = original_quad->resource_id();
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
// Check that all the quads are gone.
EXPECT_EQ(0U, main_pass->quad_list.size());
// Check that we have only one overlay.
EXPECT_EQ(1U, candidate_list.size());
// Check that the right resource id got extracted.
EXPECT_EQ(original_resource_id, candidate_list.front().resource_id);
gfx::Rect overlay_damage_rect =
overlay_processor_->GetAndResetOverlayDamage();
EXPECT_EQ(output_rect, overlay_damage_rect);
}
TEST_F(FullscreenOverlayTest, FailOnOutputColorMatrix) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
// This is passing a non-identity color matrix which will result in disabling
// overlays since color matrices are not supported yet.
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetNonIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(0U, candidate_list.size());
// Check that the 2 quads are not gone.
EXPECT_EQ(2U, main_pass->quad_list.size());
}
TEST_F(FullscreenOverlayTest, AlphaFail) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateTransparentCandidateQuadAt(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
pass->output_rect);
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
// Check that all the quads are gone.
EXPECT_EQ(1U, main_pass->quad_list.size());
// Check that we have only one overlay.
EXPECT_EQ(0U, candidate_list.size());
}
TEST_F(FullscreenOverlayTest, SuccessfulResourceSizeInPixels) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
original_quad->set_resource_size_in_pixels(gfx::Size(64, 64));
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
// Check that the quad is gone.
EXPECT_EQ(0U, main_pass->quad_list.size());
}
TEST_F(FullscreenOverlayTest, OnTopFail) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
// Add something in front of it.
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(0U, candidate_list.size());
// Check that the 2 quads are not gone.
EXPECT_EQ(2U, main_pass->quad_list.size());
}
TEST_F(FullscreenOverlayTest, NotCoveringFullscreenFail) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
gfx::Rect inset_rect = pass->output_rect;
inset_rect.Inset(0, 1, 0, 1);
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
inset_rect);
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(0U, candidate_list.size());
// Check that the quad is not gone.
EXPECT_EQ(1U, main_pass->quad_list.size());
}
TEST_F(FullscreenOverlayTest, RemoveFullscreenQuadFromQuadList) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
// Add something in front of it that is fully transparent.
pass->shared_quad_state_list.back()->opacity = 0.0f;
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
// Check that the fullscreen quad is gone.
for (const DrawQuad* quad : main_pass->quad_list) {
EXPECT_NE(main_pass->output_rect, quad->rect);
}
}
TEST_F(SingleOverlayOnTopTest, SuccessfulOverlay) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
unsigned original_resource_id = original_quad->resource_id();
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
// Check that the quad is gone.
EXPECT_EQ(2U, main_pass->quad_list.size());
const auto& quad_list = main_pass->quad_list;
for (auto it = quad_list.BackToFrontBegin(); it != quad_list.BackToFrontEnd();
++it) {
EXPECT_NE(DrawQuad::Material::kTextureContent, it->material);
}
// Check that the right resource id got extracted.
EXPECT_EQ(original_resource_id, candidate_list.back().resource_id);
}
TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
// Add a small quad.
const auto kSmallCandidateRect = gfx::Rect(0, 0, 16, 16);
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kSmallCandidateRect);
AddExpectedRectToOverlayValidator(gfx::RectF(kSmallCandidateRect));
// Add a bigger quad below the previous one, but not occluded.
const auto kBigCandidateRect = gfx::Rect(20, 20, 32, 32);
TextureDrawQuad* quad_big = CreateCandidateQuadAt(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
kBigCandidateRect);
AddExpectedRectToOverlayValidator(gfx::RectF(kBigCandidateRect));
unsigned resource_big = quad_big->resource_id();
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
// Check that one quad is gone.
EXPECT_EQ(2U, main_pass->quad_list.size());
// Check that we have only one overlay.
EXPECT_EQ(1U, candidate_list.size());
// Check that the right resource id (bigger quad) got extracted.
EXPECT_EQ(resource_big, candidate_list.front().resource_id);
}
TEST_F(SingleOverlayOnTopTest, DamageRect) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
damage_rect_ = kOverlayRect;
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
OverlayCandidateList candidate_list;
// Primary plane.
OverlayCandidate output_surface_plane;
output_surface_plane.display_rect = gfx::RectF(kOverlayRect);
output_surface_plane.use_output_surface_for_resource = true;
output_surface_plane.overlay_handled = true;
candidate_list.push_back(output_surface_plane);
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_TRUE(damage_rect_.IsEmpty());
}
TEST_F(SingleOverlayOnTopTest, NoCandidates) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
RenderPassList original_pass_list;
RenderPass::CopyAll(pass_list, &original_pass_list);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
// There should be nothing new here.
CompareRenderPassLists(pass_list, original_pass_list);
}
TEST_F(SingleOverlayOnTopTest, OccludedCandidates) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
RenderPassList original_pass_list;
RenderPass::CopyAll(pass_list, &original_pass_list);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
// There should be nothing new here.
CompareRenderPassLists(pass_list, original_pass_list);
}
// Test with multiple render passes.
TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, AcceptBlending) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
quad->needs_blending = true;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
damage_rect_ = quad->rect;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
EXPECT_FALSE(damage_rect_.IsEmpty());
gfx::Rect overlay_damage_rect =
overlay_processor_->GetAndResetOverlayDamage();
EXPECT_FALSE(overlay_damage_rect.IsEmpty());
}
TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
quad->background_color = SK_ColorRED;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, AcceptBlackBackgroundColor) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
quad->background_color = SK_ColorBLACK;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, RejectBlackBackgroundColorWithBlending) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
quad->background_color = SK_ColorBLACK;
quad->needs_blending = true;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, RejectBlendMode) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->blend_mode = SkBlendMode::kScreen;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, RejectOpacity) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->opacity = 0.5f;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, RejectNonAxisAlignedTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutXAxis(45.f);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, AllowClipped) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->is_clipped = true;
pass->shared_quad_state_list.back()->clip_rect = kOverlayClipRect;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
TEST_F(UnderlayTest, AllowVerticalFlip) {
gfx::Rect rect = kOverlayRect;
rect.set_width(rect.width() / 2);
rect.Offset(0, -rect.height());
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(2.0f,
-1.0f);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL,
candidate_list.back().transform);
}
TEST_F(UnderlayTest, AllowHorizontalFlip) {
gfx::Rect rect = kOverlayRect;
rect.set_height(rect.height() / 2);
rect.Offset(-rect.width(), 0);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(-1.0f,
2.0f);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL,
candidate_list.back().transform);
}
TEST_F(SingleOverlayOnTopTest, AllowPositiveScaleTransform) {
gfx::Rect rect = kOverlayRect;
rect.set_width(rect.width() / 2);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(2.0f,
1.0f);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, AcceptMirrorYTransform) {
gfx::Rect rect = kOverlayRect;
rect.Offset(0, -rect.height());
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(1.f,
-1.f);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
}
TEST_F(UnderlayTest, Allow90DegreeRotation) {
gfx::Rect rect = kOverlayRect;
rect.Offset(0, -rect.height());
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(90.f);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_90, candidate_list.back().transform);
}
TEST_F(UnderlayTest, Allow180DegreeRotation) {
gfx::Rect rect = kOverlayRect;
rect.Offset(-rect.width(), -rect.height());
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(180.f);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_180, candidate_list.back().transform);
}
TEST_F(UnderlayTest, Allow270DegreeRotation) {
gfx::Rect rect = kOverlayRect;
rect.Offset(-rect.width(), 0);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(270.f);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_270, candidate_list.back().transform);
}
TEST_F(UnderlayTest, AllowsOpaqueCandidates) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get())
->needs_blending = false;
pass->shared_quad_state_list.front()->opacity = 1.0;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
}
TEST_F(UnderlayTest, DisallowsTransparentCandidates) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get())
->needs_blending = true;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(0U, candidate_list.size());
}
TEST_F(UnderlayTest, DisallowFilteredQuadOnTop) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
int render_pass_id = 3;
RenderPassDrawQuad* quad =
pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
quad->SetNew(pass->shared_quad_state_list.back(), kOverlayRect, kOverlayRect,
render_pass_id, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get())
->needs_blending = false;
pass->shared_quad_state_list.front()->opacity = 1.0;
cc::FilterOperations filters;
filters.Append(cc::FilterOperation::CreateBlurFilter(10.f));
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
render_pass_backdrop_filters[render_pass_id] = &filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(0U, candidate_list.size());
}
TEST_F(TransparentUnderlayTest, AllowsOpaqueCandidates) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get())
->needs_blending = false;
pass->shared_quad_state_list.front()->opacity = 1.0;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
}
TEST_F(TransparentUnderlayTest, AllowsTransparentCandidates) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get())
->needs_blending = true;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) {
AddExpectedRectToOverlayValidator(gfx::RectF(kOverlayBottomRightRect));
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, AllowTransparentOnTop) {
AddExpectedRectToOverlayValidator(gfx::RectF(kOverlayBottomRightRect));
std::unique_ptr<RenderPass> pass = CreateRenderPass();
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 0.f;
CreateSolidColorQuadAt(shared_state, SK_ColorBLACK, pass.get(),
kOverlayBottomRightRect);
shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
shared_state, pass.get(), kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, AllowTransparentColorOnTop) {
AddExpectedRectToOverlayValidator(gfx::RectF(kOverlayBottomRightRect));
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateSolidColorQuadAt(pass->shared_quad_state_list.back(),
SK_ColorTRANSPARENT, pass.get(),
kOverlayBottomRightRect);
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, RejectOpaqueColorOnTop) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 0.5f;
CreateSolidColorQuadAt(shared_state, SK_ColorBLACK, pass.get(),
kOverlayBottomRightRect);
shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
shared_state, pass.get(), kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, RejectTransparentColorOnTopWithoutBlending) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
CreateSolidColorQuadAt(shared_state, SK_ColorTRANSPARENT, pass.get(),
kOverlayBottomRightRect)
->needs_blending = false;
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
shared_state, pass.get(), kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
TEST_F(SingleOverlayOnTopTest, DoNotPromoteIfContentsDontChange) {
// Resource ID for the repeated quads. Value should be equivalent to
// OverlayStrategySingleOnTop::kMaxFrameCandidateWithSameResourceId.
constexpr size_t kFramesSkippedBeforeNotPromoting = 3;
ResourceId previous_resource_id;
for (size_t i = 0; i < 3 + kFramesSkippedBeforeNotPromoting; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
RenderPass* main_pass = pass.get();
ResourceId resource_id;
if (i == 0 || i == 1) {
// Create a unique resource only for the first 2 frames.
resource_id = CreateResource(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->output_rect.size(),
true /*is_overlay_candidate*/);
previous_resource_id = resource_id;
} else {
// Starting the 3rd frame, they should have the same resource ID.
resource_id = previous_resource_id;
}
// Create a quad with the resource ID selected above.
TextureDrawQuad* original_quad =
main_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
original_quad->SetNew(
pass->shared_quad_state_list.back(), pass->output_rect,
pass->output_rect, false /*needs_blending*/, resource_id,
false /*premultiplied_alpha*/, kUVTopLeft, kUVBottomRight,
SK_ColorTRANSPARENT, vertex_opacity, false /*flipped*/,
false /*nearest_neighbor*/, false /*secure_output_only*/,
ui::ProtectedVideoType::kClear);
original_quad->set_resource_size_in_pixels(pass->output_rect.size());
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), main_pass);
// Check for potential candidates.
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
if (i <= kFramesSkippedBeforeNotPromoting) {
EXPECT_EQ(1U, candidate_list.size());
// Check that the right resource id got extracted.
EXPECT_EQ(resource_id, candidate_list.back().resource_id);
// Check that the quad is gone.
EXPECT_EQ(1U, main_pass->quad_list.size());
} else {
// Check nothing has been promoted.
EXPECT_EQ(2U, main_pass->quad_list.size());
}
}
}
TEST_F(UnderlayTest, OverlayLayerUnderMainLayer) {
AddExpectedRectToOverlayValidator(gfx::RectF(kOverlayBottomRightRect));
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(-1, candidate_list[0].plane_z_order);
EXPECT_EQ(2U, main_pass->quad_list.size());
// The overlay quad should have changed to a SOLID_COLOR quad.
EXPECT_EQ(main_pass->quad_list.back()->material,
DrawQuad::Material::kSolidColor);
auto* quad = static_cast<SolidColorDrawQuad*>(main_pass->quad_list.back());
EXPECT_EQ(quad->rect, quad->visible_rect);
EXPECT_EQ(false, quad->needs_blending);
EXPECT_EQ(SK_ColorTRANSPARENT, quad->color);
}
TEST_F(UnderlayTest, AllowOnTop) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->CreateAndAppendSharedQuadState()->opacity = 0.5f;
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
RenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(-1, candidate_list[0].plane_z_order);
// The overlay quad should have changed to a SOLID_COLOR quad.
EXPECT_EQ(main_pass->quad_list.front()->material,
DrawQuad::Material::kSolidColor);
auto* quad = static_cast<SolidColorDrawQuad*>(main_pass->quad_list.front());
EXPECT_EQ(quad->rect, quad->visible_rect);
EXPECT_EQ(false, quad->needs_blending);
EXPECT_EQ(SK_ColorTRANSPARENT, quad->color);
}
// The first time an underlay is scheduled its damage must not be subtracted.
TEST_F(UnderlayTest, InitialUnderlayDamageNotSubtracted) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
damage_rect_ = kOverlayRect;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(kOverlayRect, damage_rect_);
}
// An identical underlay for two frames in a row means the damage can be
// subtracted the second time.
TEST_F(UnderlayTest, DamageSubtractedForConsecutiveIdenticalUnderlays) {
for (int i = 0; i < 2; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
damage_rect_ = kOverlayRect;
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
}
// The second time the same overlay rect is scheduled it will be subtracted
// from the damage rect.
EXPECT_TRUE(damage_rect_.IsEmpty());
}
// Underlay damage can only be subtracted if the previous frame's underlay
// was the same rect.
TEST_F(UnderlayTest, DamageNotSubtractedForNonIdenticalConsecutiveUnderlays) {
gfx::Rect overlay_rects[] = {kOverlayBottomRightRect, kOverlayRect};
for (int i = 0; i < 2; ++i) {
AddExpectedRectToOverlayValidator(gfx::RectF(overlay_rects[i]));
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
overlay_rects[i]);
damage_rect_ = overlay_rects[i];
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(overlay_rects[i], damage_rect_);
}
}
// Underlay damage can only be subtracted if the previous frame's underlay
// exists.
TEST_F(UnderlayTest, DamageNotSubtractedForNonConsecutiveIdenticalUnderlays) {
bool has_fullscreen_candidate[] = {true, false, true};
for (int i = 0; i < 3; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
if (has_fullscreen_candidate[i]) {
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(),
pass.get());
}
damage_rect_ = kOverlayRect;
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
}
EXPECT_EQ(kOverlayRect, damage_rect_);
}
// An identical overlay that is occluded should not have damage subtracted until
// it has been unoccluded for more than one frame.
TEST_F(UnderlayTest, DamageSubtractedForOneFrameAfterBecomingUnoccluded) {
for (int i = 0; i < 3; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
if (i == 0) {
// Add an overlapping quad above the candidate for the first frame.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(),
pass.get());
}
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
damage_rect_ = kOverlayRect;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
// The damage rect should not be subtracted if the underlay is occluded
// (i==0) or it is unoccluded for the first time (i==1).
if (i < 2)
EXPECT_FALSE(damage_rect_.IsEmpty());
}
// The second time the same overlay rect is scheduled it should be subtracted
// from the damage rect.
EXPECT_TRUE(damage_rect_.IsEmpty());
}
TEST_F(UnderlayTest, DamageNotSubtractedWhenQuadsAboveOverlap) {
for (int i = 0; i < 2; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
// Add an overlapping quad above the candidate.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
damage_rect_ = kOverlayRect;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
}
EXPECT_EQ(kOverlayRect, damage_rect_);
}
TEST_F(UnderlayTest, DamageSubtractedWhenQuadsAboveDontOverlap) {
AddExpectedRectToOverlayValidator(gfx::RectF(kOverlayBottomRightRect));
for (int i = 0; i < 2; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
// Add a non-overlapping quad above the candidate.
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayBottomRightRect);
damage_rect_ = kOverlayBottomRightRect;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
}
EXPECT_TRUE(damage_rect_.IsEmpty());
}
TEST_F(UnderlayTest, PrimaryPlaneOverlayIsTransparentWithUnderlay) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
gfx::Rect output_rect = pass->output_rect;
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
output_rect, SK_ColorWHITE);
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayRect);
OverlayCandidateList candidate_list;
OverlayCandidate candidate;
candidate.use_output_surface_for_resource = true;
candidate.is_opaque = true;
candidate_list.push_back(candidate);
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(2U, candidate_list.size());
ASSERT_EQ(false, candidate_list[0].is_opaque);
}
TEST_F(UnderlayTest, UpdateDamageWhenChangingUnderlays) {
AddExpectedRectToOverlayValidator(gfx::RectF(kOverlayTopLeftRect));
for (size_t i = 0; i < 2; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
if (i == 0) {
CreateCandidateQuadAt(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(),
pass.get(), kOverlayRect);
}
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
}
EXPECT_EQ(kOverlayRect, damage_rect_);
}
TEST_F(UnderlayTest, UpdateDamageRectWhenNoPromotion) {
// In the first pass there is an overlay promotion and the expected damage
// size should be unchanged.
// In the second pass there is no overlay promotion, but the damage should be
// the union of the damage_rect with CreateRenderPass's output_rect which is
// {0, 0, 256, 256}.
bool has_fullscreen_candidate[] = {true, false};
gfx::Rect damages[] = {gfx::Rect(0, 0, 32, 32), gfx::Rect(0, 0, 312, 16)};
gfx::Rect expected_damages[] = {gfx::Rect(0, 0, 32, 32),
gfx::Rect(0, 0, 312, 256)};
size_t expected_candidate_size[] = {1, 0};
for (int i = 0; i < 2; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
if (has_fullscreen_candidate[i]) {
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(),
pass.get());
}
gfx::Rect damage_rect{damages[i]};
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_background_filters, &candidate_list,
nullptr, nullptr, &damage_rect, &content_bounds_);
EXPECT_EQ(expected_damages[i], damage_rect);
ASSERT_EQ(expected_candidate_size[i], candidate_list.size());
}
}
// Tests that no damage occurs when the quad shared state has no occluding
// damage.
TEST_F(UnderlayTest, CandidateNoDamageWhenQuadSharedStateNoOccludingDamage) {
for (int i = 0; i < 4; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
gfx::Rect rect(2, 3);
SharedQuadState* default_damaged_shared_quad_state =
pass->shared_quad_state_list.AllocateAndCopyFrom(
pass->shared_quad_state_list.back());
if (i == 2) {
auto* sqs = pass->shared_quad_state_list.front();
sqs->occluding_damage_rect = gfx::Rect();
} else if (i == 3) {
auto* sqs = pass->shared_quad_state_list.front();
sqs->occluding_damage_rect = gfx::Rect(1, 1, 10, 10);
}
CreateSolidColorQuadAt(default_damaged_shared_quad_state, SK_ColorBLACK,
pass.get(), rect);
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.front(),
pass.get());
damage_rect_ = kOverlayRect;
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
if (i == 0 || i == 1 || i == 3)
EXPECT_FALSE(damage_rect_.IsEmpty());
else if (i == 2)
EXPECT_TRUE(damage_rect_.IsEmpty());
}
}
TEST_F(UnderlayCastTest, NoOverlayContentBounds) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, content_bounds_.size());
}
TEST_F(UnderlayCastTest, FullScreenOverlayContentBounds) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateVideoHoleDrawQuadAt(pass->shared_quad_state_list.back(), pass.get(),
kOverlayRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_TRUE(content_bounds_[0].IsEmpty());
}
TEST_F(UnderlayCastTest, BlackOutsideOverlayContentBounds) {
AddExpectedRectToOverlayValidator(gfx::RectF(kOverlayBottomRightRect));
const gfx::Rect kLeftSide(0, 0, 128, 256);
const gfx::Rect kTopRight(128, 0, 128, 128);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateVideoHoleDrawQuadAt(pass->shared_quad_state_list.back(), pass.get(),
kOverlayBottomRightRect);
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), kLeftSide,
SK_ColorBLACK);
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), kTopRight,
SK_ColorBLACK);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_TRUE(content_bounds_[0].IsEmpty());
}
TEST_F(UnderlayCastTest, OverlayOccludedContentBounds) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
CreateVideoHoleDrawQuadAt(pass->shared_quad_state_list.back(), pass.get(),
kOverlayRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_EQ(kOverlayTopLeftRect, content_bounds_[0]);
}
TEST_F(UnderlayCastTest, OverlayOccludedUnionContentBounds) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayBottomRightRect);
CreateVideoHoleDrawQuadAt(pass->shared_quad_state_list.back(), pass.get(),
kOverlayRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_EQ(kOverlayRect, content_bounds_[0]);
}
TEST_F(UnderlayCastTest, RoundOverlayContentBounds) {
// Check rounding behaviour on overlay quads. Be conservative (content
// potentially visible on boundary).
const gfx::Rect overlay_rect(1, 1, 8, 8);
AddExpectedRectToOverlayValidator(gfx::RectF(1.5f, 1.5f, 8, 8));
gfx::Transform transform;
transform.Translate(0.5f, 0.5f);
std::unique_ptr<RenderPass> pass = CreateRenderPassWithTransform(transform);
CreateVideoHoleDrawQuadAt(pass->shared_quad_state_list.back(), pass.get(),
overlay_rect);
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 0, 10, 10), SK_ColorWHITE);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_EQ(gfx::Rect(0, 0, 11, 11), content_bounds_[0]);
}
TEST_F(UnderlayCastTest, RoundContentBounds) {
// Check rounding behaviour on content quads (bounds should be enclosing
// rect).
gfx::Rect overlay_rect = kOverlayRect;
overlay_rect.Inset(0, 0, 1, 1);
AddExpectedRectToOverlayValidator(gfx::RectF(0.5f, 0.5f, 255, 255));
gfx::Transform transform;
transform.Translate(0.5f, 0.5f);
std::unique_ptr<RenderPass> pass = CreateRenderPassWithTransform(transform);
CreateVideoHoleDrawQuadAt(pass->shared_quad_state_list.back(), pass.get(),
overlay_rect);
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 0, 255, 255), SK_ColorWHITE);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_EQ(kOverlayRect, content_bounds_[0]);
}
TEST_F(UnderlayCastTest, PrimaryPlaneOverlayIsAlwaysTransparent) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
gfx::Rect output_rect = pass->output_rect;
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
output_rect, SK_ColorWHITE);
OverlayCandidateList candidate_list;
OverlayCandidate candidate;
candidate.use_output_surface_for_resource = true;
candidate.is_opaque = true;
candidate_list.push_back(candidate);
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_EQ(false, candidate_list[0].is_opaque);
EXPECT_EQ(0U, content_bounds_.size());
}
TEST_F(UnderlayCastTest, NoOverlayPromotionWithoutProtectedContent) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayRect);
OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
ASSERT_TRUE(candidate_list.empty());
EXPECT_TRUE(content_bounds_.empty());
}
OverlayCandidateList BackbufferOverlayList(const RenderPass* root_render_pass) {
OverlayCandidateList list;
OverlayCandidate output_surface_plane;
output_surface_plane.display_rect = gfx::RectF(root_render_pass->output_rect);
output_surface_plane.use_output_surface_for_resource = true;
output_surface_plane.overlay_handled = true;
list.push_back(output_surface_plane);
return list;
}
TEST_F(CALayerOverlayTest, AllowNonAxisAlignedTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(45.f);
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
&ca_layer_list, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, ca_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
TEST_F(CALayerOverlayTest, ThreeDTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutXAxis(45.f);
CALayerOverlayList ca_layer_list;
OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
&ca_layer_list, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, ca_layer_list.size());
gfx::Transform expected_transform;
expected_transform.RotateAboutXAxis(45.f);
gfx::Transform actual_transform(ca_layer_list.back().shared_state->transform);
EXPECT_EQ(expected_transform.ToString(), actual_transform.ToString());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
TEST_F(CALayerOverlayTest, AllowContainingClip) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->is_clipped = true;
pass->shared_quad_state_list.back()->clip_rect = kOverlayRect;
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
&ca_layer_list, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, ca_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
TEST_F(CALayerOverlayTest, NontrivialClip) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->is_clipped = true;
pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(64, 64, 128, 128);
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
&ca_layer_list, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, ca_layer_list.size());
EXPECT_TRUE(ca_layer_list.back().shared_state->is_clipped);
EXPECT_EQ(gfx::RectF(64, 64, 128, 128),
ca_layer_list.back().shared_state->clip_rect);
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
TEST_F(CALayerOverlayTest, SkipTransparent) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->opacity = 0;
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
&ca_layer_list, nullptr, &damage_rect_, &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(0U, ca_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
class DCLayerOverlayTest : public OverlayTest<DCLayerValidator> {};
TEST_F(DCLayerOverlayTest, AllowNonAxisAlignedTransform) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kDirectCompositionComplexOverlays);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(45.f);
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list, nullptr,
&dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(1, dc_layer_list.back().z_order);
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(gfx::Rect(1, 1, 10, 10), damage_rect_);
}
TEST_F(DCLayerOverlayTest, AllowRequiredNonAxisAlignedTransform) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kDirectCompositionNonrootOverlays);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
YUVVideoDrawQuad* yuv_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
// Set the protected video flag will force DCLayerOverlay to use hw overlay
yuv_quad->protected_video_type = ui::ProtectedVideoType::kHardwareProtected;
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(45.f);
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list, nullptr,
&dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(0U, overlay_list.size());
ASSERT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(1, dc_layer_list.back().z_order);
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(gfx::Rect(1, 1, 10, 10), damage_rect_);
}
TEST_F(DCLayerOverlayTest, Occluded) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
{
std::unique_ptr<RenderPass> pass = CreateRenderPass();
SharedQuadState* first_shared_state = pass->shared_quad_state_list.back();
first_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10);
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 3, 100, 100), SK_ColorWHITE);
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
SharedQuadState* second_shared_state =
pass->CreateAndAppendSharedQuadState();
second_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10);
auto* second_video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
// Set the protected video flag will force DCLayerOverlay to use hw overlay
second_video_quad->protected_video_type =
ui::ProtectedVideoType::kHardwareProtected;
second_video_quad->rect.set_origin(gfx::Point(2, 2));
second_video_quad->visible_rect.set_origin(gfx::Point(2, 2));
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(2U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.front().z_order);
EXPECT_EQ(-2, dc_layer_list.back().z_order);
// Entire underlay rect must be redrawn.
EXPECT_EQ(gfx::Rect(0, 0, 256, 256), damage_rect_);
}
{
std::unique_ptr<RenderPass> pass = CreateRenderPass();
SharedQuadState* first_shared_state = pass->shared_quad_state_list.back();
first_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10);
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(3, 3, 100, 100), SK_ColorWHITE);
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
SharedQuadState* second_shared_state =
pass->CreateAndAppendSharedQuadState();
second_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10);
auto* second_video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
second_video_quad->protected_video_type =
ui::ProtectedVideoType::kHardwareProtected;
second_video_quad->rect.set_origin(gfx::Point(2, 2));
second_video_quad->visible_rect.set_origin(gfx::Point(2, 2));
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(2U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.front().z_order);
EXPECT_EQ(-2, dc_layer_list.back().z_order);
// The underlay rectangle is the same, so the damage for first video quad is
// contained within the combined occluding rects for this and the last
// frame. Second video quad also adds its damage.
// This is calculated by carving out the underlay rect size from the
// damage_rect, adding back the quads on top and then the overlay/underlay
// rects from the previous frame. The damage rect carried over from the
// revious frame with multiple overlays cannot be skipped.
EXPECT_EQ(gfx::Rect(0, 0, 256, 256), damage_rect_);
}
}
TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
{
std::unique_ptr<RenderPass> pass = CreateRenderPass();
SharedQuadState* shared_quad_state = pass->shared_quad_state_list.back();
shared_quad_state->occluding_damage_rect = gfx::Rect(210, 210, 20, 20);
// Occluding quad fully contained in video rect.
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 3, 100, 100), SK_ColorWHITE);
// Non-occluding quad fully outside video rect
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(210, 210, 20, 20), SK_ColorWHITE);
// Underlay video quad
auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
video_quad->rect = gfx::Rect(0, 0, 200, 200);
video_quad->visible_rect = video_quad->rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
// Damage rect fully outside video quad
damage_rect_ = gfx::Rect(210, 210, 20, 20);
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
// All rects must be redrawn at the first frame.
EXPECT_EQ(gfx::Rect(0, 0, 230, 230), damage_rect_);
}
{
std::unique_ptr<RenderPass> pass = CreateRenderPass();
SharedQuadState* shared_quad_state = pass->shared_quad_state_list.back();
shared_quad_state->occluding_damage_rect = gfx::Rect(210, 210, 20, 20);
// Occluding quad fully contained in video rect.
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 3, 100, 100), SK_ColorWHITE);
// Non-occluding quad fully outside video rect
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(210, 210, 20, 20), SK_ColorWHITE);
// Underlay video quad
auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
video_quad->rect = gfx::Rect(0, 0, 200, 200);
video_quad->visible_rect = video_quad->rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
// Damage rect fully outside video quad
damage_rect_ = gfx::Rect(210, 210, 20, 20);
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
// Only the non-overlay damaged rect need to be drawn by the gl compositor
EXPECT_EQ(gfx::Rect(210, 210, 20, 20), damage_rect_);
}
}
TEST_F(DCLayerOverlayTest, DamageRectWithNonRootOverlay) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures({features::kDirectCompositionUnderlays,
features::kDirectCompositionNonrootOverlays},
{});
{
// A root solid quad
std::unique_ptr<RenderPass> root_pass = CreateRenderPass();
CreateOpaqueQuadAt(
resource_provider_.get(), root_pass->shared_quad_state_list.back(),
root_pass.get(), gfx::Rect(210, 0, 20, 20), SK_ColorWHITE);
// A non-root video quad
std::unique_ptr<RenderPass> nonroot_pass = CreateRenderPass();
auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), nonroot_pass->shared_quad_state_list.back(),
nonroot_pass.get());
video_quad->rect = gfx::Rect(0, 0, 200, 200);
video_quad->visible_rect = video_quad->rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
// Damage rect fully outside video quad
damage_rect_ = gfx::Rect(210, 0, 20, 20);
RenderPassList pass_list;
pass_list.push_back(std::move(nonroot_pass));
pass_list.push_back(std::move(root_pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
// damage_rect returned from ProcessForOverlays() is for root render pass
// only. Non-root damage rect is not included.
EXPECT_EQ(gfx::Rect(210, 0, 20, 20), damage_rect_);
}
{
// A root solid quad
std::unique_ptr<RenderPass> root_pass = CreateRenderPass();
CreateOpaqueQuadAt(
resource_provider_.get(), root_pass->shared_quad_state_list.back(),
root_pass.get(), gfx::Rect(210, 0, 20, 20), SK_ColorWHITE);
// A non-root video quad
std::unique_ptr<RenderPass> nonroot_pass = CreateRenderPass();
auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), nonroot_pass->shared_quad_state_list.back(),
nonroot_pass.get());
video_quad->rect = gfx::Rect(0, 0, 200, 200);
video_quad->visible_rect = video_quad->rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
// Damage rect fully outside video quad
damage_rect_ = gfx::Rect(210, 0, 20, 20);
RenderPassList pass_list;
pass_list.push_back(std::move(nonroot_pass));
pass_list.push_back(std::move(root_pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
// Nonroot damage_rect from the previous frame should be added to this frame
EXPECT_EQ(gfx::Rect(0, 0, 230, 200), damage_rect_);
}
}
TEST_F(DCLayerOverlayTest, DamageRect) {
for (int i = 0; i < 2; i++) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(1, dc_layer_list.back().z_order);
// Damage rect should be unchanged on initial frame because of resize, but
// should be empty on the second frame because everything was put in a
// layer.
if (i == 1)
EXPECT_TRUE(damage_rect_.IsEmpty());
else
EXPECT_EQ(gfx::Rect(1, 1, 10, 10), damage_rect_);
}
}
TEST_F(DCLayerOverlayTest, MultiplePassDamageRect) {
gfx::Transform child_pass1_transform;
child_pass1_transform.Translate(0, 100);
RenderPassId child_pass1_id(5);
std::unique_ptr<RenderPass> child_pass1 = CreateRenderPass();
ASSERT_EQ(child_pass1->shared_quad_state_list.size(), 1u);
child_pass1->id = child_pass1_id;
child_pass1->damage_rect = gfx::Rect();
child_pass1->transform_to_root_target = child_pass1_transform;
child_pass1->shared_quad_state_list.back()->opacity = 0.9f;
child_pass1->shared_quad_state_list.back()->blend_mode =
SkBlendMode::kSrcOver;
YUVVideoDrawQuad* yuv_quad_required = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), child_pass1->shared_quad_state_list.back(),
child_pass1.get());
// Set the protected video flag will force DCLayerOverlay to use hw overlay
yuv_quad_required->protected_video_type =
ui::ProtectedVideoType::kHardwareProtected;
RenderPassId child_pass2_id(6);
std::unique_ptr<RenderPass> child_pass2 = CreateRenderPass();
ASSERT_EQ(child_pass2->shared_quad_state_list.size(), 1u);
child_pass2->id = child_pass2_id;
child_pass2->damage_rect = gfx::Rect();
child_pass2->transform_to_root_target = gfx::Transform();
child_pass2->shared_quad_state_list.back()->opacity = 0.8f;
YUVVideoDrawQuad* yuv_quad_not_required =
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), child_pass2->shared_quad_state_list.back(),
child_pass2.get());
std::unique_ptr<RenderPass> root_pass = CreateRenderPass();
root_pass->CreateAndAppendSharedQuadState();
ASSERT_EQ(root_pass->shared_quad_state_list.size(), 2u);
SharedQuadState* child_pass1_sqs =
root_pass->shared_quad_state_list.ElementAt(0);
child_pass1_sqs->quad_to_target_transform =
child_pass1->transform_to_root_target;
child_pass1_sqs->opacity = 0.7f;
gfx::Rect unit_rect(0, 0, 1, 1);
auto* child_pass1_rpdq =
root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
child_pass1_rpdq->SetNew(child_pass1_sqs, unit_rect, unit_rect,
child_pass1_id, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(), gfx::PointF(),
gfx::RectF(0, 0, 1, 1), false, 1.0f);
SharedQuadState* child_pass2_sqs =
root_pass->shared_quad_state_list.ElementAt(1);
child_pass2_sqs->quad_to_target_transform =
child_pass2->transform_to_root_target;
child_pass2_sqs->opacity = 0.6f;
auto* child_pass2_rpdq =
root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
child_pass2_rpdq->SetNew(child_pass2_sqs, unit_rect, unit_rect,
child_pass2_id, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(), gfx::PointF(),
gfx::RectF(0, 0, 1, 1), false, 1.0f);
root_pass->damage_rect = gfx::Rect();
gfx::Rect root_damage_rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(child_pass1));
pass_list.push_back(std::move(child_pass2));
pass_list.push_back(std::move(root_pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list, nullptr,
&dc_layer_list, &root_damage_rect, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
// Only the kHardwareProtectedVideo video quad produces damage.
ASSERT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
EXPECT_EQ(gfx::Rect(0, 0, 256, 256), pass_list[0]->damage_rect);
EXPECT_EQ(gfx::Rect(), pass_list[1]->damage_rect);
EXPECT_EQ(gfx::Rect(0, 100, 256, 156), root_damage_rect);
// Overlay damage handling is done entirely within DCOverlayProcessor so this
// is expected to return an empty rect
gfx::Rect overlay_damage = overlay_processor_->GetAndResetOverlayDamage();
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), overlay_damage);
EXPECT_EQ(1u, pass_list[0]->quad_list.size());
EXPECT_EQ(DrawQuad::Material::kSolidColor,
pass_list[0]->quad_list.ElementAt(0)->material);
// The kHardwareProtectedVideo video quad is put into an underlay, and
// replaced by a solid color quad.
auto* yuv_solid_color_quad =
static_cast<SolidColorDrawQuad*>(pass_list[0]->quad_list.ElementAt(0));
EXPECT_EQ(SK_ColorBLACK, yuv_solid_color_quad->color);
EXPECT_EQ(gfx::Rect(0, 0, 256, 256), yuv_solid_color_quad->rect);
EXPECT_TRUE(yuv_solid_color_quad->shared_quad_state->quad_to_target_transform
.IsIdentity());
EXPECT_EQ(0.9f, yuv_solid_color_quad->shared_quad_state->opacity);
EXPECT_EQ(SkBlendMode::kDstOut,
yuv_solid_color_quad->shared_quad_state->blend_mode);
// The non required video quad is not put into an underlay.
EXPECT_EQ(1u, pass_list[1]->quad_list.size());
EXPECT_EQ(yuv_quad_not_required, pass_list[1]->quad_list.ElementAt(0));
EXPECT_EQ(3u, pass_list[2]->quad_list.size());
// The RPDQs are not modified.
EXPECT_EQ(DrawQuad::Material::kRenderPass,
pass_list[2]->quad_list.ElementAt(0)->material);
EXPECT_EQ(child_pass1_id, static_cast<RenderPassDrawQuad*>(
pass_list[2]->quad_list.ElementAt(0))
->render_pass_id);
// A solid color quad is put behind the RPDQ containing the video.
EXPECT_EQ(DrawQuad::Material::kSolidColor,
pass_list[2]->quad_list.ElementAt(1)->material);
auto* rpdq_solid_color_quad =
static_cast<SolidColorDrawQuad*>(pass_list[2]->quad_list.ElementAt(1));
EXPECT_EQ(SK_ColorTRANSPARENT, rpdq_solid_color_quad->color);
EXPECT_EQ(child_pass1_transform,
rpdq_solid_color_quad->shared_quad_state->quad_to_target_transform);
EXPECT_EQ(1.f, rpdq_solid_color_quad->shared_quad_state->opacity);
EXPECT_FALSE(rpdq_solid_color_quad->ShouldDrawWithBlending());
EXPECT_EQ(DrawQuad::Material::kRenderPass,
pass_list[2]->quad_list.ElementAt(2)->material);
EXPECT_EQ(child_pass2_id, static_cast<RenderPassDrawQuad*>(
pass_list[2]->quad_list.ElementAt(2))
->render_pass_id);
}
TEST_F(DCLayerOverlayTest, ClipRect) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
// Process twice. The second time through the overlay list shouldn't change,
// which will allow the damage rect to reflect just the changes in that
// frame.
for (size_t i = 0; i < 2; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 2, 100, 100), SK_ColorWHITE);
pass->shared_quad_state_list.back()->is_clipped = true;
pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(0, 3, 100, 100);
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), shared_state, pass.get());
shared_state->is_clipped = true;
// Clipped rect shouldn't be overlapped by clipped opaque quad rect.
shared_state->clip_rect = gfx::Rect(0, 0, 100, 3);
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
damage_rect_ = gfx::Rect(1, 1, 10, 10);
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
// Because of clip rects the overlay isn't occluded and shouldn't be an
// underlay.
EXPECT_EQ(1, dc_layer_list.back().z_order);
EXPECT_TRUE(dc_layer_list.back().is_clipped);
EXPECT_EQ(gfx::Rect(0, 0, 100, 3), dc_layer_list.back().clip_rect);
if (i == 1) {
// The damage rect should only contain contents that aren't in the
// clipped overlay rect.
EXPECT_EQ(gfx::Rect(1, 3, 10, 8), damage_rect_);
}
}
}
TEST_F(DCLayerOverlayTest, TransparentOnTop) {
// Process twice. The second time through the overlay list shouldn't change,
// which will allow the damage rect to reflect just the changes in that
// frame.
for (size_t i = 0; i < 2; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->opacity = 0.5f;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(1, dc_layer_list.back().z_order);
// Quad isn't opaque, so underlying damage must remain the same.
EXPECT_EQ(gfx::Rect(1, 1, 10, 10), damage_rect_);
}
}
TEST_F(DCLayerOverlayTest, UnderlayDamageRectWithQuadOnTopUnchanged) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
for (int i = 0; i < 3; i++) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
// Add a solid color quad on top
SharedQuadState* shared_state_on_top = pass->shared_quad_state_list.back();
CreateSolidColorQuadAt(shared_state_on_top, SK_ColorRED, pass.get(),
kOverlayBottomRightRect);
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), shared_state, pass.get());
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters;
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
gfx::Rect damage_rect_ = kOverlayRect;
// The quad on top does not give damage on the third frame
if (i == 2)
shared_state->occluding_damage_rect = gfx::Rect();
else
shared_state->occluding_damage_rect = kOverlayBottomRightRect;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters, &overlay_list,
nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
// Damage rect should be unchanged on initial frame, but should be reduced
// to the size of quad on top, and empty on the third frame.
if (i == 0)
EXPECT_EQ(kOverlayRect, damage_rect_);
else if (i == 1)
EXPECT_EQ(kOverlayBottomRightRect, damage_rect_);
else if (i == 2)
EXPECT_EQ(gfx::Rect(), damage_rect_);
}
}
class OverlayInfoRendererGL : public GLRenderer {
public:
OverlayInfoRendererGL(const RendererSettings* settings,
OutputSurface* output_surface,
DisplayResourceProvider* resource_provider)
: GLRenderer(settings, output_surface, resource_provider, nullptr),
expect_overlays_(false) {}
MOCK_METHOD2(DoDrawQuad,
void(const DrawQuad* quad, const gfx::QuadF* draw_region));
void SetCurrentFrame(const DrawingFrame& frame) {
SetCurrentFrameForTesting(frame);
}
using GLRenderer::BeginDrawingFrame;
void FinishDrawingFrame() override {
GLRenderer::FinishDrawingFrame();
if (!expect_overlays_) {
EXPECT_EQ(0U, current_frame()->overlay_list.size());
return;
}
ASSERT_EQ(2U, current_frame()->overlay_list.size());
EXPECT_GE(current_frame()->overlay_list.back().resource_id, 0U);
}
void set_expect_overlays(bool expect_overlays) {
expect_overlays_ = expect_overlays;
}
private:
bool expect_overlays_;
};
class MockOverlayScheduler {
public:
MOCK_METHOD7(Schedule,
void(int plane_z_order,
gfx::OverlayTransform plane_transform,
unsigned overlay_texture_id,
const gfx::Rect& display_bounds,
const gfx::RectF& uv_rect,
bool enable_blend,
unsigned gpu_fence_id));
};
class GLRendererWithOverlaysTest : public testing::Test {
using OutputSurfaceType = OverlayOutputSurface<SingleOverlayValidator>;
using OverlayProcessorType = TypedOverlayProcessor<SingleOverlayValidator>;
protected:
GLRendererWithOverlaysTest() {
provider_ = TestContextProvider::Create();
provider_->BindToCurrentThread();
output_surface_ = std::make_unique<OutputSurfaceType>(provider_);
output_surface_->BindToClient(&output_surface_client_);
resource_provider_ = std::make_unique<DisplayResourceProvider>(
DisplayResourceProvider::kGpu, provider_.get(), nullptr);
provider_->support()->SetScheduleOverlayPlaneCallback(base::BindRepeating(
&MockOverlayScheduler::Schedule, base::Unretained(&scheduler_)));
child_provider_ = TestContextProvider::Create();
child_provider_->BindToCurrentThread();
child_resource_provider_ = std::make_unique<ClientResourceProvider>(true);
}
~GLRendererWithOverlaysTest() override {
child_resource_provider_->ShutdownAndReleaseAllResources();
}
void Init(bool use_validator) {
if (use_validator) {
output_surface_->SetOverlayCandidateValidator(new SingleOverlayValidator);
overlay_processor_ = std::make_unique<OverlayProcessorType>(
output_surface_->GetOverlayCandidateValidator(),
output_surface_->context_provider());
}
renderer_ = std::make_unique<OverlayInfoRendererGL>(
&settings_, output_surface_.get(), resource_provider_.get());
renderer_->Initialize();
renderer_->SetVisible(true);
}
void DrawFrame(RenderPassList* pass_list, const gfx::Size& viewport_size) {
renderer_->DrawFrame(pass_list, 1.f, viewport_size);
}
void SwapBuffers() {
renderer_->SwapBuffers(std::vector<ui::LatencyInfo>());
renderer_->SwapBuffersComplete();
}
void SwapBuffersWithoutComplete() {
renderer_->SwapBuffers(std::vector<ui::LatencyInfo>());
}
void SwapBuffersComplete() { renderer_->SwapBuffersComplete(); }
void ReturnResourceInUseQuery(ResourceId id) {
DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
id);
gpu::TextureInUseResponse response;
response.texture = lock.texture_id();
response.in_use = false;
gpu::TextureInUseResponses responses;
responses.push_back(response);
renderer_->DidReceiveTextureInUseResponses(responses);
}
void AddExpectedRectToOverlayValidator(const gfx::RectF& rect) {
overlay_processor_->GetTypedOverlayCandidateValidator()->AddExpectedRect(
rect);
}
RendererSettings settings_;
cc::FakeOutputSurfaceClient output_surface_client_;
std::unique_ptr<OutputSurfaceType> output_surface_;
std::unique_ptr<DisplayResourceProvider> resource_provider_;
std::unique_ptr<OverlayInfoRendererGL> renderer_;
std::unique_ptr<OverlayProcessorType> overlay_processor_;
scoped_refptr<TestContextProvider> provider_;
scoped_refptr<TestContextProvider> child_provider_;
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
MockOverlayScheduler scheduler_;
};
TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) {
bool use_validator = true;
Init(use_validator);
renderer_->set_expect_overlays(true);
AddExpectedRectToOverlayValidator(gfx::RectF(kOverlayBottomRightRect));
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayBottomRightRect);
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
// Candidate pass was taken out and extra skipped pass added,
// so only draw 2 quads.
EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(2);
EXPECT_CALL(scheduler_,
Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, _,
gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1), _, _))
.Times(1);
EXPECT_CALL(
scheduler_,
Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, kOverlayBottomRightRect,
BoundingRect(kUVTopLeft, kUVBottomRight), _, _))
.Times(1);
DrawFrame(&pass_list, kDisplaySize);
EXPECT_EQ(1U, output_surface_->bind_framebuffer_count());
SwapBuffers();
Mock::VerifyAndClearExpectations(renderer_.get());
Mock::VerifyAndClearExpectations(&scheduler_);
}
TEST_F(GLRendererWithOverlaysTest, OccludedQuadInUnderlay) {
bool use_validator = true;
Init(use_validator);
renderer_->set_expect_overlays(true);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
// Candidate quad should fail to be overlaid on top because of occlusion.
// Expect to be replaced with transparent hole quad and placed in underlay.
EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(3);
EXPECT_CALL(scheduler_,
Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, _,
gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1), _, _))
.Times(1);
EXPECT_CALL(scheduler_,
Schedule(-1, gfx::OVERLAY_TRANSFORM_NONE, _, kOverlayRect,
BoundingRect(kUVTopLeft, kUVBottomRight), _, _))
.Times(1);
DrawFrame(&pass_list, kDisplaySize);
EXPECT_EQ(1U, output_surface_->bind_framebuffer_count());
SwapBuffers();
Mock::VerifyAndClearExpectations(renderer_.get());
Mock::VerifyAndClearExpectations(&scheduler_);
}
TEST_F(GLRendererWithOverlaysTest, NoValidatorNoOverlay) {
bool use_validator = false;
Init(use_validator);
renderer_->set_expect_overlays(false);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
// Should not see the primary surface's overlay.
output_surface_->set_is_displayed_as_overlay_plane(false);
EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(3);
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(0);
DrawFrame(&pass_list, kDisplaySize);
EXPECT_EQ(1U, output_surface_->bind_framebuffer_count());
SwapBuffers();
Mock::VerifyAndClearExpectations(renderer_.get());
Mock::VerifyAndClearExpectations(&scheduler_);
}
// GLRenderer skips drawing occluded quads when partial swap is enabled.
TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenPartialSwapEnabled) {
provider_->TestContextGL()->set_have_post_sub_buffer(true);
settings_.partial_swap_enabled = true;
bool use_validator = true;
Init(use_validator);
renderer_->set_expect_overlays(true);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
output_surface_->set_is_displayed_as_overlay_plane(true);
EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(0);
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
DrawFrame(&pass_list, kDisplaySize);
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
SwapBuffers();
Mock::VerifyAndClearExpectations(renderer_.get());
Mock::VerifyAndClearExpectations(&scheduler_);
}
// GLRenderer skips drawing occluded quads when empty swap is enabled.
TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenEmptySwapAllowed) {
provider_->TestContextGL()->set_have_commit_overlay_planes(true);
bool use_validator = true;
Init(use_validator);
renderer_->set_expect_overlays(true);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
output_surface_->set_is_displayed_as_overlay_plane(true);
EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(0);
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
DrawFrame(&pass_list, kDisplaySize);
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
SwapBuffers();
Mock::VerifyAndClearExpectations(renderer_.get());
Mock::VerifyAndClearExpectations(&scheduler_);
}
TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
bool use_validator = true;
Init(use_validator);
renderer_->set_expect_overlays(true);
ResourceId resource1 = CreateResourceInLayerTree(
child_resource_provider_.get(), gfx::Size(32, 32), true);
ResourceId resource2 = CreateResourceInLayerTree(
child_resource_provider_.get(), gfx::Size(32, 32), true);
ResourceId resource3 = CreateResourceInLayerTree(
child_resource_provider_.get(), gfx::Size(32, 32), true);
// Return the resource map.
std::unordered_map<ResourceId, ResourceId> resource_map =
cc::SendResourceAndGetChildToParentMap(
{resource1, resource2, resource3}, resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get());
ResourceId mapped_resource1 = resource_map[resource1];
ResourceId mapped_resource2 = resource_map[resource2];
ResourceId mapped_resource3 = resource_map[resource3];
std::unique_ptr<RenderPass> pass = CreateRenderPass();
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
DirectRenderer::DrawingFrame frame1;
frame1.render_passes_in_draw_order = &pass_list;
frame1.overlay_list.resize(2);
frame1.overlay_list.front().use_output_surface_for_resource = true;
OverlayCandidate& overlay1 = frame1.overlay_list.back();
overlay1.resource_id = mapped_resource1;
overlay1.plane_z_order = 1;
DirectRenderer::DrawingFrame frame2;
frame2.render_passes_in_draw_order = &pass_list;
frame2.overlay_list.resize(2);
frame2.overlay_list.front().use_output_surface_for_resource = true;
OverlayCandidate& overlay2 = frame2.overlay_list.back();
overlay2.resource_id = mapped_resource2;
overlay2.plane_z_order = 1;
DirectRenderer::DrawingFrame frame3;
frame3.render_passes_in_draw_order = &pass_list;
frame3.overlay_list.resize(2);
frame3.overlay_list.front().use_output_surface_for_resource = true;
OverlayCandidate& overlay3 = frame3.overlay_list.back();
overlay3.resource_id = mapped_resource3;
overlay3.plane_z_order = 1;
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame1);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(resource1));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(resource2));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(resource3));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
SwapBuffersWithoutComplete();
Mock::VerifyAndClearExpectations(&scheduler_);
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
SwapBuffersComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame2);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
SwapBuffersWithoutComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
Mock::VerifyAndClearExpectations(&scheduler_);
SwapBuffersComplete();
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame3);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
SwapBuffersWithoutComplete();
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
Mock::VerifyAndClearExpectations(&scheduler_);
SwapBuffersComplete();
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
// No overlays, release the resource.
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(0);
DirectRenderer::DrawingFrame frame_no_overlays;
frame_no_overlays.render_passes_in_draw_order = &pass_list;
renderer_->set_expect_overlays(false);
renderer_->SetCurrentFrame(frame_no_overlays);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
SwapBuffersWithoutComplete();
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
Mock::VerifyAndClearExpectations(&scheduler_);
SwapBuffersComplete();
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
// Use the same buffer twice.
renderer_->set_expect_overlays(true);
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame1);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
SwapBuffersWithoutComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
Mock::VerifyAndClearExpectations(&scheduler_);
SwapBuffersComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame1);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
SwapBuffersWithoutComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
Mock::VerifyAndClearExpectations(&scheduler_);
SwapBuffersComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(0);
renderer_->set_expect_overlays(false);
renderer_->SetCurrentFrame(frame_no_overlays);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
SwapBuffersWithoutComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
Mock::VerifyAndClearExpectations(&scheduler_);
SwapBuffersComplete();
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
Mock::VerifyAndClearExpectations(&scheduler_);
}
TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) {
bool use_validator = true;
settings_.release_overlay_resources_after_gpu_query = true;
Init(use_validator);
renderer_->set_expect_overlays(true);
ResourceId resource1 = CreateResourceInLayerTree(
child_resource_provider_.get(), gfx::Size(32, 32), true);
ResourceId resource2 = CreateResourceInLayerTree(
child_resource_provider_.get(), gfx::Size(32, 32), true);
ResourceId resource3 = CreateResourceInLayerTree(
child_resource_provider_.get(), gfx::Size(32, 32), true);
// Return the resource map.
std::unordered_map<ResourceId, ResourceId> resource_map =
cc::SendResourceAndGetChildToParentMap(
{resource1, resource2, resource3}, resource_provider_.get(),
child_resource_provider_.get(), child_provider_.get());
ResourceId mapped_resource1 = resource_map[resource1];
ResourceId mapped_resource2 = resource_map[resource2];
ResourceId mapped_resource3 = resource_map[resource3];
std::unique_ptr<RenderPass> pass = CreateRenderPass();
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
DirectRenderer::DrawingFrame frame1;
frame1.render_passes_in_draw_order = &pass_list;
frame1.overlay_list.resize(2);
frame1.overlay_list.front().use_output_surface_for_resource = true;
OverlayCandidate& overlay1 = frame1.overlay_list.back();
overlay1.resource_id = mapped_resource1;
overlay1.plane_z_order = 1;
DirectRenderer::DrawingFrame frame2;
frame2.render_passes_in_draw_order = &pass_list;
frame2.overlay_list.resize(2);
frame2.overlay_list.front().use_output_surface_for_resource = true;
OverlayCandidate& overlay2 = frame2.overlay_list.back();
overlay2.resource_id = mapped_resource2;
overlay2.plane_z_order = 1;
DirectRenderer::DrawingFrame frame3;
frame3.render_passes_in_draw_order = &pass_list;
frame3.overlay_list.resize(2);
frame3.overlay_list.front().use_output_surface_for_resource = true;
OverlayCandidate& overlay3 = frame3.overlay_list.back();
overlay3.resource_id = mapped_resource3;
overlay3.plane_z_order = 1;
// First frame, with no swap completion.
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame1);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
SwapBuffersWithoutComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
Mock::VerifyAndClearExpectations(&scheduler_);
// Second frame, with no swap completion.
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame2);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
SwapBuffersWithoutComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
Mock::VerifyAndClearExpectations(&scheduler_);
// Third frame, still with no swap completion (where the resources would
// otherwise have been released).
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame3);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
SwapBuffersWithoutComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
Mock::VerifyAndClearExpectations(&scheduler_);
// This completion corresponds to the first frame.
SwapBuffersComplete();
EXPECT_TRUE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
// This completion corresponds to the second frame. The first resource is no
// longer in use.
ReturnResourceInUseQuery(mapped_resource1);
SwapBuffersComplete();
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
// This completion corresponds to the third frame.
SwapBuffersComplete();
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
ReturnResourceInUseQuery(mapped_resource2);
ReturnResourceInUseQuery(mapped_resource3);
EXPECT_FALSE(resource_provider_->InUse(mapped_resource1));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
}
class CALayerOverlayRPDQTest : public CALayerOverlayTest {
protected:
void SetUp() override {
CALayerOverlayTest::SetUp();
pass_list_.push_back(CreateRenderPass());
pass_ = pass_list_.back().get();
quad_ = pass_->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
render_pass_id_ = 3;
}
void ProcessForOverlays() {
overlay_list_ = BackbufferOverlayList(pass_);
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list_, GetIdentityColorMatrix(),
render_pass_filters_, render_pass_backdrop_filters_, &overlay_list_,
&ca_layer_list_, nullptr, &damage_rect_, &content_bounds_);
}
RenderPassList pass_list_;
RenderPass* pass_;
RenderPassDrawQuad* quad_;
int render_pass_id_;
cc::FilterOperations filters_;
cc::FilterOperations backdrop_filters_;
OverlayProcessor::FilterOperationsMap render_pass_filters_;
OverlayProcessor::FilterOperationsMap render_pass_backdrop_filters_;
CALayerOverlayList ca_layer_list_;
OverlayCandidateList overlay_list_;
};
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadNoFilters) {
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
ProcessForOverlays();
EXPECT_EQ(1U, ca_layer_list_.size());
}
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadAllValidFilters) {
filters_.Append(cc::FilterOperation::CreateGrayscaleFilter(0.1f));
filters_.Append(cc::FilterOperation::CreateSepiaFilter(0.2f));
filters_.Append(cc::FilterOperation::CreateSaturateFilter(0.3f));
filters_.Append(cc::FilterOperation::CreateHueRotateFilter(0.4f));
filters_.Append(cc::FilterOperation::CreateInvertFilter(0.5f));
filters_.Append(cc::FilterOperation::CreateBrightnessFilter(0.6f));
filters_.Append(cc::FilterOperation::CreateContrastFilter(0.7f));
filters_.Append(cc::FilterOperation::CreateOpacityFilter(0.8f));
filters_.Append(cc::FilterOperation::CreateBlurFilter(0.9f));
filters_.Append(cc::FilterOperation::CreateDropShadowFilter(
gfx::Point(10, 20), 1.0f, SK_ColorGREEN));
render_pass_filters_[render_pass_id_] = &filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
ProcessForOverlays();
EXPECT_EQ(1U, ca_layer_list_.size());
}
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadOpacityFilterScale) {
filters_.Append(cc::FilterOperation::CreateOpacityFilter(0.8f));
render_pass_filters_[render_pass_id_] = &filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 2), gfx::PointF(), gfx::RectF(), false, 1.0f);
ProcessForOverlays();
EXPECT_EQ(1U, ca_layer_list_.size());
}
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadBlurFilterScale) {
filters_.Append(cc::FilterOperation::CreateBlurFilter(0.8f));
render_pass_filters_[render_pass_id_] = &filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 2), gfx::PointF(), gfx::RectF(), false, 1.0f);
ProcessForOverlays();
EXPECT_EQ(1U, ca_layer_list_.size());
}
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadDropShadowFilterScale) {
filters_.Append(cc::FilterOperation::CreateDropShadowFilter(
gfx::Point(10, 20), 1.0f, SK_ColorGREEN));
render_pass_filters_[render_pass_id_] = &filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 2), gfx::PointF(), gfx::RectF(), false, 1.0f);
ProcessForOverlays();
EXPECT_EQ(1U, ca_layer_list_.size());
}
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadBackgroundFilter) {
backdrop_filters_.Append(cc::FilterOperation::CreateGrayscaleFilter(0.1f));
render_pass_backdrop_filters_[render_pass_id_] = &backdrop_filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
ProcessForOverlays();
EXPECT_EQ(0U, ca_layer_list_.size());
}
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadMask) {
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 2, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
ProcessForOverlays();
EXPECT_EQ(1U, ca_layer_list_.size());
}
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadUnsupportedFilter) {
filters_.Append(cc::FilterOperation::CreateZoomFilter(0.9f, 1));
render_pass_filters_[render_pass_id_] = &filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
ProcessForOverlays();
EXPECT_EQ(0U, ca_layer_list_.size());
}
TEST_F(CALayerOverlayRPDQTest, TooManyRenderPassDrawQuads) {
filters_.Append(cc::FilterOperation::CreateBlurFilter(0.8f));
int count = 35;
for (int i = 0; i < count; ++i) {
auto* quad = pass_->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
quad->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 2, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false,
1.0f);
}
ProcessForOverlays();
EXPECT_EQ(0U, ca_layer_list_.size());
}
} // namespace
} // namespace viz