Elim cr-checkbox
[chromium-blink-merge.git] / gpu / command_buffer / service / context_group.cc
blob24a54b13e2aa8c7b4ca20ff3658c25360fe37f04
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/service/context_group.h"
7 #include <algorithm>
8 #include <string>
10 #include "base/command_line.h"
11 #include "gpu/command_buffer/common/value_state.h"
12 #include "gpu/command_buffer/service/buffer_manager.h"
13 #include "gpu/command_buffer/service/framebuffer_manager.h"
14 #include "gpu/command_buffer/service/gpu_switches.h"
15 #include "gpu/command_buffer/service/mailbox_manager_impl.h"
16 #include "gpu/command_buffer/service/path_manager.h"
17 #include "gpu/command_buffer/service/program_manager.h"
18 #include "gpu/command_buffer/service/renderbuffer_manager.h"
19 #include "gpu/command_buffer/service/shader_manager.h"
20 #include "gpu/command_buffer/service/texture_manager.h"
21 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
22 #include "gpu/command_buffer/service/valuebuffer_manager.h"
23 #include "ui/gl/gl_bindings.h"
24 #include "ui/gl/gl_version_info.h"
26 namespace gpu {
27 namespace gles2 {
29 ContextGroup::ContextGroup(
30 const scoped_refptr<MailboxManager>& mailbox_manager,
31 const scoped_refptr<MemoryTracker>& memory_tracker,
32 const scoped_refptr<ShaderTranslatorCache>& shader_translator_cache,
33 const scoped_refptr<FramebufferCompletenessCache>&
34 framebuffer_completeness_cache,
35 const scoped_refptr<FeatureInfo>& feature_info,
36 const scoped_refptr<SubscriptionRefSet>& subscription_ref_set,
37 const scoped_refptr<ValueStateMap>& pending_valuebuffer_state,
38 bool bind_generates_resource)
39 : context_type_(CONTEXT_TYPE_UNDEFINED),
40 mailbox_manager_(mailbox_manager),
41 memory_tracker_(memory_tracker),
42 shader_translator_cache_(shader_translator_cache),
43 #if defined(OS_MACOSX)
44 // Framebuffer completeness is not cacheable on OS X because of dynamic
45 // graphics switching.
46 // http://crbug.com/180876
47 // TODO(tobiasjs): determine whether GPU switching is possible
48 // programmatically, rather than just hardcoding this behaviour
49 // for OS X.
50 framebuffer_completeness_cache_(NULL),
51 #else
52 framebuffer_completeness_cache_(framebuffer_completeness_cache),
53 #endif
54 subscription_ref_set_(subscription_ref_set),
55 pending_valuebuffer_state_(pending_valuebuffer_state),
56 enforce_gl_minimums_(
57 base::CommandLine::InitializedForCurrentProcess()
58 ? base::CommandLine::ForCurrentProcess()->HasSwitch(
59 switches::kEnforceGLMinimums)
60 : false),
61 bind_generates_resource_(bind_generates_resource),
62 max_vertex_attribs_(0u),
63 max_texture_units_(0u),
64 max_texture_image_units_(0u),
65 max_vertex_texture_image_units_(0u),
66 max_fragment_uniform_vectors_(0u),
67 max_varying_vectors_(0u),
68 max_vertex_uniform_vectors_(0u),
69 max_color_attachments_(1u),
70 max_draw_buffers_(1u),
71 program_cache_(NULL),
72 feature_info_(feature_info) {
74 if (!mailbox_manager_.get())
75 mailbox_manager_ = new MailboxManagerImpl;
76 if (!subscription_ref_set_.get())
77 subscription_ref_set_ = new SubscriptionRefSet();
78 if (!pending_valuebuffer_state_.get())
79 pending_valuebuffer_state_ = new ValueStateMap();
80 if (!feature_info.get())
81 feature_info_ = new FeatureInfo;
82 transfer_buffer_manager_ = new TransferBufferManager(memory_tracker_.get());
86 static void GetIntegerv(GLenum pname, uint32* var) {
87 GLint value = 0;
88 glGetIntegerv(pname, &value);
89 *var = value;
92 // static
93 ContextGroup::ContextType ContextGroup::GetContextType(
94 unsigned webgl_version) {
95 switch (webgl_version) {
96 case 0:
97 return CONTEXT_TYPE_OTHER;
98 case 1:
99 return CONTEXT_TYPE_WEBGL1;
100 case 2:
101 return CONTEXT_TYPE_WEBGL2;
102 default:
103 return CONTEXT_TYPE_UNDEFINED;
107 bool ContextGroup::Initialize(
108 GLES2Decoder* decoder,
109 ContextGroup::ContextType context_type,
110 const DisallowedFeatures& disallowed_features) {
111 if (context_type == CONTEXT_TYPE_UNDEFINED) {
112 LOG(ERROR) << "ContextGroup::Initialize failed because of unknown "
113 << "context type.";
114 return false;
116 if (context_type_ == CONTEXT_TYPE_UNDEFINED) {
117 context_type_ = context_type;
118 } else if (context_type_ != context_type) {
119 LOG(ERROR) << "ContextGroup::Initialize failed because the type of "
120 << "the context does not fit with the group.";
121 return false;
124 // If we've already initialized the group just add the context.
125 if (HaveContexts()) {
126 decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
127 return true;
130 if (!feature_info_->Initialize(disallowed_features)) {
131 LOG(ERROR) << "ContextGroup::Initialize failed because FeatureInfo "
132 << "initialization failed.";
133 return false;
136 transfer_buffer_manager_->Initialize();
138 const GLint kMinRenderbufferSize = 512; // GL says 1 pixel!
139 GLint max_renderbuffer_size = 0;
140 if (!QueryGLFeature(
141 GL_MAX_RENDERBUFFER_SIZE, kMinRenderbufferSize,
142 &max_renderbuffer_size)) {
143 LOG(ERROR) << "ContextGroup::Initialize failed because maximum "
144 << "renderbuffer size too small (" << max_renderbuffer_size
145 << ", should be " << kMinRenderbufferSize << ").";
146 return false;
148 GLint max_samples = 0;
149 if (feature_info_->feature_flags().chromium_framebuffer_multisample ||
150 feature_info_->feature_flags().multisampled_render_to_texture) {
151 if (feature_info_->feature_flags(
152 ).use_img_for_multisampled_render_to_texture) {
153 glGetIntegerv(GL_MAX_SAMPLES_IMG, &max_samples);
154 } else {
155 glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
159 if (feature_info_->feature_flags().ext_draw_buffers) {
160 GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &max_color_attachments_);
161 if (max_color_attachments_ < 1)
162 max_color_attachments_ = 1;
163 GetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &max_draw_buffers_);
164 if (max_draw_buffers_ < 1)
165 max_draw_buffers_ = 1;
168 buffer_manager_.reset(
169 new BufferManager(memory_tracker_.get(), feature_info_.get()));
170 framebuffer_manager_.reset(
171 new FramebufferManager(max_draw_buffers_, max_color_attachments_,
172 context_type, framebuffer_completeness_cache_));
173 renderbuffer_manager_.reset(new RenderbufferManager(
174 memory_tracker_.get(), max_renderbuffer_size, max_samples,
175 feature_info_.get()));
176 shader_manager_.reset(new ShaderManager());
177 valuebuffer_manager_.reset(
178 new ValuebufferManager(subscription_ref_set_.get(),
179 pending_valuebuffer_state_.get()));
181 // Lookup GL things we need to know.
182 const GLint kGLES2RequiredMinimumVertexAttribs = 8u;
183 if (!QueryGLFeatureU(
184 GL_MAX_VERTEX_ATTRIBS, kGLES2RequiredMinimumVertexAttribs,
185 &max_vertex_attribs_)) {
186 LOG(ERROR) << "ContextGroup::Initialize failed because too few "
187 << "vertex attributes supported.";
188 return false;
191 const GLuint kGLES2RequiredMinimumTextureUnits = 8u;
192 if (!QueryGLFeatureU(
193 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, kGLES2RequiredMinimumTextureUnits,
194 &max_texture_units_)) {
195 LOG(ERROR) << "ContextGroup::Initialize failed because too few "
196 << "texture units supported.";
197 return false;
200 GLint max_texture_size = 0;
201 GLint max_cube_map_texture_size = 0;
202 GLint max_rectangle_texture_size = 0;
203 GLint max_3d_texture_size = 0;
205 const GLint kMinTextureSize = 2048; // GL actually says 64!?!?
206 // TODO(zmo): In ES3, max cubemap size is required to be at least 2048.
207 const GLint kMinCubeMapSize = 256; // GL actually says 16!?!?
208 const GLint kMinRectangleTextureSize = 64;
209 const GLint kMin3DTextureSize = 256;
211 if (!QueryGLFeature(GL_MAX_TEXTURE_SIZE, kMinTextureSize,
212 &max_texture_size) ||
213 !QueryGLFeature(GL_MAX_CUBE_MAP_TEXTURE_SIZE, kMinCubeMapSize,
214 &max_cube_map_texture_size) ||
215 (feature_info_->gl_version_info().IsES3Capable() &&
216 !QueryGLFeature(GL_MAX_3D_TEXTURE_SIZE, kMin3DTextureSize,
217 &max_3d_texture_size)) ||
218 (feature_info_->feature_flags().arb_texture_rectangle &&
219 !QueryGLFeature(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB,
220 kMinRectangleTextureSize,
221 &max_rectangle_texture_size))) {
222 LOG(ERROR) << "ContextGroup::Initialize failed because maximum "
223 << "texture size is too small.";
224 return false;
227 if (feature_info_->workarounds().max_texture_size) {
228 max_texture_size = std::min(
229 max_texture_size,
230 feature_info_->workarounds().max_texture_size);
231 max_rectangle_texture_size = std::min(
232 max_rectangle_texture_size,
233 feature_info_->workarounds().max_texture_size);
235 if (feature_info_->workarounds().max_cube_map_texture_size) {
236 max_cube_map_texture_size = std::min(
237 max_cube_map_texture_size,
238 feature_info_->workarounds().max_cube_map_texture_size);
241 texture_manager_.reset(new TextureManager(memory_tracker_.get(),
242 feature_info_.get(),
243 max_texture_size,
244 max_cube_map_texture_size,
245 max_rectangle_texture_size,
246 max_3d_texture_size,
247 bind_generates_resource_));
248 texture_manager_->set_framebuffer_manager(framebuffer_manager_.get());
250 const GLint kMinTextureImageUnits = 8;
251 const GLint kMinVertexTextureImageUnits = 0;
252 if (!QueryGLFeatureU(
253 GL_MAX_TEXTURE_IMAGE_UNITS, kMinTextureImageUnits,
254 &max_texture_image_units_) ||
255 !QueryGLFeatureU(
256 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, kMinVertexTextureImageUnits,
257 &max_vertex_texture_image_units_)) {
258 LOG(ERROR) << "ContextGroup::Initialize failed because too few "
259 << "texture units.";
260 return false;
263 if (feature_info_->gl_version_info().BehavesLikeGLES()) {
264 GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS,
265 &max_fragment_uniform_vectors_);
266 GetIntegerv(GL_MAX_VARYING_VECTORS, &max_varying_vectors_);
267 GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &max_vertex_uniform_vectors_);
268 } else {
269 GetIntegerv(
270 GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max_fragment_uniform_vectors_);
271 max_fragment_uniform_vectors_ /= 4;
272 GetIntegerv(GL_MAX_VARYING_FLOATS, &max_varying_vectors_);
273 max_varying_vectors_ /= 4;
274 GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &max_vertex_uniform_vectors_);
275 max_vertex_uniform_vectors_ /= 4;
278 const GLint kMinFragmentUniformVectors = 16;
279 const GLint kMinVaryingVectors = 8;
280 const GLint kMinVertexUniformVectors = 128;
281 if (!CheckGLFeatureU(
282 kMinFragmentUniformVectors, &max_fragment_uniform_vectors_) ||
283 !CheckGLFeatureU(kMinVaryingVectors, &max_varying_vectors_) ||
284 !CheckGLFeatureU(
285 kMinVertexUniformVectors, &max_vertex_uniform_vectors_)) {
286 LOG(ERROR) << "ContextGroup::Initialize failed because too few "
287 << "uniforms or varyings supported.";
288 return false;
291 // Some shaders in Skia need more than the min available vertex and
292 // fragment shader uniform vectors in case of OSMesa GL Implementation
293 if (feature_info_->workarounds().max_fragment_uniform_vectors) {
294 max_fragment_uniform_vectors_ = std::min(
295 max_fragment_uniform_vectors_,
296 static_cast<uint32>(
297 feature_info_->workarounds().max_fragment_uniform_vectors));
299 if (feature_info_->workarounds().max_varying_vectors) {
300 max_varying_vectors_ = std::min(
301 max_varying_vectors_,
302 static_cast<uint32>(feature_info_->workarounds().max_varying_vectors));
304 if (feature_info_->workarounds().max_vertex_uniform_vectors) {
305 max_vertex_uniform_vectors_ =
306 std::min(max_vertex_uniform_vectors_,
307 static_cast<uint32>(
308 feature_info_->workarounds().max_vertex_uniform_vectors));
311 path_manager_.reset(new PathManager());
313 program_manager_.reset(new ProgramManager(
314 program_cache_, max_varying_vectors_));
316 if (!texture_manager_->Initialize()) {
317 LOG(ERROR) << "Context::Group::Initialize failed because texture manager "
318 << "failed to initialize.";
319 return false;
322 decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
323 return true;
326 namespace {
328 bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) {
329 return !decoder.get();
332 template <typename T>
333 class WeakPtrEquals {
334 public:
335 explicit WeakPtrEquals(T* t) : t_(t) {}
337 bool operator()(const base::WeakPtr<T>& t) {
338 return t.get() == t_;
341 private:
342 T* const t_;
345 } // namespace anonymous
347 bool ContextGroup::HaveContexts() {
348 decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), IsNull),
349 decoders_.end());
350 return !decoders_.empty();
353 void ContextGroup::Destroy(GLES2Decoder* decoder, bool have_context) {
354 decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(),
355 WeakPtrEquals<gles2::GLES2Decoder>(decoder)),
356 decoders_.end());
357 // If we still have contexts do nothing.
358 if (HaveContexts()) {
359 return;
362 if (buffer_manager_ != NULL) {
363 buffer_manager_->Destroy(have_context);
364 buffer_manager_.reset();
367 if (framebuffer_manager_ != NULL) {
368 framebuffer_manager_->Destroy(have_context);
369 if (texture_manager_)
370 texture_manager_->set_framebuffer_manager(NULL);
371 framebuffer_manager_.reset();
374 if (renderbuffer_manager_ != NULL) {
375 renderbuffer_manager_->Destroy(have_context);
376 renderbuffer_manager_.reset();
379 if (texture_manager_ != NULL) {
380 texture_manager_->Destroy(have_context);
381 texture_manager_.reset();
384 if (path_manager_ != NULL) {
385 path_manager_->Destroy(have_context);
386 path_manager_.reset();
389 if (program_manager_ != NULL) {
390 program_manager_->Destroy(have_context);
391 program_manager_.reset();
394 if (shader_manager_ != NULL) {
395 shader_manager_->Destroy(have_context);
396 shader_manager_.reset();
399 if (valuebuffer_manager_ != NULL) {
400 valuebuffer_manager_->Destroy();
401 valuebuffer_manager_.reset();
404 memory_tracker_ = NULL;
407 uint32 ContextGroup::GetMemRepresented() const {
408 uint32 total = 0;
409 if (buffer_manager_.get())
410 total += buffer_manager_->mem_represented();
411 if (renderbuffer_manager_.get())
412 total += renderbuffer_manager_->mem_represented();
413 if (texture_manager_.get())
414 total += texture_manager_->mem_represented();
415 return total;
418 void ContextGroup::LoseContexts(error::ContextLostReason reason) {
419 for (size_t ii = 0; ii < decoders_.size(); ++ii) {
420 if (decoders_[ii].get()) {
421 decoders_[ii]->MarkContextLost(reason);
426 ContextGroup::~ContextGroup() {
427 CHECK(!HaveContexts());
430 bool ContextGroup::CheckGLFeature(GLint min_required, GLint* v) {
431 GLint value = *v;
432 if (enforce_gl_minimums_) {
433 value = std::min(min_required, value);
435 *v = value;
436 return value >= min_required;
439 bool ContextGroup::CheckGLFeatureU(GLint min_required, uint32* v) {
440 GLint value = *v;
441 if (enforce_gl_minimums_) {
442 value = std::min(min_required, value);
444 *v = value;
445 return value >= min_required;
448 bool ContextGroup::QueryGLFeature(
449 GLenum pname, GLint min_required, GLint* v) {
450 GLint value = 0;
451 glGetIntegerv(pname, &value);
452 *v = value;
453 return CheckGLFeature(min_required, v);
456 bool ContextGroup::QueryGLFeatureU(
457 GLenum pname, GLint min_required, uint32* v) {
458 uint32 value = 0;
459 GetIntegerv(pname, &value);
460 bool result = CheckGLFeatureU(min_required, &value);
461 *v = value;
462 return result;
465 bool ContextGroup::GetBufferServiceId(
466 GLuint client_id, GLuint* service_id) const {
467 Buffer* buffer = buffer_manager_->GetBuffer(client_id);
468 if (!buffer)
469 return false;
470 *service_id = buffer->service_id();
471 return true;
474 } // namespace gles2
475 } // namespace gpu