| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "gpu/command_buffer/service/context_group.h" |
| |
| #include <algorithm> |
| #include <string> |
| |
| #include "base/command_line.h" |
| #include "base/string_util.h" |
| #include "gpu/command_buffer/common/id_allocator.h" |
| #include "gpu/command_buffer/service/buffer_manager.h" |
| #include "gpu/command_buffer/service/framebuffer_manager.h" |
| #include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
| #include "gpu/command_buffer/service/gpu_switches.h" |
| #include "gpu/command_buffer/service/mailbox_manager.h" |
| #include "gpu/command_buffer/service/memory_tracking.h" |
| #include "gpu/command_buffer/service/program_manager.h" |
| #include "gpu/command_buffer/service/renderbuffer_manager.h" |
| #include "gpu/command_buffer/service/shader_manager.h" |
| #include "gpu/command_buffer/service/texture_manager.h" |
| #include "gpu/command_buffer/service/transfer_buffer_manager.h" |
| #include "ui/gl/gl_implementation.h" |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| ContextGroup::ContextGroup( |
| MailboxManager* mailbox_manager, |
| MemoryTracker* memory_tracker, |
| bool bind_generates_resource) |
| : mailbox_manager_(mailbox_manager ? mailbox_manager : new MailboxManager), |
| memory_tracker_(memory_tracker), |
| num_contexts_(0), |
| enforce_gl_minimums_(CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnforceGLMinimums)), |
| bind_generates_resource_(bind_generates_resource), |
| max_vertex_attribs_(0u), |
| max_texture_units_(0u), |
| max_texture_image_units_(0u), |
| max_vertex_texture_image_units_(0u), |
| max_fragment_uniform_vectors_(0u), |
| max_varying_vectors_(0u), |
| max_vertex_uniform_vectors_(0u), |
| program_cache_(NULL), |
| feature_info_(new FeatureInfo()) { |
| { |
| TransferBufferManager* manager = new TransferBufferManager(); |
| transfer_buffer_manager_.reset(manager); |
| manager->Initialize(); |
| } |
| |
| id_namespaces_[id_namespaces::kBuffers].reset(new IdAllocator); |
| id_namespaces_[id_namespaces::kFramebuffers].reset(new IdAllocator); |
| id_namespaces_[id_namespaces::kProgramsAndShaders].reset( |
| new NonReusedIdAllocator); |
| id_namespaces_[id_namespaces::kRenderbuffers].reset(new IdAllocator); |
| id_namespaces_[id_namespaces::kTextures].reset(new IdAllocator); |
| id_namespaces_[id_namespaces::kQueries].reset(new IdAllocator); |
| } |
| |
| static void GetIntegerv(GLenum pname, uint32* var) { |
| GLint value = 0; |
| glGetIntegerv(pname, &value); |
| *var = value; |
| } |
| |
| bool ContextGroup::Initialize(const DisallowedFeatures& disallowed_features, |
| const char* allowed_features) { |
| if (num_contexts_ > 0) { |
| ++num_contexts_; |
| return true; |
| } |
| |
| if (!feature_info_->Initialize(disallowed_features, allowed_features)) { |
| LOG(ERROR) << "ContextGroup::Initialize failed because FeatureInfo " |
| << "initialization failed."; |
| return false; |
| } |
| |
| const GLint kMinRenderbufferSize = 512; // GL says 1 pixel! |
| GLint max_renderbuffer_size = 0; |
| if (!QueryGLFeature( |
| GL_MAX_RENDERBUFFER_SIZE, kMinRenderbufferSize, |
| &max_renderbuffer_size)) { |
| LOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "renderbuffer size too small."; |
| return false; |
| } |
| GLint max_samples = 0; |
| if (feature_info_->feature_flags().chromium_framebuffer_multisample) { |
| glGetIntegerv(GL_MAX_SAMPLES, &max_samples); |
| } |
| |
| buffer_manager_.reset(new BufferManager(memory_tracker_)); |
| framebuffer_manager_.reset(new FramebufferManager()); |
| renderbuffer_manager_.reset(new RenderbufferManager(memory_tracker_, |
| max_renderbuffer_size, |
| max_samples)); |
| shader_manager_.reset(new ShaderManager()); |
| program_manager_.reset(new ProgramManager(program_cache_)); |
| |
| // Lookup GL things we need to know. |
| const GLint kGLES2RequiredMinimumVertexAttribs = 8u; |
| if (!QueryGLFeatureU( |
| GL_MAX_VERTEX_ATTRIBS, kGLES2RequiredMinimumVertexAttribs, |
| &max_vertex_attribs_)) { |
| LOG(ERROR) << "ContextGroup::Initialize failed because too few " |
| << "vertex attributes supported."; |
| return false; |
| } |
| |
| const GLuint kGLES2RequiredMinimumTextureUnits = 8u; |
| if (!QueryGLFeatureU( |
| GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, kGLES2RequiredMinimumTextureUnits, |
| &max_texture_units_)) { |
| LOG(ERROR) << "ContextGroup::Initialize failed because too few " |
| << "texture units supported."; |
| return false; |
| } |
| |
| GLint max_texture_size = 0; |
| GLint max_cube_map_texture_size = 0; |
| const GLint kMinTextureSize = 2048; // GL actually says 64!?!? |
| const GLint kMinCubeMapSize = 256; // GL actually says 16!?!? |
| if (!QueryGLFeature( |
| GL_MAX_TEXTURE_SIZE, kMinTextureSize, &max_texture_size) || |
| !QueryGLFeature( |
| GL_MAX_CUBE_MAP_TEXTURE_SIZE, kMinCubeMapSize, |
| &max_cube_map_texture_size)) { |
| LOG(ERROR) << "ContextGroup::Initialize failed because maximum texture size" |
| << "is too small."; |
| return false; |
| } |
| |
| // Limit Intel on Mac to 4096 max tex size and 512 max cube map tex size. |
| // Limit AMD on Mac to 4096 max tex size and max cube map tex size. |
| // TODO(gman): Update this code to check for a specific version of |
| // the drivers above which we no longer need this fix. |
| #if defined(OS_MACOSX) |
| if (!feature_info_->feature_flags().disable_workarounds) { |
| if (feature_info_->feature_flags().is_intel) { |
| max_texture_size = std::min( |
| static_cast<GLint>(4096), max_texture_size); |
| max_cube_map_texture_size = std::min( |
| static_cast<GLint>(512), max_cube_map_texture_size); |
| } |
| if (feature_info_->feature_flags().is_amd) { |
| max_texture_size = std::min( |
| static_cast<GLint>(4096), max_texture_size); |
| max_cube_map_texture_size = std::min( |
| static_cast<GLint>(4096), max_cube_map_texture_size); |
| } |
| } |
| #endif |
| texture_manager_.reset(new TextureManager(memory_tracker_, |
| feature_info_.get(), |
| max_texture_size, |
| max_cube_map_texture_size)); |
| |
| const GLint kMinTextureImageUnits = 8; |
| const GLint kMinVertexTextureImageUnits = 0; |
| if (!QueryGLFeatureU( |
| GL_MAX_TEXTURE_IMAGE_UNITS, kMinTextureImageUnits, |
| &max_texture_image_units_) || |
| !QueryGLFeatureU( |
| GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, kMinVertexTextureImageUnits, |
| &max_vertex_texture_image_units_)) { |
| LOG(ERROR) << "ContextGroup::Initialize failed because too few " |
| << "texture units."; |
| return false; |
| } |
| |
| if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) { |
| GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, |
| &max_fragment_uniform_vectors_); |
| GetIntegerv(GL_MAX_VARYING_VECTORS, &max_varying_vectors_); |
| GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &max_vertex_uniform_vectors_); |
| } else { |
| GetIntegerv( |
| GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max_fragment_uniform_vectors_); |
| max_fragment_uniform_vectors_ /= 4; |
| GetIntegerv(GL_MAX_VARYING_FLOATS, &max_varying_vectors_); |
| max_varying_vectors_ /= 4; |
| GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &max_vertex_uniform_vectors_); |
| max_vertex_uniform_vectors_ /= 4; |
| } |
| |
| const GLint kMinFragmentUniformVectors = 16; |
| const GLint kMinVaryingVectors = 8; |
| const GLint kMinVertexUniformVectors = 128; |
| if (!CheckGLFeatureU( |
| kMinFragmentUniformVectors, &max_fragment_uniform_vectors_) || |
| !CheckGLFeatureU(kMinVaryingVectors, &max_varying_vectors_) || |
| !CheckGLFeatureU( |
| kMinVertexUniformVectors, &max_vertex_uniform_vectors_)) { |
| LOG(ERROR) << "ContextGroup::Initialize failed because too few " |
| << "uniforms or varyings supported."; |
| return false; |
| } |
| |
| if (!texture_manager_->Initialize()) { |
| LOG(ERROR) << "Context::Group::Initialize failed because texture manager " |
| << "failed to initialize."; |
| return false; |
| } |
| |
| ++num_contexts_; |
| return true; |
| } |
| |
| void ContextGroup::Destroy(bool have_context) { |
| DCHECK(num_contexts_ > 0); |
| if (--num_contexts_ > 0) |
| return; |
| |
| if (buffer_manager_ != NULL) { |
| buffer_manager_->Destroy(have_context); |
| buffer_manager_.reset(); |
| } |
| |
| if (framebuffer_manager_ != NULL) { |
| framebuffer_manager_->Destroy(have_context); |
| framebuffer_manager_.reset(); |
| } |
| |
| if (renderbuffer_manager_ != NULL) { |
| renderbuffer_manager_->Destroy(have_context); |
| renderbuffer_manager_.reset(); |
| } |
| |
| if (texture_manager_ != NULL) { |
| mailbox_manager_->DestroyOwnedTextures(texture_manager_.get(), |
| have_context); |
| texture_manager_->Destroy(have_context); |
| texture_manager_.reset(); |
| } |
| |
| if (program_manager_ != NULL) { |
| program_manager_->Destroy(have_context); |
| program_manager_.reset(); |
| } |
| |
| if (shader_manager_ != NULL) { |
| shader_manager_->Destroy(have_context); |
| shader_manager_.reset(); |
| } |
| |
| memory_tracker_ = NULL; |
| } |
| |
| IdAllocatorInterface* ContextGroup::GetIdAllocator(unsigned namespace_id) { |
| if (namespace_id >= arraysize(id_namespaces_)) |
| return NULL; |
| |
| return id_namespaces_[namespace_id].get(); |
| } |
| |
| uint32 ContextGroup::GetMemRepresented() const { |
| uint32 total = 0; |
| if (buffer_manager_.get()) |
| total += buffer_manager_->mem_represented(); |
| if (renderbuffer_manager_.get()) |
| total += renderbuffer_manager_->mem_represented(); |
| if (texture_manager_.get()) |
| total += texture_manager_->mem_represented(); |
| return total; |
| } |
| |
| ContextGroup::~ContextGroup() { |
| CHECK(num_contexts_ == 0); |
| } |
| |
| bool ContextGroup::CheckGLFeature(GLint min_required, GLint* v) { |
| GLint value = *v; |
| if (enforce_gl_minimums_) { |
| value = std::min(min_required, value); |
| } |
| *v = value; |
| return value >= min_required; |
| } |
| |
| bool ContextGroup::CheckGLFeatureU(GLint min_required, uint32* v) { |
| GLint value = *v; |
| if (enforce_gl_minimums_) { |
| value = std::min(min_required, value); |
| } |
| *v = value; |
| return value >= min_required; |
| } |
| |
| bool ContextGroup::QueryGLFeature( |
| GLenum pname, GLint min_required, GLint* v) { |
| GLint value = 0; |
| glGetIntegerv(pname, &value); |
| *v = value; |
| return CheckGLFeature(min_required, v); |
| } |
| |
| bool ContextGroup::QueryGLFeatureU( |
| GLenum pname, GLint min_required, uint32* v) { |
| uint32 value = 0; |
| GetIntegerv(pname, &value); |
| bool result = CheckGLFeatureU(min_required, &value); |
| *v = value; |
| return result; |
| } |
| |
| } // namespace gles2 |
| } // namespace gpu |