blob: 9f980c302b63b4226d0ed5573663fac65a17a5ee [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_delegating_output_surface.h"
#include <stdint.h>
#include <utility>
#include "cc/output/begin_frame_args.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/texture_mailbox_deleter.h"
#include "cc/test/begin_frame_args_test.h"
static constexpr uint32_t kCompositorClientId = 1;
namespace cc {
TestDelegatingOutputSurface::TestDelegatingOutputSurface(
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,
base::SingleThreadTaskRunner* task_runner,
bool synchronous_composite,
bool force_disable_reclaim_resources)
: OutputSurface(std::move(compositor_context_provider),
std::move(worker_context_provider),
nullptr),
surface_manager_(new SurfaceManager),
surface_id_allocator_(new SurfaceIdAllocator(kCompositorClientId)),
surface_factory_(new SurfaceFactory(surface_manager_.get(), this)),
weak_ptrs_(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)));
} else {
begin_frame_source.reset(new DelayBasedBeginFrameSource(
base::MakeUnique<DelayBasedTimeSource>(task_runner)));
begin_frame_source->SetAuthoritativeVSyncInterval(
base::TimeDelta::FromMilliseconds(1000.f /
renderer_settings.refresh_rate));
}
scheduler.reset(new DisplayScheduler(
begin_frame_source.get(), task_runner,
display_output_surface->capabilities().max_frames_pending));
}
const bool context_shared_with_compositor =
display_output_surface->context_provider() == context_provider();
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)));
capabilities_.delegated_rendering = true;
// Since this OutputSurface 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;
capabilities_.delegated_sync_points_required =
!context_shared_with_compositor;
}
TestDelegatingOutputSurface::~TestDelegatingOutputSurface() {
DCHECK(copy_requests_.empty());
}
void TestDelegatingOutputSurface::RequestCopyOfOutput(
std::unique_ptr<CopyOutputRequest> request) {
copy_requests_.push_back(std::move(request));
}
bool TestDelegatingOutputSurface::BindToClient(OutputSurfaceClient* client) {
if (!OutputSurface::BindToClient(client))
return false;
// We want the Display's output surface to hear about lost context, and since
// this shares a context with it (when delegated_sync_points_required is
// false), we should not be listening for lost context callbacks on the
// context here.
if (!capabilities_.delegated_sync_points_required && context_provider())
context_provider()->SetLostContextCallback(base::Closure());
surface_manager_->RegisterSurfaceClientId(surface_id_allocator_->client_id());
surface_manager_->RegisterSurfaceFactoryClient(
surface_id_allocator_->client_id(), this);
display_->Initialize(this, surface_manager_.get(),
surface_id_allocator_->client_id());
bound_ = true;
return true;
}
void TestDelegatingOutputSurface::DetachFromClient() {
// Some tests make BindToClient fail on purpose. ^__^
if (bound_) {
if (!delegated_surface_id_.is_null())
surface_factory_->Destroy(delegated_surface_id_);
surface_manager_->UnregisterSurfaceFactoryClient(
surface_id_allocator_->client_id());
surface_manager_->InvalidateSurfaceClientId(
surface_id_allocator_->client_id());
bound_ = false;
}
display_ = nullptr;
surface_factory_ = nullptr;
surface_id_allocator_ = nullptr;
surface_manager_ = nullptr;
weak_ptrs_.InvalidateWeakPtrs();
OutputSurface::DetachFromClient();
}
void TestDelegatingOutputSurface::SwapBuffers(CompositorFrame frame) {
if (test_client_)
test_client_->DisplayReceivedCompositorFrame(frame);
if (delegated_surface_id_.is_null()) {
delegated_surface_id_ = surface_id_allocator_->GenerateId();
surface_factory_->Create(delegated_surface_id_);
}
display_->SetSurfaceId(delegated_surface_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();
surface_factory_->SubmitCompositorFrame(
delegated_surface_id_, std::move(frame),
base::Bind(&TestDelegatingOutputSurface::DidDrawCallback,
weak_ptrs_.GetWeakPtr(), synchronous));
for (std::unique_ptr<CopyOutputRequest>& copy_request : copy_requests_)
surface_factory_->RequestCopyOfSurface(delegated_surface_id_,
std::move(copy_request));
copy_requests_.clear();
if (synchronous)
display_->DrawAndSwap();
}
void TestDelegatingOutputSurface::DidDrawCallback(bool synchronous) {
// This is the frame ack to unthrottle the next frame, not actually a notice
// that drawing is done.
if (synchronous) {
// For synchronous draws, this must be posted to a new stack because we are
// still the original call to SwapBuffers, and we want to leave that before
// saying that it is done.
OutputSurface::PostSwapBuffersComplete();
} else {
client_->DidSwapBuffersComplete();
}
}
void TestDelegatingOutputSurface::ForceReclaimResources() {
if (capabilities_.can_force_reclaim_resources &&
!delegated_surface_id_.is_null()) {
surface_factory_->SubmitCompositorFrame(delegated_surface_id_,
CompositorFrame(),
SurfaceFactory::DrawCallback());
}
}
void TestDelegatingOutputSurface::BindFramebuffer() {
// This is a delegating output surface, no framebuffer/direct drawing support.
NOTREACHED();
}
uint32_t TestDelegatingOutputSurface::GetFramebufferCopyTextureFormat() {
// This is a delegating output surface, no framebuffer/direct drawing support.
NOTREACHED();
return 0;
}
void TestDelegatingOutputSurface::ReturnResources(
const ReturnedResourceArray& resources) {
client_->ReclaimResources(resources);
}
void TestDelegatingOutputSurface::SetBeginFrameSource(
BeginFrameSource* begin_frame_source) {
client_->SetBeginFrameSource(begin_frame_source);
}
void TestDelegatingOutputSurface::DisplayOutputSurfaceLost() {
DidLoseOutputSurface();
}
void TestDelegatingOutputSurface::DisplaySetMemoryPolicy(
const ManagedMemoryPolicy& policy) {
SetMemoryPolicy(policy);
}
void TestDelegatingOutputSurface::DisplayWillDrawAndSwap(
bool will_draw_and_swap,
const RenderPassList& render_passes) {
if (test_client_)
test_client_->DisplayWillDrawAndSwap(will_draw_and_swap, render_passes);
}
void TestDelegatingOutputSurface::DisplayDidDrawAndSwap() {
if (test_client_)
test_client_->DisplayDidDrawAndSwap();
}
} // namespace cc