blob: 2a51a1b72113574058b9e095ba2ce4f9d2babe37 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/compositor/reflector_impl.h"
#include "base/callback.h"
#include "base/feature_list.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/frame_sinks/delay_based_time_source.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display/overlay_candidate_validator.h"
#include "components/viz/test/test_context_provider.h"
#include "content/browser/compositor/browser_compositor_output_surface.h"
#include "content/browser/compositor/reflector_texture.h"
#include "content/browser/compositor/test/test_image_transport_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/test/test_context_factories.h"
#if defined(USE_OZONE)
#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/display_embedder/overlay_candidate_validator_ozone.h"
#include "ui/ozone/public/overlay_candidates_ozone.h"
#endif // defined(USE_OZONE)
namespace content {
namespace {
class FakeTaskRunner : public base::SingleThreadTaskRunner {
public:
FakeTaskRunner() {}
bool PostNonNestableDelayedTask(const base::Location& from_here,
base::OnceClosure task,
base::TimeDelta delay) override {
return true;
}
bool PostDelayedTask(const base::Location& from_here,
base::OnceClosure task,
base::TimeDelta delay) override {
return true;
}
bool RunsTasksInCurrentSequence() const override { return true; }
protected:
~FakeTaskRunner() override {}
};
#if defined(USE_OZONE)
class TestOverlayCandidatesOzone : public ui::OverlayCandidatesOzone {
public:
TestOverlayCandidatesOzone() {}
~TestOverlayCandidatesOzone() override {}
void CheckOverlaySupport(OverlaySurfaceCandidateList* surfaces) override {
(*surfaces)[0].overlay_handled = true;
}
};
#endif // defined(USE_OZONE)
#if defined(USE_OZONE)
std::unique_ptr<viz::OverlayCandidateValidator> CreateTestValidatorOzone() {
std::vector<viz::OverlayStrategy> strategies = {
viz::OverlayStrategy::kSingleOnTop, viz::OverlayStrategy::kUnderlay};
return std::make_unique<viz::OverlayCandidateValidatorOzone>(
std::make_unique<TestOverlayCandidatesOzone>(), std::move(strategies));
}
#endif // defined(USE_OZONE)
class TestOverlayProcessor : public viz::OverlayProcessor {
public:
explicit TestOverlayProcessor(const viz::ContextProvider* context_provider)
: OverlayProcessor(context_provider) {
#if defined(USE_OZONE)
auto validator = CreateTestValidatorOzone();
overlay_validator_ = validator.get();
SetOverlayCandidateValidator(std::move(validator));
#endif // defined(USE_OZONE)
}
viz::OverlayCandidateValidator* get_overlay_validator() const {
return overlay_validator_;
}
private:
viz::OverlayCandidateValidator* overlay_validator_;
};
std::unique_ptr<TestOverlayProcessor> CreateTestOverlayProcessor(
const viz::ContextProvider* context_provider) {
#if defined(USE_OZONE)
return std::make_unique<TestOverlayProcessor>(context_provider);
#else
return nullptr;
#endif // defined(USE_OZONE)
}
class TestOutputSurface : public BrowserCompositorOutputSurface {
public:
TestOutputSurface(scoped_refptr<viz::ContextProvider> context_provider)
: BrowserCompositorOutputSurface(std::move(context_provider)) {}
void SetFlip(bool flip) { capabilities_.flipped_output_surface = flip; }
void BindToClient(viz::OutputSurfaceClient* client) override {}
void EnsureBackbuffer() override {}
void DiscardBackbuffer() override {}
void BindFramebuffer() override {}
void SetDrawRectangle(const gfx::Rect& draw_rectangle) 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(viz::OutputSurfaceFrame frame) override {}
uint32_t GetFramebufferCopyTextureFormat() override { return GL_RGB; }
bool IsDisplayedAsOverlayPlane() const override { return false; }
unsigned GetOverlayTextureId() const override { return 0; }
gfx::BufferFormat GetOverlayBufferFormat() const override {
return gfx::BufferFormat::RGBX_8888;
}
void OnReflectorChanged() override {
if (!reflector_) {
reflector_texture_.reset();
} else {
reflector_texture_.reset(new ReflectorTexture(context_provider()));
reflector_->OnSourceTextureMailboxUpdated(reflector_texture_->mailbox());
}
}
unsigned UpdateGpuFence() override { return 0; }
private:
std::unique_ptr<ReflectorTexture> reflector_texture_;
};
const gfx::Rect kSubRect(0, 0, 64, 64);
const gfx::Size kSurfaceSize(256, 256);
} // namespace
class ReflectorImplTest : public testing::Test {
public:
void SetUp() override {
const bool enable_pixel_output = false;
context_factories_ =
std::make_unique<ui::TestContextFactories>(enable_pixel_output);
ImageTransportFactory::SetFactory(
std::make_unique<TestImageTransportFactory>());
task_runner_ = base::ThreadTaskRunnerHandle::Get();
compositor_task_runner_ = new FakeTaskRunner();
begin_frame_source_ = std::make_unique<viz::DelayBasedBeginFrameSource>(
std::make_unique<viz::DelayBasedTimeSource>(
compositor_task_runner_.get()),
viz::BeginFrameSource::kNotRestartableId);
compositor_ = std::make_unique<ui::Compositor>(
context_factories_->GetContextFactoryPrivate()->AllocateFrameSinkId(),
context_factories_->GetContextFactory(),
context_factories_->GetContextFactoryPrivate(),
compositor_task_runner_.get(), false /* enable_pixel_canvas */);
compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
auto context_provider = viz::TestContextProvider::Create();
context_provider->BindToCurrentThread();
output_surface_ =
std::make_unique<TestOutputSurface>(std::move(context_provider));
overlay_processor_ =
CreateTestOverlayProcessor(output_surface_->context_provider());
root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
compositor_->SetRootLayer(root_layer_.get());
mirroring_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
compositor_->root_layer()->Add(mirroring_layer_.get());
output_surface_->Reshape(kSurfaceSize, 1.f, gfx::ColorSpace(), false,
false);
mirroring_layer_->SetBounds(gfx::Rect(kSurfaceSize));
}
void SetUpReflector() {
reflector_ = std::make_unique<ReflectorImpl>(compositor_.get(),
mirroring_layer_.get());
reflector_->OnSourceSurfaceReady(output_surface_.get());
}
void TearDown() override {
if (reflector_)
reflector_->RemoveMirroringLayer(mirroring_layer_.get());
viz::TransferableResource resource;
std::unique_ptr<viz::SingleReleaseCallback> release;
if (mirroring_layer_->PrepareTransferableResource(nullptr, &resource,
&release)) {
release->Run(gpu::SyncToken(), false);
}
compositor_.reset();
context_factories_.reset();
ImageTransportFactory::Terminate();
}
void UpdateTexture() {
reflector_->OnSourcePostSubBuffer(kSubRect, kSurfaceSize);
}
#if defined(USE_OZONE)
void ProcessForOverlays(viz::OverlayCandidateList* surfaces) {
overlay_processor_->SetSoftwareMirrorMode(
output_surface_->IsSoftwareMirrorMode());
DCHECK(overlay_processor_->get_overlay_validator());
overlay_processor_->get_overlay_validator()->CheckOverlaySupport(surfaces);
}
#endif // defined(USE_OZONE)
protected:
std::unique_ptr<ui::TestContextFactories> context_factories_;
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
std::unique_ptr<viz::SyntheticBeginFrameSource> begin_frame_source_;
base::test::ScopedTaskEnvironment task_environment_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
std::unique_ptr<ui::Compositor> compositor_;
std::unique_ptr<ui::Layer> root_layer_;
std::unique_ptr<ui::Layer> mirroring_layer_;
std::unique_ptr<ReflectorImpl> reflector_;
std::unique_ptr<TestOutputSurface> output_surface_;
std::unique_ptr<TestOverlayProcessor> overlay_processor_;
};
namespace {
TEST_F(ReflectorImplTest, CheckNormalOutputSurface) {
// TODO(jonross): Re-enable once Reflector is re-written to work with
// VizDisplayCompositor. https://crbug.com/601869
if (features::IsVizDisplayCompositorEnabled())
return;
output_surface_->SetFlip(false);
SetUpReflector();
UpdateTexture();
EXPECT_TRUE(mirroring_layer_->TextureFlipped());
gfx::Rect expected_rect = kSubRect + gfx::Vector2d(0, kSurfaceSize.height()) -
gfx::Vector2d(0, kSubRect.height());
EXPECT_EQ(expected_rect, mirroring_layer_->damaged_region());
}
TEST_F(ReflectorImplTest, CheckInvertedOutputSurface) {
// TODO(jonross): Re-enable once Reflector is re-written to work with
// VizDisplayCompositor. https://crbug.com/601869
if (features::IsVizDisplayCompositorEnabled())
return;
output_surface_->SetFlip(true);
SetUpReflector();
UpdateTexture();
EXPECT_FALSE(mirroring_layer_->TextureFlipped());
EXPECT_EQ(kSubRect, mirroring_layer_->damaged_region());
}
#if defined(USE_OZONE)
TEST_F(ReflectorImplTest, CheckOverlayNoReflector) {
// TODO(jonross): Re-enable once Reflector is re-written to work with
// VizDisplayCompositor. https://crbug.com/601869
if (features::IsVizDisplayCompositorEnabled())
return;
viz::OverlayCandidateList list;
viz::OverlayCandidate plane_1, plane_2;
plane_1.plane_z_order = 0;
plane_2.plane_z_order = 1;
list.push_back(plane_1);
list.push_back(plane_2);
ProcessForOverlays(&list);
EXPECT_TRUE(list[0].overlay_handled);
}
TEST_F(ReflectorImplTest, CheckOverlaySWMirroring) {
// TODO(jonross): Re-enable once Reflector is re-written to work with
// VizDisplayCompositor. https://crbug.com/601869
if (features::IsVizDisplayCompositorEnabled())
return;
SetUpReflector();
viz::OverlayCandidateList list;
viz::OverlayCandidate plane_1, plane_2;
plane_1.plane_z_order = 0;
plane_2.plane_z_order = 1;
list.push_back(plane_1);
list.push_back(plane_2);
ProcessForOverlays(&list);
EXPECT_FALSE(list[0].overlay_handled);
}
#endif // defined(USE_OZONE)
} // namespace
} // namespace content