blob: 5d79d61031855a4aa5b02e50d8223a69bf564a73 [file] [log] [blame]
// Copyright 2016 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/test/test_compositor_frame_sink.h"
#include <stdint.h>
#include <utility>
#include "cc/output/begin_frame_args.h"
#include "cc/output/compositor_frame_sink_client.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/direct_renderer.h"
#include "cc/output/output_surface.h"
#include "cc/output/texture_mailbox_deleter.h"
namespace cc {
static constexpr FrameSinkId kCompositorFrameSinkId(1, 1);
TestCompositorFrameSink::TestCompositorFrameSink(
scoped_refptr<ContextProvider> compositor_context_provider,
scoped_refptr<ContextProvider> worker_context_provider,
std::unique_ptr<OutputSurface> display_output_surface,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
const RendererSettings& renderer_settings,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
bool synchronous_composite,
bool force_disable_reclaim_resources)
: CompositorFrameSink(std::move(compositor_context_provider),
std::move(worker_context_provider)),
task_runner_(std::move(task_runner)),
frame_sink_id_(kCompositorFrameSinkId),
surface_manager_(new SurfaceManager),
surface_id_allocator_(new SurfaceIdAllocator()),
surface_factory_(
new SurfaceFactory(frame_sink_id_, surface_manager_.get(), this)),
display_context_shared_with_compositor_(
display_output_surface->context_provider() == context_provider()),
weak_ptr_factory_(this) {
std::unique_ptr<SyntheticBeginFrameSource> begin_frame_source;
std::unique_ptr<DisplayScheduler> scheduler;
if (!synchronous_composite) {
if (renderer_settings.disable_display_vsync) {
begin_frame_source.reset(new BackToBackBeginFrameSource(
base::MakeUnique<DelayBasedTimeSource>(task_runner_.get())));
} else {
begin_frame_source.reset(new DelayBasedBeginFrameSource(
base::MakeUnique<DelayBasedTimeSource>(task_runner_.get())));
begin_frame_source->SetAuthoritativeVSyncInterval(
base::TimeDelta::FromMilliseconds(1000.f /
renderer_settings.refresh_rate));
}
scheduler.reset(new DisplayScheduler(
begin_frame_source.get(), task_runner_.get(),
display_output_surface->capabilities().max_frames_pending));
}
display_.reset(
new Display(shared_bitmap_manager, gpu_memory_buffer_manager,
renderer_settings, std::move(begin_frame_source),
std::move(display_output_surface), std::move(scheduler),
base::MakeUnique<TextureMailboxDeleter>(task_runner_.get())));
// Since this CompositorFrameSink and the Display are tightly coupled and in
// the same process/thread, the LayerTreeHostImpl can reclaim resources from
// the Display. But we allow tests to disable this to mimic an out-of-process
// Display.
capabilities_.can_force_reclaim_resources = !force_disable_reclaim_resources;
// Always use sync tokens so that code paths in resource provider that deal
// with sync tokens are tested.
capabilities_.delegated_sync_points_required = true;
}
TestCompositorFrameSink::~TestCompositorFrameSink() {
DCHECK(copy_requests_.empty());
}
void TestCompositorFrameSink::RequestCopyOfOutput(
std::unique_ptr<CopyOutputRequest> request) {
copy_requests_.push_back(std::move(request));
}
bool TestCompositorFrameSink::BindToClient(CompositorFrameSinkClient* client) {
if (!CompositorFrameSink::BindToClient(client))
return false;
// We want the Display's OutputSurface to hear about lost context, and when
// this shares a context with it we should not be listening for lost context
// callbacks on the context here.
if (display_context_shared_with_compositor_ && context_provider())
context_provider()->SetLostContextCallback(base::Closure());
surface_manager_->RegisterFrameSinkId(frame_sink_id_);
surface_manager_->RegisterSurfaceFactoryClient(frame_sink_id_, this);
display_->Initialize(this, surface_manager_.get(), frame_sink_id_);
display_->renderer_for_testing()->SetEnlargePassTextureAmountForTesting(
enlarge_pass_texture_amount_);
display_->SetVisible(true);
bound_ = true;
return true;
}
void TestCompositorFrameSink::DetachFromClient() {
// Some tests make BindToClient fail on purpose. ^__^
if (bound_) {
if (!delegated_local_frame_id_.is_null())
surface_factory_->Destroy(delegated_local_frame_id_);
surface_manager_->UnregisterSurfaceFactoryClient(frame_sink_id_);
surface_manager_->InvalidateFrameSinkId(frame_sink_id_);
bound_ = false;
}
display_ = nullptr;
surface_factory_ = nullptr;
surface_id_allocator_ = nullptr;
surface_manager_ = nullptr;
CompositorFrameSink::DetachFromClient();
}
void TestCompositorFrameSink::SubmitCompositorFrame(CompositorFrame frame) {
if (test_client_)
test_client_->DisplayReceivedCompositorFrame(frame);
if (delegated_local_frame_id_.is_null()) {
delegated_local_frame_id_ = surface_id_allocator_->GenerateId();
surface_factory_->Create(delegated_local_frame_id_);
}
display_->SetSurfaceId(SurfaceId(frame_sink_id_, delegated_local_frame_id_),
frame.metadata.device_scale_factor);
gfx::Size frame_size =
frame.delegated_frame_data->render_pass_list.back()->output_rect.size();
display_->Resize(frame_size);
bool synchronous = !display_->has_scheduler();
SurfaceFactory::DrawCallback draw_callback;
if (!synchronous) {
// For async draws, we use a callback tell when it is done, but for sync
// draws we don't need one. Unretained is safe here because the callback
// will be run when |surface_factory_| is destroyed which is owned by this
// class.
draw_callback = base::Bind(&TestCompositorFrameSink::DidDrawCallback,
base::Unretained(this));
}
surface_factory_->SubmitCompositorFrame(delegated_local_frame_id_,
std::move(frame), draw_callback);
for (std::unique_ptr<CopyOutputRequest>& copy_request : copy_requests_) {
surface_factory_->RequestCopyOfSurface(delegated_local_frame_id_,
std::move(copy_request));
}
copy_requests_.clear();
if (synchronous) {
display_->DrawAndSwap();
// Post this to get a new stack frame so that we exit this function before
// calling the client to tell it that it is done.
task_runner_->PostTask(FROM_HERE,
base::Bind(&TestCompositorFrameSink::DidDrawCallback,
weak_ptr_factory_.GetWeakPtr()));
}
}
void TestCompositorFrameSink::DidDrawCallback() {
// This is to unthrottle the next frame, not actually a notice that drawing is
// done.
client_->DidReceiveCompositorFrameAck();
}
void TestCompositorFrameSink::ForceReclaimResources() {
if (capabilities_.can_force_reclaim_resources &&
!delegated_local_frame_id_.is_null()) {
surface_factory_->SubmitCompositorFrame(delegated_local_frame_id_,
CompositorFrame(),
SurfaceFactory::DrawCallback());
}
}
void TestCompositorFrameSink::ReturnResources(
const ReturnedResourceArray& resources) {
client_->ReclaimResources(resources);
}
void TestCompositorFrameSink::SetBeginFrameSource(
BeginFrameSource* begin_frame_source) {
client_->SetBeginFrameSource(begin_frame_source);
}
void TestCompositorFrameSink::DisplayOutputSurfaceLost() {
client_->DidLoseCompositorFrameSink();
}
void TestCompositorFrameSink::DisplayWillDrawAndSwap(
bool will_draw_and_swap,
const RenderPassList& render_passes) {
if (test_client_)
test_client_->DisplayWillDrawAndSwap(will_draw_and_swap, render_passes);
}
void TestCompositorFrameSink::DisplayDidDrawAndSwap() {
if (test_client_)
test_client_->DisplayDidDrawAndSwap();
}
} // namespace cc