summaryrefslogtreecommitdiffstats
path: root/content/browser/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/gpu')
-rw-r--r--content/browser/gpu/browser_gpu_channel_host_factory.cc248
-rw-r--r--content/browser/gpu/browser_gpu_channel_host_factory.h58
-rw-r--r--content/browser/gpu/gpu_ipc_browsertests.cc147
3 files changed, 350 insertions, 103 deletions
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc
index 7bc6fca..8de6d11 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -5,6 +5,7 @@
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "base/bind.h"
+#include "base/debug/trace_event.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
@@ -20,7 +21,7 @@ namespace content {
BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
BrowserGpuChannelHostFactory::CreateRequest::CreateRequest()
- : event(false, false),
+ : event(true, false),
gpu_host_id(0),
route_id(MSG_ROUTING_NONE) {
}
@@ -29,32 +30,137 @@ BrowserGpuChannelHostFactory::CreateRequest::~CreateRequest() {
}
BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
- CauseForGpuLaunch cause)
- : event(false, false),
- cause_for_gpu_launch(cause),
- gpu_host_id(0),
- reused_gpu_process(true) {
+ CauseForGpuLaunch cause,
+ int gpu_client_id,
+ int gpu_host_id)
+ : event_(false, false),
+ cause_for_gpu_launch_(cause),
+ gpu_client_id_(gpu_client_id),
+ gpu_host_id_(gpu_host_id),
+ reused_gpu_process_(false),
+ finished_(false),
+ main_loop_(base::MessageLoopProxy::current()) {
+ scoped_refptr<base::MessageLoopProxy> loop =
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
+ loop->PostTask(
+ FROM_HERE,
+ base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
+ this));
}
BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() {
}
-void BrowserGpuChannelHostFactory::Initialize() {
- instance_ = new BrowserGpuChannelHostFactory();
+void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
+ GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
+ if (!host) {
+ host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ cause_for_gpu_launch_);
+ if (!host) {
+ FinishOnIO();
+ return;
+ }
+ gpu_host_id_ = host->host_id();
+ reused_gpu_process_ = false;
+ } else {
+ if (reused_gpu_process_) {
+ // We come here if we retried to establish the channel because of a
+ // failure in ChannelEstablishedOnIO, but we ended up with the same
+ // process ID, meaning the failure was not because of a channel error,
+ // but another reason. So fail now.
+ FinishOnIO();
+ return;
+ }
+ reused_gpu_process_ = true;
+ }
+
+ host->EstablishGpuChannel(
+ gpu_client_id_,
+ true,
+ base::Bind(
+ &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
+ this));
+}
+
+void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
+ const IPC::ChannelHandle& channel_handle,
+ const gpu::GPUInfo& gpu_info) {
+ if (channel_handle.name.empty() && reused_gpu_process_) {
+ // We failed after re-using the GPU process, but it may have died in the
+ // mean time. Retry to have a chance to create a fresh GPU process.
+ EstablishOnIO();
+ } else {
+ channel_handle_ = channel_handle;
+ gpu_info_ = gpu_info;
+ FinishOnIO();
+ }
+}
+
+void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
+ event_.Signal();
+ main_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
+ this));
+}
+
+void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
+ if (!finished_) {
+ BrowserGpuChannelHostFactory* factory =
+ BrowserGpuChannelHostFactory::instance();
+ factory->GpuChannelEstablished();
+ finished_ = true;
+ }
+}
+
+void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
+ DCHECK(main_loop_->BelongsToCurrentThread());
+ {
+ // We're blocking the UI thread, which is generally undesirable.
+ // In this case we need to wait for this before we can show any UI
+ // /anyway/, so it won't cause additional jank.
+ // TODO(piman): Make this asynchronous (http://crbug.com/125248).
+ TRACE_EVENT0("browser",
+ "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
+ base::ThreadRestrictions::ScopedAllowWait allow_wait;
+ event_.Wait();
+ }
+ FinishOnMain();
+}
+
+void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
+ DCHECK(main_loop_->BelongsToCurrentThread());
+ finished_ = true;
+}
+
+void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
+ DCHECK(!instance_);
+ instance_ = new BrowserGpuChannelHostFactory(establish_gpu_channel);
}
void BrowserGpuChannelHostFactory::Terminate() {
+ DCHECK(instance_);
delete instance_;
instance_ = NULL;
}
-BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
+BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory(
+ bool establish_gpu_channel)
: gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
shutdown_event_(new base::WaitableEvent(true, false)),
gpu_host_id_(0) {
+ if (establish_gpu_channel) {
+ pending_request_ = new EstablishRequest(
+ CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP, gpu_client_id_, gpu_host_id_);
+ }
}
BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
+ DCHECK(IsMainThread());
+ if (pending_request_)
+ pending_request_->Cancel();
+ for (size_t n = 0; n < established_callbacks_.size(); n++)
+ established_callbacks_[n].Run();
shutdown_event_->Signal();
}
@@ -126,6 +232,8 @@ int32 BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
// In this case we need to wait for this before we can show any UI /anyway/,
// so it won't cause additional jank.
// TODO(piman): Make this asynchronous (http://crbug.com/125248).
+ TRACE_EVENT0("browser",
+ "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
base::ThreadRestrictions::ScopedAllowWait allow_wait;
request.event.Wait();
return request.route_id;
@@ -197,91 +305,65 @@ void BrowserGpuChannelHostFactory::DeleteImage(
sync_point));
}
-void BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO(
- EstablishRequest* request) {
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
- if (!host) {
- host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- request->cause_for_gpu_launch);
- if (!host) {
- request->event.Signal();
- return;
- }
- gpu_host_id_ = host->host_id();
- request->reused_gpu_process = false;
- } else {
- if (host->host_id() == request->gpu_host_id) {
- // We come here if we retried to establish the channel because of a
- // failure in GpuChannelEstablishedOnIO, but we ended up with the same
- // process ID, meaning the failure was not because of a channel error, but
- // another reason. So fail now.
- request->event.Signal();
- return;
- }
- request->reused_gpu_process = true;
- }
- request->gpu_host_id = gpu_host_id_;
+GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
+ CauseForGpuLaunch cause_for_gpu_launch) {
+ EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
- host->EstablishGpuChannel(
- gpu_client_id_,
- true,
- base::Bind(&BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO,
- base::Unretained(this),
- request));
-}
+ if (pending_request_)
+ pending_request_->Wait();
-void BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO(
- EstablishRequest* request,
- const IPC::ChannelHandle& channel_handle,
- const gpu::GPUInfo& gpu_info) {
- if (channel_handle.name.empty() && request->reused_gpu_process) {
- // We failed after re-using the GPU process, but it may have died in the
- // mean time. Retry to have a chance to create a fresh GPU process.
- EstablishGpuChannelOnIO(request);
- } else {
- request->channel_handle = channel_handle;
- request->gpu_info = gpu_info;
- request->event.Signal();
- }
+ return gpu_channel_.get();
}
-GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
- CauseForGpuLaunch cause_for_gpu_launch) {
- if (gpu_channel_.get()) {
+void BrowserGpuChannelHostFactory::EstablishGpuChannel(
+ CauseForGpuLaunch cause_for_gpu_launch,
+ const base::Closure& callback) {
+ if (gpu_channel_.get() && gpu_channel_->IsLost()) {
+ DCHECK(!pending_request_);
// Recreate the channel if it has been lost.
- if (gpu_channel_->IsLost())
- gpu_channel_ = NULL;
- else
- return gpu_channel_.get();
+ gpu_channel_ = NULL;
}
- // Ensure initialization on the main thread.
- GpuDataManagerImpl::GetInstance();
- EstablishRequest request(cause_for_gpu_launch);
- GetIOLoopProxy()->PostTask(
- FROM_HERE,
- base::Bind(
- &BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO,
- base::Unretained(this),
- &request));
+ if (!gpu_channel_ && !pending_request_) {
+ // We should only get here if the context was lost.
+ pending_request_ = new EstablishRequest(
+ cause_for_gpu_launch, gpu_client_id_, gpu_host_id_);
+ }
- {
- // We're blocking the UI thread, which is generally undesirable.
- // In this case we need to wait for this before we can show any UI /anyway/,
- // so it won't cause additional jank.
- // TODO(piman): Make this asynchronous (http://crbug.com/125248).
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- request.event.Wait();
+ if (!callback.is_null()) {
+ if (gpu_channel_)
+ callback.Run();
+ else
+ established_callbacks_.push_back(callback);
}
+}
- if (request.channel_handle.name.empty())
- return NULL;
+GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
+ if (gpu_channel_ && !gpu_channel_->IsLost())
+ return gpu_channel_;
- GetContentClient()->SetGpuInfo(request.gpu_info);
- gpu_channel_ = GpuChannelHost::Create(
- this, request.gpu_host_id, gpu_client_id_,
- request.gpu_info, request.channel_handle);
- return gpu_channel_.get();
+ return NULL;
+}
+
+void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
+ DCHECK(IsMainThread());
+ DCHECK(pending_request_);
+ if (pending_request_->channel_handle().name.empty())
+ return;
+
+ GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
+ gpu_channel_ = GpuChannelHost::Create(this,
+ pending_request_->gpu_host_id(),
+ gpu_client_id_,
+ pending_request_->gpu_info(),
+ pending_request_->channel_handle());
+ gpu_host_id_ = pending_request_->gpu_host_id();
+ pending_request_ = NULL;
+
+ for (size_t n = 0; n < established_callbacks_.size(); n++)
+ established_callbacks_[n].Run();
+
+ established_callbacks_.clear();
}
// static
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.h b/content/browser/gpu/browser_gpu_channel_host_factory.h
index ca31183..1944155 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.h
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_GPU_BROWSER_GPU_CHANNEL_HOST_FACTORY_H_
#define CONTENT_BROWSER_GPU_BROWSER_GPU_CHANNEL_HOST_FACTORY_H_
+#include <vector>
+
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/process.h"
@@ -17,7 +19,7 @@ namespace content {
class CONTENT_EXPORT BrowserGpuChannelHostFactory
: public GpuChannelHostFactory {
public:
- static void Initialize();
+ static void Initialize(bool establish_gpu_channel);
static void Terminate();
static BrowserGpuChannelHostFactory* instance() { return instance_; }
@@ -36,8 +38,6 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
int32 image_id,
const CreateImageCallback& callback) OVERRIDE;
virtual void DeleteImage(int32 image_idu, int32 sync_point) OVERRIDE;
- virtual GpuChannelHost* EstablishGpuChannelSync(
- CauseForGpuLaunch cause_for_gpu_launch) OVERRIDE;
// Specify a task runner and callback to be used for a set of messages. The
// callback will be set up on the current GpuProcessHost, identified by
@@ -48,6 +48,11 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
const base::Callback<void(const IPC::Message&)>& handler,
base::TaskRunner* target_task_runner);
int GpuProcessHostId() { return gpu_host_id_; }
+ GpuChannelHost* EstablishGpuChannelSync(
+ CauseForGpuLaunch cause_for_gpu_launch);
+ void EstablishGpuChannel(CauseForGpuLaunch cause_for_gpu_launch,
+ const base::Closure& callback);
+ GpuChannelHost* GetGpuChannel();
private:
struct CreateRequest {
@@ -58,20 +63,42 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
int32 route_id;
};
- struct EstablishRequest {
- explicit EstablishRequest(CauseForGpuLaunch);
+ class EstablishRequest : public base::RefCountedThreadSafe<EstablishRequest> {
+ public:
+ explicit EstablishRequest(CauseForGpuLaunch cause,
+ int gpu_client_id,
+ int gpu_host_id);
+ void Wait();
+ void Cancel();
+
+ int gpu_host_id() { return gpu_host_id_; }
+ IPC::ChannelHandle& channel_handle() { return channel_handle_; }
+ gpu::GPUInfo gpu_info() { return gpu_info_; }
+
+ private:
+ friend class base::RefCountedThreadSafe<EstablishRequest>;
~EstablishRequest();
- base::WaitableEvent event;
- CauseForGpuLaunch cause_for_gpu_launch;
- int gpu_host_id;
- bool reused_gpu_process;
- IPC::ChannelHandle channel_handle;
- gpu::GPUInfo gpu_info;
+ void EstablishOnIO();
+ void OnEstablishedOnIO(const IPC::ChannelHandle& channel_handle,
+ const gpu::GPUInfo& gpu_info);
+ void FinishOnIO();
+ void FinishOnMain();
+
+ base::WaitableEvent event_;
+ CauseForGpuLaunch cause_for_gpu_launch_;
+ int gpu_client_id_;
+ int gpu_host_id_;
+ bool reused_gpu_process_;
+ IPC::ChannelHandle channel_handle_;
+ gpu::GPUInfo gpu_info_;
+ bool finished_;
+ scoped_refptr<base::MessageLoopProxy> main_loop_;
};
- BrowserGpuChannelHostFactory();
+ explicit BrowserGpuChannelHostFactory(bool establish_gpu_channel);
virtual ~BrowserGpuChannelHostFactory();
+ void GpuChannelEstablished();
void CreateViewCommandBufferOnIO(
CreateRequest* request,
int32 surface_id,
@@ -86,11 +113,6 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
static void OnImageCreated(
const CreateImageCallback& callback, const gfx::Size size);
void DeleteImageOnIO(int32 image_id, int32 sync_point);
- void EstablishGpuChannelOnIO(EstablishRequest* request);
- void GpuChannelEstablishedOnIO(
- EstablishRequest* request,
- const IPC::ChannelHandle& channel_handle,
- const gpu::GPUInfo& gpu_info);
static void AddFilterOnIO(
int gpu_host_id,
scoped_refptr<IPC::ChannelProxy::MessageFilter> filter);
@@ -99,6 +121,8 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
scoped_ptr<base::WaitableEvent> shutdown_event_;
scoped_refptr<GpuChannelHost> gpu_channel_;
int gpu_host_id_;
+ scoped_refptr<EstablishRequest> pending_request_;
+ std::vector<base::Closure> established_callbacks_;
static BrowserGpuChannelHostFactory* instance_;
diff --git a/content/browser/gpu/gpu_ipc_browsertests.cc b/content/browser/gpu/gpu_ipc_browsertests.cc
index 0ee93db..3fda855 100644
--- a/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -3,8 +3,13 @@
// found in the LICENSE file.
#include "base/command_line.h"
+#include "base/run_loop.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
+#include "content/browser/gpu/gpu_process_host_ui_shim.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
+#include "content/common/gpu/gpu_process_launch_causes.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "content/test/content_browser_test.h"
#include "ui/gl/gl_switches.h"
@@ -15,10 +20,19 @@ namespace {
class ContextTestBase : public content::ContentBrowserTest {
public:
virtual void SetUpOnMainThread() OVERRIDE {
- CHECK(content::BrowserGpuChannelHostFactory::instance());
+ if (!content::BrowserGpuChannelHostFactory::instance())
+ content::BrowserGpuChannelHostFactory::Initialize(true);
+
+ content::BrowserGpuChannelHostFactory* factory =
+ content::BrowserGpuChannelHostFactory::instance();
+ CHECK(factory);
+ scoped_refptr<content::GpuChannelHost> gpu_channel_host(
+ factory->EstablishGpuChannelSync(
+ content::
+ CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
context_.reset(
content::WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
- content::BrowserGpuChannelHostFactory::instance(),
+ gpu_channel_host.get(),
WebKit::WebGraphicsContext3D::Attributes(),
GURL()));
CHECK(context_.get());
@@ -38,6 +52,133 @@ class ContextTestBase : public content::ContentBrowserTest {
} // namespace
-// Include the actual tests.
+// Include the shared tests.
#define CONTEXT_TEST_F IN_PROC_BROWSER_TEST_F
#include "content/common/gpu/client/gpu_context_tests.h"
+
+namespace content {
+
+class BrowserGpuChannelHostFactoryTest : public ContextTestBase {
+ public:
+ virtual void SetUpOnMainThread() OVERRIDE {
+ // Start all tests without a gpu channel so that the tests exercise a
+ // consistent codepath.
+ if (!content::BrowserGpuChannelHostFactory::instance())
+ content::BrowserGpuChannelHostFactory::Initialize(false);
+
+ CHECK(GetFactory());
+
+ ContentBrowserTest::SetUpOnMainThread();
+ }
+
+ virtual void TearDownOnMainThread() OVERRIDE {
+ ContextTestBase::TearDownOnMainThread();
+ }
+
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ // Start all tests without a gpu channel so that the tests exercise a
+ // consistent codepath.
+ command_line->AppendSwitch(switches::kDisableGpuProcessPrelaunch);
+ }
+
+ void OnContextLost(const base::Closure callback, int* counter) {
+ (*counter)++;
+ callback.Run();
+ }
+
+ protected:
+ BrowserGpuChannelHostFactory* GetFactory() {
+ return BrowserGpuChannelHostFactory::instance();
+ }
+
+ bool IsChannelEstablished() {
+ return GetFactory()->GetGpuChannel() != NULL;
+ }
+
+ void EstablishAndWait() {
+ base::RunLoop run_loop;
+ GetFactory()->EstablishGpuChannel(
+ CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
+ run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
+ GpuChannelHost* GetGpuChannel() {
+ return GetFactory()->GetGpuChannel();
+ }
+
+ static void Signal(bool *event) {
+ CHECK_EQ(*event, false);
+ *event = true;
+ }
+
+ scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContext() {
+ return make_scoped_ptr(
+ WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
+ GetGpuChannel(),
+ WebKit::WebGraphicsContext3D::Attributes(),
+ GURL()));
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, Basic) {
+ DCHECK(!IsChannelEstablished());
+ EstablishAndWait();
+ EXPECT_TRUE(GetGpuChannel() != NULL);
+}
+
+IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
+ EstablishAndTerminate) {
+ DCHECK(!IsChannelEstablished());
+ base::RunLoop run_loop;
+ GetFactory()->EstablishGpuChannel(
+ CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
+ run_loop.QuitClosure());
+ GetFactory()->Terminate();
+
+ // The callback should still trigger.
+ run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, AlreadyEstablished) {
+ DCHECK(!IsChannelEstablished());
+ scoped_refptr<GpuChannelHost> gpu_channel =
+ GetFactory()->EstablishGpuChannelSync(
+ CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE);
+
+ // Expect established callback immediately.
+ bool event = false;
+ GetFactory()->EstablishGpuChannel(
+ CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
+ base::Bind(&BrowserGpuChannelHostFactoryTest::Signal, &event));
+ EXPECT_TRUE(event);
+ EXPECT_EQ(gpu_channel, GetGpuChannel());
+}
+
+IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, CrashAndRecover) {
+ DCHECK(!IsChannelEstablished());
+ EstablishAndWait();
+ scoped_refptr<GpuChannelHost> host = GetGpuChannel();
+
+ scoped_refptr<ContextProviderCommandBuffer> provider =
+ ContextProviderCommandBuffer::Create(CreateContext(),
+ "BrowserGpuChannelHostFactoryTest");
+ base::RunLoop run_loop;
+ int counter = 0;
+ provider->SetLostContextCallback(
+ base::Bind(&BrowserGpuChannelHostFactoryTest::OnContextLost,
+ base::Unretained(this), run_loop.QuitClosure(), &counter));
+ EXPECT_TRUE(provider->BindToCurrentThread());
+ GpuProcessHostUIShim* shim =
+ GpuProcessHostUIShim::FromID(GetFactory()->GpuProcessHostId());
+ EXPECT_TRUE(shim != NULL);
+ shim->SimulateCrash();
+ run_loop.Run();
+
+ EXPECT_EQ(1, counter);
+ EXPECT_FALSE(IsChannelEstablished());
+ EstablishAndWait();
+ EXPECT_TRUE(IsChannelEstablished());
+}
+
+} // namespace content