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       leak_on_destroy_(false),
     54       destroyed_(false) {
     55   DCHECK(main_thread_checker_.CalledOnValidThread());
     56   DCHECK(context3d_);
     57   context_thread_checker_.DetachFromThread();
     58 }
     59 
     60 ContextProviderCommandBuffer::~ContextProviderCommandBuffer() {
     61   DCHECK(main_thread_checker_.CalledOnValidThread() ||
     62          context_thread_checker_.CalledOnValidThread());
     63 
     64   base::AutoLock lock(main_thread_lock_);
     65 
     66   // Destroy references to the context3d_ before leaking it.
     67   if (context3d_->GetCommandBufferProxy()) {
     68     context3d_->GetCommandBufferProxy()->SetMemoryAllocationChangedCallback(
     69         CommandBufferProxyImpl::MemoryAllocationChangedCallback());
     70   }
     71   lost_context_callback_proxy_.reset();
     72 
     73   if (leak_on_destroy_) {
     74     WebGraphicsContext3DCommandBufferImpl* context3d ALLOW_UNUSED =
     75         context3d_.release();
     76     webkit::gpu::GrContextForWebGraphicsContext3D* gr_context ALLOW_UNUSED =
     77         gr_context_.release();
     78   }
     79 }
     80 
     81 bool ContextProviderCommandBuffer::BindToCurrentThread() {
     82   // This is called on the thread the context will be used.
     83   DCHECK(context_thread_checker_.CalledOnValidThread());
     84 
     85   if (lost_context_callback_proxy_)
     86     return true;
     87 
     88   if (!context3d_->makeContextCurrent())
     89     return false;
     90 
     91   InitializeCapabilities();
     92 
     93   std::string unique_context_name =
     94       base::StringPrintf("%s-%p", debug_name_.c_str(), context3d_.get());
     95   context3d_->pushGroupMarkerEXT(unique_context_name.c_str());
     96 
     97   lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
     98   context3d_->GetCommandBufferProxy()->SetMemoryAllocationChangedCallback(
     99       base::Bind(&ContextProviderCommandBuffer::OnMemoryAllocationChanged,
    100                  base::Unretained(this)));
    101   return true;
    102 }
    103 
    104 WebGraphicsContext3DCommandBufferImpl*
    105 ContextProviderCommandBuffer::Context3d() {
    106   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    107   DCHECK(context_thread_checker_.CalledOnValidThread());
    108 
    109   return context3d_.get();
    110 }
    111 
    112 gpu::gles2::GLES2Interface* ContextProviderCommandBuffer::ContextGL() {
    113   DCHECK(context3d_);
    114   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    115   DCHECK(context_thread_checker_.CalledOnValidThread());
    116 
    117   return context3d_->GetImplementation();
    118 }
    119 
    120 gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() {
    121   return context3d_->GetContextSupport();
    122 }
    123 
    124 class GrContext* ContextProviderCommandBuffer::GrContext() {
    125   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    126   DCHECK(context_thread_checker_.CalledOnValidThread());
    127 
    128   if (gr_context_)
    129     return gr_context_->get();
    130 
    131   gr_context_.reset(
    132       new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
    133   return gr_context_->get();
    134 }
    135 
    136 void ContextProviderCommandBuffer::MakeGrContextCurrent() {
    137   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    138   DCHECK(context_thread_checker_.CalledOnValidThread());
    139   DCHECK(gr_context_);
    140 
    141   context3d_->makeContextCurrent();
    142 }
    143 
    144 cc::ContextProvider::Capabilities
    145 ContextProviderCommandBuffer::ContextCapabilities() {
    146   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    147   DCHECK(context_thread_checker_.CalledOnValidThread());
    148 
    149   return capabilities_;
    150 }
    151 
    152 bool ContextProviderCommandBuffer::IsContextLost() {
    153   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    154   DCHECK(context_thread_checker_.CalledOnValidThread());
    155 
    156   return context3d_->isContextLost();
    157 }
    158 
    159 void ContextProviderCommandBuffer::VerifyContexts() {
    160   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    161   DCHECK(context_thread_checker_.CalledOnValidThread());
    162 
    163   if (context3d_->isContextLost())
    164     OnLostContext();
    165 }
    166 
    167 void ContextProviderCommandBuffer::OnLostContext() {
    168   DCHECK(context_thread_checker_.CalledOnValidThread());
    169   {
    170     base::AutoLock lock(main_thread_lock_);
    171     if (destroyed_)
    172       return;
    173     destroyed_ = true;
    174   }
    175   if (!lost_context_callback_.is_null())
    176     base::ResetAndReturn(&lost_context_callback_).Run();
    177 }
    178 
    179 void ContextProviderCommandBuffer::OnMemoryAllocationChanged(
    180     const gpu::MemoryAllocation& allocation) {
    181   DCHECK(context_thread_checker_.CalledOnValidThread());
    182 
    183   if (gr_context_) {
    184     bool nonzero_allocation = !!allocation.bytes_limit_when_visible;
    185     gr_context_->SetMemoryLimit(nonzero_allocation);
    186   }
    187 
    188   if (memory_policy_changed_callback_.is_null())
    189     return;
    190 
    191   memory_policy_changed_callback_.Run(cc::ManagedMemoryPolicy(allocation));
    192 }
    193 
    194 void ContextProviderCommandBuffer::InitializeCapabilities() {
    195   Capabilities caps(context3d_->GetImplementation()->capabilities());
    196 
    197   size_t mapped_memory_limit = context3d_->GetMappedMemoryLimit();
    198   caps.max_transfer_buffer_usage_bytes =
    199       mapped_memory_limit == WebGraphicsContext3DCommandBufferImpl::kNoLimit
    200       ? std::numeric_limits<size_t>::max() : mapped_memory_limit;
    201 
    202   capabilities_ = caps;
    203 }
    204 
    205 
    206 bool ContextProviderCommandBuffer::DestroyedOnMainThread() {
    207   DCHECK(main_thread_checker_.CalledOnValidThread());
    208 
    209   base::AutoLock lock(main_thread_lock_);
    210   return destroyed_;
    211 }
    212 
    213 void ContextProviderCommandBuffer::SetLostContextCallback(
    214     const LostContextCallback& lost_context_callback) {
    215   DCHECK(context_thread_checker_.CalledOnValidThread());
    216   DCHECK(lost_context_callback_.is_null() ||
    217          lost_context_callback.is_null());
    218   lost_context_callback_ = lost_context_callback;
    219 }
    220 
    221 void ContextProviderCommandBuffer::SetMemoryPolicyChangedCallback(
    222     const MemoryPolicyChangedCallback& memory_policy_changed_callback) {
    223   DCHECK(context_thread_checker_.CalledOnValidThread());
    224   DCHECK(memory_policy_changed_callback_.is_null() ||
    225          memory_policy_changed_callback.is_null());
    226   memory_policy_changed_callback_ = memory_policy_changed_callback;
    227 }
    228 
    229 }  // namespace content
    230