Commit 49c92571 authored by Sadrul Habib Chowdhury's avatar Sadrul Habib Chowdhury Committed by Commit Bot

gpu: Retry gpu channel connection in the host.

If establishing a gpu channel fails, then it could be because access to
gpu is not allowed, in which case the client should use software fallback.
If, on the other hand, the failure happens because the gpu process was
killed, or the gpu process crashed, then the attempt to establish the
channel should be retried. But instead of retrying in the clients, retry
in the host, which has better information to know whether a retry attempt
may be successful or not.

Remove the retry logic in the renderer (in RenderWidgetCompositor), since
the host (GpuClient) will be taking care of that.

BUG=609316

Change-Id: Ibcc1d5e79f354ccb282bad2321fca26d1c06402c
Reviewed-on: https://chromium-review.googlesource.com/571490Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Commit-Queue: Sadrul Chowdhury <sadrul@chromium.org>
Cr-Commit-Position: refs/heads/master@{#486835}
parent 5c41b0a0
......@@ -43,6 +43,20 @@ void GpuClient::OnEstablishGpuChannel(
const IPC::ChannelHandle& channel,
const gpu::GPUInfo& gpu_info,
GpuProcessHost::EstablishChannelStatus status) {
if (status == GpuProcessHost::EstablishChannelStatus::GPU_ACCESS_DENIED) {
// GPU access is not allowed. Notify the client immediately.
DCHECK(!channel.mojo_handle.is_valid());
callback.Run(render_process_id_, mojo::ScopedMessagePipeHandle(), gpu_info);
return;
}
if (status == GpuProcessHost::EstablishChannelStatus::GPU_HOST_INVALID) {
// GPU process may have crashed or been killed. Try again.
DCHECK(!channel.mojo_handle.is_valid());
EstablishGpuChannel(callback);
return;
}
DCHECK(channel.mojo_handle.is_valid());
mojo::ScopedMessagePipeHandle channel_handle;
channel_handle.reset(channel.mojo_handle);
callback.Run(render_process_id_, std::move(channel_handle), gpu_info);
......
......@@ -259,8 +259,7 @@ std::unique_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
RenderWidgetCompositor::RenderWidgetCompositor(
RenderWidgetCompositorDelegate* delegate,
CompositorDependencies* compositor_deps)
: num_failed_recreate_attempts_(0),
delegate_(delegate),
: delegate_(delegate),
compositor_deps_(compositor_deps),
threaded_(!!compositor_deps_->GetCompositorImplThreadTaskRunner()),
never_visible_(false),
......@@ -1154,30 +1153,26 @@ void RenderWidgetCompositor::RequestNewLayerTreeFrameSink() {
if (delegate_->IsClosing())
return;
bool fallback = num_failed_recreate_attempts_ >=
LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK;
#ifdef OS_ANDROID
LOG_IF(FATAL, fallback) << "Android does not support fallback frame sinks.";
LOG_IF(FATAL, attempt_software_fallback_)
<< "Android does not support fallback frame sinks.";
#endif
delegate_->RequestNewLayerTreeFrameSink(
fallback, base::Bind(&RenderWidgetCompositor::SetLayerTreeFrameSink,
weak_factory_.GetWeakPtr()));
attempt_software_fallback_,
base::Bind(&RenderWidgetCompositor::SetLayerTreeFrameSink,
weak_factory_.GetWeakPtr()));
}
void RenderWidgetCompositor::DidInitializeLayerTreeFrameSink() {
num_failed_recreate_attempts_ = 0;
attempt_software_fallback_ = false;
}
void RenderWidgetCompositor::DidFailToInitializeLayerTreeFrameSink() {
++num_failed_recreate_attempts_;
// Tolerate a certain number of recreation failures to work around races
// in the output-surface-lost machinery.
LOG_IF(FATAL,
(num_failed_recreate_attempts_ >= MAX_LAYER_TREE_FRAME_SINK_RETRIES))
LOG_IF(FATAL, attempt_software_fallback_)
<< "Failed to create a fallback LayerTreeFrameSink.";
attempt_software_fallback_ = true;
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&RenderWidgetCompositor::RequestNewLayerTreeFrameSink,
......
......@@ -210,11 +210,6 @@ class CONTENT_EXPORT RenderWidgetCompositor
void DidLoseLayerTreeFrameSink() override;
void RequestBeginMainFrameNotExpected(bool new_state) override;
enum {
LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK = 4,
MAX_LAYER_TREE_FRAME_SINK_RETRIES = 5,
};
protected:
friend class RenderViewImplScaleFactorTest;
......@@ -231,7 +226,7 @@ class CONTENT_EXPORT RenderWidgetCompositor
bool CompositeIsSynchronous() const;
void SynchronouslyComposite();
int num_failed_recreate_attempts_;
bool attempt_software_fallback_ = false;
RenderWidgetCompositorDelegate* const delegate_;
CompositorDependencies* const compositor_deps_;
const bool threaded_;
......
......@@ -13,6 +13,7 @@
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "cc/animation/animation_host.h"
#include "cc/output/begin_frame_args.h"
#include "cc/output/copy_output_request.h"
......@@ -34,6 +35,11 @@ using testing::Field;
namespace content {
namespace {
enum FailureMode {
NO_FAILURE,
GPU_CHANNEL_FAILURE,
};
class StubRenderWidgetCompositorDelegate
: public RenderWidgetCompositorDelegate {
public:
......@@ -73,10 +79,6 @@ class FakeRenderWidgetCompositorDelegate
void RequestNewLayerTreeFrameSink(
bool fallback,
const LayerTreeFrameSinkCallback& callback) override {
EXPECT_EQ(num_requests_since_last_success_ >
RenderWidgetCompositor::
LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK,
fallback);
last_create_was_fallback_ = fallback;
bool success = num_failures_ >= num_failures_before_success_;
......@@ -94,6 +96,15 @@ class FakeRenderWidgetCompositorDelegate
cc::FakeLayerTreeFrameSink::Create3d(std::move(context_provider)));
}
void Reset() {
num_requests_ = 0;
num_requests_since_last_success_ = 0;
num_failures_ = 0;
num_failures_before_success_ = 0;
num_fallback_successes_ = 0;
num_successes_ = 0;
}
void add_success() {
if (last_create_was_fallback_)
++num_fallback_successes_;
......@@ -123,9 +134,6 @@ class FakeRenderWidgetCompositorDelegate
void set_use_null_layer_tree_frame_sink(bool u) {
use_null_layer_tree_frame_sink_ = u;
}
bool use_null_layer_tree_frame_sink() const {
return use_null_layer_tree_frame_sink_;
}
private:
int num_requests_ = 0;
......@@ -171,11 +179,11 @@ class RenderWidgetLayerTreeFrameSink : public RenderWidgetCompositor {
}
void DidInitializeLayerTreeFrameSink() override {
RenderWidgetCompositor::DidInitializeLayerTreeFrameSink();
delegate_->add_success();
if (delegate_->num_requests() == expected_requests_) {
EndTest();
} else {
RenderWidgetCompositor::DidInitializeLayerTreeFrameSink();
// Post the synchronous composite task so that it is not called
// reentrantly as a part of RequestNewLayerTreeFrameSink.
base::ThreadTaskRunnerHandle::Get()->PostTask(
......@@ -186,38 +194,48 @@ class RenderWidgetLayerTreeFrameSink : public RenderWidgetCompositor {
}
void DidFailToInitializeLayerTreeFrameSink() override {
RenderWidgetCompositor::DidFailToInitializeLayerTreeFrameSink();
delegate_->add_failure();
if (delegate_->num_requests() == expected_requests_) {
EndTest();
return;
}
RenderWidgetCompositor::DidFailToInitializeLayerTreeFrameSink();
}
void SetUp(int expected_successes, int expected_fallback_succeses) {
void SetUp(int expected_successes, FailureMode failure_mode) {
failure_mode_ = failure_mode;
switch (failure_mode_) {
case NO_FAILURE:
expected_requests_ = 1;
break;
case GPU_CHANNEL_FAILURE:
expected_requests_ = 2;
break;
}
expected_successes_ = expected_successes;
expected_fallback_successes_ = expected_fallback_succeses;
expected_requests_ = delegate_->num_failures_before_success() +
expected_successes_ + expected_fallback_successes_;
expected_requests_ += (expected_successes - 1);
}
void EndTest() { base::MessageLoop::current()->QuitWhenIdle(); }
void AfterTest() {
EXPECT_EQ(delegate_->num_failures_before_success(),
delegate_->num_failures());
EXPECT_EQ(expected_successes_, delegate_->num_successes());
EXPECT_EQ(expected_fallback_successes_,
delegate_->num_fallback_successes());
if (failure_mode_ == NO_FAILURE) {
EXPECT_EQ(expected_successes_, delegate_->num_successes());
EXPECT_EQ(0, delegate_->num_fallback_successes());
} else if (failure_mode_ == GPU_CHANNEL_FAILURE) {
EXPECT_EQ(0, delegate_->num_successes());
EXPECT_EQ(1, delegate_->num_fallback_successes());
} else {
NOTREACHED();
}
EXPECT_EQ(expected_requests_, delegate_->num_requests());
}
private:
FakeRenderWidgetCompositorDelegate* delegate_;
int expected_successes_ = 0;
int expected_fallback_successes_ = 0;
int expected_requests_ = 0;
FailureMode failure_mode_ = NO_FAILURE;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetLayerTreeFrameSink);
};
......@@ -240,15 +258,14 @@ class RenderWidgetLayerTreeFrameSinkTest : public testing::Test {
}
void RunTest(bool use_null_layer_tree_frame_sink,
int num_failures_before_success,
int expected_successes,
int expected_fallback_succeses) {
FailureMode failure_mode) {
compositor_delegate_.Reset();
compositor_delegate_.set_use_null_layer_tree_frame_sink(
use_null_layer_tree_frame_sink);
compositor_delegate_.set_num_failures_before_success(
num_failures_before_success);
render_widget_compositor_.SetUp(expected_successes,
expected_fallback_succeses);
failure_mode == NO_FAILURE ? 0 : 1);
render_widget_compositor_.SetUp(expected_successes, failure_mode);
render_widget_compositor_.SetVisible(true);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
......@@ -270,48 +287,31 @@ class RenderWidgetLayerTreeFrameSinkTest : public testing::Test {
};
TEST_F(RenderWidgetLayerTreeFrameSinkTest, SucceedOnce) {
RunTest(false, 0, 1, 0);
RunTest(false, 1, NO_FAILURE);
}
TEST_F(RenderWidgetLayerTreeFrameSinkTest, SucceedTwice) {
RunTest(false, 0, 2, 0);
RunTest(false, 2, NO_FAILURE);
}
TEST_F(RenderWidgetLayerTreeFrameSinkTest, FailOnceNull) {
static_assert(
RenderWidgetCompositor::LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK >=
2,
"Adjust the values of this test if this fails");
RunTest(true, 1, 1, 0);
}
TEST_F(RenderWidgetLayerTreeFrameSinkTest, FailOnceBind) {
static_assert(
RenderWidgetCompositor::LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK >=
2,
"Adjust the values of this test if this fails");
RunTest(false, 1, 1, 0);
RunTest(true, 1, NO_FAILURE);
}
// Android doesn't support fallback frame sinks. (crbug.com/721102)
#ifndef OS_ANDROID
TEST_F(RenderWidgetLayerTreeFrameSinkTest, FallbackSuccessNull) {
RunTest(true,
RenderWidgetCompositor::LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK,
0, 1);
#if !defined(OS_ANDROID)
TEST_F(RenderWidgetLayerTreeFrameSinkTest, SoftwareFallbackSucceed) {
RunTest(false, 1, GPU_CHANNEL_FAILURE);
}
TEST_F(RenderWidgetLayerTreeFrameSinkTest, FallbackSuccessBind) {
RunTest(false,
RenderWidgetCompositor::LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK,
0, 1);
TEST_F(RenderWidgetLayerTreeFrameSinkTest, FallbackSuccessNull) {
RunTest(true, 1, GPU_CHANNEL_FAILURE);
}
TEST_F(RenderWidgetLayerTreeFrameSinkTest, FallbackSuccessNormalSuccess) {
// The first success is a fallback, but the next should not be a fallback.
RunTest(false,
RenderWidgetCompositor::LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK,
1, 1);
RunTest(false, 1, GPU_CHANNEL_FAILURE);
RunTest(false, 1, NO_FAILURE);
}
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment