OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "android_webview/browser/deferred_gpu_command_service.h" | 5 #include "android_webview/browser/deferred_gpu_command_service.h" |
6 | 6 |
7 #include "android_webview/browser/gl_view_renderer_manager.h" | 7 #include "android_webview/browser/gl_view_renderer_manager.h" |
8 #include "android_webview/browser/shared_renderer_state.h" | 8 #include "android_webview/browser/shared_renderer_state.h" |
9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 10 #include "base/lazy_instance.h" |
10 #include "base/synchronization/lock.h" | 11 #include "base/synchronization/lock.h" |
11 #include "content/public/browser/android/synchronous_compositor.h" | 12 #include "content/public/browser/android/synchronous_compositor.h" |
12 #include "gpu/command_buffer/service/shader_translator_cache.h" | 13 #include "gpu/command_buffer/service/shader_translator_cache.h" |
13 | 14 |
14 namespace android_webview { | 15 namespace android_webview { |
15 | 16 |
16 namespace { | 17 namespace { |
17 | |
18 // TODO(boliu): Consider using base/atomicops.h. | |
19 class ThreadSafeBool { | |
20 public: | |
21 ThreadSafeBool(); | |
22 void Set(bool boolean); | |
23 bool Get(); | |
24 bool GetAndSet(); | |
25 | |
26 private: | |
27 base::Lock lock_; | |
28 bool boolean_; | |
29 DISALLOW_COPY_AND_ASSIGN(ThreadSafeBool); | |
30 }; | |
31 | |
32 ThreadSafeBool::ThreadSafeBool() : boolean_(false) { | |
33 } | |
34 | |
35 void ThreadSafeBool::Set(bool boolean) { | |
36 base::AutoLock lock(lock_); | |
37 boolean_ = boolean; | |
38 } | |
39 | |
40 bool ThreadSafeBool::GetAndSet() { | |
41 base::AutoLock lock(lock_); | |
42 bool rv = boolean_; | |
43 boolean_ = true; | |
44 return rv; | |
45 } | |
46 | |
47 bool ThreadSafeBool::Get() { | |
48 base::AutoLock lock(lock_); | |
49 return boolean_; | |
50 } | |
51 | |
52 base::LazyInstance<ThreadSafeBool> g_request_pending = | |
53 LAZY_INSTANCE_INITIALIZER; | |
54 | |
55 // Because request is posted to UI thread, have to treat requests on UI thread | |
56 // specifically because UI can immediately block waiting for the request. | |
57 base::LazyInstance<ThreadSafeBool> g_request_pending_on_ui = | |
58 LAZY_INSTANCE_INITIALIZER; | |
59 | |
60 base::LazyInstance<scoped_refptr<DeferredGpuCommandService> > | 18 base::LazyInstance<scoped_refptr<DeferredGpuCommandService> > |
61 g_service = LAZY_INSTANCE_INITIALIZER; | 19 g_service = LAZY_INSTANCE_INITIALIZER; |
62 } // namespace | 20 } // namespace |
63 | 21 |
64 base::LazyInstance<base::ThreadLocalBoolean> ScopedAllowGL::allow_gl; | 22 base::LazyInstance<base::ThreadLocalBoolean> ScopedAllowGL::allow_gl; |
65 | 23 |
66 // static | 24 // static |
67 bool ScopedAllowGL::IsAllowed() { | 25 bool ScopedAllowGL::IsAllowed() { |
68 return allow_gl.Get().Get(); | 26 return allow_gl.Get().Get(); |
69 } | 27 } |
70 | 28 |
71 ScopedAllowGL::ScopedAllowGL() { | 29 ScopedAllowGL::ScopedAllowGL() { |
72 DCHECK(!allow_gl.Get().Get()); | 30 DCHECK(!allow_gl.Get().Get()); |
73 allow_gl.Get().Set(true); | 31 allow_gl.Get().Set(true); |
74 | 32 |
75 if (g_service.Get()) | 33 if (g_service.Get()) |
76 g_service.Get()->RunTasks(); | 34 g_service.Get()->RunTasks(); |
77 } | 35 } |
78 | 36 |
79 ScopedAllowGL::~ScopedAllowGL() { | 37 ScopedAllowGL::~ScopedAllowGL() { |
80 allow_gl.Get().Set(false); | 38 allow_gl.Get().Set(false); |
81 g_request_pending.Get().Set(false); | |
82 g_request_pending_on_ui.Get().Set(false); | |
83 | 39 |
84 DeferredGpuCommandService* service = g_service.Get(); | 40 DeferredGpuCommandService* service = g_service.Get(); |
85 if (service) { | 41 if (service) { |
86 service->RunTasks(); | 42 service->RunTasks(); |
87 if (service->HasIdleWork()) { | 43 if (service->IdleQueueSize()) { |
88 service->RequestProcessGL(); | 44 service->RequestProcessGL(); |
89 } | 45 } |
90 } | 46 } |
91 } | 47 } |
92 | 48 |
93 // static | 49 // static |
94 void DeferredGpuCommandService::SetInstance() { | 50 void DeferredGpuCommandService::SetInstance() { |
95 if (!g_service.Get()) { | 51 if (!g_service.Get()) { |
96 g_service.Get() = new DeferredGpuCommandService; | 52 g_service.Get() = new DeferredGpuCommandService; |
97 content::SynchronousCompositor::SetGpuService(g_service.Get()); | 53 content::SynchronousCompositor::SetGpuService(g_service.Get()); |
98 | |
99 // Initialize global booleans. | |
100 g_request_pending.Get().Set(false); | |
101 g_request_pending_on_ui.Get().Set(false); | |
102 } | 54 } |
103 } | 55 } |
104 | 56 |
105 // static | 57 // static |
106 DeferredGpuCommandService* DeferredGpuCommandService::GetInstance() { | 58 DeferredGpuCommandService* DeferredGpuCommandService::GetInstance() { |
107 DCHECK(g_service.Get().get()); | 59 DCHECK(g_service.Get().get()); |
108 return g_service.Get().get(); | 60 return g_service.Get().get(); |
109 } | 61 } |
110 | 62 |
111 DeferredGpuCommandService::DeferredGpuCommandService() {} | 63 DeferredGpuCommandService::DeferredGpuCommandService() {} |
112 | 64 |
113 DeferredGpuCommandService::~DeferredGpuCommandService() { | 65 DeferredGpuCommandService::~DeferredGpuCommandService() { |
114 base::AutoLock lock(tasks_lock_); | 66 base::AutoLock lock(tasks_lock_); |
115 DCHECK(tasks_.empty()); | 67 DCHECK(tasks_.empty()); |
116 } | 68 } |
117 | 69 |
118 // This method can be called on any thread. | 70 // This method can be called on any thread. |
119 // static | 71 // static |
120 void DeferredGpuCommandService::RequestProcessGL() { | 72 void DeferredGpuCommandService::RequestProcessGL() { |
121 SharedRendererState* renderer_state = | 73 SharedRendererState* renderer_state = |
122 GLViewRendererManager::GetInstance()->GetMostRecentlyDrawn(); | 74 GLViewRendererManager::GetInstance()->GetMostRecentlyDrawn(); |
123 if (!renderer_state) { | 75 if (!renderer_state) { |
124 LOG(ERROR) << "No hardware renderer. Deadlock likely"; | 76 LOG(ERROR) << "No hardware renderer. Deadlock likely"; |
125 return; | 77 return; |
126 } | 78 } |
127 | 79 renderer_state->ClientRequestDrawGL(); |
128 bool on_ui_thread = renderer_state->CurrentlyOnUIThread(); | |
129 bool need_request = on_ui_thread ? !g_request_pending_on_ui.Get().GetAndSet() | |
130 : !g_request_pending.Get().GetAndSet(); | |
131 if (need_request) { | |
132 g_request_pending.Get().Set(true); | |
133 renderer_state->ClientRequestDrawGL(); | |
134 } | |
135 } | 80 } |
136 | 81 |
137 // Called from different threads! | 82 // Called from different threads! |
138 void DeferredGpuCommandService::ScheduleTask(const base::Closure& task) { | 83 void DeferredGpuCommandService::ScheduleTask(const base::Closure& task) { |
139 { | 84 { |
140 base::AutoLock lock(tasks_lock_); | 85 base::AutoLock lock(tasks_lock_); |
141 tasks_.push(task); | 86 tasks_.push(task); |
142 } | 87 } |
143 if (ScopedAllowGL::IsAllowed()) { | 88 if (ScopedAllowGL::IsAllowed()) { |
144 RunTasks(); | 89 RunTasks(); |
145 } else { | 90 } else { |
146 RequestProcessGL(); | 91 RequestProcessGL(); |
147 } | 92 } |
148 } | 93 } |
149 | 94 |
150 bool DeferredGpuCommandService::HasIdleWork() { | 95 size_t DeferredGpuCommandService::IdleQueueSize() { |
151 base::AutoLock lock(tasks_lock_); | 96 base::AutoLock lock(tasks_lock_); |
152 return idle_tasks_.size() > 0; | 97 return idle_tasks_.size(); |
153 } | 98 } |
154 | 99 |
155 void DeferredGpuCommandService::ScheduleIdleWork( | 100 void DeferredGpuCommandService::ScheduleIdleWork( |
156 const base::Closure& callback) { | 101 const base::Closure& callback) { |
157 { | 102 { |
158 base::AutoLock lock(tasks_lock_); | 103 base::AutoLock lock(tasks_lock_); |
159 idle_tasks_.push(std::make_pair(base::Time::Now(), callback)); | 104 idle_tasks_.push(std::make_pair(base::Time::Now(), callback)); |
160 } | 105 } |
161 RequestProcessGL(); | 106 RequestProcessGL(); |
162 } | 107 } |
163 | 108 |
164 void DeferredGpuCommandService::PerformIdleWork(bool is_idle) { | 109 void DeferredGpuCommandService::PerformIdleWork(bool is_idle) { |
165 TRACE_EVENT1("android_webview", | 110 TRACE_EVENT1("android_webview", |
166 "DeferredGpuCommandService::PerformIdleWork", | 111 "DeferredGpuCommandService::PerformIdleWork", |
167 "is_idle", | 112 "is_idle", |
168 is_idle); | 113 is_idle); |
169 DCHECK(ScopedAllowGL::IsAllowed()); | 114 DCHECK(ScopedAllowGL::IsAllowed()); |
170 static const base::TimeDelta kMaxIdleAge = | 115 static const base::TimeDelta kMaxIdleAge = |
171 base::TimeDelta::FromMilliseconds(16); | 116 base::TimeDelta::FromMilliseconds(16); |
172 | 117 |
173 const base::Time now = base::Time::Now(); | 118 const base::Time now = base::Time::Now(); |
174 while (HasIdleWork()) { | 119 size_t queue_size = IdleQueueSize(); |
| 120 while (queue_size--) { |
175 base::Closure task; | 121 base::Closure task; |
176 { | 122 { |
177 base::AutoLock lock(tasks_lock_); | 123 base::AutoLock lock(tasks_lock_); |
178 if (!is_idle) { | 124 if (!is_idle) { |
179 // Only run old tasks if we are not really idle right now. | 125 // Only run old tasks if we are not really idle right now. |
180 base::TimeDelta age(now - idle_tasks_.front().first); | 126 base::TimeDelta age(now - idle_tasks_.front().first); |
181 if (age < kMaxIdleAge) | 127 if (age < kMaxIdleAge) |
182 break; | 128 break; |
183 } | 129 } |
184 task = idle_tasks_.front().second; | 130 task = idle_tasks_.front().second; |
185 idle_tasks_.pop(); | 131 idle_tasks_.pop(); |
186 } | 132 } |
187 task.Run(); | 133 task.Run(); |
188 } | 134 } |
189 } | 135 } |
190 | 136 |
| 137 void DeferredGpuCommandService::PerformAllIdleWork() { |
| 138 TRACE_EVENT0("android_webview", |
| 139 "DeferredGpuCommandService::PerformAllIdleWork"); |
| 140 while (IdleQueueSize()) { |
| 141 PerformIdleWork(true); |
| 142 } |
| 143 } |
| 144 |
191 bool DeferredGpuCommandService::UseVirtualizedGLContexts() { return true; } | 145 bool DeferredGpuCommandService::UseVirtualizedGLContexts() { return true; } |
192 | 146 |
193 scoped_refptr<gpu::gles2::ShaderTranslatorCache> | 147 scoped_refptr<gpu::gles2::ShaderTranslatorCache> |
194 DeferredGpuCommandService::shader_translator_cache() { | 148 DeferredGpuCommandService::shader_translator_cache() { |
195 if (!shader_translator_cache_.get()) | 149 if (!shader_translator_cache_.get()) |
196 shader_translator_cache_ = new gpu::gles2::ShaderTranslatorCache; | 150 shader_translator_cache_ = new gpu::gles2::ShaderTranslatorCache; |
197 return shader_translator_cache_; | 151 return shader_translator_cache_; |
198 } | 152 } |
199 | 153 |
200 void DeferredGpuCommandService::RunTasks() { | 154 void DeferredGpuCommandService::RunTasks() { |
(...skipping 20 matching lines...) Expand all Loading... |
221 | 175 |
222 void DeferredGpuCommandService::AddRef() const { | 176 void DeferredGpuCommandService::AddRef() const { |
223 base::RefCountedThreadSafe<DeferredGpuCommandService>::AddRef(); | 177 base::RefCountedThreadSafe<DeferredGpuCommandService>::AddRef(); |
224 } | 178 } |
225 | 179 |
226 void DeferredGpuCommandService::Release() const { | 180 void DeferredGpuCommandService::Release() const { |
227 base::RefCountedThreadSafe<DeferredGpuCommandService>::Release(); | 181 base::RefCountedThreadSafe<DeferredGpuCommandService>::Release(); |
228 } | 182 } |
229 | 183 |
230 } // namespace android_webview | 184 } // namespace android_webview |
OLD | NEW |