Handle account removal correctly on all platforms.
[chromium-blink-merge.git] / gpu / command_buffer / client / gl_in_process_context.cc
blob1441d034e52936cf6c5553ebe94691febb5410bb
1 // Copyright (c) 2012 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 "gpu/command_buffer/client/gl_in_process_context.h"
7 #include <set>
8 #include <utility>
9 #include <vector>
11 #include <GLES2/gl2.h>
12 #ifndef GL_GLEXT_PROTOTYPES
13 #define GL_GLEXT_PROTOTYPES 1
14 #endif
15 #include <GLES2/gl2ext.h>
16 #include <GLES2/gl2extchromium.h>
18 #include "base/bind.h"
19 #include "base/bind_helpers.h"
20 #include "base/lazy_instance.h"
21 #include "base/logging.h"
22 #include "base/memory/scoped_ptr.h"
23 #include "base/memory/weak_ptr.h"
24 #include "base/message_loop/message_loop.h"
25 #include "gpu/command_buffer/client/gles2_implementation.h"
26 #include "gpu/command_buffer/client/transfer_buffer.h"
27 #include "gpu/command_buffer/common/command_buffer.h"
28 #include "gpu/command_buffer/common/constants.h"
29 #include "ui/gfx/size.h"
30 #include "ui/gl/gl_image.h"
32 #if defined(OS_ANDROID)
33 #include "ui/gl/android/surface_texture.h"
34 #endif
36 namespace gpu {
38 namespace {
40 const int32 kDefaultCommandBufferSize = 1024 * 1024;
41 const unsigned int kDefaultStartTransferBufferSize = 4 * 1024 * 1024;
42 const unsigned int kDefaultMinTransferBufferSize = 1 * 256 * 1024;
43 const unsigned int kDefaultMaxTransferBufferSize = 16 * 1024 * 1024;
45 class GLInProcessContextImpl
46 : public GLInProcessContext,
47 public base::SupportsWeakPtr<GLInProcessContextImpl> {
48 public:
49 explicit GLInProcessContextImpl(
50 const GLInProcessContextSharedMemoryLimits& mem_limits);
51 virtual ~GLInProcessContextImpl();
53 bool Initialize(
54 scoped_refptr<gfx::GLSurface> surface,
55 bool is_offscreen,
56 bool use_global_share_group,
57 GLInProcessContext* share_context,
58 gfx::AcceleratedWidget window,
59 const gfx::Size& size,
60 const gpu::gles2::ContextCreationAttribHelper& attribs,
61 gfx::GpuPreference gpu_preference,
62 const scoped_refptr<InProcessCommandBuffer::Service>& service);
64 // GLInProcessContext implementation:
65 virtual void SetContextLostCallback(const base::Closure& callback) OVERRIDE;
66 virtual gles2::GLES2Implementation* GetImplementation() OVERRIDE;
67 virtual size_t GetMappedMemoryLimit() OVERRIDE;
69 #if defined(OS_ANDROID)
70 virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
71 uint32 stream_id) OVERRIDE;
72 #endif
74 private:
75 void Destroy();
76 void OnContextLost();
77 void OnSignalSyncPoint(const base::Closure& callback);
79 scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_;
80 scoped_ptr<TransferBuffer> transfer_buffer_;
81 scoped_ptr<gles2::GLES2Implementation> gles2_implementation_;
82 scoped_ptr<InProcessCommandBuffer> command_buffer_;
84 const GLInProcessContextSharedMemoryLimits mem_limits_;
85 bool context_lost_;
86 base::Closure context_lost_callback_;
88 DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl);
91 base::LazyInstance<base::Lock> g_all_shared_contexts_lock =
92 LAZY_INSTANCE_INITIALIZER;
93 base::LazyInstance<std::set<GLInProcessContextImpl*> > g_all_shared_contexts =
94 LAZY_INSTANCE_INITIALIZER;
96 GLInProcessContextImpl::GLInProcessContextImpl(
97 const GLInProcessContextSharedMemoryLimits& mem_limits)
98 : mem_limits_(mem_limits), context_lost_(false) {
101 GLInProcessContextImpl::~GLInProcessContextImpl() {
103 base::AutoLock lock(g_all_shared_contexts_lock.Get());
104 g_all_shared_contexts.Get().erase(this);
106 Destroy();
109 gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() {
110 return gles2_implementation_.get();
113 size_t GLInProcessContextImpl::GetMappedMemoryLimit() {
114 return mem_limits_.mapped_memory_reclaim_limit;
117 void GLInProcessContextImpl::SetContextLostCallback(
118 const base::Closure& callback) {
119 context_lost_callback_ = callback;
122 void GLInProcessContextImpl::OnContextLost() {
123 context_lost_ = true;
124 if (!context_lost_callback_.is_null()) {
125 context_lost_callback_.Run();
129 bool GLInProcessContextImpl::Initialize(
130 scoped_refptr<gfx::GLSurface> surface,
131 bool is_offscreen,
132 bool use_global_share_group,
133 GLInProcessContext* share_context,
134 gfx::AcceleratedWidget window,
135 const gfx::Size& size,
136 const gles2::ContextCreationAttribHelper& attribs,
137 gfx::GpuPreference gpu_preference,
138 const scoped_refptr<InProcessCommandBuffer::Service>& service) {
139 DCHECK(!use_global_share_group || !share_context);
140 DCHECK(size.width() >= 0 && size.height() >= 0);
142 std::vector<int32> attrib_vector;
143 attribs.Serialize(&attrib_vector);
145 base::Closure wrapped_callback =
146 base::Bind(&GLInProcessContextImpl::OnContextLost, AsWeakPtr());
147 command_buffer_.reset(new InProcessCommandBuffer(service));
149 scoped_ptr<base::AutoLock> scoped_shared_context_lock;
150 scoped_refptr<gles2::ShareGroup> share_group;
151 InProcessCommandBuffer* share_command_buffer = NULL;
152 if (use_global_share_group) {
153 scoped_shared_context_lock.reset(
154 new base::AutoLock(g_all_shared_contexts_lock.Get()));
155 for (std::set<GLInProcessContextImpl*>::const_iterator it =
156 g_all_shared_contexts.Get().begin();
157 it != g_all_shared_contexts.Get().end();
158 it++) {
159 const GLInProcessContextImpl* context = *it;
160 if (!context->context_lost_) {
161 share_group = context->gles2_implementation_->share_group();
162 share_command_buffer = context->command_buffer_.get();
163 DCHECK(share_group.get());
164 DCHECK(share_command_buffer);
165 break;
168 } else if (share_context) {
169 GLInProcessContextImpl* impl =
170 static_cast<GLInProcessContextImpl*>(share_context);
171 share_group = impl->gles2_implementation_->share_group();
172 share_command_buffer = impl->command_buffer_.get();
173 DCHECK(share_group.get());
174 DCHECK(share_command_buffer);
177 if (!command_buffer_->Initialize(surface,
178 is_offscreen,
179 window,
180 size,
181 attrib_vector,
182 gpu_preference,
183 wrapped_callback,
184 share_command_buffer)) {
185 LOG(ERROR) << "Failed to initialize InProcessCommmandBuffer";
186 return false;
189 // Create the GLES2 helper, which writes the command buffer protocol.
190 gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get()));
191 if (!gles2_helper_->Initialize(mem_limits_.command_buffer_size)) {
192 LOG(ERROR) << "Failed to initialize GLES2CmdHelper";
193 Destroy();
194 return false;
197 // Create a transfer buffer.
198 transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get()));
200 // Check for consistency.
201 DCHECK(!attribs.bind_generates_resource);
202 bool bind_generates_resource = false;
204 // Create the object exposing the OpenGL API.
205 gles2_implementation_.reset(
206 new gles2::GLES2Implementation(gles2_helper_.get(),
207 share_group.get(),
208 transfer_buffer_.get(),
209 bind_generates_resource,
210 attribs.lose_context_when_out_of_memory,
211 command_buffer_.get()));
213 if (use_global_share_group) {
214 g_all_shared_contexts.Get().insert(this);
215 scoped_shared_context_lock.reset();
218 if (!gles2_implementation_->Initialize(
219 mem_limits_.start_transfer_buffer_size,
220 mem_limits_.min_transfer_buffer_size,
221 mem_limits_.max_transfer_buffer_size,
222 mem_limits_.mapped_memory_reclaim_limit)) {
223 return false;
226 return true;
229 void GLInProcessContextImpl::Destroy() {
230 if (gles2_implementation_) {
231 // First flush the context to ensure that any pending frees of resources
232 // are completed. Otherwise, if this context is part of a share group,
233 // those resources might leak. Also, any remaining side effects of commands
234 // issued on this context might not be visible to other contexts in the
235 // share group.
236 gles2_implementation_->Flush();
238 gles2_implementation_.reset();
241 transfer_buffer_.reset();
242 gles2_helper_.reset();
243 command_buffer_.reset();
246 #if defined(OS_ANDROID)
247 scoped_refptr<gfx::SurfaceTexture>
248 GLInProcessContextImpl::GetSurfaceTexture(uint32 stream_id) {
249 return command_buffer_->GetSurfaceTexture(stream_id);
251 #endif
253 } // anonymous namespace
255 GLInProcessContextSharedMemoryLimits::GLInProcessContextSharedMemoryLimits()
256 : command_buffer_size(kDefaultCommandBufferSize),
257 start_transfer_buffer_size(kDefaultStartTransferBufferSize),
258 min_transfer_buffer_size(kDefaultMinTransferBufferSize),
259 max_transfer_buffer_size(kDefaultMaxTransferBufferSize),
260 mapped_memory_reclaim_limit(gles2::GLES2Implementation::kNoLimit) {
263 // static
264 GLInProcessContext* GLInProcessContext::Create(
265 scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
266 scoped_refptr<gfx::GLSurface> surface,
267 bool is_offscreen,
268 gfx::AcceleratedWidget window,
269 const gfx::Size& size,
270 GLInProcessContext* share_context,
271 bool use_global_share_group,
272 const ::gpu::gles2::ContextCreationAttribHelper& attribs,
273 gfx::GpuPreference gpu_preference,
274 const GLInProcessContextSharedMemoryLimits& memory_limits) {
275 DCHECK(!use_global_share_group || !share_context);
276 if (surface.get()) {
277 DCHECK_EQ(surface->IsOffscreen(), is_offscreen);
278 DCHECK(surface->GetSize() == size);
279 DCHECK_EQ(gfx::kNullAcceleratedWidget, window);
282 scoped_ptr<GLInProcessContextImpl> context(
283 new GLInProcessContextImpl(memory_limits));
284 if (!context->Initialize(surface,
285 is_offscreen,
286 use_global_share_group,
287 share_context,
288 window,
289 size,
290 attribs,
291 gpu_preference,
292 service))
293 return NULL;
295 return context.release();
298 } // namespace gpu