blob: 3bc52f1621a94e17fc062330e0baf5cf091090fe [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 "cc/surfaces/direct_compositor_frame_sink.h"
#include <memory>
#include "base/memory/ptr_util.h"
#include "cc/output/renderer_settings.h"
#include "cc/output/texture_mailbox_deleter.h"
#include "cc/scheduler/begin_frame_source.h"
#include "cc/scheduler/delay_based_time_source.h"
#include "cc/surfaces/display.h"
#include "cc/surfaces/display_scheduler.h"
#include "cc/surfaces/frame_sink_id.h"
#include "cc/surfaces/local_surface_id_allocator.h"
#include "cc/surfaces/surface_manager.h"
#include "cc/test/begin_frame_args_test.h"
#include "cc/test/fake_compositor_frame_sink_client.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/ordered_simple_task_runner.h"
#include "cc/test/test_context_provider.h"
#include "cc/test/test_gpu_memory_buffer_manager.h"
#include "cc/test/test_shared_bitmap_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
class ObserverTrackingBeginFrameSource : public BackToBackBeginFrameSource {
public:
using BackToBackBeginFrameSource::BackToBackBeginFrameSource;
void DidFinishFrame(BeginFrameObserver* obs,
const BeginFrameAck& ack) override {
BackToBackBeginFrameSource::DidFinishFrame(obs, ack);
if (obs == tracked_observer_)
last_ack_ = ack;
}
void set_tracked_observer(BeginFrameObserver* obs) {
tracked_observer_ = obs;
}
const BeginFrameAck& last_ack() const { return last_ack_; }
private:
BeginFrameObserver* tracked_observer_ = nullptr;
BeginFrameAck last_ack_;
};
class TestDirectCompositorFrameSink : public DirectCompositorFrameSink {
public:
using DirectCompositorFrameSink::DirectCompositorFrameSink;
CompositorFrameSinkSupport* support() const { return support_.get(); }
};
class DirectCompositorFrameSinkTest : public testing::Test {
public:
DirectCompositorFrameSinkTest()
: now_src_(new base::SimpleTestTickClock()),
task_runner_(new OrderedSimpleTaskRunner(now_src_.get(), true)),
display_size_(1920, 1080),
display_rect_(display_size_),
context_provider_(TestContextProvider::Create()) {
surface_manager_.RegisterFrameSinkId(kArbitraryFrameSinkId);
std::unique_ptr<FakeOutputSurface> display_output_surface =
FakeOutputSurface::Create3d();
display_output_surface_ = display_output_surface.get();
begin_frame_source_.reset(new ObserverTrackingBeginFrameSource(
base::MakeUnique<DelayBasedTimeSource>(task_runner_.get())));
int max_frames_pending = 2;
std::unique_ptr<DisplayScheduler> scheduler(
new DisplayScheduler(task_runner_.get(), max_frames_pending));
display_.reset(new Display(
&bitmap_manager_, &gpu_memory_buffer_manager_, RendererSettings(),
kArbitraryFrameSinkId, begin_frame_source_.get(),
std::move(display_output_surface), std::move(scheduler),
base::MakeUnique<TextureMailboxDeleter>(task_runner_.get())));
compositor_frame_sink_.reset(new TestDirectCompositorFrameSink(
kArbitraryFrameSinkId, &surface_manager_, display_.get(),
context_provider_, nullptr, &gpu_memory_buffer_manager_,
&bitmap_manager_));
compositor_frame_sink_->BindToClient(&compositor_frame_sink_client_);
begin_frame_source_->set_tracked_observer(
compositor_frame_sink_->support());
display_->Resize(display_size_);
display_->SetVisible(true);
EXPECT_FALSE(
compositor_frame_sink_client_.did_lose_compositor_frame_sink_called());
}
~DirectCompositorFrameSinkTest() override {
compositor_frame_sink_->DetachFromClient();
}
void SwapBuffersWithDamage(const gfx::Rect& damage_rect) {
std::unique_ptr<RenderPass> render_pass(RenderPass::Create());
render_pass->SetNew(1, display_rect_, damage_rect, gfx::Transform());
CompositorFrame frame;
frame.render_pass_list.push_back(std::move(render_pass));
compositor_frame_sink_->SubmitCompositorFrame(std::move(frame));
}
void SetUp() override {
// Draw the first frame to start in an "unlocked" state.
SwapBuffersWithDamage(display_rect_);
EXPECT_EQ(0u, display_output_surface_->num_sent_frames());
task_runner_->RunUntilIdle();
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
}
protected:
std::unique_ptr<base::SimpleTestTickClock> now_src_;
scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
const gfx::Size display_size_;
const gfx::Rect display_rect_;
SurfaceManager surface_manager_;
TestSharedBitmapManager bitmap_manager_;
TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
scoped_refptr<TestContextProvider> context_provider_;
FakeOutputSurface* display_output_surface_ = nullptr;
std::unique_ptr<ObserverTrackingBeginFrameSource> begin_frame_source_;
std::unique_ptr<Display> display_;
FakeCompositorFrameSinkClient compositor_frame_sink_client_;
std::unique_ptr<TestDirectCompositorFrameSink> compositor_frame_sink_;
};
TEST_F(DirectCompositorFrameSinkTest, DamageTriggersSwapBuffers) {
SwapBuffersWithDamage(display_rect_);
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
task_runner_->RunUntilIdle();
EXPECT_EQ(2u, display_output_surface_->num_sent_frames());
}
TEST_F(DirectCompositorFrameSinkTest, NoDamageDoesNotTriggerSwapBuffers) {
SwapBuffersWithDamage(gfx::Rect());
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
task_runner_->RunUntilIdle();
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
}
TEST_F(DirectCompositorFrameSinkTest, SuspendedDoesNotTriggerSwapBuffers) {
SwapBuffersWithDamage(display_rect_);
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
display_output_surface_->set_suspended_for_recycle(true);
task_runner_->RunUntilIdle();
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
SwapBuffersWithDamage(display_rect_);
task_runner_->RunUntilIdle();
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
display_output_surface_->set_suspended_for_recycle(false);
SwapBuffersWithDamage(display_rect_);
task_runner_->RunUntilIdle();
EXPECT_EQ(2u, display_output_surface_->num_sent_frames());
}
TEST_F(DirectCompositorFrameSinkTest,
LockingResourcesDoesNotIndirectlyCauseDamage) {
compositor_frame_sink_->ForceReclaimResources();
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
task_runner_->RunPendingTasks();
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
SwapBuffersWithDamage(gfx::Rect());
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
task_runner_->RunUntilIdle();
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
}
class TestBeginFrameObserver : public BeginFrameObserverBase {
public:
explicit TestBeginFrameObserver(BeginFrameSource* source) : source_(source) {}
void FinishFrame() { source_->DidFinishFrame(this, ack()); }
const BeginFrameAck& ack() const { return ack_; }
private:
bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) override {
ack_ = BeginFrameAck(args.source_id, args.sequence_number,
args.sequence_number, 0, true);
return true;
}
void OnBeginFrameSourcePausedChanged(bool paused) override{};
BeginFrameSource* source_;
BeginFrameAck ack_;
};
TEST_F(DirectCompositorFrameSinkTest, AcknowledgesBeginFrames) {
// Request a BeginFrame from the CompositorFrameSinkClient.
TestBeginFrameObserver observer(begin_frame_source_.get());
compositor_frame_sink_client_.begin_frame_source()->AddObserver(&observer);
observer.FinishFrame();
compositor_frame_sink_client_.begin_frame_source()->RemoveObserver(&observer);
// Verify that the frame sink acknowledged the last BeginFrame.
EXPECT_EQ(observer.ack(), begin_frame_source_->last_ack());
}
} // namespace
} // namespace cc