Index: content/renderer/pepper_platform_context_3d_impl.cc |
=================================================================== |
--- content/renderer/pepper_platform_context_3d_impl.cc (revision 106379) |
+++ content/renderer/pepper_platform_context_3d_impl.cc (working copy) |
@@ -5,6 +5,7 @@ |
#include "content/renderer/pepper_platform_context_3d_impl.h" |
#include "base/bind.h" |
+#include "content/renderer/pepper_parent_context_provider.h" |
#include "content/renderer/render_thread_impl.h" |
#include "content/renderer/gpu/renderer_gl_context.h" |
#include "content/renderer/gpu/gpu_channel_host.h" |
@@ -16,8 +17,9 @@ |
#ifdef ENABLE_GPU |
-PlatformContext3DImpl::PlatformContext3DImpl(RendererGLContext* parent_context) |
- : parent_context_(parent_context->AsWeakPtr()), |
+PlatformContext3DImpl::PlatformContext3DImpl( |
+ PepperParentContextProvider* parent_context_provider) |
+ : parent_context_provider_(parent_context_provider), |
parent_texture_id_(0), |
command_buffer_(NULL), |
weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
@@ -37,6 +39,9 @@ |
DCHECK(channel_.get()); |
channel_->DestroyCommandBuffer(command_buffer_); |
command_buffer_ = NULL; |
+ if (channel_->WillGpuSwitchOccur(false, gfx::PreferDiscreteGpu)) { |
+ channel_->ForciblyCloseChannel(); |
+ } |
} |
channel_ = NULL; |
@@ -47,27 +52,36 @@ |
if (command_buffer_) |
return true; |
- // Parent may already have been deleted. |
- if (!parent_context_.get()) |
+ if (!parent_context_provider_) |
return false; |
RenderThreadImpl* render_thread = RenderThreadImpl::current(); |
if (!render_thread) |
return false; |
- channel_ = render_thread->GetGpuChannel(); |
- if (!channel_.get()) |
- return false; |
+ bool retry = false; |
+ gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; |
- DCHECK(channel_->state() == GpuChannelHost::kConnected); |
+ // Note similar code in WebGraphicsContext3DCommandBufferImpl::initialize. |
+ do { |
+ channel_ = render_thread->EstablishGpuChannelSync( |
+ content::CAUSE_FOR_GPU_LAUNCH_PEPPERPLATFORMCONTEXT3DIMPL_INITIALIZE); |
+ if (!channel_.get()) |
+ return false; |
+ DCHECK(channel_->state() == GpuChannelHost::kConnected); |
+ if (!retry) { |
+ // If the creation of this context requires all contexts for this |
+ // renderer to be destroyed on the GPU process side, then drop the |
+ // channel and recreate it. |
+ if (channel_->WillGpuSwitchOccur(true, gpu_preference)) { |
+ channel_->ForciblyCloseChannel(); |
+ retry = true; |
+ } |
+ } else { |
+ retry = false; |
+ } |
+ } while (retry); |
- // Flush any remaining commands in the parent context to make sure the |
- // texture id accounting stays consistent. |
- gpu::gles2::GLES2Implementation* parent_gles2 = |
- parent_context_->GetImplementation(); |
- parent_gles2->helper()->CommandBufferHelper::Finish(); |
- parent_texture_id_ = parent_gles2->MakeTextureId(); |
- |
gfx::Size surface_size; |
std::vector<int32> attribs; |
// TODO(alokp): Change GpuChannelHost::CreateOffscreenCommandBuffer() |
@@ -93,25 +107,43 @@ |
attribs.push_back(RendererGLContext::NONE); |
} |
- CommandBufferProxy* parent_command_buffer = |
- parent_context_->GetCommandBufferProxy(); |
command_buffer_ = channel_->CreateOffscreenCommandBuffer( |
surface_size, |
NULL, |
"*", |
attribs, |
GURL::EmptyGURL(), |
- gfx::PreferDiscreteGpu); |
+ gpu_preference); |
if (!command_buffer_) |
return false; |
- if (!command_buffer_->SetParent(parent_command_buffer, parent_texture_id_)) |
- return false; |
- |
command_buffer_->SetChannelErrorCallback( |
base::Bind(&PlatformContext3DImpl::OnContextLost, |
weak_ptr_factory_.GetWeakPtr())); |
+ // Fetch the parent context now, after any potential shutdown of the |
+ // channel due to GPU switching, and creation of the Pepper 3D |
+ // context with the discrete GPU preference. |
+ RendererGLContext* parent_context = |
+ parent_context_provider_->GetParentContextForPlatformContext3D(); |
+ if (!parent_context) |
+ return false; |
+ |
+ parent_context_provider_ = NULL; |
+ parent_context_ = parent_context->AsWeakPtr(); |
+ |
+ // Flush any remaining commands in the parent context to make sure the |
+ // texture id accounting stays consistent. |
+ gpu::gles2::GLES2Implementation* parent_gles2 = |
+ parent_context_->GetImplementation(); |
+ parent_gles2->helper()->CommandBufferHelper::Finish(); |
+ parent_texture_id_ = parent_gles2->MakeTextureId(); |
+ |
+ CommandBufferProxy* parent_command_buffer = |
+ parent_context_->GetCommandBufferProxy(); |
+ if (!command_buffer_->SetParent(parent_command_buffer, parent_texture_id_)) |
+ return false; |
+ |
return true; |
} |