Commit 20f589a8 authored by husky@google.com's avatar husky@google.com

Split WebGraphicsContext3DCommandBufferImpl::initialize() into two stages.

After the context is created, the remaining calls should be done on
the compositor thread. This CL adds a MaybeInitializeGL() method, which
we run on each call to makeContextCurrent().

Added asserts to RendererGLContext to check that it's always used on
the same thread.

Review URL: http://codereview.chromium.org/7713015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98392 0039d316-1c4b-4281-b951-d872f2087c98
parent 6f75c952
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/message_loop.h"
#include "base/shared_memory.h" #include "base/shared_memory.h"
#include "content/common/view_messages.h" #include "content/common/view_messages.h"
#include "content/renderer/gpu/command_buffer_proxy.h" #include "content/renderer/gpu/command_buffer_proxy.h"
...@@ -209,6 +210,7 @@ void RendererGLContext::SetContextLostCallback( ...@@ -209,6 +210,7 @@ void RendererGLContext::SetContextLostCallback(
bool RendererGLContext::MakeCurrent(RendererGLContext* context) { bool RendererGLContext::MakeCurrent(RendererGLContext* context) {
if (context) { if (context) {
DCHECK(MessageLoop::current() == context->message_loop_);
gles2::SetGLContext(context->gles2_implementation_); gles2::SetGLContext(context->gles2_implementation_);
// Don't request latest error status from service. Just use the locally // Don't request latest error status from service. Just use the locally
...@@ -284,7 +286,11 @@ RendererGLContext::RendererGLContext(GpuChannelHost* channel) ...@@ -284,7 +286,11 @@ RendererGLContext::RendererGLContext(GpuChannelHost* channel)
transfer_buffer_id_(-1), transfer_buffer_id_(-1),
gles2_implementation_(NULL), gles2_implementation_(NULL),
last_error_(SUCCESS), last_error_(SUCCESS),
frame_number_(0) { frame_number_(0)
#ifndef NDEBUG
, message_loop_(MessageLoop::current())
#endif
{
DCHECK(channel); DCHECK(channel);
} }
...@@ -297,6 +303,7 @@ bool RendererGLContext::Initialize(bool onscreen, ...@@ -297,6 +303,7 @@ bool RendererGLContext::Initialize(bool onscreen,
const char* allowed_extensions, const char* allowed_extensions,
const int32* attrib_list, const int32* attrib_list,
const GURL& active_url) { const GURL& active_url) {
DCHECK(MessageLoop::current() == message_loop_);
DCHECK(size.width() >= 0 && size.height() >= 0); DCHECK(size.width() >= 0 && size.height() >= 0);
TRACE_EVENT2("gpu", "RendererGLContext::Initialize", TRACE_EVENT2("gpu", "RendererGLContext::Initialize",
"on_screen", onscreen, "num_pixels", size.GetArea()); "on_screen", onscreen, "num_pixels", size.GetArea());
...@@ -415,6 +422,7 @@ bool RendererGLContext::Initialize(bool onscreen, ...@@ -415,6 +422,7 @@ bool RendererGLContext::Initialize(bool onscreen,
void RendererGLContext::Destroy() { void RendererGLContext::Destroy() {
TRACE_EVENT0("gpu", "RendererGLContext::Destroy"); TRACE_EVENT0("gpu", "RendererGLContext::Destroy");
DCHECK(MessageLoop::current() == message_loop_);
SetParent(NULL); SetParent(NULL);
if (gles2_implementation_) { if (gles2_implementation_) {
......
...@@ -201,6 +201,10 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> { ...@@ -201,6 +201,10 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> {
gpu::gles2::GLES2Implementation* gles2_implementation_; gpu::gles2::GLES2Implementation* gles2_implementation_;
Error last_error_; Error last_error_;
int frame_number_; int frame_number_;
#ifndef NDEBUG
// Used to assert that this object is used on a single thread.
MessageLoop* message_loop_;
#endif
DISALLOW_COPY_AND_ASSIGN(RendererGLContext); DISALLOW_COPY_AND_ASSIGN(RendererGLContext);
}; };
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "base/debug/trace_event.h" #include "base/debug/trace_event.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "base/synchronization/lock.h"
#include "content/common/content_switches.h" #include "content/common/content_switches.h"
#include "content/renderer/gpu/gpu_channel_host.h" #include "content/renderer/gpu/gpu_channel_host.h"
#include "content/renderer/render_thread.h" #include "content/renderer/render_thread.h"
...@@ -32,6 +33,8 @@ ...@@ -32,6 +33,8 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "webkit/glue/gl_bindings_skia_cmd_buffer.h" #include "webkit/glue/gl_bindings_skia_cmd_buffer.h"
static base::LazyInstance<base::Lock>
g_all_contexts_lock(base::LINKER_INITIALIZED);
static base::LazyInstance<std::set<WebGraphicsContext3DCommandBufferImpl*> > static base::LazyInstance<std::set<WebGraphicsContext3DCommandBufferImpl*> >
g_all_contexts(base::LINKER_INITIALIZED); g_all_contexts(base::LINKER_INITIALIZED);
...@@ -54,7 +57,10 @@ WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl() ...@@ -54,7 +57,10 @@ WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl()
WebGraphicsContext3DCommandBufferImpl:: WebGraphicsContext3DCommandBufferImpl::
~WebGraphicsContext3DCommandBufferImpl() { ~WebGraphicsContext3DCommandBufferImpl() {
g_all_contexts.Pointer()->erase(this); {
base::AutoLock lock(g_all_contexts_lock.Get());
g_all_contexts.Pointer()->erase(this);
}
delete context_; delete context_;
} }
...@@ -70,38 +76,20 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize( ...@@ -70,38 +76,20 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize(
WebGraphicsContext3D::Attributes attributes, WebGraphicsContext3D::Attributes attributes,
WebKit::WebView* web_view, WebKit::WebView* web_view,
bool render_directly_to_web_view) { bool render_directly_to_web_view) {
DCHECK(!context_);
TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::initialize"); TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::initialize");
webkit_glue::BindSkiaToCommandBufferGL(); webkit_glue::BindSkiaToCommandBufferGL();
RenderThread* render_thread = RenderThread::current(); RenderThread* render_thread = RenderThread::current();
if (!render_thread) if (!render_thread)
return false; return false;
GpuChannelHost* host = render_thread->EstablishGpuChannelSync( host_ = render_thread->EstablishGpuChannelSync(
content:: content::
CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE); CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE);
if (!host) if (!host_)
return false; return false;
DCHECK(host->state() == GpuChannelHost::kConnected); DCHECK(host_->state() == GpuChannelHost::kConnected);
// Convert WebGL context creation attributes into RendererGLContext / EGL size
// requests.
const int alpha_size = attributes.alpha ? 8 : 0;
const int depth_size = attributes.depth ? 24 : 0;
const int stencil_size = attributes.stencil ? 8 : 0;
const int samples = attributes.antialias ? 4 : 0;
const int sample_buffers = attributes.antialias ? 1 : 0;
const int32 attribs[] = {
RendererGLContext::ALPHA_SIZE, alpha_size,
RendererGLContext::DEPTH_SIZE, depth_size,
RendererGLContext::STENCIL_SIZE, stencil_size,
RendererGLContext::SAMPLES, samples,
RendererGLContext::SAMPLE_BUFFERS, sample_buffers,
RendererGLContext::NONE,
};
const char* preferred_extensions = attributes.noExtensions ?
kWebGLPreferredGLExtensions : "*";
const GPUInfo& gpu_info = host->gpu_info(); const GPUInfo& gpu_info = host_->gpu_info();
UMA_HISTOGRAM_ENUMERATION( UMA_HISTOGRAM_ENUMERATION(
"GPU.WebGraphicsContext3D_Init_CanLoseContext", "GPU.WebGraphicsContext3D_Init_CanLoseContext",
attributes.canRecoverFromContextLoss * 2 + gpu_info.can_lose_context, attributes.canRecoverFromContextLoss * 2 + gpu_info.can_lose_context,
...@@ -111,53 +99,86 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize( ...@@ -111,53 +99,86 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize(
return false; return false;
} }
GURL active_url;
if (web_view && web_view->mainFrame()) if (web_view && web_view->mainFrame())
active_url = GURL(web_view->mainFrame()->document().url()); active_url_ = GURL(web_view->mainFrame()->document().url());
// HACK: Assume this is a WebGL context by looking for the noExtensions
// attribute. WebGL contexts must not go in the share group because they
// rely on destruction of the context to clean up owned resources. Putting
// them in a share group would prevent this from happening.
RendererGLContext* share_group = NULL;
if (!attributes.noExtensions) {
share_group = g_all_contexts.Pointer()->empty() ?
NULL : (*g_all_contexts.Pointer()->begin())->context_;
}
attributes_ = attributes;
render_directly_to_web_view_ = render_directly_to_web_view; render_directly_to_web_view_ = render_directly_to_web_view;
if (render_directly_to_web_view) { if (render_directly_to_web_view_) {
#ifndef WTF_USE_THREADED_COMPOSITING
RenderView* renderview = RenderView::FromWebView(web_view); RenderView* renderview = RenderView::FromWebView(web_view);
if (!renderview) if (!renderview)
return false; return false;
render_view_routing_id_ = renderview->routing_id(),
#ifndef WTF_USE_THREADED_COMPOSITING
web_view_ = web_view; web_view_ = web_view;
#endif #endif
context_ = RendererGLContext::CreateViewContext( }
host, return true;
renderview->routing_id(), }
!attributes.noExtensions,
share_group, bool WebGraphicsContext3DCommandBufferImpl::MaybeInitializeGL() {
preferred_extensions, if (context_) {
attribs, return true;
active_url); }
if (context_) { TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::MaybeInitializeGL");
context_->SetSwapBuffersCallback(
NewCallback(this, // Convert WebGL context creation attributes into RendererGLContext / EGL size
// requests.
const int alpha_size = attributes_.alpha ? 8 : 0;
const int depth_size = attributes_.depth ? 24 : 0;
const int stencil_size = attributes_.stencil ? 8 : 0;
const int samples = attributes_.antialias ? 4 : 0;
const int sample_buffers = attributes_.antialias ? 1 : 0;
const int32 attribs[] = {
RendererGLContext::ALPHA_SIZE, alpha_size,
RendererGLContext::DEPTH_SIZE, depth_size,
RendererGLContext::STENCIL_SIZE, stencil_size,
RendererGLContext::SAMPLES, samples,
RendererGLContext::SAMPLE_BUFFERS, sample_buffers,
RendererGLContext::NONE,
};
// HACK: Assume this is a WebGL context by looking for the noExtensions
// attribute. WebGL contexts must not go in the share group because they
// rely on destruction of the context to clean up owned resources. Putting
// them in a share group would prevent this from happening.
{
// Need to hold this lock until after RendererGLContext::Create, to ensure
// the context we picked for our share group isn't deleted (there's also
// a lock in the destructor).
base::AutoLock lock(g_all_contexts_lock.Get());
RendererGLContext* share_group = NULL;
if (!attributes_.noExtensions) {
share_group = g_all_contexts.Pointer()->empty() ?
NULL : (*g_all_contexts.Pointer()->begin())->context_;
}
const char* preferred_extensions = attributes_.noExtensions ?
kWebGLPreferredGLExtensions : "*";
if (render_directly_to_web_view_) {
context_ = RendererGLContext::CreateViewContext(
host_,
render_view_routing_id_,
!attributes_.noExtensions,
share_group,
preferred_extensions,
attribs,
active_url_);
if (context_) {
context_->SetSwapBuffersCallback(NewCallback(this,
&WebGraphicsContext3DCommandBufferImpl::OnSwapBuffersComplete)); &WebGraphicsContext3DCommandBufferImpl::OnSwapBuffersComplete));
} }
} else { } else {
context_ = RendererGLContext::CreateOffscreenContext( context_ = RendererGLContext::CreateOffscreenContext(
host, host_,
gfx::Size(1, 1), gfx::Size(1, 1),
!attributes.noExtensions, !attributes_.noExtensions,
share_group, share_group,
preferred_extensions, preferred_extensions,
attribs, attribs,
active_url); active_url_);
#ifndef WTF_USE_THREADED_COMPOSITING }
web_view_ = NULL;
#endif
} }
if (!context_) if (!context_)
return false; return false;
...@@ -175,7 +196,6 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize( ...@@ -175,7 +196,6 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize(
// Set attributes_ from created offscreen context. // Set attributes_ from created offscreen context.
{ {
attributes_ = attributes;
GLint alpha_bits = 0; GLint alpha_bits = 0;
getIntegerv(GL_ALPHA_BITS, &alpha_bits); getIntegerv(GL_ALPHA_BITS, &alpha_bits);
attributes_.alpha = alpha_bits > 0; attributes_.alpha = alpha_bits > 0;
...@@ -190,13 +210,17 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize( ...@@ -190,13 +210,17 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize(
attributes_.antialias = samples > 0; attributes_.antialias = samples > 0;
} }
if (!attributes.noExtensions) if (!attributes_.noExtensions) {
base::AutoLock lock(g_all_contexts_lock.Get());
g_all_contexts.Pointer()->insert(this); g_all_contexts.Pointer()->insert(this);
}
return true; return true;
} }
bool WebGraphicsContext3DCommandBufferImpl::makeContextCurrent() { bool WebGraphicsContext3DCommandBufferImpl::makeContextCurrent() {
if (!MaybeInitializeGL())
return false;
return RendererGLContext::MakeCurrent(context_); return RendererGLContext::MakeCurrent(context_);
} }
...@@ -221,7 +245,6 @@ bool WebGraphicsContext3DCommandBufferImpl::setParentContext( ...@@ -221,7 +245,6 @@ bool WebGraphicsContext3DCommandBufferImpl::setParentContext(
} }
WebGLId WebGraphicsContext3DCommandBufferImpl::getPlatformTextureId() { WebGLId WebGraphicsContext3DCommandBufferImpl::getPlatformTextureId() {
DCHECK(context_);
return context_->GetParentTextureId(); return context_->GetParentTextureId();
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "content/renderer/gpu/renderer_gl_context.h" #include "content/renderer/gpu/renderer_gl_context.h"
#include "googleurl/src/gurl.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebGraphicsContext3D.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebGraphicsContext3D.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
...@@ -57,6 +58,10 @@ class WebGraphicsContext3DCommandBufferImpl ...@@ -57,6 +58,10 @@ class WebGraphicsContext3DCommandBufferImpl
WebKit::WebView*, WebKit::WebView*,
bool renderDirectlyToWebView); bool renderDirectlyToWebView);
// Must be called after initialize() and before any of the following methods.
// Binds this object to the current thread. We can't bind to multiple threads.
// TODO(husky): Document threading restrictions in WebGraphicsContext3D.h,
// enforce strictly in all implementations.
virtual bool makeContextCurrent(); virtual bool makeContextCurrent();
virtual int width(); virtual int width();
...@@ -431,6 +436,12 @@ class WebGraphicsContext3DCommandBufferImpl ...@@ -431,6 +436,12 @@ class WebGraphicsContext3DCommandBufferImpl
WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback); WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback);
private: private:
// Initialize the underlying GL context. May be called multiple times; second
// and subsequent calls are ignored. Must be called from the thread that is
// going to use this object to issue GL commands (which might not be the main
// thread).
bool MaybeInitializeGL();
// SwapBuffers callback. // SwapBuffers callback.
void OnSwapBuffersComplete(); void OnSwapBuffersComplete();
virtual void OnContextLost(RendererGLContext::ContextLostReason reason); virtual void OnContextLost(RendererGLContext::ContextLostReason reason);
...@@ -440,6 +451,11 @@ class WebGraphicsContext3DCommandBufferImpl ...@@ -440,6 +451,11 @@ class WebGraphicsContext3DCommandBufferImpl
// The GLES2Implementation we use for OpenGL rendering. // The GLES2Implementation we use for OpenGL rendering.
gpu::gles2::GLES2Implementation* gl_; gpu::gles2::GLES2Implementation* gl_;
// State needed by InitializeGLES2.
GpuChannelHost* host_;
GURL active_url_;
int32 render_view_routing_id_;
bool render_directly_to_web_view_; bool render_directly_to_web_view_;
#ifndef WTF_USE_THREADED_COMPOSITING #ifndef WTF_USE_THREADED_COMPOSITING
// If rendering directly to WebView, weak pointer to it. // If rendering directly to WebView, weak pointer to it.
......
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