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 ShaderTranslatorCache* shader_translator_cache, 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 shader_translator_cache_(shader_translator_cache), 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 bind_generates_resource_)); 183 texture_manager_->set_framebuffer_manager(framebuffer_manager_.get()); 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 // Some shaders in Skia need more than the min available vertex and 227 // fragment shader uniform vectors in case of OSMesa GL Implementation 228 if (feature_info_->workarounds().max_fragment_uniform_vectors) { 229 max_fragment_uniform_vectors_ = std::min( 230 max_fragment_uniform_vectors_, 231 static_cast<uint32>( 232 feature_info_->workarounds().max_fragment_uniform_vectors)); 233 } 234 if (feature_info_->workarounds().max_varying_vectors) { 235 max_varying_vectors_ = std::min( 236 max_varying_vectors_, 237 static_cast<uint32>(feature_info_->workarounds().max_varying_vectors)); 238 } 239 if (feature_info_->workarounds().max_vertex_uniform_vectors) { 240 max_vertex_uniform_vectors_ = 241 std::min(max_vertex_uniform_vectors_, 242 static_cast<uint32>( 243 feature_info_->workarounds().max_vertex_uniform_vectors)); 244 } 245 246 program_manager_.reset(new ProgramManager( 247 program_cache_, max_varying_vectors_)); 248 249 if (!texture_manager_->Initialize()) { 250 LOG(ERROR) << "Context::Group::Initialize failed because texture manager " 251 << "failed to initialize."; 252 return false; 253 } 254 255 decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder)); 256 return true; 257 } 258 259 namespace { 260 261 bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) { 262 return !decoder.get(); 263 } 264 265 template <typename T> 266 class WeakPtrEquals { 267 public: 268 explicit WeakPtrEquals(T* t) : t_(t) {} 269 270 bool operator()(const base::WeakPtr<T>& t) { 271 return t.get() == t_; 272 } 273 274 private: 275 T* const t_; 276 }; 277 278 } // namespace anonymous 279 280 bool ContextGroup::HaveContexts() { 281 decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), IsNull), 282 decoders_.end()); 283 return !decoders_.empty(); 284 } 285 286 void ContextGroup::Destroy(GLES2Decoder* decoder, bool have_context) { 287 decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), 288 WeakPtrEquals<gles2::GLES2Decoder>(decoder)), 289 decoders_.end()); 290 // If we still have contexts do nothing. 291 if (HaveContexts()) { 292 return; 293 } 294 295 if (buffer_manager_ != NULL) { 296 buffer_manager_->Destroy(have_context); 297 buffer_manager_.reset(); 298 } 299 300 if (framebuffer_manager_ != NULL) { 301 framebuffer_manager_->Destroy(have_context); 302 if (texture_manager_) 303 texture_manager_->set_framebuffer_manager(NULL); 304 framebuffer_manager_.reset(); 305 } 306 307 if (renderbuffer_manager_ != NULL) { 308 renderbuffer_manager_->Destroy(have_context); 309 renderbuffer_manager_.reset(); 310 } 311 312 if (texture_manager_ != NULL) { 313 texture_manager_->Destroy(have_context); 314 texture_manager_.reset(); 315 } 316 317 if (program_manager_ != NULL) { 318 program_manager_->Destroy(have_context); 319 program_manager_.reset(); 320 } 321 322 if (shader_manager_ != NULL) { 323 shader_manager_->Destroy(have_context); 324 shader_manager_.reset(); 325 } 326 327 memory_tracker_ = NULL; 328 } 329 330 IdAllocatorInterface* ContextGroup::GetIdAllocator(unsigned namespace_id) { 331 if (namespace_id >= arraysize(id_namespaces_)) 332 return NULL; 333 334 return id_namespaces_[namespace_id].get(); 335 } 336 337 uint32 ContextGroup::GetMemRepresented() const { 338 uint32 total = 0; 339 if (buffer_manager_.get()) 340 total += buffer_manager_->mem_represented(); 341 if (renderbuffer_manager_.get()) 342 total += renderbuffer_manager_->mem_represented(); 343 if (texture_manager_.get()) 344 total += texture_manager_->mem_represented(); 345 return total; 346 } 347 348 void ContextGroup::LoseContexts(GLenum reset_status) { 349 for (size_t ii = 0; ii < decoders_.size(); ++ii) { 350 if (decoders_[ii].get()) { 351 decoders_[ii]->LoseContext(reset_status); 352 } 353 } 354 } 355 356 ContextGroup::~ContextGroup() { 357 CHECK(!HaveContexts()); 358 } 359 360 bool ContextGroup::CheckGLFeature(GLint min_required, GLint* 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::CheckGLFeatureU(GLint min_required, uint32* v) { 370 GLint value = *v; 371 if (enforce_gl_minimums_) { 372 value = std::min(min_required, value); 373 } 374 *v = value; 375 return value >= min_required; 376 } 377 378 bool ContextGroup::QueryGLFeature( 379 GLenum pname, GLint min_required, GLint* v) { 380 GLint value = 0; 381 glGetIntegerv(pname, &value); 382 *v = value; 383 return CheckGLFeature(min_required, v); 384 } 385 386 bool ContextGroup::QueryGLFeatureU( 387 GLenum pname, GLint min_required, uint32* v) { 388 uint32 value = 0; 389 GetIntegerv(pname, &value); 390 bool result = CheckGLFeatureU(min_required, &value); 391 *v = value; 392 return result; 393 } 394 395 } // namespace gles2 396 } // namespace gpu 397