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