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