Home | History | Annotate | Download | only in service
      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 
     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 
     74 static void GetIntegerv(GLenum pname, uint32* var) {
     75   GLint value = 0;
     76   glGetIntegerv(pname, &value);
     77   *var = value;
     78 }
     79 
     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 
    262 bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) {
    263   return !decoder.get();
    264 }
    265 
    266 template <typename T>
    267 class 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 
    281 bool ContextGroup::HaveContexts() {
    282   decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), IsNull),
    283                   decoders_.end());
    284   return !decoders_.empty();
    285 }
    286 
    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 
    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 
    338 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 
    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 
    357 ContextGroup::~ContextGroup() {
    358   CHECK(!HaveContexts());
    359 }
    360 
    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 
    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 
    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 
    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