1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "android_webview/browser/hardware_renderer.h"
7 #include "android_webview/browser/aw_gl_surface.h"
8 #include "android_webview/browser/browser_view_renderer_client.h"
9 #include "android_webview/browser/gl_view_renderer_manager.h"
10 #include "android_webview/browser/scoped_app_gl_state_restore.h"
11 #include "android_webview/public/browser/draw_gl.h"
12 #include "base/command_line.h"
13 #include "base/debug/trace_event.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/common/content_switches.h"
17 #include "ui/gfx/transform.h"
19 using content::BrowserThread
;
21 namespace android_webview
{
25 // Used to calculate memory and resource allocation. Determined experimentally.
26 const size_t g_memory_multiplier
= 10;
27 const size_t g_num_gralloc_limit
= 150;
28 const size_t kBytesPerPixel
= 4;
29 const size_t kMemoryAllocationStep
= 5 * 1024 * 1024;
31 base::LazyInstance
<scoped_refptr
<internal::DeferredGpuCommandService
> >
32 g_service
= LAZY_INSTANCE_INITIALIZER
;
36 HardwareRenderer::HardwareRenderer(SharedRendererState
* state
)
37 : shared_renderer_state_(state
),
38 last_egl_context_(eglGetCurrentContext()),
39 manager_key_(GLViewRendererManager::GetInstance()->PushBack(
40 shared_renderer_state_
)) {
41 DCHECK(last_egl_context_
);
42 if (!g_service
.Get()) {
43 g_service
.Get() = new internal::DeferredGpuCommandService
;
44 content::SynchronousCompositor::SetGpuService(g_service
.Get());
47 ScopedAppGLStateRestore
state_restore(
48 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT
);
49 internal::ScopedAllowGL allow_gl
;
51 gl_surface_
= new AwGLSurface
;
53 shared_renderer_state_
->GetCompositor()->
54 InitializeHwDraw(gl_surface_
);
58 HardwareRenderer::~HardwareRenderer() {
59 GLViewRendererManager
* mru
= GLViewRendererManager::GetInstance();
60 mru
->Remove(manager_key_
);
62 ScopedAppGLStateRestore
state_restore(
63 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT
);
64 internal::ScopedAllowGL allow_gl
;
66 shared_renderer_state_
->GetCompositor()->ReleaseHwDraw();
70 bool HardwareRenderer::DrawGL(AwDrawGLInfo
* draw_info
, DrawGLResult
* result
) {
71 TRACE_EVENT0("android_webview", "HardwareRenderer::DrawGL");
72 GLViewRendererManager::GetInstance()->DidDrawGL(manager_key_
);
73 const DrawGLInput input
= shared_renderer_state_
->GetDrawGLInput();
75 // We need to watch if the current Android context has changed and enforce
76 // a clean-up in the compositor.
77 EGLContext current_context
= eglGetCurrentContext();
78 if (!current_context
) {
79 DLOG(ERROR
) << "DrawGL called without EGLContext";
83 // TODO(boliu): Handle context loss.
84 if (last_egl_context_
!= current_context
)
85 DLOG(WARNING
) << "EGLContextChanged";
87 ScopedAppGLStateRestore
state_restore(ScopedAppGLStateRestore::MODE_DRAW
);
88 internal::ScopedAllowGL allow_gl
;
90 if (draw_info
->mode
== AwDrawGLInfo::kModeProcess
)
93 // Update memory budget. This will no-op in compositor if the policy has not
94 // changed since last draw.
95 content::SynchronousCompositorMemoryPolicy policy
;
96 policy
.bytes_limit
= g_memory_multiplier
* kBytesPerPixel
*
97 input
.global_visible_rect
.width() *
98 input
.global_visible_rect
.height();
99 // Round up to a multiple of kMemoryAllocationStep.
101 (policy
.bytes_limit
/ kMemoryAllocationStep
+ 1) * kMemoryAllocationStep
;
102 policy
.num_resources_limit
= g_num_gralloc_limit
;
103 SetMemoryPolicy(policy
);
105 gl_surface_
->SetBackingFrameBufferObject(
106 state_restore
.framebuffer_binding_ext());
108 gfx::Transform transform
;
109 transform
.matrix().setColMajorf(draw_info
->transform
);
110 transform
.Translate(input
.scroll_offset
.x(), input
.scroll_offset
.y());
111 gfx::Rect
clip_rect(draw_info
->clip_left
,
113 draw_info
->clip_right
- draw_info
->clip_left
,
114 draw_info
->clip_bottom
- draw_info
->clip_top
);
116 bool did_draw
= shared_renderer_state_
->GetCompositor()->
118 gfx::Size(draw_info
->width
, draw_info
->height
),
120 clip_rect
, // viewport
122 state_restore
.stencil_enabled());
123 gl_surface_
->ResetBackingFrameBufferObject();
126 result
->frame_id
= input
.frame_id
;
127 result
->clip_contains_visible_rect
=
128 clip_rect
.Contains(input
.global_visible_rect
);
133 bool HardwareRenderer::TrimMemory(int level
, bool visible
) {
134 // Constants from Android ComponentCallbacks2.
136 TRIM_MEMORY_RUNNING_LOW
= 10,
137 TRIM_MEMORY_UI_HIDDEN
= 20,
138 TRIM_MEMORY_BACKGROUND
= 40,
141 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
142 // it does not indicate memory pressure, but merely that the app is
144 if (level
< TRIM_MEMORY_RUNNING_LOW
|| level
== TRIM_MEMORY_UI_HIDDEN
)
147 // Do not release resources on view we expect to get DrawGL soon.
148 if (level
< TRIM_MEMORY_BACKGROUND
&& visible
)
151 if (!eglGetCurrentContext()) {
156 DCHECK_EQ(last_egl_context_
, eglGetCurrentContext());
158 // Just set the memory limit to 0 and drop all tiles. This will be reset to
159 // normal levels in the next DrawGL call.
160 content::SynchronousCompositorMemoryPolicy policy
;
161 policy
.bytes_limit
= 0;
162 policy
.num_resources_limit
= 0;
163 if (memory_policy_
== policy
)
166 TRACE_EVENT0("android_webview", "HardwareRenderer::TrimMemory");
167 ScopedAppGLStateRestore
state_restore(
168 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT
);
169 internal::ScopedAllowGL allow_gl
;
171 SetMemoryPolicy(policy
);
175 void HardwareRenderer::SetMemoryPolicy(
176 content::SynchronousCompositorMemoryPolicy
& new_policy
) {
177 if (memory_policy_
== new_policy
)
180 memory_policy_
= new_policy
;
181 shared_renderer_state_
->GetCompositor()->
182 SetMemoryPolicy(memory_policy_
);
186 void HardwareRenderer::CalculateTileMemoryPolicy() {
187 CommandLine
* cl
= CommandLine::ForCurrentProcess();
189 const char kDefaultTileSize
[] = "384";
190 if (!cl
->HasSwitch(switches::kDefaultTileWidth
))
191 cl
->AppendSwitchASCII(switches::kDefaultTileWidth
, kDefaultTileSize
);
193 if (!cl
->HasSwitch(switches::kDefaultTileHeight
))
194 cl
->AppendSwitchASCII(switches::kDefaultTileHeight
, kDefaultTileSize
);
199 bool ScopedAllowGL::allow_gl
= false;
202 bool ScopedAllowGL::IsAllowed() {
203 return GLViewRendererManager::GetInstance()->OnRenderThread() && allow_gl
;
206 ScopedAllowGL::ScopedAllowGL() {
207 DCHECK(GLViewRendererManager::GetInstance()->OnRenderThread());
212 g_service
.Get()->RunTasks();
215 ScopedAllowGL::~ScopedAllowGL() { allow_gl
= false; }
217 DeferredGpuCommandService::DeferredGpuCommandService() {}
219 DeferredGpuCommandService::~DeferredGpuCommandService() {
220 base::AutoLock
lock(tasks_lock_
);
221 DCHECK(tasks_
.empty());
225 void DeferredGpuCommandService::RequestProcessGLOnUIThread() {
226 SharedRendererState
* renderer_state
=
227 GLViewRendererManager::GetInstance()->GetMostRecentlyDrawn();
228 if (!renderer_state
) {
229 LOG(ERROR
) << "No hardware renderer. Deadlock likely";
232 renderer_state
->ClientRequestDrawGL();
235 // Called from different threads!
236 void DeferredGpuCommandService::ScheduleTask(const base::Closure
& task
) {
238 base::AutoLock
lock(tasks_lock_
);
241 if (ScopedAllowGL::IsAllowed()) {
244 RequestProcessGLOnUIThread();
248 void DeferredGpuCommandService::ScheduleIdleWork(
249 const base::Closure
& callback
) {
250 // TODO(sievers): Should this do anything?
253 bool DeferredGpuCommandService::UseVirtualizedGLContexts() { return true; }
255 void DeferredGpuCommandService::RunTasks() {
258 base::AutoLock
lock(tasks_lock_
);
259 has_more_tasks
= tasks_
.size() > 0;
262 while (has_more_tasks
) {
265 base::AutoLock
lock(tasks_lock_
);
266 task
= tasks_
.front();
271 base::AutoLock
lock(tasks_lock_
);
272 has_more_tasks
= tasks_
.size() > 0;
277 void DeferredGpuCommandService::AddRef() const {
278 base::RefCountedThreadSafe
<DeferredGpuCommandService
>::AddRef();
281 void DeferredGpuCommandService::Release() const {
282 base::RefCountedThreadSafe
<DeferredGpuCommandService
>::Release();
285 } // namespace internal
287 } // namespace android_webview