Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(339)

Unified Diff: android_webview/browser/hardware_renderer.cc

Issue 176543004: aw: Split hardware rendering into HardwareRenderer (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review comments Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « android_webview/browser/hardware_renderer.h ('k') | android_webview/browser/in_process_view_renderer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: android_webview/browser/hardware_renderer.cc
diff --git a/android_webview/browser/in_process_view_renderer.cc b/android_webview/browser/hardware_renderer.cc
similarity index 17%
rename from android_webview/browser/in_process_view_renderer.cc
rename to android_webview/browser/hardware_renderer.cc
index 48a43e18e2fe10854385d1750dadb52790790b99..a8a77df15ad77dd3277bb2ca4dc8a1e6e20d0ab2 100644
--- a/android_webview/browser/in_process_view_renderer.cc
+++ b/android_webview/browser/hardware_renderer.cc
@@ -1,958 +1,326 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2014 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/in_process_view_renderer.h"
+#include "android_webview/browser/hardware_renderer.h"
#include "android_webview/browser/aw_gl_surface.h"
+#include "android_webview/browser/browser_view_renderer.h"
+#include "android_webview/browser/gl_view_renderer_manager.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"
-#include "base/android/jni_android.h"
-#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
-#include "gpu/command_buffer/service/in_process_command_buffer.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkBitmapDevice.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkPicture.h"
#include "ui/gfx/transform.h"
-#include "ui/gfx/vector2d_conversions.h"
-using base::android::AttachCurrentThread;
-using base::android::JavaRef;
-using base::android::ScopedJavaLocalRef;
using content::BrowserThread;
namespace android_webview {
namespace {
-const void* kUserDataKey = &kUserDataKey;
-
-class UserData : public content::WebContents::Data {
- public:
- UserData(InProcessViewRenderer* ptr) : instance_(ptr) {}
- virtual ~UserData() {
- instance_->WebContentsGone();
- }
-
- static InProcessViewRenderer* GetInstance(content::WebContents* contents) {
- if (!contents)
- return NULL;
- UserData* data = reinterpret_cast<UserData*>(
- contents->GetUserData(kUserDataKey));
- return data ? data->instance_ : NULL;
- }
-
- private:
- InProcessViewRenderer* instance_;
-};
-
-bool HardwareEnabled() {
- static bool g_hw_enabled = !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableWebViewGLMode);
- return g_hw_enabled;
-}
-
-const int64 kFallbackTickTimeoutInMilliseconds = 20;
-
// Used to calculate memory and resource allocation. Determined experimentally.
-size_t g_memory_multiplier = 10;
-size_t g_num_gralloc_limit = 150;
+const size_t g_memory_multiplier = 10;
+const size_t g_num_gralloc_limit = 150;
const size_t kBytesPerPixel = 4;
const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
-base::LazyInstance<GLViewRendererManager>::Leaky g_view_renderer_manager =
- LAZY_INSTANCE_INITIALIZER;
-
-class ScopedAllowGL {
- public:
- ScopedAllowGL();
- ~ScopedAllowGL();
-
- static bool IsAllowed() {
- return g_view_renderer_manager.Get().OnRenderThread() && allow_gl;
- }
-
- private:
- static bool allow_gl;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL);
-};
-
-ScopedAllowGL::ScopedAllowGL() {
- DCHECK(g_view_renderer_manager.Get().OnRenderThread());
- DCHECK(!allow_gl);
- allow_gl = true;
-}
-
-ScopedAllowGL::~ScopedAllowGL() {
- allow_gl = false;
-}
-
-bool ScopedAllowGL::allow_gl = false;
-
-void RequestProcessGLOnUIThread() {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE, base::Bind(&RequestProcessGLOnUIThread));
- return;
- }
-
- InProcessViewRenderer* renderer = static_cast<InProcessViewRenderer*>(
- g_view_renderer_manager.Get().GetMostRecentlyDrawn());
- if (!renderer || !renderer->RequestProcessGL()) {
- LOG(ERROR) << "Failed to request GL process. Deadlock likely: "
- << !!renderer;
- }
-}
-
-class DeferredGpuCommandService
- : public gpu::InProcessCommandBuffer::Service,
- public base::RefCountedThreadSafe<DeferredGpuCommandService> {
- public:
- DeferredGpuCommandService();
-
- virtual void ScheduleTask(const base::Closure& task) OVERRIDE;
- virtual void ScheduleIdleWork(const base::Closure& task) OVERRIDE;
- virtual bool UseVirtualizedGLContexts() OVERRIDE;
-
- void RunTasks();
-
- virtual void AddRef() const OVERRIDE {
- base::RefCountedThreadSafe<DeferredGpuCommandService>::AddRef();
- }
- virtual void Release() const OVERRIDE {
- base::RefCountedThreadSafe<DeferredGpuCommandService>::Release();
- }
-
- protected:
- virtual ~DeferredGpuCommandService();
- friend class base::RefCountedThreadSafe<DeferredGpuCommandService>;
-
- private:
- base::Lock tasks_lock_;
- std::queue<base::Closure> tasks_;
- DISALLOW_COPY_AND_ASSIGN(DeferredGpuCommandService);
-};
-
-DeferredGpuCommandService::DeferredGpuCommandService() {}
-
-DeferredGpuCommandService::~DeferredGpuCommandService() {
- base::AutoLock lock(tasks_lock_);
- DCHECK(tasks_.empty());
-}
-
-// Called from different threads!
-void DeferredGpuCommandService::ScheduleTask(const base::Closure& task) {
- {
- base::AutoLock lock(tasks_lock_);
- tasks_.push(task);
- }
- if (ScopedAllowGL::IsAllowed()) {
- RunTasks();
- } else {
- RequestProcessGLOnUIThread();
- }
-}
-
-void DeferredGpuCommandService::ScheduleIdleWork(
- const base::Closure& callback) {
- // TODO(sievers): Should this do anything?
-}
-
-bool DeferredGpuCommandService::UseVirtualizedGLContexts() { return true; }
-
-void DeferredGpuCommandService::RunTasks() {
- bool has_more_tasks;
- {
- base::AutoLock lock(tasks_lock_);
- has_more_tasks = tasks_.size() > 0;
- }
-
- while (has_more_tasks) {
- base::Closure task;
- {
- base::AutoLock lock(tasks_lock_);
- task = tasks_.front();
- tasks_.pop();
- }
- task.Run();
- {
- base::AutoLock lock(tasks_lock_);
- has_more_tasks = tasks_.size() > 0;
- }
-
- }
-}
-
-base::LazyInstance<scoped_refptr<DeferredGpuCommandService> > g_service =
- LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<scoped_refptr<internal::DeferredGpuCommandService> >
+ g_service = LAZY_INSTANCE_INITIALIZER;
} // namespace
-InProcessViewRenderer::InProcessViewRenderer(
- BrowserViewRenderer::Client* client,
- content::WebContents* web_contents)
- : client_(client),
- web_contents_(web_contents),
- compositor_(NULL),
- is_paused_(false),
- view_visible_(false),
- window_visible_(false),
- attached_to_window_(false),
- dip_scale_(0.0),
- page_scale_factor_(1.0),
- on_new_picture_enable_(false),
- clear_view_(false),
- compositor_needs_continuous_invalidate_(false),
- block_invalidates_(false),
- width_(0),
- height_(0),
- hardware_initialized_(false),
- hardware_failed_(false),
- last_egl_context_(NULL),
- manager_key_(g_view_renderer_manager.Get().NullKey()) {
- CHECK(web_contents_);
- web_contents_->SetUserData(kUserDataKey, new UserData(this));
- content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
-
- // Currently the logic in this class relies on |compositor_| remaining NULL
- // until the DidInitializeCompositor() call, hence it is not set here.
-}
-
-InProcessViewRenderer::~InProcessViewRenderer() {
- CHECK(web_contents_);
- content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
- web_contents_->SetUserData(kUserDataKey, NULL);
- NoLongerExpectsDrawGL();
- DCHECK(web_contents_ == NULL); // WebContentsGone should have been called.
-}
-
-void InProcessViewRenderer::NoLongerExpectsDrawGL() {
- GLViewRendererManager& mru = g_view_renderer_manager.Get();
- if (manager_key_ != mru.NullKey()) {
- mru.NoLongerExpectsDrawGL(manager_key_);
- manager_key_ = mru.NullKey();
- }
-}
-
-// static
-InProcessViewRenderer* InProcessViewRenderer::FromWebContents(
- content::WebContents* contents) {
- return UserData::GetInstance(contents);
-}
+DrawGLResult::DrawGLResult()
+ : did_draw(false), clip_contains_visible_rect(false) {}
-void InProcessViewRenderer::WebContentsGone() {
- web_contents_ = NULL;
- compositor_ = NULL;
+HardwareRenderer::HardwareRenderer(content::SynchronousCompositor* compositor,
+ BrowserViewRendererClient* client)
+ : compositor_(compositor),
+ client_(client),
+ last_egl_context_(eglGetCurrentContext()),
+ manager_key_(GLViewRendererManager::GetInstance()->NullKey()) {
+ DCHECK(compositor_);
+ DCHECK(last_egl_context_);
}
-// static
-void InProcessViewRenderer::CalculateTileMemoryPolicy() {
- CommandLine* cl = CommandLine::ForCurrentProcess();
- if (cl->HasSwitch(switches::kTileMemoryMultiplier)) {
- std::string string_value =
- cl->GetSwitchValueASCII(switches::kTileMemoryMultiplier);
- int int_value = 0;
- if (base::StringToInt(string_value, &int_value) &&
- int_value >= 2 && int_value <= 50) {
- g_memory_multiplier = int_value;
- }
+HardwareRenderer::~HardwareRenderer() {
+ GLViewRendererManager* mru = GLViewRendererManager::GetInstance();
+ if (manager_key_ != mru->NullKey()) {
+ mru->NoLongerExpectsDrawGL(manager_key_);
+ manager_key_ = mru->NullKey();
}
- if (cl->HasSwitch(switches::kNumGrallocBuffersPerWebview)) {
- std::string string_value =
- cl->GetSwitchValueASCII(switches::kNumGrallocBuffersPerWebview);
- int int_value = 0;
- if (base::StringToInt(string_value, &int_value) &&
- int_value >= 50 && int_value <= 500) {
- g_num_gralloc_limit = int_value;
- }
- }
-
- const char kDefaultTileSize[] = "384";
- if (!cl->HasSwitch(switches::kDefaultTileWidth))
- cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
-
- if (!cl->HasSwitch(switches::kDefaultTileHeight))
- cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
-}
-
-bool InProcessViewRenderer::RequestProcessGL() {
- return client_->RequestDrawGL(NULL);
-}
-
-void InProcessViewRenderer::TrimMemory(int level) {
- // Constants from Android ComponentCallbacks2.
- enum {
- TRIM_MEMORY_RUNNING_LOW = 10,
- TRIM_MEMORY_UI_HIDDEN = 20,
- TRIM_MEMORY_BACKGROUND = 40,
- };
-
- // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
- // it does not indicate memory pressure, but merely that the app is
- // backgrounded.
- if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
- return;
-
- // Nothing to drop.
- if (!attached_to_window_ || !hardware_initialized_ || !compositor_)
- return;
-
- // Do not release resources on view we expect to get DrawGL soon.
- if (level < TRIM_MEMORY_BACKGROUND) {
- client_->UpdateGlobalVisibleRect();
- if (view_visible_ && window_visible_ &&
- !cached_global_visible_rect_.IsEmpty()) {
- return;
- }
- }
-
- if (!eglGetCurrentContext()) {
- NOTREACHED();
- return;
- }
-
- // Just set the memory limit to 0 and drop all tiles. This will be reset to
- // normal levels in the next DrawGL call.
- content::SynchronousCompositorMemoryPolicy policy;
- policy.bytes_limit = 0;
- policy.num_resources_limit = 0;
- if (memory_policy_ == policy)
- return;
-
- TRACE_EVENT0("android_webview", "InProcessViewRenderer::TrimMemory");
- ScopedAppGLStateRestore state_restore(
- ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
- g_service.Get()->RunTasks();
- ScopedAllowGL allow_gl;
-
- SetMemoryPolicy(policy);
- ForceFakeCompositeSW();
-}
-
-void InProcessViewRenderer::SetMemoryPolicy(
- content::SynchronousCompositorMemoryPolicy& new_policy) {
- if (memory_policy_ == new_policy)
- return;
-
- memory_policy_ = new_policy;
- compositor_->SetMemoryPolicy(memory_policy_);
-}
-
-void InProcessViewRenderer::UpdateCachedGlobalVisibleRect() {
- client_->UpdateGlobalVisibleRect();
-}
+ if (gl_surface_) {
+ ScopedAppGLStateRestore state_restore(
+ ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
+ internal::ScopedAllowGL allow_gl;
-bool InProcessViewRenderer::OnDraw(jobject java_canvas,
- bool is_hardware_canvas,
- const gfx::Vector2d& scroll,
- const gfx::Rect& clip) {
- scroll_at_start_of_frame_ = scroll;
- if (clear_view_)
- return false;
- if (is_hardware_canvas && attached_to_window_ && HardwareEnabled()) {
- // We should be performing a hardware draw here. If we don't have the
- // comositor 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 compositor_ && client_->RequestDrawGL(java_canvas);
+ compositor_->ReleaseHwDraw();
+ gl_surface_ = NULL;
}
- // Perform a software draw
- return DrawSWInternal(java_canvas, clip);
+ DCHECK(manager_key_ == GLViewRendererManager::GetInstance()->NullKey());
}
-bool InProcessViewRenderer::InitializeHwDraw() {
- TRACE_EVENT0("android_webview", "InitializeHwDraw");
- DCHECK(!gl_surface_);
- gl_surface_ = new AwGLSurface;
+bool HardwareRenderer::InitializeHardwareDraw() {
+ TRACE_EVENT0("android_webview", "InitializeHardwareDraw");
if (!g_service.Get()) {
- g_service.Get() = new DeferredGpuCommandService;
+ g_service.Get() = new internal::DeferredGpuCommandService;
content::SynchronousCompositor::SetGpuService(g_service.Get());
}
- hardware_failed_ = !compositor_->InitializeHwDraw(gl_surface_);
- hardware_initialized_ = true;
- if (hardware_failed_)
- gl_surface_ = NULL;
+ bool success = true;
+ if (!gl_surface_) {
+ scoped_refptr<AwGLSurface> gl_surface = new AwGLSurface;
+ success = compositor_->InitializeHwDraw(gl_surface);
+ if (success)
+ gl_surface_ = gl_surface;
+ }
- return !hardware_failed_;
+ return success;
}
-void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) {
- TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL");
-
- manager_key_ = g_view_renderer_manager.Get().DidDrawGL(manager_key_, this);
+DrawGLResult HardwareRenderer::DrawGL(AwDrawGLInfo* draw_info,
+ const DrawGLInput& input) {
+ TRACE_EVENT0("android_webview", "HardwareRenderer::DrawGL");
+ manager_key_ =
+ GLViewRendererManager::GetInstance()->DidDrawGL(manager_key_, this);
+ DrawGLResult result;
// We need to watch if the current Android context has changed and enforce
// a clean-up in the compositor.
EGLContext current_context = eglGetCurrentContext();
if (!current_context) {
- TRACE_EVENT_INSTANT0(
- "android_webview", "EarlyOut_NullEGLContext", TRACE_EVENT_SCOPE_THREAD);
- return;
+ DLOG(ERROR) << "DrawGL called without EGLContext";
+ return result;
}
- ScopedAppGLStateRestore state_restore(ScopedAppGLStateRestore::MODE_DRAW);
- if (g_service.Get())
- g_service.Get()->RunTasks();
- ScopedAllowGL allow_gl;
-
- if (!attached_to_window_) {
- TRACE_EVENT_INSTANT0(
- "android_webview", "EarlyOut_NotAttached", TRACE_EVENT_SCOPE_THREAD);
- return;
- }
-
- if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
- TRACE_EVENT_INSTANT0(
- "android_webview", "EarlyOut_ModeProcess", TRACE_EVENT_SCOPE_THREAD);
- return;
- }
-
- if (compositor_ && !hardware_initialized_) {
- if (InitializeHwDraw()) {
- last_egl_context_ = current_context;
- } else {
- TRACE_EVENT_INSTANT0(
- "android_webview", "EarlyOut_HwInitFail", TRACE_EVENT_SCOPE_THREAD);
- LOG(ERROR) << "WebView hardware initialization failed";
- return;
- }
- }
+ // TODO(boliu): Handle context loss.
+ if (last_egl_context_ != current_context)
+ DLOG(WARNING) << "EGLContextChanged";
- UpdateCachedGlobalVisibleRect();
- if (cached_global_visible_rect_.IsEmpty()) {
- TRACE_EVENT_INSTANT0("android_webview",
- "EarlyOut_EmptyVisibleRect",
- TRACE_EVENT_SCOPE_THREAD);
- return;
- }
+ ScopedAppGLStateRestore state_restore(ScopedAppGLStateRestore::MODE_DRAW);
+ internal::ScopedAllowGL allow_gl;
- if (last_egl_context_ != current_context) {
- // TODO(boliu): Handle context lost
- TRACE_EVENT_INSTANT0(
- "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD);
- }
+ if (draw_info->mode == AwDrawGLInfo::kModeProcess)
+ return result;
- if (!compositor_) {
- TRACE_EVENT_INSTANT0(
- "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
- return;
+ if (!InitializeHardwareDraw()) {
+ DLOG(ERROR) << "WebView hardware initialization failed";
+ return result;
}
- // DrawGL may be called without OnDraw, so cancel |fallback_tick_| here as
- // well just to be safe.
- fallback_tick_.Cancel();
-
// Update memory budget. This will no-op in compositor if the policy has not
// changed since last draw.
content::SynchronousCompositorMemoryPolicy policy;
policy.bytes_limit = g_memory_multiplier * kBytesPerPixel *
- cached_global_visible_rect_.width() *
- cached_global_visible_rect_.height();
+ input.global_visible_rect.width() *
+ input.global_visible_rect.height();
// Round up to a multiple of kMemoryAllocationStep.
policy.bytes_limit =
(policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
policy.num_resources_limit = g_num_gralloc_limit;
SetMemoryPolicy(policy);
- 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());
+ transform.Translate(input.scroll.x(), input.scroll.y());
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);
- // Assume we always draw the full visible rect if we are drawing into a layer.
- bool drew_full_visible_rect = true;
-
gfx::Rect viewport_rect;
- if (!draw_info->is_layer) {
- viewport_rect = cached_global_visible_rect_;
- clip_rect.Intersect(viewport_rect);
- drew_full_visible_rect = clip_rect.Contains(viewport_rect);
- } else {
+ if (draw_info->is_layer) {
viewport_rect = clip_rect;
+ } else {
+ viewport_rect = input.global_visible_rect;
+ clip_rect.Intersect(viewport_rect);
}
+ result.clip_contains_visible_rect = clip_rect.Contains(viewport_rect);
- block_invalidates_ = true;
- // TODO(joth): Check return value.
- compositor_->DemandDrawHw(gfx::Size(draw_info->width, draw_info->height),
- transform,
- viewport_rect,
- clip_rect,
- state_restore.stencil_enabled());
- block_invalidates_ = false;
+ result.did_draw =
+ compositor_->DemandDrawHw(gfx::Size(draw_info->width, draw_info->height),
+ transform,
+ viewport_rect,
+ clip_rect,
+ state_restore.stencil_enabled());
gl_surface_->ResetBackingFrameBufferObject();
- EnsureContinuousInvalidation(draw_info, !drew_full_visible_rect);
-}
-
-void InProcessViewRenderer::SetGlobalVisibleRect(
- const gfx::Rect& visible_rect) {
- cached_global_visible_rect_ = visible_rect;
+ return result;
}
-bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas,
- const gfx::Rect& clip) {
- if (clip.IsEmpty()) {
- TRACE_EVENT_INSTANT0(
- "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD);
- return true;
- }
+bool HardwareRenderer::TrimMemory(int level, bool visible) {
+ // Constants from Android ComponentCallbacks2.
+ enum {
+ TRIM_MEMORY_RUNNING_LOW = 10,
+ TRIM_MEMORY_UI_HIDDEN = 20,
+ TRIM_MEMORY_BACKGROUND = 40,
+ };
- if (!compositor_) {
- TRACE_EVENT_INSTANT0(
- "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
+ // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
+ // it does not indicate memory pressure, but merely that the app is
+ // backgrounded.
+ if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
return false;
- }
-
- return JavaHelper::GetInstance()->RenderViaAuxilaryBitmapIfNeeded(
- java_canvas,
- scroll_at_start_of_frame_,
- clip,
- base::Bind(&InProcessViewRenderer::CompositeSW, base::Unretained(this)));
-}
-skia::RefPtr<SkPicture> InProcessViewRenderer::CapturePicture(int width,
- int height) {
- TRACE_EVENT0("android_webview", "InProcessViewRenderer::CapturePicture");
+ // Do not release resources on view we expect to get DrawGL soon.
+ if (level < TRIM_MEMORY_BACKGROUND && visible)
+ return false;
- // Return empty Picture objects for empty SkPictures.
- skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
- if (width <= 0 || height <= 0) {
- return picture;
+ if (!eglGetCurrentContext()) {
+ NOTREACHED();
+ return false;
}
- // Reset scroll back to the origin, will go back to the old
- // value when scroll_reset is out of scope.
- base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
- gfx::Vector2d());
+ DCHECK_EQ(last_egl_context_, eglGetCurrentContext());
- SkCanvas* rec_canvas = picture->beginRecording(width, height, 0);
- if (compositor_)
- CompositeSW(rec_canvas);
- picture->endRecording();
- return picture;
-}
-
-void InProcessViewRenderer::EnableOnNewPicture(bool enabled) {
- on_new_picture_enable_ = enabled;
- EnsureContinuousInvalidation(NULL, false);
-}
-
-void InProcessViewRenderer::ClearView() {
- TRACE_EVENT_INSTANT0("android_webview",
- "InProcessViewRenderer::ClearView",
- TRACE_EVENT_SCOPE_THREAD);
- if (clear_view_)
- return;
-
- clear_view_ = true;
- // Always invalidate ignoring the compositor to actually clear the webview.
- EnsureContinuousInvalidation(NULL, true);
-}
+ // Just set the memory limit to 0 and drop all tiles. This will be reset to
+ // normal levels in the next DrawGL call.
+ content::SynchronousCompositorMemoryPolicy policy;
+ policy.bytes_limit = 0;
+ policy.num_resources_limit = 0;
+ if (memory_policy_ == policy)
+ return false;
-void InProcessViewRenderer::SetIsPaused(bool paused) {
- TRACE_EVENT_INSTANT1("android_webview",
- "InProcessViewRenderer::SetIsPaused",
- TRACE_EVENT_SCOPE_THREAD,
- "paused",
- paused);
- is_paused_ = paused;
- EnsureContinuousInvalidation(NULL, false);
-}
+ TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
+ ScopedAppGLStateRestore state_restore(
+ ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
+ internal::ScopedAllowGL allow_gl;
-void InProcessViewRenderer::SetViewVisibility(bool view_visible) {
- TRACE_EVENT_INSTANT1("android_webview",
- "InProcessViewRenderer::SetViewVisibility",
- TRACE_EVENT_SCOPE_THREAD,
- "view_visible",
- view_visible);
- view_visible_ = view_visible;
+ SetMemoryPolicy(policy);
+ return true;
}
-void InProcessViewRenderer::SetWindowVisibility(bool window_visible) {
- TRACE_EVENT_INSTANT1("android_webview",
- "InProcessViewRenderer::SetWindowVisibility",
- TRACE_EVENT_SCOPE_THREAD,
- "window_visible",
- window_visible);
- window_visible_ = window_visible;
- EnsureContinuousInvalidation(NULL, false);
-}
+void HardwareRenderer::SetMemoryPolicy(
+ content::SynchronousCompositorMemoryPolicy& new_policy) {
+ if (memory_policy_ == new_policy)
+ return;
-void InProcessViewRenderer::OnSizeChanged(int width, int height) {
- TRACE_EVENT_INSTANT2("android_webview",
- "InProcessViewRenderer::OnSizeChanged",
- TRACE_EVENT_SCOPE_THREAD,
- "width",
- width,
- "height",
- height);
- width_ = width;
- height_ = height;
+ memory_policy_ = new_policy;
+ compositor_->SetMemoryPolicy(memory_policy_);
}
-void InProcessViewRenderer::OnAttachedToWindow(int width, int height) {
- TRACE_EVENT2("android_webview",
- "InProcessViewRenderer::OnAttachedToWindow",
- "width",
- width,
- "height",
- height);
- attached_to_window_ = true;
- width_ = width;
- height_ = height;
+bool HardwareRenderer::RequestDrawGL() {
+ return client_->RequestDrawGL(NULL);
}
-void InProcessViewRenderer::OnDetachedFromWindow() {
- TRACE_EVENT0("android_webview",
- "InProcessViewRenderer::OnDetachedFromWindow");
-
- NoLongerExpectsDrawGL();
- if (hardware_initialized_) {
- DCHECK(compositor_);
+// static
+void HardwareRenderer::CalculateTileMemoryPolicy() {
+ CommandLine* cl = CommandLine::ForCurrentProcess();
- ScopedAppGLStateRestore state_restore(
- ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
- g_service.Get()->RunTasks();
- ScopedAllowGL allow_gl;
- compositor_->ReleaseHwDraw();
- hardware_initialized_ = false;
- }
+ const char kDefaultTileSize[] = "384";
+ if (!cl->HasSwitch(switches::kDefaultTileWidth))
+ cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
- gl_surface_ = NULL;
- attached_to_window_ = false;
+ if (!cl->HasSwitch(switches::kDefaultTileHeight))
+ cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
}
-bool InProcessViewRenderer::IsAttachedToWindow() {
- return attached_to_window_;
-}
+namespace internal {
-bool InProcessViewRenderer::IsVisible() {
- // Ignore |window_visible_| if |attached_to_window_| is false.
- return view_visible_ && (!attached_to_window_ || window_visible_);
-}
+bool ScopedAllowGL::allow_gl = false;
-gfx::Rect InProcessViewRenderer::GetScreenRect() {
- return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
+// static
+bool ScopedAllowGL::IsAllowed() {
+ return GLViewRendererManager::GetInstance()->OnRenderThread() && allow_gl;
}
-void InProcessViewRenderer::DidInitializeCompositor(
- content::SynchronousCompositor* compositor) {
- TRACE_EVENT0("android_webview",
- "InProcessViewRenderer::DidInitializeCompositor");
- DCHECK(compositor && compositor_ == NULL);
- compositor_ = compositor;
- hardware_initialized_ = false;
- hardware_failed_ = false;
-}
+ScopedAllowGL::ScopedAllowGL() {
+ DCHECK(GLViewRendererManager::GetInstance()->OnRenderThread());
+ DCHECK(!allow_gl);
+ allow_gl = true;
-void InProcessViewRenderer::DidDestroyCompositor(
- content::SynchronousCompositor* compositor) {
- TRACE_EVENT0("android_webview",
- "InProcessViewRenderer::DidDestroyCompositor");
- DCHECK(compositor_ == compositor);
-
- // This can fail if Apps call destroy while the webview is still attached
- // to the view tree. This is an illegal operation that will lead to leaks.
- // Log for now. Consider a proper fix if this becomes a problem.
- LOG_IF(ERROR, hardware_initialized_)
- << "Destroy called before OnDetachedFromWindow. May Leak GL resources";
- compositor_ = NULL;
+ if (g_service.Get())
+ g_service.Get()->RunTasks();
}
-void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate) {
- if (compositor_needs_continuous_invalidate_ == invalidate)
- return;
+ScopedAllowGL::~ScopedAllowGL() { allow_gl = false; }
- TRACE_EVENT_INSTANT1("android_webview",
- "InProcessViewRenderer::SetContinuousInvalidate",
- TRACE_EVENT_SCOPE_THREAD,
- "invalidate",
- invalidate);
- compositor_needs_continuous_invalidate_ = invalidate;
- EnsureContinuousInvalidation(NULL, false);
-}
-
-void InProcessViewRenderer::SetDipScale(float dip_scale) {
- dip_scale_ = dip_scale;
- CHECK(dip_scale_ > 0);
-}
+DeferredGpuCommandService::DeferredGpuCommandService() {}
-gfx::Vector2d InProcessViewRenderer::max_scroll_offset() const {
- DCHECK_GT(dip_scale_, 0);
- return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
- max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
+DeferredGpuCommandService::~DeferredGpuCommandService() {
+ base::AutoLock lock(tasks_lock_);
+ DCHECK(tasks_.empty());
}
-void InProcessViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
- gfx::Vector2d max_offset = max_scroll_offset();
- gfx::Vector2dF scroll_offset_dip;
- // To preserve the invariant that scrolling to the maximum physical pixel
- // value also scrolls to the maximum dip pixel value we transform the physical
- // offset into the dip offset by using a proportion (instead of dividing by
- // dip_scale * page_scale_factor).
- if (max_offset.x()) {
- scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
- max_offset.x());
- }
- if (max_offset.y()) {
- scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
- max_offset.y());
+namespace {
+void RequestProcessGL() {
+ HardwareRenderer* renderer =
+ GLViewRendererManager::GetInstance()->GetMostRecentlyDrawn();
+ if (!renderer || !renderer->RequestDrawGL()) {
+ LOG(ERROR) << "Failed to request GL process. Deadlock likely: "
+ << !!renderer;
}
-
- DCHECK_LE(0, scroll_offset_dip.x());
- DCHECK_LE(0, scroll_offset_dip.y());
- DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
- DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
-
- if (scroll_offset_dip_ == scroll_offset_dip)
- return;
-
- scroll_offset_dip_ = scroll_offset_dip;
-
- if (compositor_)
- compositor_->DidChangeRootLayerScrollOffset();
}
+} // namespace
-void InProcessViewRenderer::DidUpdateContent() {
- TRACE_EVENT_INSTANT0("android_webview",
- "InProcessViewRenderer::DidUpdateContent",
- TRACE_EVENT_SCOPE_THREAD);
- clear_view_ = false;
- EnsureContinuousInvalidation(NULL, false);
- if (on_new_picture_enable_)
- client_->OnNewPicture();
-}
-
-void InProcessViewRenderer::SetMaxRootLayerScrollOffset(
- gfx::Vector2dF new_value_dip) {
- DCHECK_GT(dip_scale_, 0);
-
- max_scroll_offset_dip_ = new_value_dip;
- DCHECK_LE(0, max_scroll_offset_dip_.x());
- DCHECK_LE(0, max_scroll_offset_dip_.y());
-
- client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
+// static
+void DeferredGpuCommandService::RequestProcessGLOnUIThread() {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ RequestProcessGL();
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE, base::Bind(&RequestProcessGL));
+ }
}
-void InProcessViewRenderer::SetTotalRootLayerScrollOffset(
- gfx::Vector2dF scroll_offset_dip) {
- // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
- // DrawGl when http://crbug.com/249972 is fixed.
- if (scroll_offset_dip_ == scroll_offset_dip)
- return;
-
- scroll_offset_dip_ = scroll_offset_dip;
-
- gfx::Vector2d max_offset = max_scroll_offset();
- gfx::Vector2d scroll_offset;
- // For an explanation as to why this is done this way see the comment in
- // InProcessViewRenderer::ScrollTo.
- if (max_scroll_offset_dip_.x()) {
- scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
- max_scroll_offset_dip_.x());
+// Called from different threads!
+void DeferredGpuCommandService::ScheduleTask(const base::Closure& task) {
+ {
+ base::AutoLock lock(tasks_lock_);
+ tasks_.push(task);
}
-
- if (max_scroll_offset_dip_.y()) {
- scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
- max_scroll_offset_dip_.y());
+ if (ScopedAllowGL::IsAllowed()) {
+ RunTasks();
+ } else {
+ RequestProcessGLOnUIThread();
}
-
- DCHECK(0 <= scroll_offset.x());
- DCHECK(0 <= scroll_offset.y());
- // Disabled because the conditions are being violated while running
- // AwZoomTest.testMagnification, see http://crbug.com/340648
- // DCHECK(scroll_offset.x() <= max_offset.x());
- // DCHECK(scroll_offset.y() <= max_offset.y());
-
- client_->ScrollContainerViewTo(scroll_offset);
-}
-
-gfx::Vector2dF InProcessViewRenderer::GetTotalRootLayerScrollOffset() {
- return scroll_offset_dip_;
-}
-
-bool InProcessViewRenderer::IsExternalFlingActive() const {
- return client_->IsFlingActive();
}
-void InProcessViewRenderer::SetRootLayerPageScaleFactorAndLimits(
- float page_scale_factor,
- float min_page_scale_factor,
- float max_page_scale_factor) {
- page_scale_factor_ = page_scale_factor;
- DCHECK_GT(page_scale_factor_, 0);
- client_->SetPageScaleFactorAndLimits(
- page_scale_factor, min_page_scale_factor, max_page_scale_factor);
-}
-
-void InProcessViewRenderer::SetRootLayerScrollableSize(
- gfx::SizeF scrollable_size) {
- client_->SetContentsSize(scrollable_size);
-}
-
-void InProcessViewRenderer::DidOverscroll(
- gfx::Vector2dF accumulated_overscroll,
- gfx::Vector2dF latest_overscroll_delta,
- gfx::Vector2dF current_fling_velocity) {
- const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
- if (accumulated_overscroll == latest_overscroll_delta)
- overscroll_rounding_error_ = gfx::Vector2dF();
- gfx::Vector2dF scaled_overscroll_delta =
- gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
- gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
- scaled_overscroll_delta + overscroll_rounding_error_);
- overscroll_rounding_error_ =
- scaled_overscroll_delta - rounded_overscroll_delta;
- client_->DidOverscroll(rounded_overscroll_delta);
+void DeferredGpuCommandService::ScheduleIdleWork(
+ const base::Closure& callback) {
+ // TODO(sievers): Should this do anything?
}
-void InProcessViewRenderer::EnsureContinuousInvalidation(
- AwDrawGLInfo* draw_info,
- bool invalidate_ignore_compositor) {
- // This method should be called again when any of these conditions change.
- bool need_invalidate =
- compositor_needs_continuous_invalidate_ || invalidate_ignore_compositor;
- if (!need_invalidate || block_invalidates_)
- return;
+bool DeferredGpuCommandService::UseVirtualizedGLContexts() { return true; }
- // Always call view invalidate. We rely the Android framework to ignore the
- // invalidate when it's not needed such as when view is not visible.
- if (draw_info) {
- draw_info->dirty_left = cached_global_visible_rect_.x();
- draw_info->dirty_top = cached_global_visible_rect_.y();
- draw_info->dirty_right = cached_global_visible_rect_.right();
- draw_info->dirty_bottom = cached_global_visible_rect_.bottom();
- draw_info->status_mask |= AwDrawGLInfo::kStatusMaskDraw;
- } else {
- client_->PostInvalidate();
+void DeferredGpuCommandService::RunTasks() {
+ bool has_more_tasks;
+ {
+ base::AutoLock lock(tasks_lock_);
+ has_more_tasks = tasks_.size() > 0;
}
- // Stop fallback ticks when one of these is true.
- // 1) Webview is paused. Also need to check we are not in clear view since
- // paused, offscreen still expect clear view to recover.
- // 2) If we are attached to window and the window is not visible (eg when
- // app is in the background). We are sure in this case the webview is used
- // "on-screen" but that updates are not needed when in the background.
- bool throttle_fallback_tick =
- (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
- if (throttle_fallback_tick)
- return;
-
- block_invalidates_ = compositor_needs_continuous_invalidate_;
-
- // Unretained here is safe because the callback is cancelled when
- // |fallback_tick_| is destroyed.
- fallback_tick_.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired,
- base::Unretained(this)));
-
- // No need to reschedule fallback tick if compositor does not need to be
- // ticked. This can happen if this is reached because
- // invalidate_ignore_compositor is true.
- if (compositor_needs_continuous_invalidate_) {
- BrowserThread::PostDelayedTask(
- BrowserThread::UI,
- FROM_HERE,
- fallback_tick_.callback(),
- base::TimeDelta::FromMilliseconds(
- kFallbackTickTimeoutInMilliseconds));
+ while (has_more_tasks) {
+ base::Closure task;
+ {
+ base::AutoLock lock(tasks_lock_);
+ task = tasks_.front();
+ tasks_.pop();
+ }
+ task.Run();
+ {
+ base::AutoLock lock(tasks_lock_);
+ has_more_tasks = tasks_.size() > 0;
+ }
}
}
-void InProcessViewRenderer::FallbackTickFired() {
- TRACE_EVENT1("android_webview",
- "InProcessViewRenderer::FallbackTickFired",
- "compositor_needs_continuous_invalidate_",
- compositor_needs_continuous_invalidate_);
-
- // This should only be called if OnDraw or DrawGL did not come in time, which
- // means block_invalidates_ must still be true.
- DCHECK(block_invalidates_);
- if (compositor_needs_continuous_invalidate_ && compositor_)
- ForceFakeCompositeSW();
-}
-
-void InProcessViewRenderer::ForceFakeCompositeSW() {
- DCHECK(compositor_);
- SkBitmapDevice device(SkBitmap::kARGB_8888_Config, 1, 1);
- SkCanvas canvas(&device);
- CompositeSW(&canvas);
+void DeferredGpuCommandService::AddRef() const {
+ base::RefCountedThreadSafe<DeferredGpuCommandService>::AddRef();
}
-bool InProcessViewRenderer::CompositeSW(SkCanvas* canvas) {
- DCHECK(compositor_);
-
- fallback_tick_.Cancel();
- block_invalidates_ = true;
- bool result = compositor_->DemandDrawSw(canvas);
- block_invalidates_ = false;
- EnsureContinuousInvalidation(NULL, false);
- return result;
+void DeferredGpuCommandService::Release() const {
+ base::RefCountedThreadSafe<DeferredGpuCommandService>::Release();
}
-std::string InProcessViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
- std::string str;
- base::StringAppendF(&str, "is_paused: %d ", is_paused_);
- base::StringAppendF(&str, "view_visible: %d ", view_visible_);
- base::StringAppendF(&str, "window_visible: %d ", window_visible_);
- base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
- base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
- base::StringAppendF(&str,
- "compositor_needs_continuous_invalidate: %d ",
- compositor_needs_continuous_invalidate_);
- base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
- base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
- base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
- base::StringAppendF(&str, "hardware_initialized: %d ", hardware_initialized_);
- base::StringAppendF(&str, "hardware_failed: %d ", hardware_failed_);
- base::StringAppendF(&str,
- "global visible rect: %s ",
- cached_global_visible_rect_.ToString().c_str());
- base::StringAppendF(&str,
- "scroll_at_start_of_frame: %s ",
- scroll_at_start_of_frame_.ToString().c_str());
- base::StringAppendF(
- &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
- base::StringAppendF(&str,
- "overscroll_rounding_error_: %s ",
- overscroll_rounding_error_.ToString().c_str());
- base::StringAppendF(
- &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
- base::StringAppendF(&str, "clear_view: %d ", clear_view_);
- if (draw_info) {
- base::StringAppendF(&str,
- "clip left top right bottom: [%d %d %d %d] ",
- draw_info->clip_left,
- draw_info->clip_top,
- draw_info->clip_right,
- draw_info->clip_bottom);
- base::StringAppendF(&str,
- "surface width height: [%d %d] ",
- draw_info->width,
- draw_info->height);
- base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
- }
- return str;
-}
+} // namespace internal
} // namespace android_webview
« no previous file with comments | « android_webview/browser/hardware_renderer.h ('k') | android_webview/browser/in_process_view_renderer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698