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