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