Fix partial swap support
[chromium-blink-merge.git] / content / common / gpu / client / context_provider_command_buffer.cc
blob9d4a183dde4fda1a35112ce29355cd1b57c2c420
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.
5 #include "content/common/gpu/client/context_provider_command_buffer.h"
7 #include <set>
8 #include <vector>
10 #include "base/callback_helpers.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/stringprintf.h"
13 #include "cc/output/managed_memory_policy.h"
14 #include "gpu/command_buffer/client/gles2_implementation.h"
15 #include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
16 #include "webkit/common/gpu/managed_memory_policy_convert.h"
18 namespace content {
20 class ContextProviderCommandBuffer::LostContextCallbackProxy
21 : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
22 public:
23 explicit LostContextCallbackProxy(ContextProviderCommandBuffer* provider)
24 : provider_(provider) {
25 provider_->context3d_->setContextLostCallback(this);
28 virtual ~LostContextCallbackProxy() {
29 provider_->context3d_->setContextLostCallback(NULL);
32 virtual void onContextLost() {
33 provider_->OnLostContext();
36 private:
37 ContextProviderCommandBuffer* provider_;
40 class ContextProviderCommandBuffer::SwapBuffersCompleteCallbackProxy
41 : public WebKit::WebGraphicsContext3D::
42 WebGraphicsSwapBuffersCompleteCallbackCHROMIUM {
43 public:
44 explicit SwapBuffersCompleteCallbackProxy(
45 ContextProviderCommandBuffer* provider)
46 : provider_(provider) {
47 provider_->context3d_->setSwapBuffersCompleteCallbackCHROMIUM(this);
50 virtual ~SwapBuffersCompleteCallbackProxy() {
51 provider_->context3d_->setSwapBuffersCompleteCallbackCHROMIUM(NULL);
54 virtual void onSwapBuffersComplete() {
55 provider_->OnSwapBuffersComplete();
58 private:
59 ContextProviderCommandBuffer* provider_;
62 class ContextProviderCommandBuffer::MemoryAllocationCallbackProxy
63 : public WebKit::WebGraphicsContext3D::
64 WebGraphicsMemoryAllocationChangedCallbackCHROMIUM {
65 public:
66 explicit MemoryAllocationCallbackProxy(ContextProviderCommandBuffer* provider)
67 : provider_(provider) {
68 provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(this);
71 virtual ~MemoryAllocationCallbackProxy() {
72 provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(NULL);
75 virtual void onMemoryAllocationChanged(
76 WebKit::WebGraphicsMemoryAllocation allocation) {
77 provider_->OnMemoryAllocationChanged(allocation);
80 private:
81 ContextProviderCommandBuffer* provider_;
84 scoped_refptr<ContextProviderCommandBuffer>
85 ContextProviderCommandBuffer::Create(
86 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
87 const std::string& debug_name) {
88 if (!context3d)
89 return NULL;
91 return new ContextProviderCommandBuffer(context3d.Pass(), debug_name);
94 ContextProviderCommandBuffer::ContextProviderCommandBuffer(
95 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
96 const std::string& debug_name)
97 : context3d_(context3d.Pass()),
98 debug_name_(debug_name),
99 leak_on_destroy_(false),
100 destroyed_(false) {
101 DCHECK(main_thread_checker_.CalledOnValidThread());
102 DCHECK(context3d_);
103 context_thread_checker_.DetachFromThread();
106 ContextProviderCommandBuffer::~ContextProviderCommandBuffer() {
107 DCHECK(main_thread_checker_.CalledOnValidThread() ||
108 context_thread_checker_.CalledOnValidThread());
110 base::AutoLock lock(main_thread_lock_);
111 if (leak_on_destroy_) {
112 WebGraphicsContext3DCommandBufferImpl* context3d ALLOW_UNUSED =
113 context3d_.release();
114 webkit::gpu::GrContextForWebGraphicsContext3D* gr_context ALLOW_UNUSED =
115 gr_context_.release();
119 bool ContextProviderCommandBuffer::BindToCurrentThread() {
120 DCHECK(context3d_);
122 // This is called on the thread the context will be used.
123 DCHECK(context_thread_checker_.CalledOnValidThread());
125 if (lost_context_callback_proxy_)
126 return true;
128 if (!context3d_->makeContextCurrent())
129 return false;
131 InitializeCapabilities();
133 std::string unique_context_name =
134 base::StringPrintf("%s-%p", debug_name_.c_str(), context3d_.get());
135 context3d_->pushGroupMarkerEXT(unique_context_name.c_str());
137 lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
138 swap_buffers_complete_callback_proxy_.reset(
139 new SwapBuffersCompleteCallbackProxy(this));
140 memory_allocation_callback_proxy_.reset(
141 new MemoryAllocationCallbackProxy(this));
142 return true;
145 WebGraphicsContext3DCommandBufferImpl*
146 ContextProviderCommandBuffer::Context3d() {
147 DCHECK(context3d_);
148 DCHECK(lost_context_callback_proxy_); // Is bound to thread.
149 DCHECK(context_thread_checker_.CalledOnValidThread());
151 return context3d_.get();
154 class GrContext* ContextProviderCommandBuffer::GrContext() {
155 DCHECK(context3d_);
156 DCHECK(lost_context_callback_proxy_); // Is bound to thread.
157 DCHECK(context_thread_checker_.CalledOnValidThread());
159 if (gr_context_)
160 return gr_context_->get();
162 gr_context_.reset(
163 new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
164 return gr_context_->get();
167 cc::ContextProvider::Capabilities
168 ContextProviderCommandBuffer::ContextCapabilities() {
169 DCHECK(context3d_);
170 DCHECK(lost_context_callback_proxy_); // Is bound to thread.
171 DCHECK(context_thread_checker_.CalledOnValidThread());
173 return capabilities_;
176 void ContextProviderCommandBuffer::VerifyContexts() {
177 DCHECK(context3d_);
178 DCHECK(lost_context_callback_proxy_); // Is bound to thread.
179 DCHECK(context_thread_checker_.CalledOnValidThread());
181 if (context3d_->isContextLost())
182 OnLostContext();
185 void ContextProviderCommandBuffer::OnLostContext() {
186 DCHECK(context_thread_checker_.CalledOnValidThread());
188 base::AutoLock lock(main_thread_lock_);
189 if (destroyed_)
190 return;
191 destroyed_ = true;
193 if (!lost_context_callback_.is_null())
194 base::ResetAndReturn(&lost_context_callback_).Run();
197 void ContextProviderCommandBuffer::OnSwapBuffersComplete() {
198 DCHECK(context_thread_checker_.CalledOnValidThread());
199 if (!swap_buffers_complete_callback_.is_null())
200 swap_buffers_complete_callback_.Run();
203 void ContextProviderCommandBuffer::OnMemoryAllocationChanged(
204 const WebKit::WebGraphicsMemoryAllocation& allocation) {
205 DCHECK(context_thread_checker_.CalledOnValidThread());
207 if (gr_context_) {
208 bool nonzero_allocation = !!allocation.gpuResourceSizeInBytes;
209 gr_context_->SetMemoryLimit(nonzero_allocation);
212 if (memory_policy_changed_callback_.is_null())
213 return;
215 bool discard_backbuffer_when_not_visible;
216 cc::ManagedMemoryPolicy policy =
217 webkit::gpu::ManagedMemoryPolicyConvert::Convert(
218 allocation,
219 &discard_backbuffer_when_not_visible);
221 memory_policy_changed_callback_.Run(
222 policy, discard_backbuffer_when_not_visible);
225 void ContextProviderCommandBuffer::InitializeCapabilities() {
226 // The command buffer provides the following capabilities always.
227 // TODO(jamesr): This information is duplicated with
228 // gpu::gles2::FeatureInfo::AddFeatures().
229 Capabilities caps;
230 caps.bind_uniform_location = true;
231 caps.discard_backbuffer = true;
232 caps.set_visibility = true;
234 // TODO(jamesr): These are also added in
235 // gpu::gles2::GLES2Implementation::GetStringHelper() on the client side.
236 caps.map_sub = true;
237 caps.shallow_flush = true;
239 // The swapbuffers complete callback is always supported by multi-process
240 // command buffer implementations.
241 caps.swapbuffers_complete_callback = true;
243 std::string extensions = reinterpret_cast<const char*>(
244 context3d_->GetImplementation()->GetString(0x1F03 /* GL_EXTENSIONS */));
245 std::vector<std::string> extension_list;
246 base::SplitString(extensions, ' ', &extension_list);
247 std::set<std::string> extension_set(extension_list.begin(),
248 extension_list.end());
251 // caps.map_image depends on GL_CHROMIUM_map_image, which is set client-side
252 // based on the presence of GpuControl.
253 caps.map_image = extension_set.count("GL_CHROMIUM_map_image") > 0;
255 // caps.fast_npot_mo8_textures depends on
256 // workarounds_.enable_chromium_fast_npot_mo8_textures which controls
257 // GL_CHROMIUM_fast_NPOT_MO8_textures
258 caps.fast_npot_mo8_textures =
259 extension_set.count("GL_CHROMIUM_fast_NPOT_MO8_textures") > 0;
261 caps.egl_image_external =
262 extension_set.count("GL_OES_EGL_image_external") > 0;
264 caps.texture_format_bgra8888 =
265 extension_set.count("GL_EXT_texture_format_BGRA8888") > 0;
266 caps.texture_rectangle = extension_set.count("GL_ARB_texture_rectangle") > 0;
268 caps.post_sub_buffer = extension_set.count("GL_CHROMIUM_post_sub_buffer") > 0;
270 // TODO(jamesr): This is unconditionally true on mac, no need to test for it
271 // at runtime.
272 caps.iosurface = extension_set.count("GL_CHROMIUM_iosurface") > 0;
274 caps.texture_usage = extension_set.count("GL_ANGLE_texture_usage") > 0;
275 caps.texture_storage = extension_set.count("GL_EXT_texture_storage") > 0;
277 caps.discard_framebuffer =
278 extension_set.count("GL_EXT_discard_framebuffer") > 0;
279 size_t mapped_memory_limit = context3d_->GetMappedMemoryLimit();
280 caps.max_transfer_buffer_usage_bytes =
281 mapped_memory_limit == WebGraphicsContext3DCommandBufferImpl::kNoLimit
282 ? std::numeric_limits<size_t>::max() : mapped_memory_limit;
284 capabilities_ = caps;
288 bool ContextProviderCommandBuffer::DestroyedOnMainThread() {
289 DCHECK(main_thread_checker_.CalledOnValidThread());
291 base::AutoLock lock(main_thread_lock_);
292 return destroyed_;
295 void ContextProviderCommandBuffer::SetLostContextCallback(
296 const LostContextCallback& lost_context_callback) {
297 DCHECK(context_thread_checker_.CalledOnValidThread());
298 DCHECK(lost_context_callback_.is_null() ||
299 lost_context_callback.is_null());
300 lost_context_callback_ = lost_context_callback;
303 void ContextProviderCommandBuffer::SetSwapBuffersCompleteCallback(
304 const SwapBuffersCompleteCallback& swap_buffers_complete_callback) {
305 DCHECK(context_thread_checker_.CalledOnValidThread());
306 DCHECK(swap_buffers_complete_callback_.is_null() ||
307 swap_buffers_complete_callback.is_null());
308 swap_buffers_complete_callback_ = swap_buffers_complete_callback;
311 void ContextProviderCommandBuffer::SetMemoryPolicyChangedCallback(
312 const MemoryPolicyChangedCallback& memory_policy_changed_callback) {
313 DCHECK(context_thread_checker_.CalledOnValidThread());
314 DCHECK(memory_policy_changed_callback_.is_null() ||
315 memory_policy_changed_callback.is_null());
316 memory_policy_changed_callback_ = memory_policy_changed_callback;
319 } // namespace content