Home | History | Annotate | Download | only in client
      1 // Copyright (c) 2013 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 "content/common/gpu/client/context_provider_command_buffer.h"
      6 
      7 #include <set>
      8 #include <vector>
      9 
     10 #include "base/callback_helpers.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "cc/output/managed_memory_policy.h"
     13 #include "gpu/command_buffer/client/gles2_implementation.h"
     14 #include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
     15 
     16 namespace content {
     17 
     18 class ContextProviderCommandBuffer::LostContextCallbackProxy
     19     : public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback {
     20  public:
     21   explicit LostContextCallbackProxy(ContextProviderCommandBuffer* provider)
     22       : provider_(provider) {
     23     provider_->context3d_->setContextLostCallback(this);
     24   }
     25 
     26   virtual ~LostContextCallbackProxy() {
     27     provider_->context3d_->setContextLostCallback(NULL);
     28   }
     29 
     30   virtual void onContextLost() {
     31     provider_->OnLostContext();
     32   }
     33 
     34  private:
     35   ContextProviderCommandBuffer* provider_;
     36 };
     37 
     38 scoped_refptr<ContextProviderCommandBuffer>
     39 ContextProviderCommandBuffer::Create(
     40     scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
     41     const std::string& debug_name) {
     42   if (!context3d)
     43     return NULL;
     44 
     45   return new ContextProviderCommandBuffer(context3d.Pass(), debug_name);
     46 }
     47 
     48 ContextProviderCommandBuffer::ContextProviderCommandBuffer(
     49     scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
     50     const std::string& debug_name)
     51     : context3d_(context3d.Pass()),
     52       debug_name_(debug_name),
     53       destroyed_(false) {
     54   DCHECK(main_thread_checker_.CalledOnValidThread());
     55   DCHECK(context3d_);
     56   context_thread_checker_.DetachFromThread();
     57 }
     58 
     59 ContextProviderCommandBuffer::~ContextProviderCommandBuffer() {
     60   DCHECK(main_thread_checker_.CalledOnValidThread() ||
     61          context_thread_checker_.CalledOnValidThread());
     62 
     63   base::AutoLock lock(main_thread_lock_);
     64 
     65   // Destroy references to the context3d_ before leaking it.
     66   if (context3d_->GetCommandBufferProxy()) {
     67     context3d_->GetCommandBufferProxy()->SetMemoryAllocationChangedCallback(
     68         CommandBufferProxyImpl::MemoryAllocationChangedCallback());
     69   }
     70   lost_context_callback_proxy_.reset();
     71 }
     72 
     73 
     74 CommandBufferProxyImpl* ContextProviderCommandBuffer::GetCommandBufferProxy() {
     75   return context3d_->GetCommandBufferProxy();
     76 }
     77 
     78 WebGraphicsContext3DCommandBufferImpl*
     79 ContextProviderCommandBuffer::WebContext3D() {
     80   DCHECK(context3d_);
     81   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
     82   DCHECK(context_thread_checker_.CalledOnValidThread());
     83 
     84   return context3d_.get();
     85 }
     86 
     87 bool ContextProviderCommandBuffer::BindToCurrentThread() {
     88   // This is called on the thread the context will be used.
     89   DCHECK(context_thread_checker_.CalledOnValidThread());
     90 
     91   if (lost_context_callback_proxy_)
     92     return true;
     93 
     94   if (!context3d_->InitializeOnCurrentThread())
     95     return false;
     96 
     97   InitializeCapabilities();
     98 
     99   std::string unique_context_name =
    100       base::StringPrintf("%s-%p", debug_name_.c_str(), context3d_.get());
    101   context3d_->pushGroupMarkerEXT(unique_context_name.c_str());
    102 
    103   lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
    104   context3d_->GetCommandBufferProxy()->SetMemoryAllocationChangedCallback(
    105       base::Bind(&ContextProviderCommandBuffer::OnMemoryAllocationChanged,
    106                  base::Unretained(this)));
    107   return true;
    108 }
    109 
    110 gpu::gles2::GLES2Interface* ContextProviderCommandBuffer::ContextGL() {
    111   DCHECK(context3d_);
    112   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    113   DCHECK(context_thread_checker_.CalledOnValidThread());
    114 
    115   return context3d_->GetImplementation();
    116 }
    117 
    118 gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() {
    119   return context3d_->GetContextSupport();
    120 }
    121 
    122 class GrContext* ContextProviderCommandBuffer::GrContext() {
    123   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    124   DCHECK(context_thread_checker_.CalledOnValidThread());
    125 
    126   if (gr_context_)
    127     return gr_context_->get();
    128 
    129   gr_context_.reset(
    130       new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
    131   return gr_context_->get();
    132 }
    133 
    134 cc::ContextProvider::Capabilities
    135 ContextProviderCommandBuffer::ContextCapabilities() {
    136   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    137   DCHECK(context_thread_checker_.CalledOnValidThread());
    138 
    139   return capabilities_;
    140 }
    141 
    142 bool ContextProviderCommandBuffer::IsContextLost() {
    143   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    144   DCHECK(context_thread_checker_.CalledOnValidThread());
    145 
    146   return context3d_->isContextLost();
    147 }
    148 
    149 void ContextProviderCommandBuffer::VerifyContexts() {
    150   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    151   DCHECK(context_thread_checker_.CalledOnValidThread());
    152 
    153   if (context3d_->isContextLost())
    154     OnLostContext();
    155 }
    156 
    157 void ContextProviderCommandBuffer::DeleteCachedResources() {
    158   DCHECK(context_thread_checker_.CalledOnValidThread());
    159 
    160   if (gr_context_)
    161     gr_context_->FreeGpuResources();
    162 }
    163 
    164 void ContextProviderCommandBuffer::OnLostContext() {
    165   DCHECK(context_thread_checker_.CalledOnValidThread());
    166   {
    167     base::AutoLock lock(main_thread_lock_);
    168     if (destroyed_)
    169       return;
    170     destroyed_ = true;
    171   }
    172   if (!lost_context_callback_.is_null())
    173     base::ResetAndReturn(&lost_context_callback_).Run();
    174   if (gr_context_)
    175     gr_context_->OnLostContext();
    176 }
    177 
    178 void ContextProviderCommandBuffer::OnMemoryAllocationChanged(
    179     const gpu::MemoryAllocation& allocation) {
    180   DCHECK(context_thread_checker_.CalledOnValidThread());
    181 
    182   if (memory_policy_changed_callback_.is_null())
    183     return;
    184 
    185   memory_policy_changed_callback_.Run(cc::ManagedMemoryPolicy(allocation));
    186 }
    187 
    188 void ContextProviderCommandBuffer::InitializeCapabilities() {
    189   Capabilities caps;
    190   caps.gpu = context3d_->GetImplementation()->capabilities();
    191 
    192   size_t mapped_memory_limit = context3d_->GetMappedMemoryLimit();
    193   caps.max_transfer_buffer_usage_bytes =
    194       mapped_memory_limit == WebGraphicsContext3DCommandBufferImpl::kNoLimit
    195       ? std::numeric_limits<size_t>::max() : mapped_memory_limit;
    196 
    197   capabilities_ = caps;
    198 }
    199 
    200 bool ContextProviderCommandBuffer::DestroyedOnMainThread() {
    201   DCHECK(main_thread_checker_.CalledOnValidThread());
    202 
    203   base::AutoLock lock(main_thread_lock_);
    204   return destroyed_;
    205 }
    206 
    207 void ContextProviderCommandBuffer::SetLostContextCallback(
    208     const LostContextCallback& lost_context_callback) {
    209   DCHECK(context_thread_checker_.CalledOnValidThread());
    210   DCHECK(lost_context_callback_.is_null() ||
    211          lost_context_callback.is_null());
    212   lost_context_callback_ = lost_context_callback;
    213 }
    214 
    215 void ContextProviderCommandBuffer::SetMemoryPolicyChangedCallback(
    216     const MemoryPolicyChangedCallback& memory_policy_changed_callback) {
    217   DCHECK(context_thread_checker_.CalledOnValidThread());
    218   DCHECK(memory_policy_changed_callback_.is_null() ||
    219          memory_policy_changed_callback.is_null());
    220   memory_policy_changed_callback_ = memory_policy_changed_callback;
    221 }
    222 
    223 }  // namespace content
    224