| 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 |