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. 4 5 #include "android_webview/browser/deferred_gpu_command_service.h" 6 7 #include "android_webview/browser/gl_view_renderer_manager.h" 8 #include "android_webview/browser/shared_renderer_state.h" 9 #include "base/debug/trace_event.h" 10 #include "base/lazy_instance.h" 11 #include "base/synchronization/lock.h" 12 #include "content/public/browser/android/synchronous_compositor.h" 13 #include "gpu/command_buffer/service/shader_translator_cache.h" 14 15 namespace android_webview { 16 17 namespace { 18 base::LazyInstance<scoped_refptr<DeferredGpuCommandService> > 19 g_service = LAZY_INSTANCE_INITIALIZER; 20 } // namespace 21 22 base::LazyInstance<base::ThreadLocalBoolean> ScopedAllowGL::allow_gl; 23 24 // static 25 bool ScopedAllowGL::IsAllowed() { 26 return allow_gl.Get().Get(); 27 } 28 29 ScopedAllowGL::ScopedAllowGL() { 30 DCHECK(!allow_gl.Get().Get()); 31 allow_gl.Get().Set(true); 32 33 if (g_service.Get()) 34 g_service.Get()->RunTasks(); 35 } 36 37 ScopedAllowGL::~ScopedAllowGL() { 38 allow_gl.Get().Set(false); 39 40 DeferredGpuCommandService* service = g_service.Get(); 41 if (service) { 42 service->RunTasks(); 43 if (service->IdleQueueSize()) { 44 service->RequestProcessGL(); 45 } 46 } 47 } 48 49 // static 50 void DeferredGpuCommandService::SetInstance() { 51 if (!g_service.Get()) { 52 g_service.Get() = new DeferredGpuCommandService; 53 content::SynchronousCompositor::SetGpuService(g_service.Get()); 54 } 55 } 56 57 // static 58 DeferredGpuCommandService* DeferredGpuCommandService::GetInstance() { 59 DCHECK(g_service.Get().get()); 60 return g_service.Get().get(); 61 } 62 63 DeferredGpuCommandService::DeferredGpuCommandService() {} 64 65 DeferredGpuCommandService::~DeferredGpuCommandService() { 66 base::AutoLock lock(tasks_lock_); 67 DCHECK(tasks_.empty()); 68 } 69 70 // This method can be called on any thread. 71 // static 72 void DeferredGpuCommandService::RequestProcessGL() { 73 SharedRendererState* renderer_state = 74 GLViewRendererManager::GetInstance()->GetMostRecentlyDrawn(); 75 if (!renderer_state) { 76 LOG(ERROR) << "No hardware renderer. Deadlock likely"; 77 return; 78 } 79 renderer_state->ClientRequestDrawGL(); 80 } 81 82 // Called from different threads! 83 void DeferredGpuCommandService::ScheduleTask(const base::Closure& task) { 84 { 85 base::AutoLock lock(tasks_lock_); 86 tasks_.push(task); 87 } 88 if (ScopedAllowGL::IsAllowed()) { 89 RunTasks(); 90 } else { 91 RequestProcessGL(); 92 } 93 } 94 95 size_t DeferredGpuCommandService::IdleQueueSize() { 96 base::AutoLock lock(tasks_lock_); 97 return idle_tasks_.size(); 98 } 99 100 void DeferredGpuCommandService::ScheduleIdleWork( 101 const base::Closure& callback) { 102 { 103 base::AutoLock lock(tasks_lock_); 104 idle_tasks_.push(std::make_pair(base::Time::Now(), callback)); 105 } 106 RequestProcessGL(); 107 } 108 109 void DeferredGpuCommandService::PerformIdleWork(bool is_idle) { 110 TRACE_EVENT1("android_webview", 111 "DeferredGpuCommandService::PerformIdleWork", 112 "is_idle", 113 is_idle); 114 DCHECK(ScopedAllowGL::IsAllowed()); 115 static const base::TimeDelta kMaxIdleAge = 116 base::TimeDelta::FromMilliseconds(16); 117 118 const base::Time now = base::Time::Now(); 119 size_t queue_size = IdleQueueSize(); 120 while (queue_size--) { 121 base::Closure task; 122 { 123 base::AutoLock lock(tasks_lock_); 124 if (!is_idle) { 125 // Only run old tasks if we are not really idle right now. 126 base::TimeDelta age(now - idle_tasks_.front().first); 127 if (age < kMaxIdleAge) 128 break; 129 } 130 task = idle_tasks_.front().second; 131 idle_tasks_.pop(); 132 } 133 task.Run(); 134 } 135 } 136 137 void DeferredGpuCommandService::PerformAllIdleWork() { 138 TRACE_EVENT0("android_webview", 139 "DeferredGpuCommandService::PerformAllIdleWork"); 140 while (IdleQueueSize()) { 141 PerformIdleWork(true); 142 } 143 } 144 145 bool DeferredGpuCommandService::UseVirtualizedGLContexts() { return true; } 146 147 scoped_refptr<gpu::gles2::ShaderTranslatorCache> 148 DeferredGpuCommandService::shader_translator_cache() { 149 if (!shader_translator_cache_.get()) 150 shader_translator_cache_ = new gpu::gles2::ShaderTranslatorCache; 151 return shader_translator_cache_; 152 } 153 154 void DeferredGpuCommandService::RunTasks() { 155 bool has_more_tasks; 156 { 157 base::AutoLock lock(tasks_lock_); 158 has_more_tasks = tasks_.size() > 0; 159 } 160 161 while (has_more_tasks) { 162 base::Closure task; 163 { 164 base::AutoLock lock(tasks_lock_); 165 task = tasks_.front(); 166 tasks_.pop(); 167 } 168 task.Run(); 169 { 170 base::AutoLock lock(tasks_lock_); 171 has_more_tasks = tasks_.size() > 0; 172 } 173 } 174 } 175 176 void DeferredGpuCommandService::AddRef() const { 177 base::RefCountedThreadSafe<DeferredGpuCommandService>::AddRef(); 178 } 179 180 void DeferredGpuCommandService::Release() const { 181 base::RefCountedThreadSafe<DeferredGpuCommandService>::Release(); 182 } 183 184 } // namespace android_webview 185