Commit d6417554 authored by boliu@chromium.org's avatar boliu@chromium.org

aw: Fix hardware init/tear down in pop up flow

Previously we did not call onDetached on old native AwContents,
which now no longer cleans up hardware resources correctly.

This also had the side effect that the following onAttach with the new
native AwContents is ignored in java code due to attach/detach mismatch.

As make onDetached more strict with respect to ordering. And lock to
protect variable accessed on multiple threads.

Also need to ensure we never requestDrawGL on the blank native
AwContents that's destroyed during pop up.

BUG=376622

Review URL: https://codereview.chromium.org/288983007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272500 0039d316-1c4b-4281-b951-d872f2087c98
parent 8dd612a1
...@@ -25,6 +25,11 @@ GLViewRendererManager::GLViewRendererManager() {} ...@@ -25,6 +25,11 @@ GLViewRendererManager::GLViewRendererManager() {}
GLViewRendererManager::~GLViewRendererManager() {} GLViewRendererManager::~GLViewRendererManager() {}
GLViewRendererManager::Key GLViewRendererManager::NullKey() {
AutoLock auto_lock(lock_);
return mru_list_.end();
}
GLViewRendererManager::Key GLViewRendererManager::PushBack(RendererType view) { GLViewRendererManager::Key GLViewRendererManager::PushBack(RendererType view) {
AutoLock auto_lock(lock_); AutoLock auto_lock(lock_);
DCHECK(mru_list_.end() == DCHECK(mru_list_.end() ==
......
...@@ -28,9 +28,7 @@ class GLViewRendererManager { ...@@ -28,9 +28,7 @@ class GLViewRendererManager {
static GLViewRendererManager* GetInstance(); static GLViewRendererManager* GetInstance();
Key NullKey() { Key NullKey();
return mru_list_.end();
}
Key PushBack(RendererType view); Key PushBack(RendererType view);
......
...@@ -23,6 +23,7 @@ SharedRendererState::SharedRendererState( ...@@ -23,6 +23,7 @@ SharedRendererState::SharedRendererState(
ui_thread_weak_ptr_(weak_factory_on_ui_thread_.GetWeakPtr()), ui_thread_weak_ptr_(weak_factory_on_ui_thread_.GetWeakPtr()),
compositor_(NULL), compositor_(NULL),
memory_policy_dirty_(false), memory_policy_dirty_(false),
hardware_allowed_(false),
hardware_initialized_(false) { hardware_initialized_(false) {
DCHECK(ui_loop_->BelongsToCurrentThread()); DCHECK(ui_loop_->BelongsToCurrentThread());
DCHECK(client_on_ui_); DCHECK(client_on_ui_);
...@@ -86,27 +87,14 @@ DrawGLInput SharedRendererState::GetDrawGLInput() const { ...@@ -86,27 +87,14 @@ DrawGLInput SharedRendererState::GetDrawGLInput() const {
return draw_gl_input_; return draw_gl_input_;
} }
void SharedRendererState::ClearClosureQueue() { void SharedRendererState::SetHardwareAllowed(bool allowed) {
base::AutoLock lock(lock_); base::AutoLock lock(lock_);
std::queue<base::Closure> empty; hardware_allowed_ = allowed;
std::swap(closure_queue_, empty);
} }
void SharedRendererState::AppendClosure(const base::Closure& closure) { bool SharedRendererState::IsHardwareAllowed() const {
base::AutoLock lock(lock_); base::AutoLock lock(lock_);
closure_queue_.push(closure); return hardware_allowed_;
}
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) { void SharedRendererState::SetHardwareInitialized(bool initialized) {
......
...@@ -5,9 +5,6 @@ ...@@ -5,9 +5,6 @@
#ifndef ANDROID_WEBVIEW_BROWSER_SHARED_RENDERER_STATE_H_ #ifndef ANDROID_WEBVIEW_BROWSER_SHARED_RENDERER_STATE_H_
#define 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/message_loop/message_loop_proxy.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "content/public/browser/android/synchronous_compositor.h" #include "content/public/browser/android/synchronous_compositor.h"
...@@ -64,11 +61,11 @@ class SharedRendererState { ...@@ -64,11 +61,11 @@ class SharedRendererState {
void SetDrawGLInput(const DrawGLInput& input); void SetDrawGLInput(const DrawGLInput& input);
DrawGLInput GetDrawGLInput() const; DrawGLInput GetDrawGLInput() const;
void ClearClosureQueue(); // Set by UI and read by RT.
void AppendClosure(const base::Closure& closure); void SetHardwareAllowed(bool allowed);
// Will return empty closure if queue empty. bool IsHardwareAllowed() const;
base::Closure PopFrontClosure();
// Set by RT and read by UI.
void SetHardwareInitialized(bool initialized); void SetHardwareInitialized(bool initialized);
bool IsHardwareInitialized() const; bool IsHardwareInitialized() const;
...@@ -89,7 +86,7 @@ class SharedRendererState { ...@@ -89,7 +86,7 @@ class SharedRendererState {
// Set to false when memory policy is read and enforced to compositor. // Set to false when memory policy is read and enforced to compositor.
bool memory_policy_dirty_; bool memory_policy_dirty_;
DrawGLInput draw_gl_input_; DrawGLInput draw_gl_input_;
std::queue<base::Closure> closure_queue_; bool hardware_allowed_;
bool hardware_initialized_; bool hardware_initialized_;
}; };
......
...@@ -621,16 +621,17 @@ public class AwContents { ...@@ -621,16 +621,17 @@ public class AwContents {
if (wasWindowFocused) onWindowFocusChanged(false); if (wasWindowFocused) onWindowFocusChanged(false);
if (wasViewVisible) setViewVisibilityInternal(false); if (wasViewVisible) setViewVisibilityInternal(false);
if (wasWindowVisible) setWindowVisibilityInternal(false); if (wasWindowVisible) setWindowVisibilityInternal(false);
if (wasAttached) onDetachedFromWindow();
if (!wasPaused) onPause(); if (!wasPaused) onPause();
// Not calling onDetachedFromWindow here because native code requires GL context to release
// GL resources. This case is properly handled when destroy is called while still attached
// to window.
setNewAwContents(popupNativeAwContents); setNewAwContents(popupNativeAwContents);
// Finally refresh all view state for mContentViewCore and mNativeAwContents. // Finally refresh all view state for mContentViewCore and mNativeAwContents.
if (!wasPaused) onResume(); if (!wasPaused) onResume();
if (wasAttached) onAttachedToWindow(); if (wasAttached) {
onAttachedToWindow();
postInvalidateOnAnimation();
}
onSizeChanged(mContainerView.getWidth(), mContainerView.getHeight(), 0, 0); onSizeChanged(mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
if (wasWindowVisible) setWindowVisibilityInternal(true); if (wasWindowVisible) setWindowVisibilityInternal(true);
if (wasViewVisible) setViewVisibilityInternal(true); if (wasViewVisible) setViewVisibilityInternal(true);
......
...@@ -326,7 +326,13 @@ jlong AwContents::GetAwDrawGLViewContext(JNIEnv* env, jobject obj) { ...@@ -326,7 +326,13 @@ jlong AwContents::GetAwDrawGLViewContext(JNIEnv* env, jobject obj) {
} }
void AwContents::DrawGL(AwDrawGLInfo* draw_info) { void AwContents::DrawGL(AwDrawGLInfo* draw_info) {
GLViewRendererManager::GetInstance()->DidDrawGL(renderer_manager_key_); {
GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
base::AutoLock lock(render_thread_lock_);
if (renderer_manager_key_ != manager->NullKey()) {
manager->DidDrawGL(renderer_manager_key_);
}
}
ScopedAppGLStateRestore state_restore( ScopedAppGLStateRestore state_restore(
draw_info->mode == AwDrawGLInfo::kModeDraw draw_info->mode == AwDrawGLInfo::kModeDraw
...@@ -334,15 +340,21 @@ void AwContents::DrawGL(AwDrawGLInfo* draw_info) { ...@@ -334,15 +340,21 @@ void AwContents::DrawGL(AwDrawGLInfo* draw_info) {
: ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT); : ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
ScopedAllowGL allow_gl; ScopedAllowGL allow_gl;
for (base::Closure c = shared_renderer_state_.PopFrontClosure(); !c.is_null(); if (!shared_renderer_state_.IsHardwareAllowed()) {
c = shared_renderer_state_.PopFrontClosure()) { hardware_renderer_.reset();
c.Run(); shared_renderer_state_.SetHardwareInitialized(false);
return;
} }
if (!hardware_renderer_) if (draw_info->mode != AwDrawGLInfo::kModeDraw)
return; return;
// TODO(boliu): Make this a task as well. if (!hardware_renderer_) {
DCHECK(!shared_renderer_state_.IsHardwareInitialized());
hardware_renderer_.reset(new HardwareRenderer(&shared_renderer_state_));
shared_renderer_state_.SetHardwareInitialized(true);
}
DrawGLResult result; DrawGLResult result;
if (hardware_renderer_->DrawGL(state_restore.stencil_enabled(), if (hardware_renderer_->DrawGL(state_restore.stencil_enabled(),
state_restore.framebuffer_binding_ext(), state_restore.framebuffer_binding_ext(),
...@@ -777,64 +789,53 @@ void AwContents::SetIsPaused(JNIEnv* env, jobject obj, bool paused) { ...@@ -777,64 +789,53 @@ void AwContents::SetIsPaused(JNIEnv* env, jobject obj, bool paused) {
void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) { void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
shared_renderer_state_.SetHardwareAllowed(true);
browser_view_renderer_.OnAttachedToWindow(w, h); browser_view_renderer_.OnAttachedToWindow(w, h);
} }
void AwContents::InitializeHardwareDrawIfNeeded() { void AwContents::InitializeHardwareDrawIfNeeded() {
GLViewRendererManager* manager = GLViewRendererManager::GetInstance(); GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
base::AutoLock lock(render_thread_lock_);
if (renderer_manager_key_ == manager->NullKey()) { if (renderer_manager_key_ == manager->NullKey()) {
// 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)));
renderer_manager_key_ = manager->PushBack(&shared_renderer_state_); renderer_manager_key_ = manager->PushBack(&shared_renderer_state_);
DeferredGpuCommandService::SetInstance(); DeferredGpuCommandService::SetInstance();
} }
} }
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) { void AwContents::OnDetachedFromWindow(JNIEnv* env, jobject obj) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
shared_renderer_state_.SetHardwareAllowed(false);
shared_renderer_state_.ClearClosureQueue();
shared_renderer_state_.AppendClosure(base::Bind( bool hardware_initialized = shared_renderer_state_.IsHardwareInitialized();
&AwContents::ReleaseHardwareDrawOnRenderThread, base::Unretained(this))); if (hardware_initialized) {
bool draw_functor_succeeded = RequestDrawGL(NULL, true); bool draw_functor_succeeded = RequestDrawGL(NULL, true);
if (!draw_functor_succeeded && if (!draw_functor_succeeded && hardware_initialized) {
shared_renderer_state_.IsHardwareInitialized()) { LOG(ERROR) << "Unable to free GL resources. Has the Window leaked?";
LOG(ERROR) << "Unable to free GL resources. Has the Window leaked?"; // Calling release on wrong thread intentionally.
// Calling release on wrong thread intentionally. AwDrawGLInfo info;
AwDrawGLInfo info; info.mode = AwDrawGLInfo::kModeProcess;
info.mode = AwDrawGLInfo::kModeProcess; DrawGL(&info);
DrawGL(&info); }
} else {
shared_renderer_state_.ClearClosureQueue();
} }
DCHECK(!hardware_renderer_);
browser_view_renderer_.OnDetachedFromWindow(); browser_view_renderer_.OnDetachedFromWindow();
GLViewRendererManager* manager = GLViewRendererManager::GetInstance(); GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
if (renderer_manager_key_ != manager->NullKey()) {
manager->Remove(renderer_manager_key_);
renderer_manager_key_ = manager->NullKey();
}
}
void AwContents::ReleaseHardwareDrawOnRenderThread() { {
// No point in running any other commands if we released hardware already. base::AutoLock lock(render_thread_lock_);
shared_renderer_state_.ClearClosureQueue(); if (renderer_manager_key_ != manager->NullKey()) {
if (!shared_renderer_state_.IsHardwareInitialized()) manager->Remove(renderer_manager_key_);
return; renderer_manager_key_ = manager->NullKey();
}
}
hardware_renderer_.reset(); if (hardware_initialized) {
shared_renderer_state_.SetHardwareInitialized(false); // Flush any invoke functors that's caused by OnDetachedFromWindow.
RequestDrawGL(NULL, true);
}
} }
base::android::ScopedJavaLocalRef<jbyteArray> base::android::ScopedJavaLocalRef<jbyteArray>
......
...@@ -216,8 +216,6 @@ class AwContents : public FindHelper::Listener, ...@@ -216,8 +216,6 @@ class AwContents : public FindHelper::Listener,
void InitAutofillIfNecessary(bool enabled); void InitAutofillIfNecessary(bool enabled);
void InitializeHardwareDrawIfNeeded(); void InitializeHardwareDrawIfNeeded();
void InitializeHardwareDrawOnRenderThread();
void ReleaseHardwareDrawOnRenderThread();
JavaObjectWeakGlobalRef java_ref_; JavaObjectWeakGlobalRef java_ref_;
scoped_ptr<content::WebContents> web_contents_; scoped_ptr<content::WebContents> web_contents_;
...@@ -240,6 +238,7 @@ class AwContents : public FindHelper::Listener, ...@@ -240,6 +238,7 @@ class AwContents : public FindHelper::Listener,
// The first element in the list is always the currently pending request. // The first element in the list is always the currently pending request.
std::list<OriginCallback> pending_geolocation_prompts_; std::list<OriginCallback> pending_geolocation_prompts_;
base::Lock render_thread_lock_;
GLViewRendererManager::Key renderer_manager_key_; GLViewRendererManager::Key renderer_manager_key_;
DISALLOW_COPY_AND_ASSIGN(AwContents); DISALLOW_COPY_AND_ASSIGN(AwContents);
......
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