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"
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"
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
50 framebuffer_completeness_cache_(NULL
),
52 framebuffer_completeness_cache_(framebuffer_completeness_cache
),
54 subscription_ref_set_(subscription_ref_set
),
55 pending_valuebuffer_state_(pending_valuebuffer_state
),
57 base::CommandLine::InitializedForCurrentProcess()
58 ? base::CommandLine::ForCurrentProcess()->HasSwitch(
59 switches::kEnforceGLMinimums
)
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),
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
) {
88 glGetIntegerv(pname
, &value
);
93 ContextGroup::ContextType
ContextGroup::GetContextType(
94 unsigned webgl_version
) {
95 switch (webgl_version
) {
97 return CONTEXT_TYPE_OTHER
;
99 return CONTEXT_TYPE_WEBGL1
;
101 return CONTEXT_TYPE_WEBGL2
;
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 "
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.";
124 // If we've already initialized the group just add the context.
125 if (HaveContexts()) {
126 decoders_
.push_back(base::AsWeakPtr
<GLES2Decoder
>(decoder
));
130 if (!feature_info_
->Initialize(disallowed_features
)) {
131 LOG(ERROR
) << "ContextGroup::Initialize failed because FeatureInfo "
132 << "initialization failed.";
136 transfer_buffer_manager_
->Initialize();
138 const GLint kMinRenderbufferSize
= 512; // GL says 1 pixel!
139 GLint max_renderbuffer_size
= 0;
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
<< ").";
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
);
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.";
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.";
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.";
227 if (feature_info_
->workarounds().max_texture_size
) {
228 max_texture_size
= std::min(
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(),
244 max_cube_map_texture_size
,
245 max_rectangle_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_
) ||
256 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
, kMinVertexTextureImageUnits
,
257 &max_vertex_texture_image_units_
)) {
258 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
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_
);
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_
) ||
285 kMinVertexUniformVectors
, &max_vertex_uniform_vectors_
)) {
286 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
287 << "uniforms or varyings supported.";
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_
,
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_
,
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.";
322 decoders_
.push_back(base::AsWeakPtr
<GLES2Decoder
>(decoder
));
328 bool IsNull(const base::WeakPtr
<gles2::GLES2Decoder
>& decoder
) {
329 return !decoder
.get();
332 template <typename T
>
333 class WeakPtrEquals
{
335 explicit WeakPtrEquals(T
* t
) : t_(t
) {}
337 bool operator()(const base::WeakPtr
<T
>& t
) {
338 return t
.get() == t_
;
345 } // namespace anonymous
347 bool ContextGroup::HaveContexts() {
348 decoders_
.erase(std::remove_if(decoders_
.begin(), decoders_
.end(), IsNull
),
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
)),
357 // If we still have contexts do nothing.
358 if (HaveContexts()) {
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 {
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();
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
) {
432 if (enforce_gl_minimums_
) {
433 value
= std::min(min_required
, value
);
436 return value
>= min_required
;
439 bool ContextGroup::CheckGLFeatureU(GLint min_required
, uint32
* v
) {
441 if (enforce_gl_minimums_
) {
442 value
= std::min(min_required
, value
);
445 return value
>= min_required
;
448 bool ContextGroup::QueryGLFeature(
449 GLenum pname
, GLint min_required
, GLint
* v
) {
451 glGetIntegerv(pname
, &value
);
453 return CheckGLFeature(min_required
, v
);
456 bool ContextGroup::QueryGLFeatureU(
457 GLenum pname
, GLint min_required
, uint32
* v
) {
459 GetIntegerv(pname
, &value
);
460 bool result
= CheckGLFeatureU(min_required
, &value
);
465 bool ContextGroup::GetBufferServiceId(
466 GLuint client_id
, GLuint
* service_id
) const {
467 Buffer
* buffer
= buffer_manager_
->GetBuffer(client_id
);
470 *service_id
= buffer
->service_id();