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.
4
5 #include "gpu/command_buffer/service/context_group.h"
6
7 #include <algorithm>
8 #include <string>
9
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"
26
27 namespace gpu {
28 namespace gles2 {
29
ContextGroup(const scoped_refptr<MailboxManager> & mailbox_manager,const scoped_refptr<MemoryTracker> & memory_tracker,const scoped_refptr<ShaderTranslatorCache> & shader_translator_cache,const scoped_refptr<FeatureInfo> & feature_info,bool bind_generates_resource)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),
51 program_cache_(NULL),
52 feature_info_(feature_info),
53 draw_buffer_(GL_BACK) {
54 {
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();
62 }
63
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);
72 }
73
GetIntegerv(GLenum pname,uint32 * var)74 static void GetIntegerv(GLenum pname, uint32* var) {
75 GLint value = 0;
76 glGetIntegerv(pname, &value);
77 *var = value;
78 }
79
Initialize(GLES2Decoder * decoder,const DisallowedFeatures & disallowed_features)80 bool ContextGroup::Initialize(
81 GLES2Decoder* decoder,
82 const DisallowedFeatures& disallowed_features) {
83 // If we've already initialized the group just add the context.
84 if (HaveContexts()) {
85 decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
86 return true;
87 }
88
89 if (!feature_info_->Initialize(disallowed_features)) {
90 LOG(ERROR) << "ContextGroup::Initialize failed because FeatureInfo "
91 << "initialization failed.";
92 return false;
93 }
94
95 const GLint kMinRenderbufferSize = 512; // GL says 1 pixel!
96 GLint max_renderbuffer_size = 0;
97 if (!QueryGLFeature(
98 GL_MAX_RENDERBUFFER_SIZE, kMinRenderbufferSize,
99 &max_renderbuffer_size)) {
100 LOG(ERROR) << "ContextGroup::Initialize failed because maximum "
101 << "renderbuffer size too small.";
102 return false;
103 }
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);
110 } else {
111 glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
112 }
113 }
114
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;
123 }
124
125 const bool depth24_supported = feature_info_->feature_flags().oes_depth24;
126
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,
133 depth24_supported));
134 shader_manager_.reset(new ShaderManager());
135
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.";
143 return false;
144 }
145
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.";
152 return false;
153 }
154
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!?!?
159 if (!QueryGLFeature(
160 GL_MAX_TEXTURE_SIZE, kMinTextureSize, &max_texture_size) ||
161 !QueryGLFeature(
162 GL_MAX_CUBE_MAP_TEXTURE_SIZE, kMinCubeMapSize,
163 &max_cube_map_texture_size)) {
164 LOG(ERROR) << "ContextGroup::Initialize failed because maximum texture size"
165 << "is too small.";
166 return false;
167 }
168
169 if (feature_info_->workarounds().max_texture_size) {
170 max_texture_size = std::min(
171 max_texture_size, feature_info_->workarounds().max_texture_size);
172 }
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);
177 }
178
179 texture_manager_.reset(new TextureManager(memory_tracker_.get(),
180 feature_info_.get(),
181 max_texture_size,
182 max_cube_map_texture_size,
183 bind_generates_resource_));
184 texture_manager_->set_framebuffer_manager(framebuffer_manager_.get());
185
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_) ||
191 !QueryGLFeatureU(
192 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, kMinVertexTextureImageUnits,
193 &max_vertex_texture_image_units_)) {
194 LOG(ERROR) << "ContextGroup::Initialize failed because too few "
195 << "texture units.";
196 return false;
197 }
198
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_);
204 } else {
205 GetIntegerv(
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;
212 }
213
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_) ||
220 !CheckGLFeatureU(
221 kMinVertexUniformVectors, &max_vertex_uniform_vectors_)) {
222 LOG(ERROR) << "ContextGroup::Initialize failed because too few "
223 << "uniforms or varyings supported.";
224 return false;
225 }
226
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_,
232 static_cast<uint32>(
233 feature_info_->workarounds().max_fragment_uniform_vectors));
234 }
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));
239 }
240 if (feature_info_->workarounds().max_vertex_uniform_vectors) {
241 max_vertex_uniform_vectors_ =
242 std::min(max_vertex_uniform_vectors_,
243 static_cast<uint32>(
244 feature_info_->workarounds().max_vertex_uniform_vectors));
245 }
246
247 program_manager_.reset(new ProgramManager(
248 program_cache_, max_varying_vectors_));
249
250 if (!texture_manager_->Initialize()) {
251 LOG(ERROR) << "Context::Group::Initialize failed because texture manager "
252 << "failed to initialize.";
253 return false;
254 }
255
256 decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
257 return true;
258 }
259
260 namespace {
261
IsNull(const base::WeakPtr<gles2::GLES2Decoder> & decoder)262 bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) {
263 return !decoder.get();
264 }
265
266 template <typename T>
267 class WeakPtrEquals {
268 public:
WeakPtrEquals(T * t)269 explicit WeakPtrEquals(T* t) : t_(t) {}
270
operator ()(const base::WeakPtr<T> & t)271 bool operator()(const base::WeakPtr<T>& t) {
272 return t.get() == t_;
273 }
274
275 private:
276 T* const t_;
277 };
278
279 } // namespace anonymous
280
HaveContexts()281 bool ContextGroup::HaveContexts() {
282 decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), IsNull),
283 decoders_.end());
284 return !decoders_.empty();
285 }
286
Destroy(GLES2Decoder * decoder,bool have_context)287 void ContextGroup::Destroy(GLES2Decoder* decoder, bool have_context) {
288 decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(),
289 WeakPtrEquals<gles2::GLES2Decoder>(decoder)),
290 decoders_.end());
291 // If we still have contexts do nothing.
292 if (HaveContexts()) {
293 return;
294 }
295
296 if (buffer_manager_ != NULL) {
297 buffer_manager_->Destroy(have_context);
298 buffer_manager_.reset();
299 }
300
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();
306 }
307
308 if (renderbuffer_manager_ != NULL) {
309 renderbuffer_manager_->Destroy(have_context);
310 renderbuffer_manager_.reset();
311 }
312
313 if (texture_manager_ != NULL) {
314 texture_manager_->Destroy(have_context);
315 texture_manager_.reset();
316 }
317
318 if (program_manager_ != NULL) {
319 program_manager_->Destroy(have_context);
320 program_manager_.reset();
321 }
322
323 if (shader_manager_ != NULL) {
324 shader_manager_->Destroy(have_context);
325 shader_manager_.reset();
326 }
327
328 memory_tracker_ = NULL;
329 }
330
GetIdAllocator(unsigned namespace_id)331 IdAllocatorInterface* ContextGroup::GetIdAllocator(unsigned namespace_id) {
332 if (namespace_id >= arraysize(id_namespaces_))
333 return NULL;
334
335 return id_namespaces_[namespace_id].get();
336 }
337
GetMemRepresented() const338 uint32 ContextGroup::GetMemRepresented() const {
339 uint32 total = 0;
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();
346 return total;
347 }
348
LoseContexts(GLenum reset_status)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);
353 }
354 }
355 }
356
~ContextGroup()357 ContextGroup::~ContextGroup() {
358 CHECK(!HaveContexts());
359 }
360
CheckGLFeature(GLint min_required,GLint * v)361 bool ContextGroup::CheckGLFeature(GLint min_required, GLint* v) {
362 GLint value = *v;
363 if (enforce_gl_minimums_) {
364 value = std::min(min_required, value);
365 }
366 *v = value;
367 return value >= min_required;
368 }
369
CheckGLFeatureU(GLint min_required,uint32 * v)370 bool ContextGroup::CheckGLFeatureU(GLint min_required, uint32* v) {
371 GLint value = *v;
372 if (enforce_gl_minimums_) {
373 value = std::min(min_required, value);
374 }
375 *v = value;
376 return value >= min_required;
377 }
378
QueryGLFeature(GLenum pname,GLint min_required,GLint * v)379 bool ContextGroup::QueryGLFeature(
380 GLenum pname, GLint min_required, GLint* v) {
381 GLint value = 0;
382 glGetIntegerv(pname, &value);
383 *v = value;
384 return CheckGLFeature(min_required, v);
385 }
386
QueryGLFeatureU(GLenum pname,GLint min_required,uint32 * v)387 bool ContextGroup::QueryGLFeatureU(
388 GLenum pname, GLint min_required, uint32* v) {
389 uint32 value = 0;
390 GetIntegerv(pname, &value);
391 bool result = CheckGLFeatureU(min_required, &value);
392 *v = value;
393 return result;
394 }
395
396 } // namespace gles2
397 } // namespace gpu
398