diff options
18 files changed, 447 insertions, 143 deletions
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp index c2f23a3..237712a 100644 --- a/android_webview/android_webview.gyp +++ b/android_webview/android_webview.gyp @@ -111,6 +111,8 @@ 'browser/aw_download_manager_delegate.h', 'browser/aw_form_database_service.cc', 'browser/aw_form_database_service.h', + 'browser/aw_gl_surface.cc', + 'browser/aw_gl_surface.h', 'browser/aw_http_auth_handler_base.cc', 'browser/aw_http_auth_handler_base.h', 'browser/aw_javascript_dialog_manager.cc', diff --git a/android_webview/browser/aw_gl_surface.cc b/android_webview/browser/aw_gl_surface.cc new file mode 100644 index 0000000..5ff9272 --- /dev/null +++ b/android_webview/browser/aw_gl_surface.cc @@ -0,0 +1,48 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "android_webview/browser/aw_gl_surface.h" + +namespace android_webview { + +AwGLSurface::AwGLSurface() : fbo_(0) {} + +AwGLSurface::~AwGLSurface() {} + +void AwGLSurface::Destroy() { +} + +bool AwGLSurface::IsOffscreen() { + return false; +} + +unsigned int AwGLSurface::GetBackingFrameBufferObject() { + return fbo_; +} + +bool AwGLSurface::SwapBuffers() { + return true; +} + +gfx::Size AwGLSurface::GetSize() { + return gfx::Size(1, 1); +} + +void* AwGLSurface::GetHandle() { + return NULL; +} + +void* AwGLSurface::GetDisplay() { + return NULL; +} + +void AwGLSurface::SetBackingFrameBufferObject(unsigned int fbo) { + fbo_ = fbo; +} + +void AwGLSurface::ResetBackingFrameBufferObject() { + fbo_ = 0; +} + +} // namespace android_webview diff --git a/android_webview/browser/aw_gl_surface.h b/android_webview/browser/aw_gl_surface.h new file mode 100644 index 0000000..99b8a1d --- /dev/null +++ b/android_webview/browser/aw_gl_surface.h @@ -0,0 +1,42 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANDROID_WEBVIEW_BROWSER_AW_GL_SURFACE_H_ +#define ANDROID_WEBVIEW_BROWSER_AW_GL_SURFACE_H_ + +#include "ui/gl/gl_surface.h" + +namespace android_webview { + +// This surface is used to represent the underlying surface provided by the App +// inside a hardware draw. Note that offscreen contexts will not be using this +// GLSurface. +class GL_EXPORT AwGLSurface : public gfx::GLSurface { + public: + AwGLSurface(); + + // Implement GLSurface. + virtual void Destroy() OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual unsigned int GetBackingFrameBufferObject() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual void* GetDisplay() OVERRIDE; + + void SetBackingFrameBufferObject(unsigned int fbo); + void ResetBackingFrameBufferObject(); + + protected: + virtual ~AwGLSurface(); + + private: + unsigned int fbo_; + + DISALLOW_COPY_AND_ASSIGN(AwGLSurface); +}; + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_BROWSER_AW_GL_SURFACE_H_ diff --git a/android_webview/browser/in_process_view_renderer.cc b/android_webview/browser/in_process_view_renderer.cc index a714956..3e25680 100644 --- a/android_webview/browser/in_process_view_renderer.cc +++ b/android_webview/browser/in_process_view_renderer.cc @@ -6,6 +6,7 @@ #include <android/bitmap.h> +#include "android_webview/browser/aw_gl_surface.h" #include "android_webview/browser/scoped_app_gl_state_restore.h" #include "android_webview/common/aw_switches.h" #include "android_webview/public/browser/draw_gl.h" @@ -289,6 +290,19 @@ bool InProcessViewRenderer::OnDraw(jobject java_canvas, return result; } +bool InProcessViewRenderer::InitializeHwDraw() { + TRACE_EVENT0("android_webview", "InitializeHwDraw"); + DCHECK(!gl_surface_); + gl_surface_ = new AwGLSurface; + hardware_failed_ = !compositor_->InitializeHwDraw(gl_surface_); + hardware_initialized_ = true; + + if (hardware_failed_) + gl_surface_ = NULL; + + return !hardware_failed_; +} + void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) { TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL"); DCHECK(visible_); @@ -309,13 +323,11 @@ void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) { ScopedAllowGL allow_gl; if (attached_to_window_ && compositor_ && !hardware_initialized_) { - TRACE_EVENT0("android_webview", "InitializeHwDraw"); - hardware_failed_ = !compositor_->InitializeHwDraw(); - hardware_initialized_ = true; - last_egl_context_ = current_context; - - if (hardware_failed_) + if (InitializeHwDraw()) { + last_egl_context_ = current_context; + } else { return; + } } if (draw_info->mode == AwDrawGLInfo::kModeProcess) @@ -330,7 +342,6 @@ void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) { TRACE_EVENT_INSTANT0( "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD); } - last_egl_context_ = current_context; if (!compositor_) { TRACE_EVENT_INSTANT0( @@ -338,21 +349,26 @@ void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) { return; } + DCHECK(gl_surface_); + gl_surface_->SetBackingFrameBufferObject( + state_restore.framebuffer_binding_ext()); + gfx::Transform transform; transform.matrix().setColMajorf(draw_info->transform); transform.Translate(scroll_at_start_of_frame_.x(), scroll_at_start_of_frame_.y()); - // TODO(joth): Check return value. - block_invalidates_ = true; gfx::Rect clip_rect(draw_info->clip_left, draw_info->clip_top, draw_info->clip_right - draw_info->clip_left, draw_info->clip_bottom - draw_info->clip_top); + block_invalidates_ = true; + // TODO(joth): Check return value. compositor_->DemandDrawHw(gfx::Size(draw_info->width, draw_info->height), transform, clip_rect, state_restore.stencil_enabled()); block_invalidates_ = false; + gl_surface_->ResetBackingFrameBufferObject(); UpdateCachedGlobalVisibleRect(); bool drew_full_visible_rect = clip_rect.Contains(cached_global_visible_rect_); @@ -554,6 +570,7 @@ void InProcessViewRenderer::OnDetachedFromWindow() { hardware_initialized_ = false; } + gl_surface_ = NULL; attached_to_window_ = false; } diff --git a/android_webview/browser/in_process_view_renderer.h b/android_webview/browser/in_process_view_renderer.h index 6e66a84..8bb2c60 100644 --- a/android_webview/browser/in_process_view_renderer.h +++ b/android_webview/browser/in_process_view_renderer.h @@ -23,6 +23,8 @@ class SkCanvas; namespace android_webview { +class AwGLSurface; + // Provides RenderViewHost wrapper functionality for sending WebView-specific // IPC messages to the renderer and from there to WebKit. class InProcessViewRenderer : public BrowserViewRenderer, @@ -93,6 +95,8 @@ class InProcessViewRenderer : public BrowserViewRenderer, void NoLongerExpectsDrawGL(); + bool InitializeHwDraw(); + // For debug tracing or logging. Return the string representation of this // view renderer's state and the |draw_info| if provided. std::string ToString(AwDrawGLInfo* draw_info) const; @@ -127,6 +131,7 @@ class InProcessViewRenderer : public BrowserViewRenderer, bool attached_to_window_; bool hardware_initialized_; bool hardware_failed_; + scoped_refptr<AwGLSurface> gl_surface_; // Used only for detecting Android View System context changes. // Not to be used between draw calls. diff --git a/android_webview/browser/scoped_app_gl_state_restore.cc b/android_webview/browser/scoped_app_gl_state_restore.cc index cb8d128..e0c8fed 100644 --- a/android_webview/browser/scoped_app_gl_state_restore.cc +++ b/android_webview/browser/scoped_app_gl_state_restore.cc @@ -132,6 +132,7 @@ ScopedAppGLStateRestore::ScopedAppGLStateRestore(CallMode mode) : mode_(mode) { glGetIntegerv(GL_STENCIL_VALUE_MASK, &stencil_mask_); glGetIntegerv(GL_STENCIL_REF, &stencil_ref_); + glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &framebuffer_binding_ext_); if (!g_gl_max_texture_units) { glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &g_gl_max_texture_units); @@ -155,6 +156,7 @@ ScopedAppGLStateRestore::~ScopedAppGLStateRestore() { TRACE_EVENT0("android_webview", "AppGLStateRestore"); MakeAppContextCurrent(); + glBindFramebufferEXT(GL_FRAMEBUFFER, framebuffer_binding_ext_); glBindBuffer(GL_ARRAY_BUFFER, vertex_array_buffer_binding_); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_buffer_binding_); diff --git a/android_webview/browser/scoped_app_gl_state_restore.h b/android_webview/browser/scoped_app_gl_state_restore.h index 7840fbf..93b5ad5 100644 --- a/android_webview/browser/scoped_app_gl_state_restore.h +++ b/android_webview/browser/scoped_app_gl_state_restore.h @@ -25,6 +25,7 @@ class ScopedAppGLStateRestore { ~ScopedAppGLStateRestore(); bool stencil_enabled() const { return stencil_test_; } + GLint framebuffer_binding_ext() const { return framebuffer_binding_ext_; } private: const CallMode mode_; @@ -83,6 +84,8 @@ class ScopedAppGLStateRestore { GLint stencil_mask_; GLint stencil_ref_; + GLint framebuffer_binding_ext_; + struct TextureBindings { GLint texture_2d; GLint texture_cube_map; diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc index 3c7dfe9..041511e 100644 --- a/content/browser/android/in_process/synchronous_compositor_impl.cc +++ b/content/browser/android/in_process/synchronous_compositor_impl.cc @@ -16,6 +16,7 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/renderer/android/synchronous_compositor_factory.h" +#include "ui/gl/gl_surface.h" #include "webkit/common/gpu/context_provider_in_process.h" namespace content { @@ -143,10 +144,12 @@ void SynchronousCompositorImpl::SetClient( compositor_client_ = compositor_client; } -bool SynchronousCompositorImpl::InitializeHwDraw() { +bool SynchronousCompositorImpl::InitializeHwDraw( + scoped_refptr<gfx::GLSurface> surface) { DCHECK(CalledOnValidThread()); DCHECK(output_surface_); return output_surface_->InitializeHwDraw( + surface, g_factory.Get().GetOffscreenContextProviderForCompositorThread()); } diff --git a/content/browser/android/in_process/synchronous_compositor_impl.h b/content/browser/android/in_process/synchronous_compositor_impl.h index f4c932b..f0ea2c6 100644 --- a/content/browser/android/in_process/synchronous_compositor_impl.h +++ b/content/browser/android/in_process/synchronous_compositor_impl.h @@ -48,7 +48,8 @@ class SynchronousCompositorImpl // SynchronousCompositor virtual void SetClient(SynchronousCompositorClient* compositor_client) OVERRIDE; - virtual bool InitializeHwDraw() OVERRIDE; + virtual bool InitializeHwDraw( + scoped_refptr<gfx::GLSurface> surface) OVERRIDE; virtual void ReleaseHwDraw() OVERRIDE; virtual bool DemandDrawHw( gfx::Size view_size, diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.cc b/content/browser/android/in_process/synchronous_compositor_output_surface.cc index fafd06f..a6115e9 100644 --- a/content/browser/android/in_process/synchronous_compositor_output_surface.cc +++ b/content/browser/android/in_process/synchronous_compositor_output_surface.cc @@ -15,30 +15,50 @@ #include "content/browser/android/in_process/synchronous_compositor_impl.h" #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" #include "content/public/browser/browser_thread.h" +#include "gpu/command_buffer/client/gl_in_process_context.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkDevice.h" #include "ui/gfx/rect_conversions.h" #include "ui/gfx/skia_util.h" #include "ui/gfx/transform.h" -#include "ui/gl/gl_context.h" +#include "ui/gl/gl_surface.h" #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h" -using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; namespace content { namespace { -// TODO(boliu): RenderThreadImpl should create in process contexts as well. -scoped_ptr<WebKit::WebGraphicsContext3D> CreateWebGraphicsContext3D() { +scoped_ptr<WebKit::WebGraphicsContext3D> CreateWebGraphicsContext3D( + scoped_refptr<gfx::GLSurface> surface) { + using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; + if (!gfx::GLSurface::InitializeOneOff()) + return scoped_ptr<WebKit::WebGraphicsContext3D>(); + + const char* allowed_extensions = "*"; + const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; + WebKit::WebGraphicsContext3D::Attributes attributes; attributes.antialias = false; attributes.shareResources = true; attributes.noAutomaticFlushes = true; + gpu::GLInProcessContextAttribs in_process_attribs; + WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes( + attributes, &in_process_attribs); + scoped_ptr<gpu::GLInProcessContext> context( + gpu::GLInProcessContext::CreateWithSurface(surface, + attributes.shareResources, + allowed_extensions, + in_process_attribs, + gpu_preference)); + + if (!context.get()) + return scoped_ptr<WebKit::WebGraphicsContext3D>(); + return scoped_ptr<WebKit::WebGraphicsContext3D>( - WebGraphicsContext3DInProcessCommandBufferImpl - ::CreateViewContext(attributes, NULL)); + WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext( + context.Pass(), attributes)); } void DidActivatePendingTree(int routing_id) { @@ -176,13 +196,15 @@ void AdjustTransformForClip(gfx::Transform* transform, gfx::Rect clip) { } // namespace bool SynchronousCompositorOutputSurface::InitializeHwDraw( + scoped_refptr<gfx::GLSurface> surface, scoped_refptr<cc::ContextProvider> offscreen_context) { DCHECK(CalledOnValidThread()); DCHECK(HasClient()); DCHECK(!context3d_); + DCHECK(surface); - return InitializeAndSetContext3D(CreateWebGraphicsContext3D().Pass(), - offscreen_context); + return InitializeAndSetContext3D( + CreateWebGraphicsContext3D(surface).Pass(), offscreen_context); } void SynchronousCompositorOutputSurface::ReleaseHwDraw() { @@ -205,8 +227,6 @@ bool SynchronousCompositorOutputSurface::DemandDrawHw( SetExternalStencilTest(stencil_enabled); InvokeComposite(clip.size()); - // TODO(boliu): Check if context is lost here. - return did_swap_buffer_; } diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.h b/content/browser/android/in_process/synchronous_compositor_output_surface.h index a3a9066..3ab1498 100644 --- a/content/browser/android/in_process/synchronous_compositor_output_surface.h +++ b/content/browser/android/in_process/synchronous_compositor_output_surface.h @@ -61,7 +61,9 @@ class SynchronousCompositorOutputSurface virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE; // Partial SynchronousCompositor API implementation. - bool InitializeHwDraw(scoped_refptr<cc::ContextProvider> offscreen_context); + bool InitializeHwDraw( + scoped_refptr<gfx::GLSurface> surface, + scoped_refptr<cc::ContextProvider> offscreen_context); void ReleaseHwDraw(); bool DemandDrawHw(gfx::Size surface_size, const gfx::Transform& transform, diff --git a/content/public/browser/android/synchronous_compositor.h b/content/public/browser/android/synchronous_compositor.h index 5223480..f559b973 100644 --- a/content/public/browser/android/synchronous_compositor.h +++ b/content/public/browser/android/synchronous_compositor.h @@ -5,6 +5,7 @@ #ifndef CONTENT_PUBLIC_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_H_ #define CONTENT_PUBLIC_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_H_ +#include "base/memory/ref_counted.h" #include "content/common/content_export.h" #include "ui/gfx/rect.h" #include "ui/gfx/size.h" @@ -12,6 +13,7 @@ class SkCanvas; namespace gfx { +class GLSurface; class Transform; }; @@ -40,8 +42,9 @@ class CONTENT_EXPORT SynchronousCompositor { // Synchronously initialize compositor for hardware draw. Can only be called // while compositor is in software only mode, either after compositor is // first created or after ReleaseHwDraw is called. It is invalid to - // DemandDrawHw before this returns true. - virtual bool InitializeHwDraw() = 0; + // DemandDrawHw before this returns true. |surface| is the GLSurface that + // should be used to create the underlying hardware context. + virtual bool InitializeHwDraw(scoped_refptr<gfx::GLSurface> surface) = 0; // Reverse of InitializeHwDraw above. Can only be called while hardware draw // is already initialized. Brings compositor back to software only mode and diff --git a/gpu/command_buffer/client/gl_in_process_context.cc b/gpu/command_buffer/client/gl_in_process_context.cc index 97f1715..cdbfc9f 100644 --- a/gpu/command_buffer/client/gl_in_process_context.cc +++ b/gpu/command_buffer/client/gl_in_process_context.cc @@ -53,16 +53,17 @@ class GLInProcessContextImpl explicit GLInProcessContextImpl(); virtual ~GLInProcessContextImpl(); - bool Initialize(bool is_offscreen, + bool Initialize(scoped_refptr<gfx::GLSurface> surface, + bool is_offscreen, bool share_resources, gfx::AcceleratedWidget window, const gfx::Size& size, const char* allowed_extensions, - const int32* attrib_list, - gfx::GpuPreference gpu_preference, - const base::Closure& context_lost_callback); + const GLInProcessContextAttribs& attribs, + gfx::GpuPreference gpu_preference); // GLInProcessContext implementation: + virtual void SetContextLostCallback(const base::Closure& callback) OVERRIDE; virtual void SignalSyncPoint(unsigned sync_point, const base::Closure& callback) OVERRIDE; virtual void SignalQuery(unsigned query, const base::Closure& callback) @@ -79,7 +80,7 @@ class GLInProcessContextImpl void Destroy(); void PollQueryCallbacks(); void CallQueryCallback(size_t index); - void OnContextLost(const base::Closure& callback); + void OnContextLost(); void OnSignalSyncPoint(const base::Closure& callback); scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_; @@ -92,6 +93,7 @@ class GLInProcessContextImpl unsigned int share_group_id_; bool context_lost_; + base::Closure context_lost_callback_; DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl); }; @@ -147,9 +149,16 @@ gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() { return gles2_implementation_.get(); } -void GLInProcessContextImpl::OnContextLost(const base::Closure& callback) { +void GLInProcessContextImpl::SetContextLostCallback( + const base::Closure& callback) { + context_lost_callback_ = callback; +} + +void GLInProcessContextImpl::OnContextLost() { context_lost_ = true; - callback.Run(); + if (!context_lost_callback_.is_null()) { + context_lost_callback_.Run(); + } } void GLInProcessContextImpl::OnSignalSyncPoint(const base::Closure& callback) { @@ -159,47 +168,63 @@ void GLInProcessContextImpl::OnSignalSyncPoint(const base::Closure& callback) { } bool GLInProcessContextImpl::Initialize( + scoped_refptr<gfx::GLSurface> surface, bool is_offscreen, bool share_resources, gfx::AcceleratedWidget window, const gfx::Size& size, const char* allowed_extensions, - const int32* attrib_list, - gfx::GpuPreference gpu_preference, - const base::Closure& context_lost_callback) { + const GLInProcessContextAttribs& attribs, + gfx::GpuPreference gpu_preference) { DCHECK(size.width() >= 0 && size.height() >= 0); - std::vector<int32> attribs; - while (attrib_list) { - int32 attrib = *attrib_list++; - switch (attrib) { - // Known attributes - case ALPHA_SIZE: - case BLUE_SIZE: - case GREEN_SIZE: - case RED_SIZE: - case DEPTH_SIZE: - case STENCIL_SIZE: - case SAMPLES: - case SAMPLE_BUFFERS: - attribs.push_back(attrib); - attribs.push_back(*attrib_list++); - break; - case NONE: - attribs.push_back(attrib); - attrib_list = NULL; - break; - default: - attribs.push_back(NONE); - attrib_list = NULL; - break; - } + const int32 ALPHA_SIZE = 0x3021; + const int32 BLUE_SIZE = 0x3022; + const int32 GREEN_SIZE = 0x3023; + const int32 RED_SIZE = 0x3024; + const int32 DEPTH_SIZE = 0x3025; + const int32 STENCIL_SIZE = 0x3026; + const int32 SAMPLES = 0x3031; + const int32 SAMPLE_BUFFERS = 0x3032; + const int32 NONE = 0x3038; + + std::vector<int32> attrib_vector; + if (attribs.alpha_size >= 0) { + attrib_vector.push_back(ALPHA_SIZE); + attrib_vector.push_back(attribs.alpha_size); + } + if (attribs.blue_size >= 0) { + attrib_vector.push_back(BLUE_SIZE); + attrib_vector.push_back(attribs.blue_size); + } + if (attribs.green_size >= 0) { + attrib_vector.push_back(GREEN_SIZE); + attrib_vector.push_back(attribs.green_size); + } + if (attribs.red_size >= 0) { + attrib_vector.push_back(RED_SIZE); + attrib_vector.push_back(attribs.red_size); + } + if (attribs.depth_size >= 0) { + attrib_vector.push_back(DEPTH_SIZE); + attrib_vector.push_back(attribs.depth_size); + } + if (attribs.stencil_size >= 0) { + attrib_vector.push_back(STENCIL_SIZE); + attrib_vector.push_back(attribs.stencil_size); + } + if (attribs.samples >= 0) { + attrib_vector.push_back(SAMPLES); + attrib_vector.push_back(attribs.samples); + } + if (attribs.sample_buffers >= 0) { + attrib_vector.push_back(SAMPLE_BUFFERS); + attrib_vector.push_back(attribs.sample_buffers); } + attrib_vector.push_back(NONE); base::Closure wrapped_callback = - base::Bind(&GLInProcessContextImpl::OnContextLost, - AsWeakPtr(), - context_lost_callback); + base::Bind(&GLInProcessContextImpl::OnContextLost, AsWeakPtr()); command_buffer_.reset(new InProcessCommandBuffer()); scoped_ptr<base::AutoLock> scoped_shared_context_lock; @@ -223,15 +248,16 @@ bool GLInProcessContextImpl::Initialize( if (!share_group && !++share_group_id_) ++share_group_id_; } - if (!command_buffer_->Initialize(is_offscreen, - share_resources, - window, - size, - allowed_extensions, - attribs, - gpu_preference, - wrapped_callback, - share_group_id_)) { + if (!command_buffer_->Initialize(surface, + is_offscreen, + share_resources, + window, + size, + allowed_extensions, + attrib_vector, + gpu_preference, + wrapped_callback, + share_group_id_)) { LOG(INFO) << "Failed to initialize InProcessCommmandBuffer"; return false; } @@ -337,6 +363,16 @@ void GLInProcessContextImpl::SignalQuery( } // anonymous namespace +GLInProcessContextAttribs::GLInProcessContextAttribs() + : alpha_size(-1), + blue_size(-1), + green_size(-1), + red_size(-1), + depth_size(-1), + stencil_size(-1), + samples(-1), + sample_buffers(-1) {} + // static GLInProcessContext* GLInProcessContext::CreateContext( bool is_offscreen, @@ -344,20 +380,42 @@ GLInProcessContext* GLInProcessContext::CreateContext( const gfx::Size& size, bool share_resources, const char* allowed_extensions, - const int32* attrib_list, - gfx::GpuPreference gpu_preference, - const base::Closure& callback) { + const GLInProcessContextAttribs& attribs, + gfx::GpuPreference gpu_preference) { scoped_ptr<GLInProcessContextImpl> context( new GLInProcessContextImpl()); if (!context->Initialize( + NULL /* surface */, is_offscreen, share_resources, window, size, allowed_extensions, - attrib_list, - gpu_preference, - callback)) + attribs, + gpu_preference)) + return NULL; + + return context.release(); +} + +// static +GLInProcessContext* GLInProcessContext::CreateWithSurface( + scoped_refptr<gfx::GLSurface> surface, + bool share_resources, + const char* allowed_extensions, + const GLInProcessContextAttribs& attribs, + gfx::GpuPreference gpu_preference) { + scoped_ptr<GLInProcessContextImpl> context( + new GLInProcessContextImpl()); + if (!context->Initialize( + surface, + surface->IsOffscreen(), + share_resources, + gfx::kNullAcceleratedWidget, + surface->GetSize(), + allowed_extensions, + attribs, + gpu_preference)) return NULL; return context.release(); diff --git a/gpu/command_buffer/client/gl_in_process_context.h b/gpu/command_buffer/client/gl_in_process_context.h index 2d0754b..09f8140 100644 --- a/gpu/command_buffer/client/gl_in_process_context.h +++ b/gpu/command_buffer/client/gl_in_process_context.h @@ -9,6 +9,7 @@ #include "base/compiler_specific.h" #include "gles2_impl_export.h" #include "ui/gfx/native_widget_types.h" +#include "ui/gl/gl_surface.h" #include "ui/gl/gpu_preference.h" namespace gfx { @@ -23,6 +24,20 @@ class GLES2Implementation; class GpuMemoryBufferFactory; +// The default uninitialized value is -1. +struct GLES2_IMPL_EXPORT GLInProcessContextAttribs { + GLInProcessContextAttribs(); + + int32 alpha_size; + int32 blue_size; + int32 green_size; + int32 red_size; + int32 depth_size; + int32 stencil_size; + int32 samples; + int32 sample_buffers; +}; + class GLES2_IMPL_EXPORT GLInProcessContext { public: virtual ~GLInProcessContext() {} @@ -30,20 +45,6 @@ class GLES2_IMPL_EXPORT GLInProcessContext { // Must be called before any GLInProcessContext instances are created. static void SetGpuMemoryBufferFactory(GpuMemoryBufferFactory* factory); - // GLInProcessContext configuration attributes. These are the same as used by - // EGL. Attributes are matched using a closest fit algorithm. - enum Attribute { - ALPHA_SIZE = 0x3021, - BLUE_SIZE = 0x3022, - GREEN_SIZE = 0x3023, - RED_SIZE = 0x3024, - DEPTH_SIZE = 0x3025, - STENCIL_SIZE = 0x3026, - SAMPLES = 0x3031, - SAMPLE_BUFFERS = 0x3032, - NONE = 0x3038 // Attrib list = terminator - }; - // Create a GLInProcessContext, if |is_offscreen| is true, renders to an // offscreen context. |attrib_list| must be NULL or a NONE-terminated list // of attribute/value pairs. @@ -53,9 +54,21 @@ class GLES2_IMPL_EXPORT GLInProcessContext { const gfx::Size& size, bool share_resources, const char* allowed_extensions, - const int32* attrib_list, - gfx::GpuPreference gpu_preference, - const base::Closure& callback); + const GLInProcessContextAttribs& attribs, + gfx::GpuPreference gpu_preference); + + // Create context with the provided GLSurface. All other arguments match + // CreateContext factory above. Can only be called if the command buffer + // service runs on the same thread as this client because GLSurface is not + // thread safe. + static GLInProcessContext* CreateWithSurface( + scoped_refptr<gfx::GLSurface> surface, + bool share_resources, + const char* allowed_extensions, + const GLInProcessContextAttribs& attribs, + gfx::GpuPreference gpu_preference); + + virtual void SetContextLostCallback(const base::Closure& callback) = 0; virtual void SignalSyncPoint(unsigned sync_point, const base::Closure& callback) = 0; diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc index 766a7e0..ccbfb32 100644 --- a/gpu/command_buffer/service/in_process_command_buffer.cc +++ b/gpu/command_buffer/service/in_process_command_buffer.cc @@ -20,6 +20,7 @@ #include "base/logging.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/sequence_checker.h" #include "base/threading/thread.h" #include "gpu/command_buffer/common/id_allocator.h" #include "gpu/command_buffer/service/command_buffer_service.h" @@ -32,7 +33,6 @@ #include "ui/gl/gl_context.h" #include "ui/gl/gl_image.h" #include "ui/gl/gl_share_group.h" -#include "ui/gl/gl_surface.h" namespace gpu { @@ -244,6 +244,7 @@ InProcessCommandBuffer::~InProcessCommandBuffer() { } bool InProcessCommandBuffer::IsContextLost() { + CheckSequencedThread(); if (context_lost_ || !command_buffer_) { return true; } @@ -252,11 +253,13 @@ bool InProcessCommandBuffer::IsContextLost() { } void InProcessCommandBuffer::OnResizeView(gfx::Size size, float scale_factor) { + CheckSequencedThread(); DCHECK(!surface_->IsOffscreen()); surface_->Resize(size); } bool InProcessCommandBuffer::MakeCurrent() { + CheckSequencedThread(); command_buffer_lock_.AssertAcquired(); if (!context_lost_ && decoder_->MakeCurrent()) @@ -268,6 +271,7 @@ bool InProcessCommandBuffer::MakeCurrent() { } void InProcessCommandBuffer::PumpCommands() { + CheckSequencedThread(); command_buffer_lock_.AssertAcquired(); if (!MakeCurrent()) @@ -277,12 +281,14 @@ void InProcessCommandBuffer::PumpCommands() { } bool InProcessCommandBuffer::GetBufferChanged(int32 transfer_buffer_id) { + CheckSequencedThread(); command_buffer_lock_.AssertAcquired(); command_buffer_->SetGetBuffer(transfer_buffer_id); return true; } bool InProcessCommandBuffer::Initialize( + scoped_refptr<gfx::GLSurface> surface, bool is_offscreen, bool share_resources, gfx::AcceleratedWidget window, @@ -297,8 +303,13 @@ bool InProcessCommandBuffer::Initialize( context_lost_callback_ = WrapCallback(context_lost_callback); share_group_id_ = share_group_id; - base::WaitableEvent completion(true, false); - bool result = false; + if (surface) { + // GPU thread must be the same as client thread due to GLSurface not being + // thread safe. + sequence_checker_.reset(new base::SequenceChecker); + surface_ = surface; + } + base::Callback<bool(void)> init_task = base::Bind(&InProcessCommandBuffer::InitializeOnGpuThread, base::Unretained(this), @@ -308,6 +319,9 @@ bool InProcessCommandBuffer::Initialize( allowed_extensions, attribs, gpu_preference); + + base::WaitableEvent completion(true, false); + bool result = false; QueueTask( base::Bind(&RunTaskWithResult<bool>, init_task, &result, &completion)); completion.Wait(); @@ -321,6 +335,7 @@ bool InProcessCommandBuffer::InitializeOnGpuThread( const char* allowed_extensions, const std::vector<int32>& attribs, gfx::GpuPreference gpu_preference) { + CheckSequencedThread(); // Use one share group for all contexts. CR_DEFINE_STATIC_LOCAL(scoped_refptr<gfx::GLShareGroup>, share_group, (new gfx::GLShareGroup)); @@ -377,10 +392,12 @@ bool InProcessCommandBuffer::InitializeOnGpuThread( decoder_->set_engine(gpu_scheduler_.get()); - if (is_offscreen) - surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size); - else - surface_ = gfx::GLSurface::CreateViewGLSurface(window); + if (!surface_) { + if (is_offscreen) + surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size); + else + surface_ = gfx::GLSurface::CreateViewGLSurface(window); + } if (!surface_.get()) { LOG(ERROR) << "Could not create GLSurface."; @@ -448,6 +465,7 @@ bool InProcessCommandBuffer::InitializeOnGpuThread( } void InProcessCommandBuffer::Destroy() { + CheckSequencedThread(); base::WaitableEvent completion(true, false); bool result = false; base::Callback<bool(void)> destroy_task = base::Bind( @@ -458,6 +476,7 @@ void InProcessCommandBuffer::Destroy() { } bool InProcessCommandBuffer::DestroyOnGpuThread() { + CheckSequencedThread(); command_buffer_.reset(); // Clean up GL resources if possible. bool have_context = context_ && context_->MakeCurrent(surface_); @@ -472,9 +491,15 @@ bool InProcessCommandBuffer::DestroyOnGpuThread() { return true; } +void InProcessCommandBuffer::CheckSequencedThread() { + DCHECK(!sequence_checker_ || + sequence_checker_->CalledOnValidSequencedThread()); +} + unsigned int InProcessCommandBuffer::CreateImageForGpuMemoryBuffer( gfx::GpuMemoryBufferHandle buffer, gfx::Size size) { + CheckSequencedThread(); unsigned int image_id; { // TODO: ID allocation should go through CommandBuffer @@ -494,12 +519,14 @@ void InProcessCommandBuffer::CreateImageOnGpuThread( gfx::GpuMemoryBufferHandle buffer, gfx::Size size, unsigned int image_id) { + CheckSequencedThread(); scoped_refptr<gfx::GLImage> gl_image = gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer, size); decoder_->GetContextGroup()->image_manager()->AddImage(gl_image, image_id); } void InProcessCommandBuffer::RemoveImage(unsigned int image_id) { + CheckSequencedThread(); { // TODO: ID allocation should go through CommandBuffer base::AutoLock lock(command_buffer_lock_); @@ -514,10 +541,12 @@ void InProcessCommandBuffer::RemoveImage(unsigned int image_id) { } void InProcessCommandBuffer::RemoveImageOnGpuThread(unsigned int image_id) { + CheckSequencedThread(); decoder_->GetContextGroup()->image_manager()->RemoveImage(image_id); } void InProcessCommandBuffer::OnContextLost() { + CheckSequencedThread(); if (!context_lost_callback_.is_null()) { context_lost_callback_.Run(); context_lost_callback_.Reset(); @@ -535,6 +564,7 @@ void InProcessCommandBuffer::OnContextLost() { } CommandBuffer::State InProcessCommandBuffer::GetStateFast() { + CheckSequencedThread(); base::AutoLock lock(state_after_last_flush_lock_); if (state_after_last_flush_.generation - last_state_.generation < 0x80000000U) last_state_ = state_after_last_flush_; @@ -542,19 +572,23 @@ CommandBuffer::State InProcessCommandBuffer::GetStateFast() { } CommandBuffer::State InProcessCommandBuffer::GetState() { + CheckSequencedThread(); return GetStateFast(); } CommandBuffer::State InProcessCommandBuffer::GetLastState() { + CheckSequencedThread(); return last_state_; } int32 InProcessCommandBuffer::GetLastToken() { + CheckSequencedThread(); GetStateFast(); return last_state_.token; } void InProcessCommandBuffer::FlushOnGpuThread(int32 put_offset) { + CheckSequencedThread(); ScopedEvent handle_flush(&flush_event_); base::AutoLock lock(command_buffer_lock_); command_buffer_->Flush(put_offset); @@ -568,6 +602,7 @@ void InProcessCommandBuffer::FlushOnGpuThread(int32 put_offset) { } void InProcessCommandBuffer::Flush(int32 put_offset) { + CheckSequencedThread(); if (last_state_.error != gpu::error::kNoError) return; @@ -583,6 +618,7 @@ void InProcessCommandBuffer::Flush(int32 put_offset) { CommandBuffer::State InProcessCommandBuffer::FlushSync(int32 put_offset, int32 last_known_get) { + CheckSequencedThread(); if (put_offset == last_known_get || last_state_.error != gpu::error::kNoError) return last_state_; @@ -598,6 +634,7 @@ CommandBuffer::State InProcessCommandBuffer::FlushSync(int32 put_offset, } void InProcessCommandBuffer::SetGetBuffer(int32 shm_id) { + CheckSequencedThread(); if (last_state_.error != gpu::error::kNoError) return; @@ -614,11 +651,13 @@ void InProcessCommandBuffer::SetGetBuffer(int32 shm_id) { gpu::Buffer InProcessCommandBuffer::CreateTransferBuffer(size_t size, int32* id) { + CheckSequencedThread(); base::AutoLock lock(command_buffer_lock_); return command_buffer_->CreateTransferBuffer(size, id); } void InProcessCommandBuffer::DestroyTransferBuffer(int32 id) { + CheckSequencedThread(); base::Closure task = base::Bind(&CommandBuffer::DestroyTransferBuffer, base::Unretained(command_buffer_.get()), id); @@ -637,10 +676,12 @@ uint32 InProcessCommandBuffer::InsertSyncPoint() { } void InProcessCommandBuffer::SignalSyncPoint(unsigned sync_point, const base::Closure& callback) { + CheckSequencedThread(); QueueTask(WrapCallback(callback)); } gpu::error::Error InProcessCommandBuffer::GetLastError() { + CheckSequencedThread(); return last_state_.error; } diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h index d2e103a..9bdbd49 100644 --- a/gpu/command_buffer/service/in_process_command_buffer.h +++ b/gpu/command_buffer/service/in_process_command_buffer.h @@ -17,8 +17,13 @@ #include "gpu/gpu_export.h" #include "ui/gfx/gpu_memory_buffer.h" #include "ui/gfx/native_widget_types.h" +#include "ui/gl/gl_surface.h" #include "ui/gl/gpu_preference.h" +namespace base { +class SequenceChecker; +} + namespace gfx { class GLContext; class GLImage; @@ -57,7 +62,11 @@ class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer { static void EnableVirtualizedContext(); - bool Initialize(bool is_offscreen, + // If |surface| is not NULL, use it directly; in this case, the command + // buffer gpu thread must be the same as the client thread. Otherwise create + // a new GLSurface. + bool Initialize(scoped_refptr<gfx::GLSurface> surface, + bool is_offscreen, bool share_resources, gfx::AcceleratedWidget window, const gfx::Size& size, @@ -118,6 +127,7 @@ class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer { base::Closure WrapCallback(const base::Closure& callback); State GetStateFast(); void QueueTask(const base::Closure& task) { queue_->QueueTask(task); } + void CheckSequencedThread(); // Callbacks: void OnContextLost(); @@ -149,6 +159,10 @@ class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer { State state_after_last_flush_; base::Lock state_after_last_flush_lock_; + // Only used with explicit scheduling and the gpu thread is the same as + // the client thread. + scoped_ptr<base::SequenceChecker> sequence_checker_; + DISALLOW_COPY_AND_ASSIGN(InProcessCommandBuffer); }; diff --git a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc index 57767ec..886e40f 100644 --- a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc +++ b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc @@ -73,7 +73,7 @@ WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext( scoped_ptr<WebKit::WebGraphicsContext3D> context; if (gfx::GLSurface::InitializeOneOff()) { context.reset(new WebGraphicsContext3DInProcessCommandBufferImpl( - attributes, false, window)); + scoped_ptr< ::gpu::GLInProcessContext>(), attributes, false, window)); } return context.Pass(); } @@ -83,12 +83,29 @@ scoped_ptr<WebKit::WebGraphicsContext3D> WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext( const WebKit::WebGraphicsContext3D::Attributes& attributes) { return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl( - attributes, true, gfx::kNullAcceleratedWidget)) + scoped_ptr< ::gpu::GLInProcessContext>(), + attributes, + true, + gfx::kNullAcceleratedWidget)) + .PassAs<WebKit::WebGraphicsContext3D>(); +} + +scoped_ptr<WebKit::WebGraphicsContext3D> +WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext( + scoped_ptr< ::gpu::GLInProcessContext> context, + const WebKit::WebGraphicsContext3D::Attributes& attributes) { + return make_scoped_ptr( + new WebGraphicsContext3DInProcessCommandBufferImpl( + context.Pass(), + attributes, + true /* is_offscreen. Not used. */, + gfx::kNullAcceleratedWidget /* window. Not used. */)) .PassAs<WebKit::WebGraphicsContext3D>(); } WebGraphicsContext3DInProcessCommandBufferImpl:: WebGraphicsContext3DInProcessCommandBufferImpl( + scoped_ptr< ::gpu::GLInProcessContext> context, const WebKit::WebGraphicsContext3D::Attributes& attributes, bool is_offscreen, gfx::AcceleratedWidget window) @@ -96,6 +113,7 @@ WebGraphicsContext3DInProcessCommandBufferImpl:: window_(window), initialized_(false), initialize_failed_(false), + context_(context.Pass()), gl_(NULL), context_lost_callback_(NULL), context_lost_reason_(GL_NO_ERROR), @@ -108,6 +126,17 @@ WebGraphicsContext3DInProcessCommandBufferImpl:: ~WebGraphicsContext3DInProcessCommandBufferImpl() { } +// static +void WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes( + const WebKit::WebGraphicsContext3D::Attributes& attributes, + ::gpu::GLInProcessContextAttribs* output_attribs) { + output_attribs->alpha_size = attributes.alpha ? 8 : 0; + output_attribs->depth_size = attributes.depth ? 24 : 0; + output_attribs->stencil_size = attributes.stencil ? 8 : 0; + output_attribs->samples = attributes.antialias ? 4 : 0; + output_attribs->sample_buffers = attributes.antialias ? 1 : 0; +} + bool WebGraphicsContext3DInProcessCommandBufferImpl::MaybeInitializeGL() { if (initialized_) return true; @@ -118,46 +147,35 @@ bool WebGraphicsContext3DInProcessCommandBufferImpl::MaybeInitializeGL() { // Ensure the gles2 library is initialized first in a thread safe way. g_gles2_initializer.Get(); - // Convert WebGL context creation attributes into GLInProcessContext / 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[] = { - GLInProcessContext::ALPHA_SIZE, alpha_size, - GLInProcessContext::DEPTH_SIZE, depth_size, - GLInProcessContext::STENCIL_SIZE, stencil_size, - GLInProcessContext::SAMPLES, samples, - GLInProcessContext::SAMPLE_BUFFERS, sample_buffers, - GLInProcessContext::NONE, - }; - - const char* preferred_extensions = "*"; - - // TODO(kbr): More work will be needed in this implementation to - // properly support GPU switching. Like in the out-of-process - // command buffer implementation, all previously created contexts - // will need to be lost either when the first context requesting the - // discrete GPU is created, or the last one is destroyed. - gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; - - base::Closure context_lost_callback = - base::Bind(&WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost, - base::Unretained(this)); - - context_.reset(GLInProcessContext::CreateContext( - is_offscreen_, - window_, - gfx::Size(1, 1), - attributes_.shareResources, - preferred_extensions, - attribs, - gpu_preference, - context_lost_callback)); - if (!context_) { + const char* preferred_extensions = "*"; + + // TODO(kbr): More work will be needed in this implementation to + // properly support GPU switching. Like in the out-of-process + // command buffer implementation, all previously created contexts + // will need to be lost either when the first context requesting the + // discrete GPU is created, or the last one is destroyed. + gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; + + ::gpu::GLInProcessContextAttribs attrib_struct; + ConvertAttributes(attributes_, &attrib_struct), + + context_.reset(GLInProcessContext::CreateContext( + is_offscreen_, + window_, + gfx::Size(1, 1), + attributes_.shareResources, + preferred_extensions, + attrib_struct, + gpu_preference)); + } + + if (context_) { + base::Closure context_lost_callback = base::Bind( + &WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost, + base::Unretained(this)); + context_->SetContextLostCallback(context_lost_callback); + } else { initialize_failed_ = true; return false; } diff --git a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h index 9ef3698..d3620b4 100644 --- a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h +++ b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h @@ -39,6 +39,7 @@ using WebKit::WGC3Dsizeiptr; namespace gpu { class GLInProcessContext; +struct GLInProcessContextAttribs; } namespace webkit { @@ -54,8 +55,18 @@ class WEBKIT_GPU_EXPORT WebGraphicsContext3DInProcessCommandBufferImpl static scoped_ptr<WebKit::WebGraphicsContext3D> CreateOffscreenContext( const WebKit::WebGraphicsContext3D::Attributes& attributes); + static scoped_ptr<WebKit::WebGraphicsContext3D> WrapContext( + scoped_ptr< ::gpu::GLInProcessContext> context, + const WebKit::WebGraphicsContext3D::Attributes& attributes); + virtual ~WebGraphicsContext3DInProcessCommandBufferImpl(); + // Convert WebGL context creation attributes into GLInProcessContext / EGL + // size requests. + static void ConvertAttributes( + const WebKit::WebGraphicsContext3D::Attributes& attributes, + ::gpu::GLInProcessContextAttribs* output_attribs); + //---------------------------------------------------------------------- // WebGraphicsContext3D methods virtual bool makeContextCurrent(); @@ -536,6 +547,7 @@ class WEBKIT_GPU_EXPORT WebGraphicsContext3DInProcessCommandBufferImpl private: WebGraphicsContext3DInProcessCommandBufferImpl( + scoped_ptr< ::gpu::GLInProcessContext> context, const WebKit::WebGraphicsContext3D::Attributes& attributes, bool is_offscreen, gfx::AcceleratedWidget window); |