| Index: gpu/command_buffer/client/gles2_implementation.cc | 
| diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc | 
| index c4c77e6bf9ba518a4338522754153839a8146680..db2bda0b60c85447992547634b9d01085deeb325 100644 | 
| --- a/gpu/command_buffer/client/gles2_implementation.cc | 
| +++ b/gpu/command_buffer/client/gles2_implementation.cc | 
| @@ -53,11 +53,13 @@ namespace gles2 { | 
| namespace { | 
|  | 
| // Class that DCHECKs if it is destructed without first having Release called. | 
| -class ScopedVisibilityImpl : public ContextSupport::ScopedVisibility { | 
| +template <typename T> | 
| +class ScopedContextSupportToken : public T { | 
| public: | 
| -  explicit ScopedVisibilityImpl(ContextSupport* context_support) | 
| +  explicit ScopedContextSupportToken(ContextSupport* context_support) | 
| : initial_context_support_(context_support) {} | 
| -  ~ScopedVisibilityImpl() { DCHECK(!initial_context_support_); } | 
| + | 
| +  ~ScopedContextSupportToken() { DCHECK(!initial_context_support_); } | 
|  | 
| void Release(ContextSupport* context_support) { | 
| DCHECK_EQ(initial_context_support_, context_support); | 
| @@ -68,6 +70,10 @@ class ScopedVisibilityImpl : public ContextSupport::ScopedVisibility { | 
| const ContextSupport* initial_context_support_; | 
| }; | 
|  | 
| +using ScopedVisibilityImpl = | 
| +    ScopedContextSupportToken<ContextSupport::ScopedVisibility>; | 
| +using ScopedBusyImpl = ScopedContextSupportToken<ContextSupport::ScopedBusy>; | 
| + | 
| void CopyRectToBuffer(const void* pixels, | 
| uint32_t height, | 
| uint32_t unpadded_row_size, | 
| @@ -101,6 +107,8 @@ uint32_t GenerateNextFlushId() { | 
| return static_cast<uint32_t>(g_flush_id.GetNext()); | 
| } | 
|  | 
| +const base::TimeDelta kIdleCallbackDelay = base::TimeDelta::FromSeconds(1); | 
| + | 
| }  // anonymous namespace | 
|  | 
| #if !defined(_MSC_VER) | 
| @@ -181,6 +189,7 @@ GLES2Implementation::GLES2Implementation( | 
| #endif | 
| current_trace_stack_(0), | 
| gpu_control_(gpu_control), | 
| +      task_runner_(std::move(task_runner)), | 
| capabilities_(gpu_control->GetCapabilities()), | 
| cached_extension_string_(nullptr), | 
| weak_ptr_factory_(this) { | 
| @@ -293,6 +302,8 @@ GLES2Implementation::~GLES2Implementation() { | 
| base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( | 
| this); | 
|  | 
| +  CancelIdleCallback(); | 
| + | 
| // Make sure the queries are finished otherwise we'll delete the | 
| // shared memory (mapped_memory_) which will free the memory used | 
| // by the queries. The GPU process when validating that memory is still | 
| @@ -5903,6 +5914,41 @@ bool GLES2Implementation::AnyClientsVisible() const { | 
| return num_visible_clients_ > 0; | 
| } | 
|  | 
| +std::unique_ptr<ContextSupport::ScopedBusy> | 
| +GLES2Implementation::ClientBecameBusy() { | 
| +  base::AutoLock hold(idle_lock_); | 
| +  DCHECK(is_idle_); | 
| +  is_idle_ = false; | 
| +  // Increment the idle callback generation to cancel any pending callbacks. | 
| +  ++current_idle_callback_generation_; | 
| + | 
| +  return base::MakeUnique<ScopedBusyImpl>(this); | 
| +} | 
| + | 
| +void GLES2Implementation::ClientBecameNotBusy( | 
| +    std::unique_ptr<ScopedBusy> busy) { | 
| +  DCHECK(busy); | 
| + | 
| +  base::AutoLock hold(idle_lock_); | 
| +  DCHECK(!is_idle_); | 
| +  is_idle_ = true; | 
| + | 
| +  if (idle_callback_ && task_runner_) { | 
| +    task_runner_->PostDelayedTask( | 
| +        FROM_HERE, base::Bind(&GLES2Implementation::RunIdleCallback, | 
| +                              weak_ptr_factory_.GetWeakPtr(), | 
| +                              current_idle_callback_generation_), | 
| +        kIdleCallbackDelay); | 
| +  } | 
| + | 
| +  static_cast<ScopedBusyImpl*>(busy.get())->Release(this); | 
| +} | 
| + | 
| +void GLES2Implementation::SetIdleCallback(const base::Closure& callback) { | 
| +  base::AutoLock hold(idle_lock_); | 
| +  idle_callback_ = callback; | 
| +} | 
| + | 
| void GLES2Implementation::SetLostContextCallback( | 
| const base::Closure& callback) { | 
| lost_context_callback_ = callback; | 
| @@ -6937,6 +6983,22 @@ void GLES2Implementation::InvalidateCachedExtensions() { | 
| cached_extensions_.clear(); | 
| } | 
|  | 
| +void GLES2Implementation::RunIdleCallback(uint32_t callback_generation) const { | 
| +  base::AutoLock hold(idle_lock_); | 
| + | 
| +  if (!idle_callback_) | 
| +    return; | 
| +  if (callback_generation != current_idle_callback_generation_) | 
| +    return; | 
| + | 
| +  idle_callback_.Run(); | 
| +} | 
| + | 
| +void GLES2Implementation::CancelIdleCallback() { | 
| +  base::AutoLock hold(idle_lock_); | 
| +  ++current_idle_callback_generation_; | 
| +} | 
| + | 
| // Include the auto-generated part of this file. We split this because it means | 
| // we can easily edit the non-auto generated parts right here in this file | 
| // instead of having to edit some template or the code generator. | 
|  |