Fix hang and failure when GPUProcessHost lives on UI thread.
The first fix is for deadlocks that would happen in content_browsertests shutdown on Windows. This occurred when HostGpuMemoryBufferManager and GpuClient were moved to the UI thread. cc::TileTaskManagerImpl::Shutdown would run on the main thread and it would wait in cc::SingleThreadTaskGraphRunner::WaitForTasksToFinishRunning to cancel existing tasks and to finish running ones. However a running task could have posted a task to the main thread to call HostGpuMemoryBufferManager::AllocateGpuMemoryBuffer and wait on it. Fix this by moving HostGpuMemoryBufferManager back to the IO thread. Since it's tightly coupled with GpuClient, move that along as well.
The previous fix also ensures that HostGpuMemoryBufferManager::IsNativeGpuMemoryBufferConfiguration won't hang on Linux as now it's always called on the IO thread as before.
The second fix is for BrowserGpuChannelHostFactory::EstablishGpuChannelSync failing if there's already a pending async request. Fix this by cancelling the previous async request and calling a synchronous Mojo version of the EstablishChannel method. This was exposed by BrowserGpuChannelHostFactoryTest.AlreadyEstablished.
The third fix is that if EstablishGpuChannelSync was called very early after GPU startup we might not have dispatched GpuHostImpl::DidInitialize. As a result GpuChannelHost would not be constructed with valid GPU infos. Fix this by returning the GPU infos in the EstablishChannel reply. This was exposed by ImageTransportFactoryBrowserTest.TestLostContext.
Bug: 904556
Change-Id: I12ade758ceebaf94d1a4cea6b10de5a03f6f2216
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2827671
Reviewed-by: kylechar <[email protected]>
Reviewed-by: Kenneth Russell <[email protected]>
Reviewed-by: Ken Rockot <[email protected]>
Reviewed-by: Nasko Oskov <[email protected]>
Commit-Queue: John Abd-El-Malek <[email protected]>
Cr-Commit-Position: refs/heads/master@{#873954}
diff --git a/components/viz/host/gpu_host_impl.cc b/components/viz/host/gpu_host_impl.cc
index 0414814..b94d3c4 100644
--- a/components/viz/host/gpu_host_impl.cc
+++ b/components/viz/host/gpu_host_impl.cc
@@ -22,6 +22,7 @@
#include "gpu/config/gpu_info.h"
#include "gpu/ipc/common/gpu_client_ids.h"
#include "gpu/ipc/host/shader_disk_cache.h"
+#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
#include "ui/base/ui_base_features.h"
#include "ui/gfx/font_render_params.h"
@@ -217,6 +218,7 @@
void GpuHostImpl::EstablishGpuChannel(int client_id,
uint64_t client_tracing_id,
bool is_gpu_host,
+ bool sync,
EstablishChannelCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
TRACE_EVENT0("gpu", "GpuHostImpl::EstablishGpuChannel");
@@ -244,16 +246,36 @@
bool cache_shaders_on_disk =
delegate_->GetShaderCacheFactory()->Get(client_id) != nullptr;
- channel_requests_.push(std::move(callback));
- gpu_service_remote_->EstablishGpuChannel(
- client_id, client_tracing_id, is_gpu_host, cache_shaders_on_disk,
- base::BindOnce(&GpuHostImpl::OnChannelEstablished,
- weak_ptr_factory_.GetWeakPtr(), client_id));
+ channel_requests_[client_id] = std::move(callback);
+ if (sync) {
+ mojo::ScopedMessagePipeHandle channel_handle;
+ gpu::GPUInfo gpu_info;
+ gpu::GpuFeatureInfo gpu_feature_info;
+ {
+ mojo::SyncCallRestrictions::ScopedAllowSyncCall scoped_allow;
+ gpu_service_remote_->EstablishGpuChannel(
+ client_id, client_tracing_id, is_gpu_host, cache_shaders_on_disk,
+ &channel_handle, &gpu_info, &gpu_feature_info);
+ }
+ OnChannelEstablished(client_id, true, std::move(channel_handle), gpu_info,
+ gpu_feature_info);
+ } else {
+ gpu_service_remote_->EstablishGpuChannel(
+ client_id, client_tracing_id, is_gpu_host, cache_shaders_on_disk,
+ base::BindOnce(&GpuHostImpl::OnChannelEstablished,
+ weak_ptr_factory_.GetWeakPtr(), client_id, false));
+ }
if (!params_.disable_gpu_shader_disk_cache)
CreateChannelCache(client_id);
}
+void GpuHostImpl::CloseChannel(int client_id) {
+ gpu_service_remote_->CloseChannel(client_id);
+
+ channel_requests_.erase(client_id);
+}
+
void GpuHostImpl::SendOutstandingReplies() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -262,13 +284,12 @@
connection_error_handlers_.clear();
// Send empty channel handles for all EstablishChannel requests.
- while (!channel_requests_.empty()) {
- auto callback = std::move(channel_requests_.front());
- channel_requests_.pop();
- std::move(callback).Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
- gpu::GpuFeatureInfo(),
- EstablishChannelStatus::kGpuHostInvalid);
+ for (auto& entry : channel_requests_) {
+ std::move(entry.second)
+ .Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
+ gpu::GpuFeatureInfo(), EstablishChannelStatus::kGpuHostInvalid);
}
+ channel_requests_.clear();
}
void GpuHostImpl::BindInterface(const std::string& interface_name,
@@ -371,13 +392,19 @@
void GpuHostImpl::OnChannelEstablished(
int client_id,
- mojo::ScopedMessagePipeHandle channel_handle) {
+ bool sync,
+ mojo::ScopedMessagePipeHandle channel_handle,
+ const gpu::GPUInfo& gpu_info,
+ const gpu::GpuFeatureInfo& gpu_feature_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
TRACE_EVENT0("gpu", "GpuHostImpl::OnChannelEstablished");
- DCHECK(!channel_requests_.empty());
- auto callback = std::move(channel_requests_.front());
- channel_requests_.pop();
+ auto it = channel_requests_.find(client_id);
+ if (it == channel_requests_.end())
+ return;
+
+ auto callback = std::move(it->second);
+ channel_requests_.erase(it);
// Currently if any of the GPU features are blocklisted, we don't establish a
// GPU channel.
@@ -391,9 +418,19 @@
return;
}
- std::move(callback).Run(std::move(channel_handle), delegate_->GetGPUInfo(),
- delegate_->GetGpuFeatureInfo(),
- EstablishChannelStatus::kSuccess);
+ // TODO(jam): always use GPUInfo & GpuFeatureInfo from the service once we
+ // know there's no issue with the ProcessHostOnUI which is the only mode
+ // that currently uses it. This is because in that mode the sync mojo call
+ // in the caller means we won't get the async DidInitialize() call before
+ // this point, so the delegate_ methods won't have the GPU info structs yet.
+ if (sync) {
+ std::move(callback).Run(std::move(channel_handle), gpu_info,
+ gpu_feature_info, EstablishChannelStatus::kSuccess);
+ } else {
+ std::move(callback).Run(std::move(channel_handle), delegate_->GetGPUInfo(),
+ delegate_->GetGpuFeatureInfo(),
+ EstablishChannelStatus::kSuccess);
+ }
}
void GpuHostImpl::DidInitialize(