blob: 44a99d512bd12d6b3975738e11e6bf5ecafc109d [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// 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 <utility>
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/trace_event.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
#include "components/viz/common/features.h"
#include "components/viz/common/gpu/context_lost_observer.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/ipc/client/client_shared_image_interface.h"
#include "gpu/ipc/client/gpu_channel_host.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(const ContextLostForwarder&) = delete;
~ContextLostForwarder() override = default;
ContextLostForwarder& operator=(const ContextLostForwarder&) = delete;
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_;
};
LayerTreeFrameSink::LayerTreeFrameSink(
scoped_refptr<viz::RasterContextProvider> context_provider,
scoped_refptr<RasterContextProviderWrapper> worker_context_provider_wrapper,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
scoped_refptr<gpu::ClientSharedImageInterface> shared_image_interface)
: context_provider_(std::move(context_provider)),
worker_context_provider_wrapper_(
std::move(worker_context_provider_wrapper)),
compositor_task_runner_(std::move(compositor_task_runner)),
gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
shared_image_interface_(std::move(shared_image_interface)) {
DETACH_FROM_THREAD(thread_checker_);
if (!base::FeatureList::IsEnabled(features::kSharedBitmapToSharedImage)) {
shared_image_interface_.reset();
}
}
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_->BindToCurrentSequence();
if (result != gpu::ContextResult::kSuccess) {
context_provider_->RemoveObserver(this);
context_provider_ = nullptr;
return false;
}
}
if (auto* worker_context_provider_ptr = worker_context_provider()) {
DCHECK(context_provider_);
DCHECK(compositor_task_runner_);
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
viz::RasterContextProvider::ScopedRasterContextLock lock(
worker_context_provider_ptr);
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_ptr->AddObserver(
worker_context_lost_forwarder_.get());
}
// Add GpuChannelLost observer
if (shared_image_interface_ &&
(!context_provider_ && !worker_context_provider())) {
client_task_runner_ = base::SingleThreadTaskRunner::GetCurrentDefault();
shared_image_interface_->gpu_channel()->AddObserver(this);
}
client_ = client;
return true;
}
void LayerTreeFrameSink::DetachFromClient() {
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_lost_forwarder_) {
auto* worker_context_provider_ptr = worker_context_provider();
CHECK(worker_context_provider_ptr);
viz::RasterContextProvider::ScopedRasterContextLock lock(
worker_context_provider_ptr);
worker_context_provider_ptr->RemoveObserver(
worker_context_lost_forwarder_.get());
worker_context_lost_forwarder_ = nullptr;
}
if (client_task_runner_ && shared_image_interface_) {
shared_image_interface_->gpu_channel()->RemoveObserver(this);
shared_image_interface_.reset();
client_task_runner_.reset();
}
}
void LayerTreeFrameSink::OnContextLost() {
DCHECK(client_);
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
TRACE_EVENT0("cc", "LayerTreeFrameSink::OnContextLost");
shared_image_interface_.reset();
client_->DidLoseLayerTreeFrameSink();
}
void LayerTreeFrameSink::OnGpuChannelLost() {
// OnGpuChannelLost() is called on the IOThread. so it has to be forwareded
// to the same thread where BindToClient is called, either the BrowserMain
// thread or the compositor thread.
DCHECK(client_task_runner_);
if (base::SingleThreadTaskRunner::GetCurrentDefault() !=
client_task_runner_) {
client_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&LayerTreeFrameSink::OnGpuChannelLost, GetWeakPtr()));
return;
}
// No need to RemoveObserver(). The Observable removes all observers
// after completing GpuChannelLost notification.
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
shared_image_interface_.reset();
client_task_runner_.reset();
DCHECK(client_);
client_->DidLoseLayerTreeFrameSink();
}
scoped_refptr<gpu::ClientSharedImageInterface>
LayerTreeFrameSink::shared_image_interface() const {
return base::FeatureList::IsEnabled(features::kSharedBitmapToSharedImage)
? shared_image_interface_
: nullptr;
}
} // namespace cc