• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
LostContextCallbackProxy(ContextProviderCommandBuffer * provider)21   explicit LostContextCallbackProxy(ContextProviderCommandBuffer* provider)
22       : provider_(provider) {
23     provider_->context3d_->setContextLostCallback(this);
24   }
25 
~LostContextCallbackProxy()26   virtual ~LostContextCallbackProxy() {
27     provider_->context3d_->setContextLostCallback(NULL);
28   }
29 
onContextLost()30   virtual void onContextLost() {
31     provider_->OnLostContext();
32   }
33 
34  private:
35   ContextProviderCommandBuffer* provider_;
36 };
37 
38 scoped_refptr<ContextProviderCommandBuffer>
Create(scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,const std::string & debug_name)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 
ContextProviderCommandBuffer(scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,const std::string & debug_name)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 
~ContextProviderCommandBuffer()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 
BindToCurrentThread()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*
Context3d()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 
ContextGL()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 
ContextSupport()120 gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() {
121   return context3d_->GetContextSupport();
122 }
123 
GrContext()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 
MakeGrContextCurrent()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
ContextCapabilities()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 
IsContextLost()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 
VerifyContexts()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 
OnLostContext()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 
OnMemoryAllocationChanged(const gpu::MemoryAllocation & allocation)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 
InitializeCapabilities()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 
DestroyedOnMainThread()206 bool ContextProviderCommandBuffer::DestroyedOnMainThread() {
207   DCHECK(main_thread_checker_.CalledOnValidThread());
208 
209   base::AutoLock lock(main_thread_lock_);
210   return destroyed_;
211 }
212 
SetLostContextCallback(const LostContextCallback & lost_context_callback)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 
SetMemoryPolicyChangedCallback(const MemoryPolicyChangedCallback & memory_policy_changed_callback)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