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/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   id_namespaces_[id_namespaces::kImages].reset(new IdAllocator);
     71 }
     72 
     73 static void GetIntegerv(GLenum pname, uint32* var) {
     74   GLint value = 0;
     75   glGetIntegerv(pname, &value);
     76   *var = value;
     77 }
     78 
     79 bool ContextGroup::Initialize(
     80     GLES2Decoder* decoder,
     81     const DisallowedFeatures& disallowed_features,
     82     const char* allowed_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, allowed_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   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   shader_manager_.reset(new ShaderManager());
    132   program_manager_.reset(new ProgramManager(program_cache_));
    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   if (!texture_manager_->Initialize()) {
    240     LOG(ERROR) << "Context::Group::Initialize failed because texture manager "
    241                << "failed to initialize.";
    242     return false;
    243   }
    244 
    245   decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
    246   return true;
    247 }
    248 
    249 namespace {
    250 
    251 bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) {
    252   return !decoder.get();
    253 }
    254 
    255 template <typename T>
    256 class WeakPtrEquals {
    257  public:
    258   explicit WeakPtrEquals(T* t) : t_(t) {}
    259 
    260   bool operator()(const base::WeakPtr<T>& t) {
    261     return t.get() == t_;
    262   }
    263 
    264  private:
    265   T* const t_;
    266 };
    267 
    268 }  // namespace anonymous
    269 
    270 bool ContextGroup::HaveContexts() {
    271   decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), IsNull),
    272                   decoders_.end());
    273   return !decoders_.empty();
    274 }
    275 
    276 void ContextGroup::Destroy(GLES2Decoder* decoder, bool have_context) {
    277   decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(),
    278                                  WeakPtrEquals<gles2::GLES2Decoder>(decoder)),
    279                   decoders_.end());
    280   // If we still have contexts do nothing.
    281   if (HaveContexts()) {
    282     return;
    283   }
    284 
    285   if (buffer_manager_ != NULL) {
    286     buffer_manager_->Destroy(have_context);
    287     buffer_manager_.reset();
    288   }
    289 
    290   if (framebuffer_manager_ != NULL) {
    291     framebuffer_manager_->Destroy(have_context);
    292     if (texture_manager_)
    293       texture_manager_->set_framebuffer_manager(NULL);
    294     framebuffer_manager_.reset();
    295   }
    296 
    297   if (renderbuffer_manager_ != NULL) {
    298     renderbuffer_manager_->Destroy(have_context);
    299     renderbuffer_manager_.reset();
    300   }
    301 
    302   if (texture_manager_ != NULL) {
    303     texture_manager_->Destroy(have_context);
    304     texture_manager_.reset();
    305   }
    306 
    307   if (program_manager_ != NULL) {
    308     program_manager_->Destroy(have_context);
    309     program_manager_.reset();
    310   }
    311 
    312   if (shader_manager_ != NULL) {
    313     shader_manager_->Destroy(have_context);
    314     shader_manager_.reset();
    315   }
    316 
    317   memory_tracker_ = NULL;
    318   stream_texture_manager_ = NULL;
    319 }
    320 
    321 IdAllocatorInterface* ContextGroup::GetIdAllocator(unsigned namespace_id) {
    322   if (namespace_id >= arraysize(id_namespaces_))
    323     return NULL;
    324 
    325   return id_namespaces_[namespace_id].get();
    326 }
    327 
    328 uint32 ContextGroup::GetMemRepresented() const {
    329   uint32 total = 0;
    330   if (buffer_manager_.get())
    331     total += buffer_manager_->mem_represented();
    332   if (renderbuffer_manager_.get())
    333     total += renderbuffer_manager_->mem_represented();
    334   if (texture_manager_.get())
    335     total += texture_manager_->mem_represented();
    336   return total;
    337 }
    338 
    339 void ContextGroup::LoseContexts(GLenum reset_status) {
    340   for (size_t ii = 0; ii < decoders_.size(); ++ii) {
    341     if (decoders_[ii].get()) {
    342       decoders_[ii]->LoseContext(reset_status);
    343     }
    344   }
    345 }
    346 
    347 ContextGroup::~ContextGroup() {
    348   CHECK(!HaveContexts());
    349 }
    350 
    351 bool ContextGroup::CheckGLFeature(GLint min_required, GLint* v) {
    352   GLint value = *v;
    353   if (enforce_gl_minimums_) {
    354     value = std::min(min_required, value);
    355   }
    356   *v = value;
    357   return value >= min_required;
    358 }
    359 
    360 bool ContextGroup::CheckGLFeatureU(GLint min_required, uint32* v) {
    361   GLint value = *v;
    362   if (enforce_gl_minimums_) {
    363     value = std::min(min_required, value);
    364   }
    365   *v = value;
    366   return value >= min_required;
    367 }
    368 
    369 bool ContextGroup::QueryGLFeature(
    370     GLenum pname, GLint min_required, GLint* v) {
    371   GLint value = 0;
    372   glGetIntegerv(pname, &value);
    373   *v = value;
    374   return CheckGLFeature(min_required, v);
    375 }
    376 
    377 bool ContextGroup::QueryGLFeatureU(
    378     GLenum pname, GLint min_required, uint32* v) {
    379   uint32 value = 0;
    380   GetIntegerv(pname, &value);
    381   bool result = CheckGLFeatureU(min_required, &value);
    382   *v = value;
    383   return result;
    384 }
    385 
    386 }  // namespace gles2
    387 }  // namespace gpu
    388