#include "android_webview/browser/shared_renderer_state.h"
-#include "android_webview/browser/browser_view_renderer_client.h"
+#include "android_webview/browser/browser_view_renderer.h"
+#include "android_webview/browser/deferred_gpu_command_service.h"
+#include "android_webview/browser/hardware_renderer.h"
+#include "android_webview/browser/scoped_app_gl_state_restore.h"
+#include "android_webview/public/browser/draw_gl.h"
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/location.h"
class RequestDrawGLTracker {
public:
RequestDrawGLTracker();
- bool ShouldRequestOnNoneUiThread(SharedRendererState* state);
+ bool ShouldRequestOnNonUiThread(SharedRendererState* state);
bool ShouldRequestOnUiThread(SharedRendererState* state);
void DidRequestOnUiThread();
void ResetPending();
: pending_ui_(NULL), pending_non_ui_(NULL) {
}
-bool RequestDrawGLTracker::ShouldRequestOnNoneUiThread(
+bool RequestDrawGLTracker::ShouldRequestOnNonUiThread(
SharedRendererState* state) {
base::AutoLock lock(lock_);
if (pending_ui_ || pending_non_ui_)
}
SharedRendererState::SharedRendererState(
- scoped_refptr<base::MessageLoopProxy> ui_loop,
- BrowserViewRendererClient* client)
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_loop,
+ BrowserViewRenderer* browser_view_renderer)
: ui_loop_(ui_loop),
- client_on_ui_(client),
+ browser_view_renderer_(browser_view_renderer),
+ renderer_manager_key_(GLViewRendererManager::GetInstance()->NullKey()),
force_commit_(false),
inside_hardware_release_(false),
needs_force_invalidate_on_next_draw_gl_(false),
weak_factory_on_ui_thread_(this) {
DCHECK(ui_loop_->BelongsToCurrentThread());
- DCHECK(client_on_ui_);
+ DCHECK(browser_view_renderer_);
ui_thread_weak_ptr_ = weak_factory_on_ui_thread_.GetWeakPtr();
ResetRequestDrawGLCallback();
}
SharedRendererState::~SharedRendererState() {
DCHECK(ui_loop_->BelongsToCurrentThread());
+ DCHECK(!hardware_renderer_.get());
}
void SharedRendererState::ClientRequestDrawGL() {
if (ui_loop_->BelongsToCurrentThread()) {
if (!g_request_draw_gl_tracker.Get().ShouldRequestOnUiThread(this))
return;
- ClientRequestDrawGLOnUIThread();
+ ClientRequestDrawGLOnUI();
} else {
- if (!g_request_draw_gl_tracker.Get().ShouldRequestOnNoneUiThread(this))
+ if (!g_request_draw_gl_tracker.Get().ShouldRequestOnNonUiThread(this))
return;
base::Closure callback;
{
void SharedRendererState::ResetRequestDrawGLCallback() {
DCHECK(ui_loop_->BelongsToCurrentThread());
base::AutoLock lock(lock_);
- request_draw_gl_cancelable_closure_.Reset(
- base::Bind(&SharedRendererState::ClientRequestDrawGLOnUIThread,
- base::Unretained(this)));
+ request_draw_gl_cancelable_closure_.Reset(base::Bind(
+ &SharedRendererState::ClientRequestDrawGLOnUI, base::Unretained(this)));
request_draw_gl_closure_ = request_draw_gl_cancelable_closure_.callback();
}
-void SharedRendererState::ClientRequestDrawGLOnUIThread() {
+void SharedRendererState::ClientRequestDrawGLOnUI() {
DCHECK(ui_loop_->BelongsToCurrentThread());
ResetRequestDrawGLCallback();
- if (!client_on_ui_->RequestDrawGL(NULL, false)) {
+ if (!browser_view_renderer_->RequestDrawGL(false)) {
g_request_draw_gl_tracker.Get().ResetPending();
LOG(ERROR) << "Failed to request GL process. Deadlock likely";
}
}
-void SharedRendererState::UpdateParentDrawConstraintsOnUIThread() {
+void SharedRendererState::UpdateParentDrawConstraintsOnUI() {
DCHECK(ui_loop_->BelongsToCurrentThread());
- client_on_ui_->UpdateParentDrawConstraints();
+ browser_view_renderer_->UpdateParentDrawConstraints();
}
-void SharedRendererState::SetScrollOffset(gfx::Vector2d scroll_offset) {
+void SharedRendererState::SetScrollOffsetOnUI(gfx::Vector2d scroll_offset) {
base::AutoLock lock(lock_);
scroll_offset_ = scroll_offset;
}
-gfx::Vector2d SharedRendererState::GetScrollOffset() {
+gfx::Vector2d SharedRendererState::GetScrollOffsetOnRT() {
base::AutoLock lock(lock_);
return scroll_offset_;
}
-bool SharedRendererState::HasCompositorFrame() const {
+bool SharedRendererState::HasCompositorFrameOnUI() const {
base::AutoLock lock(lock_);
return compositor_frame_.get();
}
-void SharedRendererState::SetCompositorFrame(
- scoped_ptr<cc::CompositorFrame> frame, bool force_commit) {
+void SharedRendererState::SetCompositorFrameOnUI(
+ scoped_ptr<cc::CompositorFrame> frame,
+ bool force_commit) {
base::AutoLock lock(lock_);
DCHECK(!compositor_frame_.get());
compositor_frame_ = frame.Pass();
force_commit_ = force_commit;
}
-scoped_ptr<cc::CompositorFrame> SharedRendererState::PassCompositorFrame() {
+scoped_ptr<cc::CompositorFrame> SharedRendererState::PassCompositorFrameOnRT() {
base::AutoLock lock(lock_);
return compositor_frame_.Pass();
}
-bool SharedRendererState::ForceCommit() const {
+scoped_ptr<cc::CompositorFrame>
+SharedRendererState::PassUncommittedFrameOnUI() {
+ base::AutoLock lock(lock_);
+ return compositor_frame_.Pass();
+}
+
+bool SharedRendererState::ForceCommitOnRT() const {
base::AutoLock lock(lock_);
return force_commit_;
}
-bool SharedRendererState::UpdateDrawConstraints(
+bool SharedRendererState::UpdateDrawConstraintsOnRT(
const ParentCompositorDrawConstraints& parent_draw_constraints) {
base::AutoLock lock(lock_);
if (needs_force_invalidate_on_next_draw_gl_ ||
return false;
}
-void SharedRendererState::PostExternalDrawConstraintsToChildCompositor(
+void SharedRendererState::PostExternalDrawConstraintsToChildCompositorOnRT(
const ParentCompositorDrawConstraints& parent_draw_constraints) {
- if (UpdateDrawConstraints(parent_draw_constraints)) {
+ if (UpdateDrawConstraintsOnRT(parent_draw_constraints)) {
// No need to hold the lock_ during the post task.
ui_loop_->PostTask(
FROM_HERE,
- base::Bind(&SharedRendererState::UpdateParentDrawConstraintsOnUIThread,
+ base::Bind(&SharedRendererState::UpdateParentDrawConstraintsOnUI,
ui_thread_weak_ptr_));
}
}
-void SharedRendererState::DidSkipCommitFrame() {
- ui_loop_->PostTask(
- FROM_HERE,
- base::Bind(&SharedRendererState::DidSkipCommitFrameOnUIThread,
- ui_thread_weak_ptr_));
+void SharedRendererState::DidSkipCommitFrameOnRT() {
+ ui_loop_->PostTask(FROM_HERE,
+ base::Bind(&SharedRendererState::DidSkipCommitFrameOnUI,
+ ui_thread_weak_ptr_));
}
-void SharedRendererState::DidSkipCommitFrameOnUIThread() {
+void SharedRendererState::DidSkipCommitFrameOnUI() {
DCHECK(ui_loop_->BelongsToCurrentThread());
- client_on_ui_->DidSkipCommitFrame();
+ browser_view_renderer_->DidSkipCommitFrame();
}
-const ParentCompositorDrawConstraints
-SharedRendererState::ParentDrawConstraints() const {
+ParentCompositorDrawConstraints
+SharedRendererState::GetParentDrawConstraintsOnUI() const {
base::AutoLock lock(lock_);
return parent_draw_constraints_;
}
-void SharedRendererState::SetForceInvalidateOnNextDrawGL(
+void SharedRendererState::SetForceInvalidateOnNextDrawGLOnUI(
bool needs_force_invalidate_on_next_draw_gl) {
base::AutoLock lock(lock_);
needs_force_invalidate_on_next_draw_gl_ =
needs_force_invalidate_on_next_draw_gl;
}
-bool SharedRendererState::NeedsForceInvalidateOnNextDrawGL() const {
+bool SharedRendererState::NeedsForceInvalidateOnNextDrawGLOnUI() const {
base::AutoLock lock(lock_);
return needs_force_invalidate_on_next_draw_gl_;
}
return inside_hardware_release_;
}
-void SharedRendererState::InsertReturnedResources(
+void SharedRendererState::InsertReturnedResourcesOnRT(
const cc::ReturnedResourceArray& resources) {
base::AutoLock lock(lock_);
returned_resources_.insert(
returned_resources_.end(), resources.begin(), resources.end());
}
-void SharedRendererState::SwapReturnedResources(
+void SharedRendererState::SwapReturnedResourcesOnUI(
cc::ReturnedResourceArray* resources) {
DCHECK(resources->empty());
base::AutoLock lock(lock_);
resources->swap(returned_resources_);
}
-bool SharedRendererState::ReturnedResourcesEmpty() const {
+bool SharedRendererState::ReturnedResourcesEmptyOnUI() const {
base::AutoLock lock(lock_);
return returned_resources_.empty();
}
-InsideHardwareReleaseReset::InsideHardwareReleaseReset(
+void SharedRendererState::DrawGL(AwDrawGLInfo* draw_info) {
+ if (draw_info->mode == AwDrawGLInfo::kModeSync) {
+ if (hardware_renderer_)
+ hardware_renderer_->CommitFrame();
+ return;
+ }
+
+ {
+ GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
+ base::AutoLock lock(lock_);
+ if (renderer_manager_key_ != manager->NullKey()) {
+ manager->DidDrawGL(renderer_manager_key_);
+ }
+ }
+
+ ScopedAppGLStateRestore state_restore(
+ draw_info->mode == AwDrawGLInfo::kModeDraw
+ ? ScopedAppGLStateRestore::MODE_DRAW
+ : ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
+ ScopedAllowGL allow_gl;
+
+ if (draw_info->mode == AwDrawGLInfo::kModeProcessNoContext) {
+ LOG(ERROR) << "Received unexpected kModeProcessNoContext";
+ }
+
+ // kModeProcessNoContext should never happen because we tear down hardware
+ // in onTrimMemory. However that guarantee is maintained outside of chromium
+ // code. Not notifying shared state in kModeProcessNoContext can lead to
+ // immediate deadlock, which is slightly more catastrophic than leaks or
+ // corruption.
+ if (draw_info->mode == AwDrawGLInfo::kModeProcess ||
+ draw_info->mode == AwDrawGLInfo::kModeProcessNoContext) {
+ DidDrawGLProcess();
+ }
+
+ if (IsInsideHardwareRelease()) {
+ hardware_renderer_.reset();
+ // Flush the idle queue in tear down.
+ DeferredGpuCommandService::GetInstance()->PerformAllIdleWork();
+ return;
+ }
+
+ if (draw_info->mode != AwDrawGLInfo::kModeDraw) {
+ if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
+ DeferredGpuCommandService::GetInstance()->PerformIdleWork(true);
+ }
+ return;
+ }
+
+ if (!hardware_renderer_) {
+ hardware_renderer_.reset(new HardwareRenderer(this));
+ hardware_renderer_->CommitFrame();
+ }
+
+ hardware_renderer_->DrawGL(state_restore.stencil_enabled(),
+ state_restore.framebuffer_binding_ext(),
+ draw_info);
+ DeferredGpuCommandService::GetInstance()->PerformIdleWork(false);
+}
+
+void SharedRendererState::ReleaseHardwareDrawIfNeededOnUI() {
+ DCHECK(ui_loop_->BelongsToCurrentThread());
+ InsideHardwareReleaseReset auto_inside_hardware_release_reset(this);
+
+ browser_view_renderer_->InvalidateOnFunctorDestroy();
+ bool hardware_initialized = browser_view_renderer_->hardware_enabled();
+ if (hardware_initialized) {
+ bool draw_functor_succeeded = browser_view_renderer_->RequestDrawGL(true);
+ if (!draw_functor_succeeded) {
+ LOG(ERROR) << "Unable to free GL resources. Has the Window leaked?";
+ // Calling release on wrong thread intentionally.
+ AwDrawGLInfo info;
+ info.mode = AwDrawGLInfo::kModeProcess;
+ DrawGL(&info);
+ }
+
+ browser_view_renderer_->ReleaseHardware();
+ }
+
+ GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
+
+ {
+ base::AutoLock lock(lock_);
+ if (renderer_manager_key_ != manager->NullKey()) {
+ manager->Remove(renderer_manager_key_);
+ renderer_manager_key_ = manager->NullKey();
+ }
+ }
+
+ if (hardware_initialized) {
+ // Flush any invoke functors that's caused by ReleaseHardware.
+ browser_view_renderer_->RequestDrawGL(true);
+ }
+}
+
+void SharedRendererState::InitializeHardwareDrawIfNeededOnUI() {
+ DCHECK(ui_loop_->BelongsToCurrentThread());
+ GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
+
+ base::AutoLock lock(lock_);
+ if (renderer_manager_key_ == manager->NullKey()) {
+ renderer_manager_key_ = manager->PushBack(this);
+ DeferredGpuCommandService::SetInstance();
+ }
+}
+
+SharedRendererState::InsideHardwareReleaseReset::InsideHardwareReleaseReset(
SharedRendererState* shared_renderer_state)
: shared_renderer_state_(shared_renderer_state) {
DCHECK(!shared_renderer_state_->IsInsideHardwareRelease());
shared_renderer_state_->SetInsideHardwareRelease(true);
}
-InsideHardwareReleaseReset::~InsideHardwareReleaseReset() {
+SharedRendererState::InsideHardwareReleaseReset::~InsideHardwareReleaseReset() {
shared_renderer_state_->SetInsideHardwareRelease(false);
}