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/program_manager.h"
20 #include "gpu/command_buffer/service/renderbuffer_manager.h"
21 #include "gpu/command_buffer/service/shader_manager.h"
22 #include "gpu/command_buffer/service/texture_manager.h"
23 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
24 #include "gpu/command_buffer/service/valuebuffer_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 const scoped_refptr
<SubscriptionRefSet
>& subscription_ref_set
,
36 const scoped_refptr
<ValueStateMap
>& pending_valuebuffer_state
,
37 bool bind_generates_resource
)
38 : mailbox_manager_(mailbox_manager
),
39 memory_tracker_(memory_tracker
),
40 shader_translator_cache_(shader_translator_cache
),
41 subscription_ref_set_(subscription_ref_set
),
42 pending_valuebuffer_state_(pending_valuebuffer_state
),
43 enforce_gl_minimums_(base::CommandLine::ForCurrentProcess()->HasSwitch(
44 switches::kEnforceGLMinimums
)),
45 bind_generates_resource_(bind_generates_resource
),
46 max_vertex_attribs_(0u),
47 max_texture_units_(0u),
48 max_texture_image_units_(0u),
49 max_vertex_texture_image_units_(0u),
50 max_fragment_uniform_vectors_(0u),
51 max_varying_vectors_(0u),
52 max_vertex_uniform_vectors_(0u),
53 max_color_attachments_(1u),
54 max_draw_buffers_(1u),
56 feature_info_(feature_info
),
57 draw_buffer_(GL_BACK
) {
59 if (!mailbox_manager_
.get())
60 mailbox_manager_
= new MailboxManagerImpl
;
61 if (!subscription_ref_set_
.get())
62 subscription_ref_set_
= new SubscriptionRefSet();
63 if (!pending_valuebuffer_state_
.get())
64 pending_valuebuffer_state_
= new ValueStateMap();
65 if (!feature_info
.get())
66 feature_info_
= new FeatureInfo
;
67 TransferBufferManager
* manager
= new TransferBufferManager();
68 transfer_buffer_manager_
.reset(manager
);
69 manager
->Initialize();
73 static void GetIntegerv(GLenum pname
, uint32
* var
) {
75 glGetIntegerv(pname
, &value
);
79 bool ContextGroup::Initialize(
80 GLES2Decoder
* decoder
,
81 const DisallowedFeatures
& disallowed_features
) {
82 // If we've already initialized the group just add the context.
84 decoders_
.push_back(base::AsWeakPtr
<GLES2Decoder
>(decoder
));
88 if (!feature_info_
->Initialize(disallowed_features
)) {
89 LOG(ERROR
) << "ContextGroup::Initialize failed because FeatureInfo "
90 << "initialization failed.";
94 const GLint kMinRenderbufferSize
= 512; // GL says 1 pixel!
95 GLint max_renderbuffer_size
= 0;
97 GL_MAX_RENDERBUFFER_SIZE
, kMinRenderbufferSize
,
98 &max_renderbuffer_size
)) {
99 LOG(ERROR
) << "ContextGroup::Initialize failed because maximum "
100 << "renderbuffer size too small (" << max_renderbuffer_size
101 << ", should be " << kMinRenderbufferSize
<< ").";
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 buffer_manager_
.reset(
126 new BufferManager(memory_tracker_
.get(), feature_info_
.get()));
127 framebuffer_manager_
.reset(
128 new FramebufferManager(max_draw_buffers_
, max_color_attachments_
));
129 renderbuffer_manager_
.reset(new RenderbufferManager(
130 memory_tracker_
.get(), max_renderbuffer_size
, max_samples
,
131 feature_info_
.get()));
132 shader_manager_
.reset(new ShaderManager());
133 valuebuffer_manager_
.reset(
134 new ValuebufferManager(subscription_ref_set_
.get(),
135 pending_valuebuffer_state_
.get()));
137 // Lookup GL things we need to know.
138 const GLint kGLES2RequiredMinimumVertexAttribs
= 8u;
139 if (!QueryGLFeatureU(
140 GL_MAX_VERTEX_ATTRIBS
, kGLES2RequiredMinimumVertexAttribs
,
141 &max_vertex_attribs_
)) {
142 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
143 << "vertex attributes supported.";
147 const GLuint kGLES2RequiredMinimumTextureUnits
= 8u;
148 if (!QueryGLFeatureU(
149 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
, kGLES2RequiredMinimumTextureUnits
,
150 &max_texture_units_
)) {
151 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
152 << "texture units supported.";
156 GLint max_texture_size
= 0;
157 GLint max_cube_map_texture_size
= 0;
158 GLint max_rectangle_texture_size
= 0;
159 const GLint kMinTextureSize
= 2048; // GL actually says 64!?!?
160 const GLint kMinCubeMapSize
= 256; // GL actually says 16!?!?
161 const GLint kMinRectangleTextureSize
= 64;
162 if (!QueryGLFeature(GL_MAX_TEXTURE_SIZE
, kMinTextureSize
,
163 &max_texture_size
) ||
164 !QueryGLFeature(GL_MAX_CUBE_MAP_TEXTURE_SIZE
, kMinCubeMapSize
,
165 &max_cube_map_texture_size
)) {
166 LOG(ERROR
) << "ContextGroup::Initialize failed because maximum "
167 << " texture size is too small.";
170 if (feature_info_
->feature_flags().arb_texture_rectangle
) {
171 if (!QueryGLFeature(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB
,
172 kMinRectangleTextureSize
,
173 &max_rectangle_texture_size
)) {
174 LOG(ERROR
) << "ContextGroup::Initialize failed because maximum "
175 << "rectangle texture size is too small.";
180 if (feature_info_
->workarounds().max_texture_size
) {
181 max_texture_size
= std::min(
183 feature_info_
->workarounds().max_texture_size
);
184 max_rectangle_texture_size
= std::min(
185 max_rectangle_texture_size
,
186 feature_info_
->workarounds().max_texture_size
);
188 if (feature_info_
->workarounds().max_cube_map_texture_size
) {
189 max_cube_map_texture_size
= std::min(
190 max_cube_map_texture_size
,
191 feature_info_
->workarounds().max_cube_map_texture_size
);
194 texture_manager_
.reset(new TextureManager(memory_tracker_
.get(),
197 max_cube_map_texture_size
,
198 max_rectangle_texture_size
,
199 bind_generates_resource_
));
200 texture_manager_
->set_framebuffer_manager(framebuffer_manager_
.get());
202 const GLint kMinTextureImageUnits
= 8;
203 const GLint kMinVertexTextureImageUnits
= 0;
204 if (!QueryGLFeatureU(
205 GL_MAX_TEXTURE_IMAGE_UNITS
, kMinTextureImageUnits
,
206 &max_texture_image_units_
) ||
208 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
, kMinVertexTextureImageUnits
,
209 &max_vertex_texture_image_units_
)) {
210 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
215 if (feature_info_
->gl_version_info().BehavesLikeGLES()) {
216 GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS
,
217 &max_fragment_uniform_vectors_
);
218 GetIntegerv(GL_MAX_VARYING_VECTORS
, &max_varying_vectors_
);
219 GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS
, &max_vertex_uniform_vectors_
);
222 GL_MAX_FRAGMENT_UNIFORM_COMPONENTS
, &max_fragment_uniform_vectors_
);
223 max_fragment_uniform_vectors_
/= 4;
224 GetIntegerv(GL_MAX_VARYING_FLOATS
, &max_varying_vectors_
);
225 max_varying_vectors_
/= 4;
226 GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS
, &max_vertex_uniform_vectors_
);
227 max_vertex_uniform_vectors_
/= 4;
230 const GLint kMinFragmentUniformVectors
= 16;
231 const GLint kMinVaryingVectors
= 8;
232 const GLint kMinVertexUniformVectors
= 128;
233 if (!CheckGLFeatureU(
234 kMinFragmentUniformVectors
, &max_fragment_uniform_vectors_
) ||
235 !CheckGLFeatureU(kMinVaryingVectors
, &max_varying_vectors_
) ||
237 kMinVertexUniformVectors
, &max_vertex_uniform_vectors_
)) {
238 LOG(ERROR
) << "ContextGroup::Initialize failed because too few "
239 << "uniforms or varyings supported.";
243 // Some shaders in Skia need more than the min available vertex and
244 // fragment shader uniform vectors in case of OSMesa GL Implementation
245 if (feature_info_
->workarounds().max_fragment_uniform_vectors
) {
246 max_fragment_uniform_vectors_
= std::min(
247 max_fragment_uniform_vectors_
,
249 feature_info_
->workarounds().max_fragment_uniform_vectors
));
251 if (feature_info_
->workarounds().max_varying_vectors
) {
252 max_varying_vectors_
= std::min(
253 max_varying_vectors_
,
254 static_cast<uint32
>(feature_info_
->workarounds().max_varying_vectors
));
256 if (feature_info_
->workarounds().max_vertex_uniform_vectors
) {
257 max_vertex_uniform_vectors_
=
258 std::min(max_vertex_uniform_vectors_
,
260 feature_info_
->workarounds().max_vertex_uniform_vectors
));
263 program_manager_
.reset(new ProgramManager(
264 program_cache_
, max_varying_vectors_
));
266 if (!texture_manager_
->Initialize()) {
267 LOG(ERROR
) << "Context::Group::Initialize failed because texture manager "
268 << "failed to initialize.";
272 decoders_
.push_back(base::AsWeakPtr
<GLES2Decoder
>(decoder
));
278 bool IsNull(const base::WeakPtr
<gles2::GLES2Decoder
>& decoder
) {
279 return !decoder
.get();
282 template <typename T
>
283 class WeakPtrEquals
{
285 explicit WeakPtrEquals(T
* t
) : t_(t
) {}
287 bool operator()(const base::WeakPtr
<T
>& t
) {
288 return t
.get() == t_
;
295 } // namespace anonymous
297 bool ContextGroup::HaveContexts() {
298 decoders_
.erase(std::remove_if(decoders_
.begin(), decoders_
.end(), IsNull
),
300 return !decoders_
.empty();
303 void ContextGroup::Destroy(GLES2Decoder
* decoder
, bool have_context
) {
304 decoders_
.erase(std::remove_if(decoders_
.begin(), decoders_
.end(),
305 WeakPtrEquals
<gles2::GLES2Decoder
>(decoder
)),
307 // If we still have contexts do nothing.
308 if (HaveContexts()) {
312 if (buffer_manager_
!= NULL
) {
313 buffer_manager_
->Destroy(have_context
);
314 buffer_manager_
.reset();
317 if (framebuffer_manager_
!= NULL
) {
318 framebuffer_manager_
->Destroy(have_context
);
319 if (texture_manager_
)
320 texture_manager_
->set_framebuffer_manager(NULL
);
321 framebuffer_manager_
.reset();
324 if (renderbuffer_manager_
!= NULL
) {
325 renderbuffer_manager_
->Destroy(have_context
);
326 renderbuffer_manager_
.reset();
329 if (texture_manager_
!= NULL
) {
330 texture_manager_
->Destroy(have_context
);
331 texture_manager_
.reset();
334 if (program_manager_
!= NULL
) {
335 program_manager_
->Destroy(have_context
);
336 program_manager_
.reset();
339 if (shader_manager_
!= NULL
) {
340 shader_manager_
->Destroy(have_context
);
341 shader_manager_
.reset();
344 if (valuebuffer_manager_
!= NULL
) {
345 valuebuffer_manager_
->Destroy();
346 valuebuffer_manager_
.reset();
349 memory_tracker_
= NULL
;
352 uint32
ContextGroup::GetMemRepresented() const {
354 if (buffer_manager_
.get())
355 total
+= buffer_manager_
->mem_represented();
356 if (renderbuffer_manager_
.get())
357 total
+= renderbuffer_manager_
->mem_represented();
358 if (texture_manager_
.get())
359 total
+= texture_manager_
->mem_represented();
363 void ContextGroup::LoseContexts(GLenum reset_status
) {
364 for (size_t ii
= 0; ii
< decoders_
.size(); ++ii
) {
365 if (decoders_
[ii
].get()) {
366 decoders_
[ii
]->LoseContext(reset_status
);
371 ContextGroup::~ContextGroup() {
372 CHECK(!HaveContexts());
375 bool ContextGroup::CheckGLFeature(GLint min_required
, GLint
* v
) {
377 if (enforce_gl_minimums_
) {
378 value
= std::min(min_required
, value
);
381 return value
>= min_required
;
384 bool ContextGroup::CheckGLFeatureU(GLint min_required
, uint32
* v
) {
386 if (enforce_gl_minimums_
) {
387 value
= std::min(min_required
, value
);
390 return value
>= min_required
;
393 bool ContextGroup::QueryGLFeature(
394 GLenum pname
, GLint min_required
, GLint
* v
) {
396 glGetIntegerv(pname
, &value
);
398 return CheckGLFeature(min_required
, v
);
401 bool ContextGroup::QueryGLFeatureU(
402 GLenum pname
, GLint min_required
, uint32
* v
) {
404 GetIntegerv(pname
, &value
);
405 bool result
= CheckGLFeatureU(min_required
, &value
);
410 bool ContextGroup::GetBufferServiceId(
411 GLuint client_id
, GLuint
* service_id
) const {
412 Buffer
* buffer
= buffer_manager_
->GetBuffer(client_id
);
415 *service_id
= buffer
->service_id();