Home | History | Annotate | Download | only in browser
      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