diff options
9 files changed, 134 insertions, 73 deletions
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc index 9e9711d..c6188e3 100644 --- a/android_webview/browser/browser_view_renderer.cc +++ b/android_webview/browser/browser_view_renderer.cc @@ -109,7 +109,7 @@ bool BrowserViewRenderer::OnDraw(jobject java_canvas, // We should be performing a hardware draw here. If we don't have the // compositor yet or if RequestDrawGL fails, it means we failed this draw // and thus return false here to clear to background color for this draw. - return has_compositor_ && client_->RequestDrawGL(java_canvas); + return has_compositor_ && client_->RequestDrawGL(java_canvas, false); } // Perform a software draw return DrawSWInternal(java_canvas, clip); diff --git a/android_webview/browser/browser_view_renderer_client.h b/android_webview/browser/browser_view_renderer_client.h index 382ce0d..fce1c80 100644 --- a/android_webview/browser/browser_view_renderer_client.h +++ b/android_webview/browser/browser_view_renderer_client.h @@ -15,9 +15,11 @@ namespace android_webview { class BrowserViewRendererClient { public: // Request DrawGL be called. Passing null |canvas| implies the request - // will be of AwDrawGLInfo::kModeProcess type. The callback - // may never be made, and the mode may be promoted to kModeDraw. - virtual bool RequestDrawGL(jobject canvas) = 0; + // will be of AwDrawGLInfo::kModeProcess type. |wait_for_completion| + // will cause the call to block until DrawGL has happened; it does not + // work when |canvas| is not NULL. The callback may never be made, and + // the mode may be promoted to kModeDraw. + virtual bool RequestDrawGL(jobject canvas, bool wait_for_completion) = 0; // Called when a new Picture is available. Needs to be enabled // via the EnableOnNewPicture method. diff --git a/android_webview/browser/shared_renderer_state.cc b/android_webview/browser/shared_renderer_state.cc index 1e82438..ffc91ea 100644 --- a/android_webview/browser/shared_renderer_state.cc +++ b/android_webview/browser/shared_renderer_state.cc @@ -20,7 +20,8 @@ SharedRendererState::SharedRendererState( : ui_loop_(ui_loop), client_on_ui_(client), weak_factory_on_ui_thread_(this), - ui_thread_weak_ptr_(weak_factory_on_ui_thread_.GetWeakPtr()) { + ui_thread_weak_ptr_(weak_factory_on_ui_thread_.GetWeakPtr()), + hardware_initialized_(false) { DCHECK(ui_loop_->BelongsToCurrentThread()); DCHECK(client_on_ui_); } @@ -40,7 +41,7 @@ void SharedRendererState::ClientRequestDrawGL() { void SharedRendererState::ClientRequestDrawGLOnUIThread() { DCHECK(ui_loop_->BelongsToCurrentThread()); - if (!client_on_ui_->RequestDrawGL(NULL)) { + if (!client_on_ui_->RequestDrawGL(NULL, false)) { LOG(ERROR) << "Failed to request GL process. Deadlock likely"; } } @@ -68,4 +69,37 @@ DrawGLInput SharedRendererState::GetDrawGLInput() const { return draw_gl_input_; } +void SharedRendererState::ClearClosureQueue() { + base::AutoLock lock(lock_); + std::queue<base::Closure> empty; + std::swap(closure_queue_, empty); +} + +void SharedRendererState::AppendClosure(const base::Closure& closure) { + base::AutoLock lock(lock_); + closure_queue_.push(closure); +} + +base::Closure SharedRendererState::PopFrontClosure() { + base::Closure closure; + + base::AutoLock lock(lock_); + if (!closure_queue_.empty()) { + closure = closure_queue_.front(); + closure_queue_.pop(); + } + + return closure; +} + +void SharedRendererState::SetHardwareInitialized(bool initialized) { + base::AutoLock lock(lock_); + hardware_initialized_ = initialized; +} + +bool SharedRendererState::IsHardwareInitialized() const { + base::AutoLock lock(lock_); + return hardware_initialized_; +} + } // namespace android_webview diff --git a/android_webview/browser/shared_renderer_state.h b/android_webview/browser/shared_renderer_state.h index ec21663..c2c1eee 100644 --- a/android_webview/browser/shared_renderer_state.h +++ b/android_webview/browser/shared_renderer_state.h @@ -5,6 +5,9 @@ #ifndef ANDROID_WEBVIEW_BROWSER_SHARED_RENDERER_STATE_H_ #define ANDROID_WEBVIEW_BROWSER_SHARED_RENDERER_STATE_H_ +#include <queue> + +#include "base/callback.h" #include "base/message_loop/message_loop_proxy.h" #include "base/synchronization/lock.h" #include "content/public/browser/android/synchronous_compositor.h" @@ -55,6 +58,14 @@ class SharedRendererState { void SetDrawGLInput(const DrawGLInput& input); DrawGLInput GetDrawGLInput() const; + void ClearClosureQueue(); + void AppendClosure(const base::Closure& closure); + // Will return empty closure if queue empty. + base::Closure PopFrontClosure(); + + void SetHardwareInitialized(bool initialized); + bool IsHardwareInitialized() const; + private: void ClientRequestDrawGLOnUIThread(); @@ -68,6 +79,8 @@ class SharedRendererState { mutable base::Lock lock_; content::SynchronousCompositor* compositor_; DrawGLInput draw_gl_input_; + std::queue<base::Closure> closure_queue_; + bool hardware_initialized_; }; } // namespace android_webview diff --git a/android_webview/buildbot/aosp_manifest.xml b/android_webview/buildbot/aosp_manifest.xml index 7597cc89..aa91a54 100644 --- a/android_webview/buildbot/aosp_manifest.xml +++ b/android_webview/buildbot/aosp_manifest.xml @@ -244,7 +244,7 @@ <project path="frameworks/testing" name="platform/frameworks/testing" /> <project path="frameworks/uiautomator" name="platform/frameworks/uiautomator" /> <project path="frameworks/volley" name="platform/frameworks/volley" /> - <project path="frameworks/webview" name="platform/frameworks/webview" revision="2e8d713894b88bf8df125735d28963690b78f154" remote="aosp" /> + <project path="frameworks/webview" name="platform/frameworks/webview" revision="24c4a3d70e8a2f1001e100ac78c0c1673c5710c3" remote="aosp" /> <project path="frameworks/wilhelm" name="platform/frameworks/wilhelm" /> <project path="hardware/akm" name="platform/hardware/akm" /> <project path="hardware/broadcom/libbt" name="platform/hardware/broadcom/libbt" groups="pdk" /> diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 875f2a0..f166d99 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -136,18 +136,14 @@ public class AwContents { * Requests a callback on the native DrawGL method (see getAwDrawGLFunction) * if called from within onDraw, |canvas| will be non-null and hardware accelerated. * otherwise, |canvas| will be null, and the container view itself will be hardware - * accelerated. + * accelerated. If |waitForCompletion| is true, this method will not return until + * functor has returned. + * Should avoid setting |waitForCompletion| when |canvas| is not null. * * @return false indicates the GL draw request was not accepted, and the caller * should fallback to the SW path. */ - boolean requestDrawGL(Canvas canvas); - - /** - * Run the action on with EGLContext current or return false. - * See hidden View#executeHardwareAction for details. - */ - public boolean executeHardwareAction(Runnable action); + boolean requestDrawGL(Canvas canvas, boolean waitForCompletion); } /** @@ -444,14 +440,7 @@ public class AwContents { if (mNativeAwContents == 0) return; boolean visibleRectEmpty = getGlobalVisibleRect().isEmpty(); final boolean visible = mIsViewVisible && mIsWindowVisible && !visibleRectEmpty; - // Don't care about return value of executeHardwareAction since if view is not - // hardware accelerated, then there is nothing to clean up anyway. - mInternalAccessAdapter.executeHardwareAction(new Runnable() { - @Override - public void run() { - nativeTrimMemoryOnRenderThread(mNativeAwContents, level, visible); - } - }); + nativeTrimMemory(mNativeAwContents, level, visible); } @Override @@ -1630,18 +1619,6 @@ public class AwContents { mIsAttachedToWindow = false; hideAutofillPopup(); if (mNativeAwContents != 0) { - Runnable releaseHardware = new Runnable() { - @Override - public void run() { - nativeReleaseHardwareDrawOnRenderThread(mNativeAwContents); - } - }; - boolean result = mInternalAccessAdapter.executeHardwareAction(releaseHardware); - if (!result) { - Log.e(TAG, "May leak or deadlock. Leaked window?"); - releaseHardware.run(); - } - nativeOnDetachedFromWindow(mNativeAwContents); } @@ -1933,8 +1910,8 @@ public class AwContents { } @CalledByNative - private boolean requestDrawGL(Canvas canvas) { - return mInternalAccessAdapter.requestDrawGL(canvas); + private boolean requestDrawGL(Canvas canvas, boolean waitForCompletion) { + return mInternalAccessAdapter.requestDrawGL(canvas, waitForCompletion); } private static final boolean SUPPORTS_ON_ANIMATION = @@ -2133,7 +2110,6 @@ public class AwContents { private native void nativeSetIsPaused(long nativeAwContents, boolean paused); private native void nativeOnAttachedToWindow(long nativeAwContents, int w, int h); private static native void nativeOnDetachedFromWindow(long nativeAwContents); - private static native void nativeReleaseHardwareDrawOnRenderThread(long nativeAwContents); private native void nativeSetDipScale(long nativeAwContents, float dipScale); private native void nativeSetFixedLayoutSize(long nativeAwContents, int widthDip, int heightDip); @@ -2160,8 +2136,7 @@ public class AwContents { private native void nativeSetJsOnlineProperty(long nativeAwContents, boolean networkUp); - private native void nativeTrimMemoryOnRenderThread(long nativeAwContents, int level, - boolean visible); + private native void nativeTrimMemory(long nativeAwContents, int level, boolean visible); private native void nativeCreatePdfExporter(long nativeAwContents, AwPdfExporter awPdfExporter); diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc index c9d38d6..ee0e87b 100644 --- a/android_webview/native/aw_contents.cc +++ b/android_webview/native/aw_contents.cc @@ -316,15 +316,14 @@ jlong AwContents::GetAwDrawGLViewContext(JNIEnv* env, jobject obj) { } void AwContents::DrawGL(AwDrawGLInfo* draw_info) { - if (!hardware_renderer_) { - // TODO(boliu): Use executeHardwareAction to synchronously initialize - // hardware on first functor request. Then functor can point directly - // to HardwareRenderer. - hardware_renderer_.reset(new HardwareRenderer(&shared_renderer_state_)); + for (base::Closure c = shared_renderer_state_.PopFrontClosure(); !c.is_null(); + c = shared_renderer_state_.PopFrontClosure()) { + c.Run(); } + // TODO(boliu): Make this a task as well. DrawGLResult result; - if (hardware_renderer_->DrawGL(draw_info, &result)) { + if (hardware_renderer_ && hardware_renderer_->DrawGL(draw_info, &result)) { content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, @@ -605,13 +604,15 @@ void AwContents::OnReceivedTouchIconUrl(const std::string& url, env, obj.obj(), ConvertUTF8ToJavaString(env, url).obj(), precomposed); } -bool AwContents::RequestDrawGL(jobject canvas) { +bool AwContents::RequestDrawGL(jobject canvas, bool wait_for_completion) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!canvas || !wait_for_completion); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); if (obj.is_null()) return false; - return Java_AwContents_requestDrawGL(env, obj.obj(), canvas); + return Java_AwContents_requestDrawGL( + env, obj.obj(), canvas, wait_for_completion); } void AwContents::PostInvalidate() { @@ -726,16 +727,47 @@ void AwContents::SetIsPaused(JNIEnv* env, jobject obj, bool paused) { void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // Add task but don't schedule it. It will run when DrawGL is called for + // the first time. + shared_renderer_state_.AppendClosure( + base::Bind(&AwContents::InitializeHardwareDrawOnRenderThread, + base::Unretained(this))); browser_view_renderer_.OnAttachedToWindow(w, h); } +void AwContents::InitializeHardwareDrawOnRenderThread() { + DCHECK(!hardware_renderer_); + DCHECK(!shared_renderer_state_.IsHardwareInitialized()); + hardware_renderer_.reset(new HardwareRenderer(&shared_renderer_state_)); + shared_renderer_state_.SetHardwareInitialized(true); +} + void AwContents::OnDetachedFromWindow(JNIEnv* env, jobject obj) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + shared_renderer_state_.ClearClosureQueue(); + shared_renderer_state_.AppendClosure(base::Bind( + &AwContents::ReleaseHardwareDrawOnRenderThread, base::Unretained(this))); + bool draw_functor_succeeded = RequestDrawGL(NULL, true); + if (!draw_functor_succeeded && + shared_renderer_state_.IsHardwareInitialized()) { + LOG(ERROR) << "Unable to free GL resources. Has the Window leaked"; + // Calling release on wrong thread intentionally. + ReleaseHardwareDrawOnRenderThread(); + } else { + shared_renderer_state_.ClearClosureQueue(); + } + browser_view_renderer_.OnDetachedFromWindow(); } -void AwContents::ReleaseHardwareDrawOnRenderThread(JNIEnv* env, jobject obj) { +void AwContents::ReleaseHardwareDrawOnRenderThread() { + DCHECK(hardware_renderer_); + DCHECK(shared_renderer_state_.IsHardwareInitialized()); + // No point in running any other commands if we released hardware already. + shared_renderer_state_.ClearClosureQueue(); hardware_renderer_.reset(); + shared_renderer_state_.SetHardwareInitialized(false); } base::android::ScopedJavaLocalRef<jbyteArray> @@ -994,17 +1026,27 @@ void AwContents::SetJsOnlineProperty(JNIEnv* env, render_view_host_ext_->SetJsOnlineProperty(network_up); } -void AwContents::TrimMemoryOnRenderThread(JNIEnv* env, - jobject obj, - jint level, - jboolean visible) { - if (hardware_renderer_) { - if (hardware_renderer_->TrimMemory(level, visible)) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::Bind(&AwContents::ForceFakeComposite, ui_thread_weak_ptr_)); - } +void AwContents::TrimMemory(JNIEnv* env, + jobject obj, + jint level, + jboolean visible) { + if (!shared_renderer_state_.IsHardwareInitialized()) + return; + + shared_renderer_state_.AppendClosure( + base::Bind(&AwContents::TrimMemoryOnRenderThread, + base::Unretained(this), + level, + visible)); + RequestDrawGL(NULL, true); +} + +void AwContents::TrimMemoryOnRenderThread(int level, bool visible) { + if (hardware_renderer_ && hardware_renderer_->TrimMemory(level, visible)) { + content::BrowserThread::PostTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&AwContents::ForceFakeComposite, ui_thread_weak_ptr_)); } } diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h index 24e430f..6c7d467 100644 --- a/android_webview/native/aw_contents.h +++ b/android_webview/native/aw_contents.h @@ -100,7 +100,6 @@ class AwContents : public FindHelper::Listener, void SetIsPaused(JNIEnv* env, jobject obj, bool paused); void OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h); void OnDetachedFromWindow(JNIEnv* env, jobject obj); - void ReleaseHardwareDrawOnRenderThread(JNIEnv* env, jobject obj); base::android::ScopedJavaLocalRef<jbyteArray> GetOpaqueState( JNIEnv* env, jobject obj); jboolean RestoreFromOpaqueState(JNIEnv* env, jobject obj, jbyteArray state); @@ -163,8 +162,8 @@ class AwContents : public FindHelper::Listener, virtual void OnWebLayoutContentsSizeChanged( const gfx::Size& contents_size) OVERRIDE; - // BrowserViewRenderer::Client implementation. - virtual bool RequestDrawGL(jobject canvas) OVERRIDE; + // BrowserViewRendererClient implementation. + virtual bool RequestDrawGL(jobject canvas, bool wait_for_completion) OVERRIDE; virtual void PostInvalidate() OVERRIDE; virtual void OnNewPicture() OVERRIDE; virtual gfx::Point GetLocationOnScreen() OVERRIDE; @@ -197,16 +196,17 @@ class AwContents : public FindHelper::Listener, void SetAwAutofillManagerDelegate(jobject delegate); void SetJsOnlineProperty(JNIEnv* env, jobject obj, jboolean network_up); - void TrimMemoryOnRenderThread(JNIEnv* env, - jobject obj, - jint level, - jboolean visible); + void TrimMemory(JNIEnv* env, jobject obj, jint level, jboolean visible); private: void InitAutofillIfNecessary(bool enabled); void DidDrawGL(const DrawGLResult& result); void ForceFakeComposite(); + void InitializeHardwareDrawOnRenderThread(); + void ReleaseHardwareDrawOnRenderThread(); + void TrimMemoryOnRenderThread(int level, bool visible); + base::WeakPtrFactory<AwContents> weak_factory_on_ui_thread_; base::WeakPtr<AwContents> ui_thread_weak_ptr_; diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java index a106096..e82c29b 100644 --- a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java +++ b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java @@ -254,12 +254,7 @@ public class AwTestContainerView extends FrameLayout { } @Override - public boolean requestDrawGL(Canvas canvas) { - return false; - } - - @Override - public boolean executeHardwareAction(Runnable action) { + public boolean requestDrawGL(Canvas canvas, boolean waitForCompletion) { return false; } } |