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