blob: 024981ce30058148e67b1c612db3350c889273e1 [file] [log] [blame]
// Copyright (c) 2013 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/trees/layer_tree_frame_sink.h"
#include <stdint.h>
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
#include "components/viz/common/gpu/context_lost_observer.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/raster_interface.h"
namespace cc {
class LayerTreeFrameSink::ContextLostForwarder
: public viz::ContextLostObserver {
public:
ContextLostForwarder(base::WeakPtr<LayerTreeFrameSink> frame_sink,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: frame_sink_(frame_sink), task_runner_(std::move(task_runner)) {}
~ContextLostForwarder() override = default;
void OnContextLost() override {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&LayerTreeFrameSink::OnContextLost, frame_sink_));
}
private:
base::WeakPtr<LayerTreeFrameSink> frame_sink_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(ContextLostForwarder);
};
LayerTreeFrameSink::LayerTreeFrameSink(
scoped_refptr<viz::ContextProvider> context_provider,
scoped_refptr<viz::RasterContextProvider> worker_context_provider,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager)
: context_provider_(std::move(context_provider)),
worker_context_provider_(std::move(worker_context_provider)),
compositor_task_runner_(std::move(compositor_task_runner)),
gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
weak_ptr_factory_(this) {
DETACH_FROM_THREAD(thread_checker_);
}
LayerTreeFrameSink::~LayerTreeFrameSink() {
if (client_)
DetachFromClient();
}
base::WeakPtr<LayerTreeFrameSink> LayerTreeFrameSink::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
bool LayerTreeFrameSink::BindToClient(LayerTreeFrameSinkClient* client) {
DCHECK(client);
DCHECK(!client_);
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Note: If |context_provider_| was always bound to a thread before here then
// the return value could be replaced with a PostTask to OnContextLost(). This
// would simplify the calling code so it didn't have to handle failures in
// BindToClient().
if (context_provider_) {
context_provider_->AddObserver(this);
auto result = context_provider_->BindToCurrentThread();
if (result != gpu::ContextResult::kSuccess) {
context_provider_->RemoveObserver(this);
context_provider_ = nullptr;
return false;
}
}
if (worker_context_provider_) {
DCHECK(context_provider_);
DCHECK(compositor_task_runner_);
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
viz::RasterContextProvider::ScopedRasterContextLock lock(
worker_context_provider_.get());
if (lock.RasterInterface()->GetGraphicsResetStatusKHR() != GL_NO_ERROR) {
context_provider_->RemoveObserver(this);
context_provider_ = nullptr;
return false;
}
// Worker context lost callback is called on the main thread so it has to be
// forwarded to compositor thread.
worker_context_lost_forwarder_ = std::make_unique<ContextLostForwarder>(
weak_ptr_factory_.GetWeakPtr(), compositor_task_runner_);
worker_context_provider_->AddObserver(worker_context_lost_forwarder_.get());
}
client_ = client;
return true;
}
void LayerTreeFrameSink::DetachFromClient() {
DCHECK(client_);
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
client_ = nullptr;
weak_ptr_factory_.InvalidateWeakPtrs();
// Do not release worker context provider here as this is called on the
// compositor thread and it must be released on the main thread. However,
// compositor context provider must be released here.
if (context_provider_) {
context_provider_->RemoveObserver(this);
context_provider_ = nullptr;
}
if (worker_context_provider_) {
viz::RasterContextProvider::ScopedRasterContextLock lock(
worker_context_provider_.get());
worker_context_provider_->RemoveObserver(
worker_context_lost_forwarder_.get());
worker_context_lost_forwarder_ = nullptr;
}
}
void LayerTreeFrameSink::OnContextLost() {
DCHECK(client_);
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
TRACE_EVENT0("cc", "LayerTreeFrameSink::OnContextLost");
client_->DidLoseLayerTreeFrameSink();
}
} // namespace cc