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 "base/strings/string_util.h"
12 #include "base/sys_info.h"
13 #include "gpu/command_buffer/service/buffer_manager.h"
14 #include "gpu/command_buffer/service/framebuffer_manager.h"
15 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
16 #include "gpu/command_buffer/service/gpu_switches.h"
17 #include "gpu/command_buffer/service/mailbox_manager_impl.h"
18 #include "gpu/command_buffer/service/memory_tracking.h"
19 #include "gpu/command_buffer/service/path_manager.h"
20 #include "gpu/command_buffer/service/program_manager.h"
21 #include "gpu/command_buffer/service/renderbuffer_manager.h"
22 #include "gpu/command_buffer/service/shader_manager.h"
23 #include "gpu/command_buffer/service/texture_manager.h"
24 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
25 #include "gpu/command_buffer/service/valuebuffer_manager.h"
26 #include "ui/gl/gl_implementation.h"
31 ContextGroup::ContextGroup(
32 const scoped_refptr
<MailboxManager
>& mailbox_manager
,
33 const scoped_refptr
<MemoryTracker
>& memory_tracker
,
34 const scoped_refptr
<ShaderTranslatorCache
>& shader_translator_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 subscription_ref_set_(subscription_ref_set
),
44 pending_valuebuffer_state_(pending_valuebuffer_state
),
45 enforce_gl_minimums_(base::CommandLine::ForCurrentProcess()->HasSwitch(
46 switches::kEnforceGLMinimums
)),
47 bind_generates_resource_(bind_generates_resource
),
48 max_vertex_attribs_(0u),
49 max_texture_units_(0u),
50 max_texture_image_units_(0u),
51 max_vertex_texture_image_units_(0u),
52 max_fragment_uniform_vectors_(0u),
53 max_varying_vectors_(0u),
54 max_vertex_uniform_vectors_(0u),
55 max_color_attachments_(1u),
56 max_draw_buffers_(1u),
58 feature_info_(feature_info
),
59 draw_buffer_(GL_BACK
) {
61 if (!mailbox_manager_
.get())
62 mailbox_manager_
= new MailboxManagerImpl
;
63 if (!subscription_ref_set_
.get())
64 subscription_ref_set_
= new SubscriptionRefSet();
65 if (!pending_valuebuffer_state_
.get())
66 pending_valuebuffer_state_
= new ValueStateMap();
67 if (!feature_info
.get())
68 feature_info_
= new FeatureInfo
;
69 TransferBufferManager
* manager
= new TransferBufferManager();
70 transfer_buffer_manager_
= manager
;
71 manager
->Initialize();
75 static void GetIntegerv(GLenum pname
, uint32
* var
) {
77 glGetIntegerv(pname
, &value
);
82 ContextGroup::ContextType
ContextGroup::GetContextType(
83 unsigned webgl_version
) {
84 switch (webgl_version
) {
86 return CONTEXT_TYPE_OTHER
;
88 return CONTEXT_TYPE_WEBGL1
;
90 return CONTEXT_TYPE_WEBGL2
;
92 return CONTEXT_TYPE_UNDEFINED
;
96 bool ContextGroup::Initialize(
97 GLES2Decoder
* decoder
,
98 ContextGroup::ContextType context_type
,
99 const DisallowedFeatures
& disallowed_features
) {
100 if (context_type
== CONTEXT_TYPE_UNDEFINED
) {
101 LOG(ERROR
) << "ContextGroup::Initialize failed because of unknown "
105 if (context_type_
== CONTEXT_TYPE_UNDEFINED
) {
106 context_type_
= context_type
;
107 } else if (context_type_
!= context_type
) {
108 LOG(ERROR
) << "ContextGroup::Initialize failed because the type of "
109 << "the context does not fit with the group.";
113 // If we've already initialized the group just add the context.
114 if (HaveContexts()) {
115 decoders_
.push_back(base::AsWeakPtr
<GLES2Decoder
>(decoder
));
119 if (!feature_info_
->Initialize(disallowed_features
)) {
120 LOG(ERROR
) << "ContextGroup::Initialize failed because FeatureInfo "
121 << "initialization failed.";
125 const GLint kMinRenderbufferSize
= 512; // GL says 1 pixel!
126 GLint max_renderbuffer_size
= 0;
128 GL_MAX_RENDERBUFFER_SIZE
, kMinRenderbufferSize
,
129 &max_renderbuffer_size
)) {
130 LOG(ERROR
) << "ContextGroup::Initialize failed because maximum "
131 << "renderbuffer size too small (" << max_renderbuffer_size
132 << ", should be " << kMinRenderbufferSize
<< ").";
135 GLint max_samples
= 0;
136 if (feature_info_
->feature_flags().chromium_framebuffer_multisample
||
137 feature_info_
->feature_flags().multisampled_render_to_texture
) {
138 if (feature_info_
->feature_flags(
139 ).use_img_for_multisampled_render_to_texture
) {
140 glGetIntegerv(GL_MAX_SAMPLES_IMG
, &max_samples
);
142 glGetIntegerv(GL_MAX_SAMPLES
, &max_samples
);
146 if (feature_info_
->feature_flags().ext_draw_buffers
) {
147 GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT
, &max_color_attachments_
);
148 if (max_color_attachments_
< 1)
149 max_color_attachments_
= 1;
150 GetIntegerv(GL_MAX_DRAW_BUFFERS_ARB
, &max_draw_buffers_
);
151 if (max_draw_buffers_
< 1)
152 max_draw_buffers_
= 1;
153 draw_buffer_
= GL_BACK
;
156 buffer_manager_
.reset(
157 new BufferManager(memory_tracker_
.get(), feature_info_
.get()));
158 framebuffer_manager_
.reset(new FramebufferManager(
159 max_draw_buffers_
, max_color_attachments_
, context_type
));
160 renderbuffer_manager_
.reset(new RenderbufferManager(
161 memory_tracker_
.get(), max_renderbuffer_size
, max_samples
,
162 feature_info_
.get()));
163 shader_manager_
.reset(new ShaderManager());
164 valuebuffer_manager_
.reset(
165 new ValuebufferManager(subscription_ref_set_
.get(),
166 pending_valuebuffer_state_
.get()));
168 // Lookup GL things we need to know.
169 const GLint kGLES2RequiredMinimumVertexAttribs
= 8u;
170 if (!QueryGLFeatureU(
171 GL_MAX_VERTEX_ATTRIBS
, kGLES2RequiredMinimumVertexAttribs
,
172 &max_vertex_attribs_
)) {
173 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
174 << "vertex attributes supported.";
178 const GLuint kGLES2RequiredMinimumTextureUnits
= 8u;
179 if (!QueryGLFeatureU(
180 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
, kGLES2RequiredMinimumTextureUnits
,
181 &max_texture_units_
)) {
182 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
183 << "texture units supported.";
187 GLint max_texture_size
= 0;
188 GLint max_cube_map_texture_size
= 0;
189 GLint max_rectangle_texture_size
= 0;
190 GLint max_3d_texture_size
= 0;
192 const GLint kMinTextureSize
= 2048; // GL actually says 64!?!?
193 // TODO(zmo): In ES3, max cubemap size is required to be at least 2048.
194 const GLint kMinCubeMapSize
= 256; // GL actually says 16!?!?
195 const GLint kMinRectangleTextureSize
= 64;
196 const GLint kMin3DTextureSize
= 256;
198 if (!QueryGLFeature(GL_MAX_TEXTURE_SIZE
, kMinTextureSize
,
199 &max_texture_size
) ||
200 !QueryGLFeature(GL_MAX_CUBE_MAP_TEXTURE_SIZE
, kMinCubeMapSize
,
201 &max_cube_map_texture_size
) ||
202 (feature_info_
->gl_version_info().IsES3Capable() &&
203 !QueryGLFeature(GL_MAX_3D_TEXTURE_SIZE
, kMin3DTextureSize
,
204 &max_3d_texture_size
)) ||
205 (feature_info_
->feature_flags().arb_texture_rectangle
&&
206 !QueryGLFeature(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB
,
207 kMinRectangleTextureSize
,
208 &max_rectangle_texture_size
))) {
209 LOG(ERROR
) << "ContextGroup::Initialize failed because maximum "
210 << "texture size is too small.";
214 if (feature_info_
->workarounds().max_texture_size
) {
215 max_texture_size
= std::min(
217 feature_info_
->workarounds().max_texture_size
);
218 max_rectangle_texture_size
= std::min(
219 max_rectangle_texture_size
,
220 feature_info_
->workarounds().max_texture_size
);
222 if (feature_info_
->workarounds().max_cube_map_texture_size
) {
223 max_cube_map_texture_size
= std::min(
224 max_cube_map_texture_size
,
225 feature_info_
->workarounds().max_cube_map_texture_size
);
228 texture_manager_
.reset(new TextureManager(memory_tracker_
.get(),
231 max_cube_map_texture_size
,
232 max_rectangle_texture_size
,
234 bind_generates_resource_
));
235 texture_manager_
->set_framebuffer_manager(framebuffer_manager_
.get());
237 const GLint kMinTextureImageUnits
= 8;
238 const GLint kMinVertexTextureImageUnits
= 0;
239 if (!QueryGLFeatureU(
240 GL_MAX_TEXTURE_IMAGE_UNITS
, kMinTextureImageUnits
,
241 &max_texture_image_units_
) ||
243 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
, kMinVertexTextureImageUnits
,
244 &max_vertex_texture_image_units_
)) {
245 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
250 if (feature_info_
->gl_version_info().BehavesLikeGLES()) {
251 GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS
,
252 &max_fragment_uniform_vectors_
);
253 GetIntegerv(GL_MAX_VARYING_VECTORS
, &max_varying_vectors_
);
254 GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS
, &max_vertex_uniform_vectors_
);
257 GL_MAX_FRAGMENT_UNIFORM_COMPONENTS
, &max_fragment_uniform_vectors_
);
258 max_fragment_uniform_vectors_
/= 4;
259 GetIntegerv(GL_MAX_VARYING_FLOATS
, &max_varying_vectors_
);
260 max_varying_vectors_
/= 4;
261 GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS
, &max_vertex_uniform_vectors_
);
262 max_vertex_uniform_vectors_
/= 4;
265 const GLint kMinFragmentUniformVectors
= 16;
266 const GLint kMinVaryingVectors
= 8;
267 const GLint kMinVertexUniformVectors
= 128;
268 if (!CheckGLFeatureU(
269 kMinFragmentUniformVectors
, &max_fragment_uniform_vectors_
) ||
270 !CheckGLFeatureU(kMinVaryingVectors
, &max_varying_vectors_
) ||
272 kMinVertexUniformVectors
, &max_vertex_uniform_vectors_
)) {
273 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
274 << "uniforms or varyings supported.";
278 // Some shaders in Skia need more than the min available vertex and
279 // fragment shader uniform vectors in case of OSMesa GL Implementation
280 if (feature_info_
->workarounds().max_fragment_uniform_vectors
) {
281 max_fragment_uniform_vectors_
= std::min(
282 max_fragment_uniform_vectors_
,
284 feature_info_
->workarounds().max_fragment_uniform_vectors
));
286 if (feature_info_
->workarounds().max_varying_vectors
) {
287 max_varying_vectors_
= std::min(
288 max_varying_vectors_
,
289 static_cast<uint32
>(feature_info_
->workarounds().max_varying_vectors
));
291 if (feature_info_
->workarounds().max_vertex_uniform_vectors
) {
292 max_vertex_uniform_vectors_
=
293 std::min(max_vertex_uniform_vectors_
,
295 feature_info_
->workarounds().max_vertex_uniform_vectors
));
298 path_manager_
.reset(new PathManager());
300 program_manager_
.reset(new ProgramManager(
301 program_cache_
, max_varying_vectors_
));
303 if (!texture_manager_
->Initialize()) {
304 LOG(ERROR
) << "Context::Group::Initialize failed because texture manager "
305 << "failed to initialize.";
309 decoders_
.push_back(base::AsWeakPtr
<GLES2Decoder
>(decoder
));
315 bool IsNull(const base::WeakPtr
<gles2::GLES2Decoder
>& decoder
) {
316 return !decoder
.get();
319 template <typename T
>
320 class WeakPtrEquals
{
322 explicit WeakPtrEquals(T
* t
) : t_(t
) {}
324 bool operator()(const base::WeakPtr
<T
>& t
) {
325 return t
.get() == t_
;
332 } // namespace anonymous
334 bool ContextGroup::HaveContexts() {
335 decoders_
.erase(std::remove_if(decoders_
.begin(), decoders_
.end(), IsNull
),
337 return !decoders_
.empty();
340 void ContextGroup::Destroy(GLES2Decoder
* decoder
, bool have_context
) {
341 decoders_
.erase(std::remove_if(decoders_
.begin(), decoders_
.end(),
342 WeakPtrEquals
<gles2::GLES2Decoder
>(decoder
)),
344 // If we still have contexts do nothing.
345 if (HaveContexts()) {
349 if (buffer_manager_
!= NULL
) {
350 buffer_manager_
->Destroy(have_context
);
351 buffer_manager_
.reset();
354 if (framebuffer_manager_
!= NULL
) {
355 framebuffer_manager_
->Destroy(have_context
);
356 if (texture_manager_
)
357 texture_manager_
->set_framebuffer_manager(NULL
);
358 framebuffer_manager_
.reset();
361 if (renderbuffer_manager_
!= NULL
) {
362 renderbuffer_manager_
->Destroy(have_context
);
363 renderbuffer_manager_
.reset();
366 if (texture_manager_
!= NULL
) {
367 texture_manager_
->Destroy(have_context
);
368 texture_manager_
.reset();
371 if (path_manager_
!= NULL
) {
372 path_manager_
->Destroy(have_context
);
373 path_manager_
.reset();
376 if (program_manager_
!= NULL
) {
377 program_manager_
->Destroy(have_context
);
378 program_manager_
.reset();
381 if (shader_manager_
!= NULL
) {
382 shader_manager_
->Destroy(have_context
);
383 shader_manager_
.reset();
386 if (valuebuffer_manager_
!= NULL
) {
387 valuebuffer_manager_
->Destroy();
388 valuebuffer_manager_
.reset();
391 memory_tracker_
= NULL
;
394 uint32
ContextGroup::GetMemRepresented() const {
396 if (buffer_manager_
.get())
397 total
+= buffer_manager_
->mem_represented();
398 if (renderbuffer_manager_
.get())
399 total
+= renderbuffer_manager_
->mem_represented();
400 if (texture_manager_
.get())
401 total
+= texture_manager_
->mem_represented();
405 void ContextGroup::LoseContexts(error::ContextLostReason reason
) {
406 for (size_t ii
= 0; ii
< decoders_
.size(); ++ii
) {
407 if (decoders_
[ii
].get()) {
408 decoders_
[ii
]->MarkContextLost(reason
);
413 ContextGroup::~ContextGroup() {
414 CHECK(!HaveContexts());
417 bool ContextGroup::CheckGLFeature(GLint min_required
, GLint
* v
) {
419 if (enforce_gl_minimums_
) {
420 value
= std::min(min_required
, value
);
423 return value
>= min_required
;
426 bool ContextGroup::CheckGLFeatureU(GLint min_required
, uint32
* v
) {
428 if (enforce_gl_minimums_
) {
429 value
= std::min(min_required
, value
);
432 return value
>= min_required
;
435 bool ContextGroup::QueryGLFeature(
436 GLenum pname
, GLint min_required
, GLint
* v
) {
438 glGetIntegerv(pname
, &value
);
440 return CheckGLFeature(min_required
, v
);
443 bool ContextGroup::QueryGLFeatureU(
444 GLenum pname
, GLint min_required
, uint32
* v
) {
446 GetIntegerv(pname
, &value
);
447 bool result
= CheckGLFeatureU(min_required
, &value
);
452 bool ContextGroup::GetBufferServiceId(
453 GLuint client_id
, GLuint
* service_id
) const {
454 Buffer
* buffer
= buffer_manager_
->GetBuffer(client_id
);
457 *service_id
= buffer
->service_id();