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
27namespace gpu {
28namespace gles2 {
29
30ContextGroup::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
74static void GetIntegerv(GLenum pname, uint32* var) {
75  GLint value = 0;
76  glGetIntegerv(pname, &value);
77  *var = value;
78}
79
80bool 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
260namespace {
261
262bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) {
263  return !decoder.get();
264}
265
266template <typename T>
267class WeakPtrEquals {
268 public:
269  explicit WeakPtrEquals(T* t) : t_(t) {}
270
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
281bool ContextGroup::HaveContexts() {
282  decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), IsNull),
283                  decoders_.end());
284  return !decoders_.empty();
285}
286
287void 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
331IdAllocatorInterface* 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
338uint32 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
349void 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
357ContextGroup::~ContextGroup() {
358  CHECK(!HaveContexts());
359}
360
361bool 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
370bool 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
379bool 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
387bool 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