diff options
author | piman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-08 23:46:29 +0000 |
---|---|---|
committer | piman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-08 23:46:29 +0000 |
commit | 03dc888f5d0e636fd4e55f8f04bb635bfad29b42 (patch) | |
tree | aecd43e4ceb1ba8f9e3bcd3c19a1fd8584489291 /content | |
parent | 10618f2764fb9cfc6fc3cc266d928a9731c0afbc (diff) | |
download | chromium_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')
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); |