Home | History | Annotate | Download | only in gpu
      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 "webkit/common/gpu/context_provider_in_process.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback_helpers.h"
      9 #include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
     10 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
     11 
     12 namespace webkit {
     13 namespace gpu {
     14 
     15 class ContextProviderInProcess::LostContextCallbackProxy
     16     : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
     17  public:
     18   explicit LostContextCallbackProxy(ContextProviderInProcess* provider)
     19       : provider_(provider) {
     20     provider_->context3d_->setContextLostCallback(this);
     21   }
     22 
     23   virtual ~LostContextCallbackProxy() {
     24     provider_->context3d_->setContextLostCallback(NULL);
     25   }
     26 
     27   virtual void onContextLost() {
     28     provider_->OnLostContext();
     29   }
     30 
     31  private:
     32   ContextProviderInProcess* provider_;
     33 };
     34 
     35 class ContextProviderInProcess::MemoryAllocationCallbackProxy
     36     : public WebKit::WebGraphicsContext3D::
     37           WebGraphicsMemoryAllocationChangedCallbackCHROMIUM {
     38  public:
     39   explicit MemoryAllocationCallbackProxy(ContextProviderInProcess* provider)
     40       : provider_(provider) {
     41     provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(this);
     42   }
     43 
     44   virtual ~MemoryAllocationCallbackProxy() {
     45     provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(NULL);
     46   }
     47 
     48   virtual void onMemoryAllocationChanged(
     49       WebKit::WebGraphicsMemoryAllocation alloc) {
     50     provider_->OnMemoryAllocationChanged(!!alloc.gpuResourceSizeInBytes);
     51   }
     52 
     53  private:
     54   ContextProviderInProcess* provider_;
     55 };
     56 
     57 // static
     58 scoped_refptr<ContextProviderInProcess> ContextProviderInProcess::Create(
     59     const CreateCallback& create_callback) {
     60   scoped_refptr<ContextProviderInProcess> provider =
     61       new ContextProviderInProcess;
     62   if (!provider->InitializeOnMainThread(create_callback))
     63     return NULL;
     64   return provider;
     65 }
     66 
     67 static scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
     68 CreateOffscreenContext() {
     69   WebKit::WebGraphicsContext3D::Attributes attributes;
     70   attributes.depth = false;
     71   attributes.stencil = true;
     72   attributes.antialias = false;
     73   attributes.shareResources = true;
     74   attributes.noAutomaticFlushes = true;
     75 
     76   return WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
     77       attributes).Pass();
     78 }
     79 
     80 // static
     81 scoped_refptr<ContextProviderInProcess>
     82 ContextProviderInProcess::CreateOffscreen() {
     83   return Create(base::Bind(&CreateOffscreenContext));
     84 }
     85 
     86 ContextProviderInProcess::ContextProviderInProcess()
     87     : destroyed_(false) {
     88   DCHECK(main_thread_checker_.CalledOnValidThread());
     89   context_thread_checker_.DetachFromThread();
     90 }
     91 
     92 ContextProviderInProcess::~ContextProviderInProcess() {
     93   DCHECK(main_thread_checker_.CalledOnValidThread() ||
     94          context_thread_checker_.CalledOnValidThread());
     95 }
     96 
     97 bool ContextProviderInProcess::InitializeOnMainThread(
     98     const CreateCallback& create_callback) {
     99   DCHECK(!context3d_);
    100   DCHECK(main_thread_checker_.CalledOnValidThread());
    101   DCHECK(!create_callback.is_null());
    102 
    103   context3d_ = create_callback.Run();
    104   return context3d_;
    105 }
    106 
    107 bool ContextProviderInProcess::BindToCurrentThread() {
    108   DCHECK(context3d_);
    109 
    110   // This is called on the thread the context will be used.
    111   DCHECK(context_thread_checker_.CalledOnValidThread());
    112 
    113   if (lost_context_callback_proxy_)
    114     return true;
    115 
    116   if (!context3d_->makeContextCurrent())
    117     return false;
    118 
    119   lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
    120   return true;
    121 }
    122 
    123 WebKit::WebGraphicsContext3D* ContextProviderInProcess::Context3d() {
    124   DCHECK(context3d_);
    125   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    126   DCHECK(context_thread_checker_.CalledOnValidThread());
    127 
    128   return context3d_.get();
    129 }
    130 
    131 class GrContext* ContextProviderInProcess::GrContext() {
    132   DCHECK(context3d_);
    133   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    134   DCHECK(context_thread_checker_.CalledOnValidThread());
    135 
    136   if (gr_context_)
    137     return gr_context_->get();
    138 
    139   gr_context_.reset(
    140       new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
    141   memory_allocation_callback_proxy_.reset(
    142       new MemoryAllocationCallbackProxy(this));
    143   return gr_context_->get();
    144 }
    145 
    146 void ContextProviderInProcess::VerifyContexts() {
    147   DCHECK(context3d_);
    148   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
    149   DCHECK(context_thread_checker_.CalledOnValidThread());
    150 
    151   if (context3d_->isContextLost())
    152     OnLostContext();
    153 }
    154 
    155 void ContextProviderInProcess::OnLostContext() {
    156   DCHECK(context_thread_checker_.CalledOnValidThread());
    157   {
    158     base::AutoLock lock(destroyed_lock_);
    159     if (destroyed_)
    160       return;
    161     destroyed_ = true;
    162   }
    163   if (!lost_context_callback_.is_null())
    164     base::ResetAndReturn(&lost_context_callback_).Run();
    165 }
    166 
    167 bool ContextProviderInProcess::DestroyedOnMainThread() {
    168   DCHECK(main_thread_checker_.CalledOnValidThread());
    169 
    170   base::AutoLock lock(destroyed_lock_);
    171   return destroyed_;
    172 }
    173 
    174 void ContextProviderInProcess::SetLostContextCallback(
    175     const LostContextCallback& lost_context_callback) {
    176   DCHECK(context_thread_checker_.CalledOnValidThread());
    177   DCHECK(lost_context_callback_.is_null());
    178   lost_context_callback_ = lost_context_callback;
    179 }
    180 
    181 void ContextProviderInProcess::OnMemoryAllocationChanged(
    182     bool nonzero_allocation) {
    183   DCHECK(context_thread_checker_.CalledOnValidThread());
    184   if (gr_context_)
    185     gr_context_->SetMemoryLimit(nonzero_allocation);
    186 }
    187 
    188 }  // namespace gpu
    189 }  // namespace webkit
    190