• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/image_manager.h"
19 #include "gpu/command_buffer/service/mailbox_manager.h"
20 #include "gpu/command_buffer/service/memory_tracking.h"
21 #include "gpu/command_buffer/service/program_manager.h"
22 #include "gpu/command_buffer/service/renderbuffer_manager.h"
23 #include "gpu/command_buffer/service/shader_manager.h"
24 #include "gpu/command_buffer/service/texture_manager.h"
25 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
26 #include "ui/gl/gl_implementation.h"
27 
28 namespace gpu {
29 namespace gles2 {
30 
ContextGroup(MailboxManager * mailbox_manager,ImageManager * image_manager,MemoryTracker * memory_tracker,StreamTextureManager * stream_texture_manager,FeatureInfo * feature_info,bool bind_generates_resource)31 ContextGroup::ContextGroup(
32     MailboxManager* mailbox_manager,
33     ImageManager* image_manager,
34     MemoryTracker* memory_tracker,
35     StreamTextureManager* stream_texture_manager,
36     FeatureInfo* feature_info,
37     bool bind_generates_resource)
38     : mailbox_manager_(mailbox_manager ? mailbox_manager : new MailboxManager),
39       image_manager_(image_manager ? image_manager : new ImageManager),
40       memory_tracker_(memory_tracker),
41       stream_texture_manager_(stream_texture_manager),
42       enforce_gl_minimums_(CommandLine::ForCurrentProcess()->HasSwitch(
43           switches::kEnforceGLMinimums)),
44       bind_generates_resource_(bind_generates_resource),
45       max_vertex_attribs_(0u),
46       max_texture_units_(0u),
47       max_texture_image_units_(0u),
48       max_vertex_texture_image_units_(0u),
49       max_fragment_uniform_vectors_(0u),
50       max_varying_vectors_(0u),
51       max_vertex_uniform_vectors_(0u),
52       max_color_attachments_(1u),
53       max_draw_buffers_(1u),
54       program_cache_(NULL),
55       feature_info_(feature_info ? feature_info : new FeatureInfo),
56       draw_buffer_(GL_BACK) {
57   {
58     TransferBufferManager* manager = new TransferBufferManager();
59     transfer_buffer_manager_.reset(manager);
60     manager->Initialize();
61   }
62 
63   id_namespaces_[id_namespaces::kBuffers].reset(new IdAllocator);
64   id_namespaces_[id_namespaces::kFramebuffers].reset(new IdAllocator);
65   id_namespaces_[id_namespaces::kProgramsAndShaders].reset(
66       new NonReusedIdAllocator);
67   id_namespaces_[id_namespaces::kRenderbuffers].reset(new IdAllocator);
68   id_namespaces_[id_namespaces::kTextures].reset(new IdAllocator);
69   id_namespaces_[id_namespaces::kQueries].reset(new IdAllocator);
70   id_namespaces_[id_namespaces::kVertexArrays].reset(new IdAllocator);
71 }
72 
GetIntegerv(GLenum pname,uint32 * var)73 static void GetIntegerv(GLenum pname, uint32* var) {
74   GLint value = 0;
75   glGetIntegerv(pname, &value);
76   *var = value;
77 }
78 
Initialize(GLES2Decoder * decoder,const DisallowedFeatures & disallowed_features)79 bool ContextGroup::Initialize(
80     GLES2Decoder* decoder,
81     const DisallowedFeatures& disallowed_features) {
82   // If we've already initialized the group just add the context.
83   if (HaveContexts()) {
84     decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
85     return true;
86   }
87 
88   if (!feature_info_->Initialize(disallowed_features)) {
89     LOG(ERROR) << "ContextGroup::Initialize failed because FeatureInfo "
90                << "initialization failed.";
91     return false;
92   }
93 
94   const GLint kMinRenderbufferSize = 512;  // GL says 1 pixel!
95   GLint max_renderbuffer_size = 0;
96   if (!QueryGLFeature(
97       GL_MAX_RENDERBUFFER_SIZE, kMinRenderbufferSize,
98       &max_renderbuffer_size)) {
99     LOG(ERROR) << "ContextGroup::Initialize failed because maximum "
100                << "renderbuffer size too small.";
101     return false;
102   }
103   GLint max_samples = 0;
104   if (feature_info_->feature_flags().chromium_framebuffer_multisample ||
105       feature_info_->feature_flags().multisampled_render_to_texture) {
106     if (feature_info_->feature_flags(
107             ).use_img_for_multisampled_render_to_texture) {
108       glGetIntegerv(GL_MAX_SAMPLES_IMG, &max_samples);
109     } else {
110       glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
111     }
112   }
113 
114   if (feature_info_->feature_flags().ext_draw_buffers) {
115     GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &max_color_attachments_);
116     if (max_color_attachments_ < 1)
117       max_color_attachments_ = 1;
118     GetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &max_draw_buffers_);
119     if (max_draw_buffers_ < 1)
120       max_draw_buffers_ = 1;
121     draw_buffer_ = GL_BACK;
122   }
123 
124   const bool depth24_supported = feature_info_->feature_flags().oes_depth24;
125 
126   buffer_manager_.reset(
127       new BufferManager(memory_tracker_.get(), feature_info_.get()));
128   framebuffer_manager_.reset(
129       new FramebufferManager(max_draw_buffers_, max_color_attachments_));
130   renderbuffer_manager_.reset(new RenderbufferManager(
131       memory_tracker_.get(), max_renderbuffer_size, max_samples,
132       depth24_supported));
133   shader_manager_.reset(new ShaderManager());
134 
135   // Lookup GL things we need to know.
136   const GLint kGLES2RequiredMinimumVertexAttribs = 8u;
137   if (!QueryGLFeatureU(
138       GL_MAX_VERTEX_ATTRIBS, kGLES2RequiredMinimumVertexAttribs,
139       &max_vertex_attribs_)) {
140     LOG(ERROR) << "ContextGroup::Initialize failed because too few "
141                << "vertex attributes supported.";
142     return false;
143   }
144 
145   const GLuint kGLES2RequiredMinimumTextureUnits = 8u;
146   if (!QueryGLFeatureU(
147       GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, kGLES2RequiredMinimumTextureUnits,
148       &max_texture_units_)) {
149     LOG(ERROR) << "ContextGroup::Initialize failed because too few "
150                << "texture units supported.";
151     return false;
152   }
153 
154   GLint max_texture_size = 0;
155   GLint max_cube_map_texture_size = 0;
156   const GLint kMinTextureSize = 2048;  // GL actually says 64!?!?
157   const GLint kMinCubeMapSize = 256;  // GL actually says 16!?!?
158   if (!QueryGLFeature(
159       GL_MAX_TEXTURE_SIZE, kMinTextureSize, &max_texture_size) ||
160       !QueryGLFeature(
161       GL_MAX_CUBE_MAP_TEXTURE_SIZE, kMinCubeMapSize,
162       &max_cube_map_texture_size)) {
163     LOG(ERROR) << "ContextGroup::Initialize failed because maximum texture size"
164                << "is too small.";
165     return false;
166   }
167 
168   if (feature_info_->workarounds().max_texture_size) {
169     max_texture_size = std::min(
170         max_texture_size, feature_info_->workarounds().max_texture_size);
171   }
172   if (feature_info_->workarounds().max_cube_map_texture_size) {
173     max_cube_map_texture_size = std::min(
174         max_cube_map_texture_size,
175         feature_info_->workarounds().max_cube_map_texture_size);
176   }
177 
178   texture_manager_.reset(new TextureManager(memory_tracker_.get(),
179                                             feature_info_.get(),
180                                             max_texture_size,
181                                             max_cube_map_texture_size));
182   texture_manager_->set_framebuffer_manager(framebuffer_manager_.get());
183   texture_manager_->set_stream_texture_manager(stream_texture_manager_);
184 
185   const GLint kMinTextureImageUnits = 8;
186   const GLint kMinVertexTextureImageUnits = 0;
187   if (!QueryGLFeatureU(
188       GL_MAX_TEXTURE_IMAGE_UNITS, kMinTextureImageUnits,
189       &max_texture_image_units_) ||
190       !QueryGLFeatureU(
191       GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, kMinVertexTextureImageUnits,
192       &max_vertex_texture_image_units_)) {
193     LOG(ERROR) << "ContextGroup::Initialize failed because too few "
194                << "texture units.";
195     return false;
196   }
197 
198   if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
199     GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS,
200         &max_fragment_uniform_vectors_);
201     GetIntegerv(GL_MAX_VARYING_VECTORS, &max_varying_vectors_);
202     GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &max_vertex_uniform_vectors_);
203   } else {
204     GetIntegerv(
205         GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max_fragment_uniform_vectors_);
206     max_fragment_uniform_vectors_ /= 4;
207     GetIntegerv(GL_MAX_VARYING_FLOATS, &max_varying_vectors_);
208     max_varying_vectors_ /= 4;
209     GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &max_vertex_uniform_vectors_);
210     max_vertex_uniform_vectors_ /= 4;
211   }
212 
213   const GLint kMinFragmentUniformVectors = 16;
214   const GLint kMinVaryingVectors = 8;
215   const GLint kMinVertexUniformVectors = 128;
216   if (!CheckGLFeatureU(
217       kMinFragmentUniformVectors, &max_fragment_uniform_vectors_) ||
218       !CheckGLFeatureU(kMinVaryingVectors, &max_varying_vectors_) ||
219       !CheckGLFeatureU(
220       kMinVertexUniformVectors, &max_vertex_uniform_vectors_)) {
221     LOG(ERROR) << "ContextGroup::Initialize failed because too few "
222                << "uniforms or varyings supported.";
223     return false;
224   }
225 
226   // TODO(gman): Use workarounds similar to max_texture_size above to implement.
227   if (gfx::GetGLImplementation() == gfx::kGLImplementationOSMesaGL) {
228     // Some shaders in Skia needed more than the min.
229     max_fragment_uniform_vectors_ =
230        std::min(static_cast<uint32>(kMinFragmentUniformVectors * 2),
231                 max_fragment_uniform_vectors_);
232     max_varying_vectors_ =
233        std::min(static_cast<uint32>(kMinVaryingVectors * 2),
234                 max_varying_vectors_);
235     max_vertex_uniform_vectors_ =
236        std::min(static_cast<uint32>(kMinVertexUniformVectors * 2),
237                 max_vertex_uniform_vectors_);
238   }
239 
240   program_manager_.reset(new ProgramManager(
241       program_cache_, max_varying_vectors_));
242 
243   if (!texture_manager_->Initialize()) {
244     LOG(ERROR) << "Context::Group::Initialize failed because texture manager "
245                << "failed to initialize.";
246     return false;
247   }
248 
249   decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
250   return true;
251 }
252 
253 namespace {
254 
IsNull(const base::WeakPtr<gles2::GLES2Decoder> & decoder)255 bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) {
256   return !decoder.get();
257 }
258 
259 template <typename T>
260 class WeakPtrEquals {
261  public:
WeakPtrEquals(T * t)262   explicit WeakPtrEquals(T* t) : t_(t) {}
263 
operator ()(const base::WeakPtr<T> & t)264   bool operator()(const base::WeakPtr<T>& t) {
265     return t.get() == t_;
266   }
267 
268  private:
269   T* const t_;
270 };
271 
272 }  // namespace anonymous
273 
HaveContexts()274 bool ContextGroup::HaveContexts() {
275   decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), IsNull),
276                   decoders_.end());
277   return !decoders_.empty();
278 }
279 
Destroy(GLES2Decoder * decoder,bool have_context)280 void ContextGroup::Destroy(GLES2Decoder* decoder, bool have_context) {
281   decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(),
282                                  WeakPtrEquals<gles2::GLES2Decoder>(decoder)),
283                   decoders_.end());
284   // If we still have contexts do nothing.
285   if (HaveContexts()) {
286     return;
287   }
288 
289   if (buffer_manager_ != NULL) {
290     buffer_manager_->Destroy(have_context);
291     buffer_manager_.reset();
292   }
293 
294   if (framebuffer_manager_ != NULL) {
295     framebuffer_manager_->Destroy(have_context);
296     if (texture_manager_)
297       texture_manager_->set_framebuffer_manager(NULL);
298     framebuffer_manager_.reset();
299   }
300 
301   if (renderbuffer_manager_ != NULL) {
302     renderbuffer_manager_->Destroy(have_context);
303     renderbuffer_manager_.reset();
304   }
305 
306   if (texture_manager_ != NULL) {
307     texture_manager_->Destroy(have_context);
308     texture_manager_.reset();
309   }
310 
311   if (program_manager_ != NULL) {
312     program_manager_->Destroy(have_context);
313     program_manager_.reset();
314   }
315 
316   if (shader_manager_ != NULL) {
317     shader_manager_->Destroy(have_context);
318     shader_manager_.reset();
319   }
320 
321   memory_tracker_ = NULL;
322   stream_texture_manager_ = NULL;
323 }
324 
GetIdAllocator(unsigned namespace_id)325 IdAllocatorInterface* ContextGroup::GetIdAllocator(unsigned namespace_id) {
326   if (namespace_id >= arraysize(id_namespaces_))
327     return NULL;
328 
329   return id_namespaces_[namespace_id].get();
330 }
331 
GetMemRepresented() const332 uint32 ContextGroup::GetMemRepresented() const {
333   uint32 total = 0;
334   if (buffer_manager_.get())
335     total += buffer_manager_->mem_represented();
336   if (renderbuffer_manager_.get())
337     total += renderbuffer_manager_->mem_represented();
338   if (texture_manager_.get())
339     total += texture_manager_->mem_represented();
340   return total;
341 }
342 
LoseContexts(GLenum reset_status)343 void ContextGroup::LoseContexts(GLenum reset_status) {
344   for (size_t ii = 0; ii < decoders_.size(); ++ii) {
345     if (decoders_[ii].get()) {
346       decoders_[ii]->LoseContext(reset_status);
347     }
348   }
349 }
350 
~ContextGroup()351 ContextGroup::~ContextGroup() {
352   CHECK(!HaveContexts());
353 }
354 
CheckGLFeature(GLint min_required,GLint * v)355 bool ContextGroup::CheckGLFeature(GLint min_required, GLint* v) {
356   GLint value = *v;
357   if (enforce_gl_minimums_) {
358     value = std::min(min_required, value);
359   }
360   *v = value;
361   return value >= min_required;
362 }
363 
CheckGLFeatureU(GLint min_required,uint32 * v)364 bool ContextGroup::CheckGLFeatureU(GLint min_required, uint32* v) {
365   GLint value = *v;
366   if (enforce_gl_minimums_) {
367     value = std::min(min_required, value);
368   }
369   *v = value;
370   return value >= min_required;
371 }
372 
QueryGLFeature(GLenum pname,GLint min_required,GLint * v)373 bool ContextGroup::QueryGLFeature(
374     GLenum pname, GLint min_required, GLint* v) {
375   GLint value = 0;
376   glGetIntegerv(pname, &value);
377   *v = value;
378   return CheckGLFeature(min_required, v);
379 }
380 
QueryGLFeatureU(GLenum pname,GLint min_required,uint32 * v)381 bool ContextGroup::QueryGLFeatureU(
382     GLenum pname, GLint min_required, uint32* v) {
383   uint32 value = 0;
384   GetIntegerv(pname, &value);
385   bool result = CheckGLFeatureU(min_required, &value);
386   *v = value;
387   return result;
388 }
389 
390 }  // namespace gles2
391 }  // namespace gpu
392