summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorpiman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-08 23:46:29 +0000
committerpiman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-08 23:46:29 +0000
commit03dc888f5d0e636fd4e55f8f04bb635bfad29b42 (patch)
treeaecd43e4ceb1ba8f9e3bcd3c19a1fd8584489291 /content
parent10618f2764fb9cfc6fc3cc266d928a9731c0afbc (diff)
downloadchromium_src-03dc888f5d0e636fd4e55f8f04bb635bfad29b42.zip
chromium_src-03dc888f5d0e636fd4e55f8f04bb635bfad29b42.tar.gz
chromium_src-03dc888f5d0e636fd4e55f8f04bb635bfad29b42.tar.bz2
Aura: recover from lost context / GPU process dying
For recovery from lost contexts, we need to: - on the UI thread, recreate the compositing surfaces (since they are textures in the UI compositor context that we lost). - on the IO thread, delay the requests from the renderer process to create view contexts, until the above has happened. BUG=116394,116839 TEST=chrome --ui-use-gpu-process --force-compositing-mode, kill GPU process, check everything still works Review URL: http://codereview.chromium.org/9632005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125727 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/gpu/browser_gpu_channel_host_factory.cc2
-rw-r--r--content/browser/renderer_host/gpu_message_filter.cc51
-rw-r--r--content/browser/renderer_host/gpu_message_filter.h12
-rw-r--r--content/browser/renderer_host/image_transport_factory.cc110
-rw-r--r--content/browser/renderer_host/image_transport_factory.h15
-rw-r--r--content/browser/renderer_host/mock_render_process_host.cc3
-rw-r--r--content/browser/renderer_host/mock_render_process_host.h1
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc14
-rw-r--r--content/browser/renderer_host/render_process_host_impl.h10
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.cc6
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.h4
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.cc19
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.h7
-rw-r--r--content/common/gpu/client/content_gl_context.cc4
-rw-r--r--content/common/gpu/client/content_gl_context.h4
-rw-r--r--content/common/gpu/client/gpu_channel_host.cc4
-rw-r--r--content/common/gpu/client/gpu_channel_host.h6
-rw-r--r--content/common/gpu/gpu_messages.h1
-rw-r--r--content/public/browser/render_process_host.h5
-rw-r--r--content/renderer/render_thread_impl.cc2
20 files changed, 250 insertions, 30 deletions
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc
index a448615..687ef0c 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -207,7 +207,7 @@ GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
browser_process_for_gpu = base::GetCurrentProcessHandle();
#endif
- gpu_channel_ = new GpuChannelHost(this, gpu_client_id_);
+ gpu_channel_ = new GpuChannelHost(this, gpu_host_id_, gpu_client_id_);
gpu_channel_->set_gpu_info(request.gpu_info);
content::GetContentClient()->SetGpuInfo(request.gpu_info);
diff --git a/content/browser/renderer_host/gpu_message_filter.cc b/content/browser/renderer_host/gpu_message_filter.cc
index 9776cbe..0bb8b70 100644
--- a/content/browser/renderer_host/gpu_message_filter.cc
+++ b/content/browser/renderer_host/gpu_message_filter.cc
@@ -20,9 +20,23 @@
using content::BrowserThread;
+struct GpuMessageFilter::CreateViewCommandBufferRequest {
+ CreateViewCommandBufferRequest(
+ int32 surface_id_,
+ const GPUCreateCommandBufferConfig& init_params_,
+ IPC::Message* reply_)
+ : surface_id(surface_id_),
+ init_params(init_params_),
+ reply(reply_) {
+ }
+ int32 surface_id;
+ GPUCreateCommandBufferConfig init_params;
+ IPC::Message* reply;
+};
+
GpuMessageFilter::GpuMessageFilter(int render_process_id,
RenderWidgetHelper* render_widget_helper)
- : gpu_host_id_(0),
+ : gpu_process_id_(0),
render_process_id_(render_process_id),
share_contexts_(false),
render_widget_helper_(render_widget_helper) {
@@ -54,6 +68,24 @@ bool GpuMessageFilter::OnMessageReceived(
return handled;
}
+void GpuMessageFilter::SurfaceUpdated(int32 surface_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ typedef std::vector<linked_ptr<CreateViewCommandBufferRequest> > RequestList;
+ RequestList retry_requests;
+ retry_requests.swap(pending_requests_);
+ for (RequestList::iterator it = retry_requests.begin();
+ it != retry_requests.end(); ++it) {
+ if ((*it)->surface_id != surface_id) {
+ pending_requests_.push_back(*it);
+ } else {
+ linked_ptr<CreateViewCommandBufferRequest> request = *it;
+ OnCreateViewCommandBuffer(request->surface_id,
+ request->init_params,
+ request->reply);
+ }
+ }
+}
+
void GpuMessageFilter::OnEstablishGpuChannel(
content::CauseForGpuLaunch cause_for_gpu_launch,
IPC::Message* reply) {
@@ -66,7 +98,7 @@ void GpuMessageFilter::OnEstablishGpuChannel(
// terminates, the renderer process will not find itself unknowingly sending
// IPCs to a newly launched GPU process. Also, I will rename this function
// to something like OnCreateGpuProcess.
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
+ GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
if (!host) {
host = GpuProcessHost::GetForClient(
render_process_id_, cause_for_gpu_launch);
@@ -76,7 +108,7 @@ void GpuMessageFilter::OnEstablishGpuChannel(
return;
}
- gpu_host_id_ = host->host_id();
+ gpu_process_id_ = host->host_id();
}
host->EstablishGpuChannel(
@@ -107,7 +139,18 @@ void GpuMessageFilter::OnCreateViewCommandBuffer(
<< " tried to access a surface for renderer " << renderer_id;
}
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
+ if (compositing_surface.parent_gpu_process_id &&
+ compositing_surface.parent_gpu_process_id != gpu_process_id_) {
+ // If the current handle for the surface is using a different (older) gpu
+ // host, it means the GPU process died and we need to wait until the UI
+ // re-allocates the surface in the new process.
+ linked_ptr<CreateViewCommandBufferRequest> request(
+ new CreateViewCommandBufferRequest(surface_id, init_params, reply));
+ pending_requests_.push_back(request);
+ return;
+ }
+
+ GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
if (!host || compositing_surface.is_null()) {
// TODO(apatrick): Eventually, this IPC message will be routed to a
// GpuProcessStub with a particular routing ID. The error will be set if
diff --git a/content/browser/renderer_host/gpu_message_filter.h b/content/browser/renderer_host/gpu_message_filter.h
index ea2adb3..aafeeca 100644
--- a/content/browser/renderer_host/gpu_message_filter.h
+++ b/content/browser/renderer_host/gpu_message_filter.h
@@ -6,6 +6,9 @@
#define CONTENT_BROWSER_RENDERER_HOST_GPU_MESSAGE_FILTER_H_
#pragma once
+#include <vector>
+
+#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop_helpers.h"
@@ -34,9 +37,15 @@ class GpuMessageFilter : public content::BrowserMessageFilter,
virtual bool OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) OVERRIDE;
+ // Signals that the handle for a surface id was updated, and it may be time to
+ // unblock existing CreateViewCommandBuffer requests using that surface.
+ void SurfaceUpdated(int32 surface_id);
+
private:
friend class content::BrowserThread;
friend class base::DeleteHelper<GpuMessageFilter>;
+ struct CreateViewCommandBufferRequest;
+
virtual ~GpuMessageFilter();
// Message handlers called on the browser IO thread:
@@ -53,11 +62,12 @@ class GpuMessageFilter : public content::BrowserMessageFilter,
const content::GPUInfo& gpu_info);
void CreateCommandBufferCallback(IPC::Message* reply, int32 route_id);
- int gpu_host_id_;
+ int gpu_process_id_;
int render_process_id_;
bool share_contexts_;
scoped_refptr<RenderWidgetHelper> render_widget_helper_;
+ std::vector<linked_ptr<CreateViewCommandBufferRequest> > pending_requests_;
DISALLOW_COPY_AND_ASSIGN(GpuMessageFilter);
};
diff --git a/content/browser/renderer_host/image_transport_factory.cc b/content/browser/renderer_host/image_transport_factory.cc
index 0cebe4b..cb074a5 100644
--- a/content/browser/renderer_host/image_transport_factory.cc
+++ b/content/browser/renderer_host/image_transport_factory.cc
@@ -4,10 +4,13 @@
#include "content/browser/renderer_host/image_transport_factory.h"
+#include <algorithm>
#include <map>
+#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/renderer_host/image_transport_client.h"
#include "content/common/gpu/client/command_buffer_proxy.h"
@@ -58,6 +61,15 @@ class DefaultTransportFactory
return NULL;
}
+ // We don't generate lost context events, so we don't need to keep track of
+ // observers
+ virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE {
+ }
+
+ virtual void RemoveObserver(
+ ImageTransportFactoryObserver* observer) OVERRIDE {
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(DefaultTransportFactory);
};
@@ -128,6 +140,15 @@ class InProcessTransportFactory : public DefaultTransportFactory {
return surface;
}
+ // We don't generate lost context events, so we don't need to keep track of
+ // observers
+ virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE {
+ }
+
+ virtual void RemoveObserver(
+ ImageTransportFactoryObserver* observer) OVERRIDE {
+ }
+
private:
scoped_refptr<gfx::GLContext> context_;
scoped_refptr<gfx::GLSurface> surface_;
@@ -157,11 +178,16 @@ class ImageTransportClientTexture : public ImageTransportClient {
DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture);
};
-class CompositorSwapClient : public base::SupportsWeakPtr<CompositorSwapClient>,
- public WebGraphicsContext3DSwapBuffersClient {
+class GpuProcessTransportFactory;
+
+class CompositorSwapClient
+ : public base::SupportsWeakPtr<CompositorSwapClient>,
+ public WebGraphicsContext3DSwapBuffersClient {
public:
- explicit CompositorSwapClient(ui::Compositor* compositor)
- : compositor_(compositor) {
+ CompositorSwapClient(ui::Compositor* compositor,
+ GpuProcessTransportFactory* factory)
+ : compositor_(compositor),
+ factory_(factory) {
}
~CompositorSwapClient() {
@@ -176,11 +202,17 @@ class CompositorSwapClient : public base::SupportsWeakPtr<CompositorSwapClient>,
}
virtual void OnViewContextSwapBuffersAborted() OVERRIDE {
- compositor_->OnSwapBuffersAborted();
+ // Recreating contexts directly from here causes issues, so post a task
+ // instead.
+ // TODO(piman): Fix the underlying issues.
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&CompositorSwapClient::OnLostContext, this->AsWeakPtr()));
}
private:
+ void OnLostContext();
ui::Compositor* compositor_;
+ GpuProcessTransportFactory* factory_;
DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient);
};
@@ -232,6 +264,7 @@ class GpuProcessTransportFactory : public ui::ContextFactory,
gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(
gfx::kNullPluginWindow, true);
ContentGLContext* context = data->shared_context->content_gl_context();
+ handle.parent_gpu_process_id = context->GetGPUProcessID();
handle.parent_client_id = context->GetChannelID();
handle.parent_context_id = context->GetContextID();
handle.parent_texture_id[0] = data->shared_context->createTexture();
@@ -240,8 +273,6 @@ class GpuProcessTransportFactory : public ui::ContextFactory,
// TODO(piman): Use a cross-channel synchronization mechanism instead.
data->shared_context->finish();
- // This handle will not be correct after a GPU process crash / context lost.
- // TODO(piman): Fix this.
return handle;
}
@@ -252,15 +283,14 @@ class GpuProcessTransportFactory : public ui::ContextFactory,
PerCompositorData* data = it->second;
DCHECK(data);
ContentGLContext* context = data->shared_context->content_gl_context();
+ int gpu_process_id = context->GetGPUProcessID();
uint32 client_id = context->GetChannelID();
uint32 context_id = context->GetContextID();
- if (surface.parent_client_id == client_id &&
+ if (surface.parent_gpu_process_id == gpu_process_id &&
+ surface.parent_client_id == client_id &&
surface.parent_context_id == context_id) {
data->shared_context->deleteTexture(surface.parent_texture_id[0]);
data->shared_context->deleteTexture(surface.parent_texture_id[1]);
- // Finish is overkill, but flush semantics don't apply cross-channel.
- // TODO(piman): Use a cross-channel synchronization mechanism instead.
- data->shared_context->finish();
break;
}
}
@@ -277,6 +307,30 @@ class GpuProcessTransportFactory : public ui::ContextFactory,
virtual gfx::ScopedMakeCurrent* GetScopedMakeCurrent() { return NULL; }
+ virtual void AddObserver(ImageTransportFactoryObserver* observer) {
+ observer_list_.AddObserver(observer);
+ }
+
+ virtual void RemoveObserver(ImageTransportFactoryObserver* observer) {
+ observer_list_.RemoveObserver(observer);
+ }
+
+ void OnLostContext(ui::Compositor* compositor) {
+ LOG(ERROR) << "Lost UI compositor context.";
+ PerCompositorData* data = per_compositor_data_[compositor];
+ DCHECK(data);
+
+ // Note: this has the effect of recreating the swap_client, which means we
+ // won't get more reports of lost context from the same gpu process. It's a
+ // good thing.
+ CreateSharedContext(compositor);
+
+ FOR_EACH_OBSERVER(ImageTransportFactoryObserver,
+ observer_list_,
+ OnLostResources(compositor));
+ compositor->OnSwapBuffersAborted();
+ }
+
private:
struct PerCompositorData {
int surface_id;
@@ -295,25 +349,47 @@ class GpuProcessTransportFactory : public ui::ContextFactory,
tracker->SetSurfaceHandle(
data->surface_id,
gfx::GLSurfaceHandle(widget, false));
- data->swap_client.reset(new CompositorSwapClient(compositor));
+ per_compositor_data_[compositor] = data;
+
+ CreateSharedContext(compositor);
+
+ return data;
+ }
+
+ void CreateSharedContext(ui::Compositor* compositor) {
+ PerCompositorData* data = per_compositor_data_[compositor];
+ DCHECK(data);
+
+ data->swap_client.reset(new CompositorSwapClient(compositor, this));
WebKit::WebGraphicsContext3D::Attributes attrs;
attrs.shareResources = true;
data->shared_context.reset(new WebGraphicsContext3DCommandBufferImpl(
data->surface_id, GURL(), data->swap_client->AsWeakPtr()));
- data->shared_context->Initialize(attrs);
- data->shared_context->makeContextCurrent();
-
- per_compositor_data_[compositor] = data;
- return data;
+ if (!data->shared_context->Initialize(attrs)) {
+ // If we can't recreate contexts, we won't be able to show the UI. Better
+ // crash at this point.
+ LOG(FATAL) << "Failed to initialize compositor shared context.";
+ }
+ if (!data->shared_context->makeContextCurrent()) {
+ // If we can't recreate contexts, we won't be able to show the UI. Better
+ // crash at this point.
+ LOG(FATAL) << "Failed to make compositor shared context current.";
+ }
}
typedef std::map<ui::Compositor*, PerCompositorData*> PerCompositorDataMap;
PerCompositorDataMap per_compositor_data_;
+ ObserverList<ImageTransportFactoryObserver> observer_list_;
DISALLOW_COPY_AND_ASSIGN(GpuProcessTransportFactory);
};
+void CompositorSwapClient::OnLostContext() {
+ factory_->OnLostContext(compositor_);
+ // Note: previous line destroyed this. Don't access members from now on.
+}
+
} // anonymous namespace
// static
diff --git a/content/browser/renderer_host/image_transport_factory.h b/content/browser/renderer_host/image_transport_factory.h
index b650a68..b4ac5c6 100644
--- a/content/browser/renderer_host/image_transport_factory.h
+++ b/content/browser/renderer_host/image_transport_factory.h
@@ -22,6 +22,16 @@ class Texture;
class ImageTransportClient;
+// This class provides a way to get notified when surface handles get lost.
+class ImageTransportFactoryObserver {
+ public:
+ virtual ~ImageTransportFactoryObserver() {}
+
+ // Notifies that the surface handles generated by ImageTransportFactory for a
+ // given compositor were lost.
+ virtual void OnLostResources(ui::Compositor* compositor) = 0;
+};
+
// This class provides the interface for creating the support for the
// cross-process image transport, both for creating the shared surface handle
// (destination surface for the GPU process) and the transport client (logic for
@@ -45,6 +55,8 @@ class ImageTransportFactory {
virtual ui::ContextFactory* AsContextFactory() = 0;
// Creates a shared surface handle, associated with the compositor.
+ // Note: the handle may get lost at any time, a state that an
+ // ImageTransportFactoryObserver gets notified of.
virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle(
ui::Compositor* compositor) = 0;
@@ -62,6 +74,9 @@ class ImageTransportFactory {
// namespace. The caller gets ownership of the object.
// This will return NULL when using out-of-process (command buffer) contexts.
virtual gfx::ScopedMakeCurrent* GetScopedMakeCurrent() = 0;
+
+ virtual void AddObserver(ImageTransportFactoryObserver* observer) = 0;
+ virtual void RemoveObserver(ImageTransportFactoryObserver* observer) = 0;
};
#endif // CONTENT_BROWSER_RENDERER_HOST_IMAGE_TRANSPORT_FACTORY_H_
diff --git a/content/browser/renderer_host/mock_render_process_host.cc b/content/browser/renderer_host/mock_render_process_host.cc
index 626960a..6c5bbb0 100644
--- a/content/browser/renderer_host/mock_render_process_host.cc
+++ b/content/browser/renderer_host/mock_render_process_host.cc
@@ -200,6 +200,9 @@ base::TimeDelta MockRenderProcessHost::GetChildProcessIdleTime() const {
return base::TimeDelta::FromMilliseconds(0);
}
+void MockRenderProcessHost::SurfaceUpdated(int32 surface_id) {
+}
+
content::RenderProcessHost::listeners_iterator
MockRenderProcessHost::ListenersIterator() {
IDMap<IPC::Channel::Listener> listeners;
diff --git a/content/browser/renderer_host/mock_render_process_host.h b/content/browser/renderer_host/mock_render_process_host.h
index 53dfd14..969a6fe 100644
--- a/content/browser/renderer_host/mock_render_process_host.h
+++ b/content/browser/renderer_host/mock_render_process_host.h
@@ -67,6 +67,7 @@ class MockRenderProcessHost : public content::RenderProcessHost {
virtual listeners_iterator ListenersIterator() OVERRIDE;
virtual bool FastShutdownForPageCount(size_t count) OVERRIDE;
virtual base::TimeDelta GetChildProcessIdleTime() const OVERRIDE;
+ virtual void SurfaceUpdated(int32 surface_id) OVERRIDE;
// IPC::Channel::Sender via RenderProcessHost.
virtual bool Send(IPC::Message* msg) OVERRIDE;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index ed47da7..b4bd350 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -484,7 +484,8 @@ void RenderProcessHostImpl::CreateMessageFilters() {
BrowserContext::GetIndexedDBContext(browser_context))));
channel_->AddFilter(GeolocationDispatcherHost::New(
GetID(), browser_context->GetGeolocationPermissionContext()));
- channel_->AddFilter(new GpuMessageFilter(GetID(), widget_helper_.get()));
+ gpu_message_filter_ = new GpuMessageFilter(GetID(), widget_helper_.get());
+ channel_->AddFilter(gpu_message_filter_);
#if defined(ENABLE_WEBRTC)
channel_->AddFilter(new media_stream::MediaStreamDispatcherHost(
resource_context, GetID(), content::BrowserMainLoop::GetAudioManager()));
@@ -1045,6 +1046,7 @@ void RenderProcessHostImpl::Cleanup() {
// away first, since deleting the channel proxy will post a
// OnChannelClosed() to IPC::ChannelProxy::Context on the IO thread.
channel_.reset();
+ gpu_message_filter_ = NULL;
// Remove ourself from the list of renderer processes so that we can't be
// reused in between now and when the Delete task runs.
@@ -1073,6 +1075,15 @@ base::TimeDelta RenderProcessHostImpl::GetChildProcessIdleTime() const {
return base::TimeTicks::Now() - child_process_activity_time_;
}
+void RenderProcessHostImpl::SurfaceUpdated(int32 surface_id) {
+ if (!gpu_message_filter_)
+ return;
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
+ &GpuMessageFilter::SurfaceUpdated,
+ gpu_message_filter_,
+ surface_id));
+}
+
IPC::ChannelProxy* RenderProcessHostImpl::GetChannel() {
return channel_.get();
}
@@ -1215,6 +1226,7 @@ void RenderProcessHostImpl::ProcessDied(base::ProcessHandle handle,
child_process_launcher_.reset();
channel_.reset();
+ gpu_message_filter_ = NULL;
IDMap<IPC::Channel::Listener>::iterator iter(&listeners_);
while (!iter.IsAtEnd()) {
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 00a6d24f..eeace2a 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -21,6 +21,7 @@
#include "ui/gfx/surface/transport_dib.h"
class CommandLine;
+class GpuMessageFilter;
class RendererMainThread;
class RenderWidgetHelper;
@@ -87,6 +88,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
virtual bool FastShutdownForPageCount(size_t count) OVERRIDE;
virtual bool FastShutdownStarted() const OVERRIDE;
virtual base::TimeDelta GetChildProcessIdleTime() const OVERRIDE;
+ virtual void SurfaceUpdated(int32 surface_id) OVERRIDE;
// IPC::Channel::Sender via RenderProcessHost.
virtual bool Send(IPC::Message* msg) OVERRIDE;
@@ -186,6 +188,14 @@ class CONTENT_EXPORT RenderProcessHostImpl
// IO thread.
scoped_refptr<RenderWidgetHelper> widget_helper_;
+ // The filter for GPU-related messages coming from the renderer.
+ // Thread safety note: this field is to be accessed from the UI thread.
+ // We don't keep a reference to it, to avoid it being destroyed on the UI
+ // thread, but we clear this field when we clear channel_. When channel_ goes
+ // away, it posts a task to the IO thread to destroy it there, so we know that
+ // it's valid if non-NULL.
+ GpuMessageFilter* gpu_message_filter_;
+
// A map of transport DIB ids to cached TransportDIBs
std::map<TransportDIB::Id, TransportDIB*> cached_dibs_;
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 492b23f..9136aeb 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -231,6 +231,12 @@ gfx::GLSurfaceHandle RenderWidgetHostImpl::GetCompositingSurface() {
return gfx::GLSurfaceHandle();
}
+void RenderWidgetHostImpl::CompositingSurfaceUpdated() {
+ GpuSurfaceTracker::Get()->SetSurfaceHandle(
+ surface_id_, GetCompositingSurface());
+ process_->SurfaceUpdated(surface_id_);
+}
+
bool RenderWidgetHostImpl::PreHandleKeyboardEvent(
const NativeWebKeyboardEvent& event,
bool* is_keyboard_shortcut) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index cf7e415..9728f68 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -336,6 +336,10 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost,
static void AcknowledgeSwapBuffers(int32 route_id, int gpu_host_id);
static void AcknowledgePostSubBuffer(int32 route_id, int gpu_host_id);
+ // Signals that the compositing surface was updated, e.g. after a lost context
+ // event.
+ void CompositingSurfaceUpdated();
+
protected:
virtual RenderWidgetHostImpl* AsRenderWidgetHostImpl() OVERRIDE;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 3770f89..ad37e67 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -7,7 +7,6 @@
#include "base/bind.h"
#include "base/logging.h"
#include "content/browser/renderer_host/backing_store_skia.h"
-#include "content/browser/renderer_host/image_transport_factory.h"
#include "content/browser/renderer_host/image_transport_client.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/web_input_event_aura.h"
@@ -313,6 +312,7 @@ void RenderWidgetHostViewAura::Destroy() {
if (!shared_surface_handle_.is_null()) {
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
factory->DestroySharedSurfaceHandle(shared_surface_handle_);
+ factory->RemoveObserver(this);
}
delete window_;
}
@@ -492,6 +492,7 @@ gfx::GLSurfaceHandle RenderWidgetHostViewAura::GetCompositingSurface() {
if (shared_surface_handle_.is_null() && compositor) {
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
shared_surface_handle_ = factory->CreateSharedSurfaceHandle(compositor);
+ factory->AddObserver(this);
}
return shared_surface_handle_;
}
@@ -938,6 +939,22 @@ void RenderWidgetHostViewAura::OnCompositingEnded(ui::Compositor* compositor) {
}
////////////////////////////////////////////////////////////////////////////////
+// RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation:
+
+void RenderWidgetHostViewAura::OnLostResources(ui::Compositor* compositor) {
+ image_transport_clients_.clear();
+ current_surface_ = 0;
+ UpdateExternalTexture();
+
+ DCHECK(!shared_surface_handle_.is_null());
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ factory->DestroySharedSurfaceHandle(shared_surface_handle_);
+ shared_surface_handle_ = factory->CreateSharedSurfaceHandle(compositor);
+ host_->CompositingSurfaceUpdated();
+ host_->ScheduleComposite();
+}
+
+////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, private:
void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 6b248c4..0719e40 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "content/browser/renderer_host/image_transport_factory.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_export.h"
#include "ui/aura/client/activation_delegate.h"
@@ -43,7 +44,8 @@ class RenderWidgetHostViewAura
public ui::CompositorObserver,
public ui::TextInputClient,
public aura::WindowDelegate,
- public aura::client::ActivationDelegate {
+ public aura::client::ActivationDelegate,
+ public ImageTransportFactoryObserver {
public:
virtual ~RenderWidgetHostViewAura();
@@ -175,6 +177,9 @@ class RenderWidgetHostViewAura
// Overridden from ui::CompositorObserver:
virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE;
+ // Overridden from ImageTransportFactoryObserver:
+ virtual void OnLostResources(ui::Compositor* compositor) OVERRIDE;
+
void UpdateCursorIfOverSelf();
void UpdateExternalTexture();
ui::InputMethod* GetInputMethod() const;
diff --git a/content/common/gpu/client/content_gl_context.cc b/content/common/gpu/client/content_gl_context.cc
index 3b38796..37f3682 100644
--- a/content/common/gpu/client/content_gl_context.cc
+++ b/content/common/gpu/client/content_gl_context.cc
@@ -263,6 +263,10 @@ CommandBufferProxy* ContentGLContext::GetCommandBufferProxy() {
return command_buffer_;
}
+int ContentGLContext::GetGPUProcessID() {
+ return channel_->gpu_process_id();
+}
+
int ContentGLContext::GetChannelID() {
return channel_->client_id();
}
diff --git a/content/common/gpu/client/content_gl_context.h b/content/common/gpu/client/content_gl_context.h
index f10efad..cb552eb 100644
--- a/content/common/gpu/client/content_gl_context.h
+++ b/content/common/gpu/client/content_gl_context.h
@@ -184,7 +184,9 @@ class ContentGLContext : public base::SupportsWeakPtr<ContentGLContext>,
CommandBufferProxy* GetCommandBufferProxy();
- // The following 2 IDs let one uniquely identify this context.
+ // The following 3 IDs let one uniquely identify this context.
+ // Gets the GPU process ID for this context.
+ int GetGPUProcessID();
// Gets the channel ID for this context.
int GetChannelID();
// Gets the context ID (relative to the channel).
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index cd932ae..1a83423 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -98,8 +98,10 @@ void GpuChannelHost::MessageFilter::OnChannelError() {
base::Bind(&GpuChannelHost::OnChannelError, parent_));
}
-GpuChannelHost::GpuChannelHost(GpuChannelHostFactory* factory, int client_id)
+GpuChannelHost::GpuChannelHost(
+ GpuChannelHostFactory* factory, int gpu_process_id, int client_id)
: factory_(factory),
+ gpu_process_id_(gpu_process_id),
client_id_(client_id),
state_(kUnconnected) {
}
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h
index 888451b..ef8e438 100644
--- a/content/common/gpu/client/gpu_channel_host.h
+++ b/content/common/gpu/client/gpu_channel_host.h
@@ -90,7 +90,9 @@ class GpuChannelHost : public IPC::Message::Sender,
};
// Called on the render thread
- GpuChannelHost(GpuChannelHostFactory* factory, int client_id);
+ GpuChannelHost(GpuChannelHostFactory* factory,
+ int gpu_process_id,
+ int client_id);
virtual ~GpuChannelHost();
// Connect to GPU process channel.
@@ -158,6 +160,7 @@ class GpuChannelHost : public IPC::Message::Sender,
void ForciblyCloseChannel();
GpuChannelHostFactory* factory() const { return factory_; }
+ int gpu_process_id() const { return gpu_process_id_; }
int client_id() const { return client_id_; }
private:
@@ -185,6 +188,7 @@ class GpuChannelHost : public IPC::Message::Sender,
};
GpuChannelHostFactory* factory_;
+ int gpu_process_id_;
int client_id_;
State state_;
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index a8cf142..55517a3 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -127,6 +127,7 @@ IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(gfx::GLSurfaceHandle)
IPC_STRUCT_TRAITS_MEMBER(handle)
IPC_STRUCT_TRAITS_MEMBER(transport)
+ IPC_STRUCT_TRAITS_MEMBER(parent_gpu_process_id)
IPC_STRUCT_TRAITS_MEMBER(parent_client_id)
IPC_STRUCT_TRAITS_MEMBER(parent_context_id)
IPC_STRUCT_TRAITS_MEMBER(parent_texture_id[0])
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 189ede6..fa95d17 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -186,6 +186,11 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Message::Sender,
// 10 milliseconds.
virtual base::TimeDelta GetChildProcessIdleTime() const = 0;
+ // Signals that a compositing surface has been updated after a lost context
+ // event, so that we can process requests from the renderer to create contexts
+ // with that surface.
+ virtual void SurfaceUpdated(int32 surface_id) = 0;
+
// Static management functions -----------------------------------------------
// Flag to run the renderer in process. This is primarily
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index f4a9d66..651f90c 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -914,7 +914,7 @@ GpuChannelHost* RenderThreadImpl::EstablishGpuChannelSync(
return NULL;
}
- gpu_channel_ = new GpuChannelHost(this, client_id);
+ gpu_channel_ = new GpuChannelHost(this, 0, client_id);
gpu_channel_->set_gpu_info(gpu_info);
content::GetContentClient()->SetGpuInfo(gpu_info);