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