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