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/common/id_allocator.h"
14 #include "gpu/command_buffer/service/buffer_manager.h"
15 #include "gpu/command_buffer/service/framebuffer_manager.h"
16 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
17 #include "gpu/command_buffer/service/gpu_switches.h"
18 #include "gpu/command_buffer/service/mailbox_manager.h"
19 #include "gpu/command_buffer/service/memory_tracking.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 "ui/gl/gl_implementation.h"
30 ContextGroup::ContextGroup(
31 const scoped_refptr
<MailboxManager
>& mailbox_manager
,
32 const scoped_refptr
<MemoryTracker
>& memory_tracker
,
33 const scoped_refptr
<ShaderTranslatorCache
>& shader_translator_cache
,
34 const scoped_refptr
<FeatureInfo
>& feature_info
,
35 bool bind_generates_resource
)
36 : mailbox_manager_(mailbox_manager
),
37 memory_tracker_(memory_tracker
),
38 shader_translator_cache_(shader_translator_cache
),
39 enforce_gl_minimums_(CommandLine::ForCurrentProcess()->HasSwitch(
40 switches::kEnforceGLMinimums
)),
41 bind_generates_resource_(bind_generates_resource
),
42 max_vertex_attribs_(0u),
43 max_texture_units_(0u),
44 max_texture_image_units_(0u),
45 max_vertex_texture_image_units_(0u),
46 max_fragment_uniform_vectors_(0u),
47 max_varying_vectors_(0u),
48 max_vertex_uniform_vectors_(0u),
49 max_color_attachments_(1u),
50 max_draw_buffers_(1u),
52 feature_info_(feature_info
),
53 draw_buffer_(GL_BACK
) {
55 if (!mailbox_manager_
.get())
56 mailbox_manager_
= new MailboxManager
;
57 if (!feature_info
.get())
58 feature_info_
= new FeatureInfo
;
59 TransferBufferManager
* manager
= new TransferBufferManager();
60 transfer_buffer_manager_
.reset(manager
);
61 manager
->Initialize();
64 id_namespaces_
[id_namespaces::kBuffers
].reset(new IdAllocator
);
65 id_namespaces_
[id_namespaces::kFramebuffers
].reset(new IdAllocator
);
66 id_namespaces_
[id_namespaces::kProgramsAndShaders
].reset(
67 new NonReusedIdAllocator
);
68 id_namespaces_
[id_namespaces::kRenderbuffers
].reset(new IdAllocator
);
69 id_namespaces_
[id_namespaces::kTextures
].reset(new IdAllocator
);
70 id_namespaces_
[id_namespaces::kQueries
].reset(new IdAllocator
);
71 id_namespaces_
[id_namespaces::kVertexArrays
].reset(new IdAllocator
);
74 static void GetIntegerv(GLenum pname
, uint32
* var
) {
76 glGetIntegerv(pname
, &value
);
80 bool ContextGroup::Initialize(
81 GLES2Decoder
* decoder
,
82 const DisallowedFeatures
& disallowed_features
) {
83 // If we've already initialized the group just add the context.
85 decoders_
.push_back(base::AsWeakPtr
<GLES2Decoder
>(decoder
));
89 if (!feature_info_
->Initialize(disallowed_features
)) {
90 LOG(ERROR
) << "ContextGroup::Initialize failed because FeatureInfo "
91 << "initialization failed.";
95 const GLint kMinRenderbufferSize
= 512; // GL says 1 pixel!
96 GLint max_renderbuffer_size
= 0;
98 GL_MAX_RENDERBUFFER_SIZE
, kMinRenderbufferSize
,
99 &max_renderbuffer_size
)) {
100 LOG(ERROR
) << "ContextGroup::Initialize failed because maximum "
101 << "renderbuffer size too small.";
104 GLint max_samples
= 0;
105 if (feature_info_
->feature_flags().chromium_framebuffer_multisample
||
106 feature_info_
->feature_flags().multisampled_render_to_texture
) {
107 if (feature_info_
->feature_flags(
108 ).use_img_for_multisampled_render_to_texture
) {
109 glGetIntegerv(GL_MAX_SAMPLES_IMG
, &max_samples
);
111 glGetIntegerv(GL_MAX_SAMPLES
, &max_samples
);
115 if (feature_info_
->feature_flags().ext_draw_buffers
) {
116 GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT
, &max_color_attachments_
);
117 if (max_color_attachments_
< 1)
118 max_color_attachments_
= 1;
119 GetIntegerv(GL_MAX_DRAW_BUFFERS_ARB
, &max_draw_buffers_
);
120 if (max_draw_buffers_
< 1)
121 max_draw_buffers_
= 1;
122 draw_buffer_
= GL_BACK
;
125 const bool depth24_supported
= feature_info_
->feature_flags().oes_depth24
;
127 buffer_manager_
.reset(
128 new BufferManager(memory_tracker_
.get(), feature_info_
.get()));
129 framebuffer_manager_
.reset(
130 new FramebufferManager(max_draw_buffers_
, max_color_attachments_
));
131 renderbuffer_manager_
.reset(new RenderbufferManager(
132 memory_tracker_
.get(), max_renderbuffer_size
, max_samples
,
134 shader_manager_
.reset(new ShaderManager());
136 // Lookup GL things we need to know.
137 const GLint kGLES2RequiredMinimumVertexAttribs
= 8u;
138 if (!QueryGLFeatureU(
139 GL_MAX_VERTEX_ATTRIBS
, kGLES2RequiredMinimumVertexAttribs
,
140 &max_vertex_attribs_
)) {
141 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
142 << "vertex attributes supported.";
146 const GLuint kGLES2RequiredMinimumTextureUnits
= 8u;
147 if (!QueryGLFeatureU(
148 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
, kGLES2RequiredMinimumTextureUnits
,
149 &max_texture_units_
)) {
150 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
151 << "texture units supported.";
155 GLint max_texture_size
= 0;
156 GLint max_cube_map_texture_size
= 0;
157 const GLint kMinTextureSize
= 2048; // GL actually says 64!?!?
158 const GLint kMinCubeMapSize
= 256; // GL actually says 16!?!?
160 GL_MAX_TEXTURE_SIZE
, kMinTextureSize
, &max_texture_size
) ||
162 GL_MAX_CUBE_MAP_TEXTURE_SIZE
, kMinCubeMapSize
,
163 &max_cube_map_texture_size
)) {
164 LOG(ERROR
) << "ContextGroup::Initialize failed because maximum texture size"
169 if (feature_info_
->workarounds().max_texture_size
) {
170 max_texture_size
= std::min(
171 max_texture_size
, feature_info_
->workarounds().max_texture_size
);
173 if (feature_info_
->workarounds().max_cube_map_texture_size
) {
174 max_cube_map_texture_size
= std::min(
175 max_cube_map_texture_size
,
176 feature_info_
->workarounds().max_cube_map_texture_size
);
179 texture_manager_
.reset(new TextureManager(memory_tracker_
.get(),
182 max_cube_map_texture_size
,
183 bind_generates_resource_
));
184 texture_manager_
->set_framebuffer_manager(framebuffer_manager_
.get());
186 const GLint kMinTextureImageUnits
= 8;
187 const GLint kMinVertexTextureImageUnits
= 0;
188 if (!QueryGLFeatureU(
189 GL_MAX_TEXTURE_IMAGE_UNITS
, kMinTextureImageUnits
,
190 &max_texture_image_units_
) ||
192 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
, kMinVertexTextureImageUnits
,
193 &max_vertex_texture_image_units_
)) {
194 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
199 if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2
) {
200 GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS
,
201 &max_fragment_uniform_vectors_
);
202 GetIntegerv(GL_MAX_VARYING_VECTORS
, &max_varying_vectors_
);
203 GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS
, &max_vertex_uniform_vectors_
);
206 GL_MAX_FRAGMENT_UNIFORM_COMPONENTS
, &max_fragment_uniform_vectors_
);
207 max_fragment_uniform_vectors_
/= 4;
208 GetIntegerv(GL_MAX_VARYING_FLOATS
, &max_varying_vectors_
);
209 max_varying_vectors_
/= 4;
210 GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS
, &max_vertex_uniform_vectors_
);
211 max_vertex_uniform_vectors_
/= 4;
214 const GLint kMinFragmentUniformVectors
= 16;
215 const GLint kMinVaryingVectors
= 8;
216 const GLint kMinVertexUniformVectors
= 128;
217 if (!CheckGLFeatureU(
218 kMinFragmentUniformVectors
, &max_fragment_uniform_vectors_
) ||
219 !CheckGLFeatureU(kMinVaryingVectors
, &max_varying_vectors_
) ||
221 kMinVertexUniformVectors
, &max_vertex_uniform_vectors_
)) {
222 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
223 << "uniforms or varyings supported.";
227 // Some shaders in Skia need more than the min available vertex and
228 // fragment shader uniform vectors in case of OSMesa GL Implementation
229 if (feature_info_
->workarounds().max_fragment_uniform_vectors
) {
230 max_fragment_uniform_vectors_
= std::min(
231 max_fragment_uniform_vectors_
,
233 feature_info_
->workarounds().max_fragment_uniform_vectors
));
235 if (feature_info_
->workarounds().max_varying_vectors
) {
236 max_varying_vectors_
= std::min(
237 max_varying_vectors_
,
238 static_cast<uint32
>(feature_info_
->workarounds().max_varying_vectors
));
240 if (feature_info_
->workarounds().max_vertex_uniform_vectors
) {
241 max_vertex_uniform_vectors_
=
242 std::min(max_vertex_uniform_vectors_
,
244 feature_info_
->workarounds().max_vertex_uniform_vectors
));
247 program_manager_
.reset(new ProgramManager(
248 program_cache_
, max_varying_vectors_
));
250 if (!texture_manager_
->Initialize()) {
251 LOG(ERROR
) << "Context::Group::Initialize failed because texture manager "
252 << "failed to initialize.";
256 decoders_
.push_back(base::AsWeakPtr
<GLES2Decoder
>(decoder
));
262 bool IsNull(const base::WeakPtr
<gles2::GLES2Decoder
>& decoder
) {
263 return !decoder
.get();
266 template <typename T
>
267 class WeakPtrEquals
{
269 explicit WeakPtrEquals(T
* t
) : t_(t
) {}
271 bool operator()(const base::WeakPtr
<T
>& t
) {
272 return t
.get() == t_
;
279 } // namespace anonymous
281 bool ContextGroup::HaveContexts() {
282 decoders_
.erase(std::remove_if(decoders_
.begin(), decoders_
.end(), IsNull
),
284 return !decoders_
.empty();
287 void ContextGroup::Destroy(GLES2Decoder
* decoder
, bool have_context
) {
288 decoders_
.erase(std::remove_if(decoders_
.begin(), decoders_
.end(),
289 WeakPtrEquals
<gles2::GLES2Decoder
>(decoder
)),
291 // If we still have contexts do nothing.
292 if (HaveContexts()) {
296 if (buffer_manager_
!= NULL
) {
297 buffer_manager_
->Destroy(have_context
);
298 buffer_manager_
.reset();
301 if (framebuffer_manager_
!= NULL
) {
302 framebuffer_manager_
->Destroy(have_context
);
303 if (texture_manager_
)
304 texture_manager_
->set_framebuffer_manager(NULL
);
305 framebuffer_manager_
.reset();
308 if (renderbuffer_manager_
!= NULL
) {
309 renderbuffer_manager_
->Destroy(have_context
);
310 renderbuffer_manager_
.reset();
313 if (texture_manager_
!= NULL
) {
314 texture_manager_
->Destroy(have_context
);
315 texture_manager_
.reset();
318 if (program_manager_
!= NULL
) {
319 program_manager_
->Destroy(have_context
);
320 program_manager_
.reset();
323 if (shader_manager_
!= NULL
) {
324 shader_manager_
->Destroy(have_context
);
325 shader_manager_
.reset();
328 memory_tracker_
= NULL
;
331 IdAllocatorInterface
* ContextGroup::GetIdAllocator(unsigned namespace_id
) {
332 if (namespace_id
>= arraysize(id_namespaces_
))
335 return id_namespaces_
[namespace_id
].get();
338 uint32
ContextGroup::GetMemRepresented() const {
340 if (buffer_manager_
.get())
341 total
+= buffer_manager_
->mem_represented();
342 if (renderbuffer_manager_
.get())
343 total
+= renderbuffer_manager_
->mem_represented();
344 if (texture_manager_
.get())
345 total
+= texture_manager_
->mem_represented();
349 void ContextGroup::LoseContexts(GLenum reset_status
) {
350 for (size_t ii
= 0; ii
< decoders_
.size(); ++ii
) {
351 if (decoders_
[ii
].get()) {
352 decoders_
[ii
]->LoseContext(reset_status
);
357 ContextGroup::~ContextGroup() {
358 CHECK(!HaveContexts());
361 bool ContextGroup::CheckGLFeature(GLint min_required
, GLint
* v
) {
363 if (enforce_gl_minimums_
) {
364 value
= std::min(min_required
, value
);
367 return value
>= min_required
;
370 bool ContextGroup::CheckGLFeatureU(GLint min_required
, uint32
* v
) {
372 if (enforce_gl_minimums_
) {
373 value
= std::min(min_required
, value
);
376 return value
>= min_required
;
379 bool ContextGroup::QueryGLFeature(
380 GLenum pname
, GLint min_required
, GLint
* v
) {
382 glGetIntegerv(pname
, &value
);
384 return CheckGLFeature(min_required
, v
);
387 bool ContextGroup::QueryGLFeatureU(
388 GLenum pname
, GLint min_required
, uint32
* v
) {
390 GetIntegerv(pname
, &value
);
391 bool result
= CheckGLFeatureU(min_required
, &value
);