| // 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_); |
| |
| 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 |