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