| // 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 <stddef.h> |
| #include <stdint.h> |
| |
| #include <algorithm> |
| #include <string> |
| |
| #include "base/command_line.h" |
| #include "gpu/command_buffer/service/buffer_manager.h" |
| #include "gpu/command_buffer/service/framebuffer_manager.h" |
| #include "gpu/command_buffer/service/gpu_preferences.h" |
| #include "gpu/command_buffer/service/mailbox_manager_impl.h" |
| #include "gpu/command_buffer/service/path_manager.h" |
| #include "gpu/command_buffer/service/program_manager.h" |
| #include "gpu/command_buffer/service/renderbuffer_manager.h" |
| #include "gpu/command_buffer/service/sampler_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_bindings.h" |
| #include "ui/gl/gl_version_info.h" |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| namespace { |
| |
| void GetIntegerv(GLenum pname, uint32_t* var) { |
| GLint value = 0; |
| glGetIntegerv(pname, &value); |
| *var = value; |
| } |
| |
| DisallowedFeatures AdjustDisallowedFeatures( |
| ContextType context_type, const DisallowedFeatures& disallowed_features) { |
| DisallowedFeatures adjusted_disallowed_features = disallowed_features; |
| if (context_type == CONTEXT_TYPE_WEBGL1) { |
| adjusted_disallowed_features.npot_support = true; |
| adjusted_disallowed_features.oes_texture_half_float_linear = true; |
| } |
| if (context_type == CONTEXT_TYPE_WEBGL1 || |
| context_type == CONTEXT_TYPE_WEBGL2) { |
| adjusted_disallowed_features.chromium_color_buffer_float_rgba = true; |
| adjusted_disallowed_features.chromium_color_buffer_float_rgb = true; |
| adjusted_disallowed_features.ext_color_buffer_float = true; |
| adjusted_disallowed_features.oes_texture_float_linear = true; |
| } |
| return adjusted_disallowed_features; |
| } |
| |
| } // namespace anonymous |
| |
| ContextGroup::ContextGroup( |
| const GpuPreferences& gpu_preferences, |
| const scoped_refptr<MailboxManager>& mailbox_manager, |
| const scoped_refptr<MemoryTracker>& memory_tracker, |
| const scoped_refptr<ShaderTranslatorCache>& shader_translator_cache, |
| const scoped_refptr<FramebufferCompletenessCache>& |
| framebuffer_completeness_cache, |
| const scoped_refptr<FeatureInfo>& feature_info, |
| bool bind_generates_resource, |
| gpu::ImageFactory* image_factory) |
| : gpu_preferences_(gpu_preferences), |
| mailbox_manager_(mailbox_manager), |
| memory_tracker_(memory_tracker), |
| shader_translator_cache_(shader_translator_cache), |
| #if defined(OS_MACOSX) |
| // Framebuffer completeness is not cacheable on OS X because of dynamic |
| // graphics switching. |
| // http://crbug.com/180876 |
| // TODO(tobiasjs): determine whether GPU switching is possible |
| // programmatically, rather than just hardcoding this behaviour |
| // for OS X. |
| framebuffer_completeness_cache_(NULL), |
| #else |
| framebuffer_completeness_cache_(framebuffer_completeness_cache), |
| #endif |
| enforce_gl_minimums_(gpu_preferences_.enforce_gl_minimums), |
| 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), |
| max_color_attachments_(1u), |
| max_draw_buffers_(1u), |
| max_dual_source_draw_buffers_(0u), |
| max_vertex_output_components_(0u), |
| max_fragment_input_components_(0u), |
| min_program_texel_offset_(0), |
| max_program_texel_offset_(0), |
| max_transform_feedback_separate_attribs_(0u), |
| max_uniform_buffer_bindings_(0u), |
| uniform_buffer_offset_alignment_(1u), |
| program_cache_(NULL), |
| feature_info_(feature_info), |
| image_factory_(image_factory) { |
| { |
| DCHECK(feature_info_); |
| if (!mailbox_manager_.get()) |
| mailbox_manager_ = new MailboxManagerImpl; |
| transfer_buffer_manager_ = new TransferBufferManager(memory_tracker_.get()); |
| } |
| } |
| |
| bool ContextGroup::Initialize(GLES2Decoder* decoder, |
| ContextType context_type, |
| const DisallowedFeatures& disallowed_features) { |
| if (HaveContexts()) { |
| if (context_type != feature_info_->context_type()) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because the type of " |
| << "the context does not fit with the group."; |
| return false; |
| } |
| // If we've already initialized the group just add the context. |
| decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder)); |
| return true; |
| } |
| |
| DisallowedFeatures adjusted_disallowed_features = |
| AdjustDisallowedFeatures(context_type, disallowed_features); |
| |
| if (!feature_info_->Initialize(context_type, adjusted_disallowed_features)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because FeatureInfo " |
| << "initialization failed."; |
| return false; |
| } |
| |
| transfer_buffer_manager_->Initialize(); |
| |
| const GLint kMinRenderbufferSize = 512; // GL says 1 pixel! |
| GLint max_renderbuffer_size = 0; |
| if (!QueryGLFeature( |
| GL_MAX_RENDERBUFFER_SIZE, kMinRenderbufferSize, |
| &max_renderbuffer_size)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "renderbuffer size too small (" << max_renderbuffer_size |
| << ", should be " << kMinRenderbufferSize << ")."; |
| return false; |
| } |
| GLint max_samples = 0; |
| if (feature_info_->feature_flags().chromium_framebuffer_multisample || |
| feature_info_->feature_flags().multisampled_render_to_texture) { |
| if (feature_info_->feature_flags( |
| ).use_img_for_multisampled_render_to_texture) { |
| glGetIntegerv(GL_MAX_SAMPLES_IMG, &max_samples); |
| } else { |
| glGetIntegerv(GL_MAX_SAMPLES, &max_samples); |
| } |
| } |
| |
| if (feature_info_->feature_flags().ext_draw_buffers) { |
| GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &max_color_attachments_); |
| if (max_color_attachments_ < 1) |
| max_color_attachments_ = 1; |
| if (max_color_attachments_ > 16) |
| max_color_attachments_ = 16; |
| GetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &max_draw_buffers_); |
| if (max_draw_buffers_ < 1) |
| max_draw_buffers_ = 1; |
| if (max_draw_buffers_ > 16) |
| max_draw_buffers_ = 16; |
| } |
| if (feature_info_->feature_flags().ext_blend_func_extended) { |
| GetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, |
| &max_dual_source_draw_buffers_); |
| DCHECK(max_dual_source_draw_buffers_ >= 1); |
| } |
| |
| if (feature_info_->gl_version_info().is_es3_capable) { |
| const GLint kMinTransformFeedbackSeparateAttribs = 4; |
| if (!QueryGLFeatureU(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, |
| kMinTransformFeedbackSeparateAttribs, |
| &max_transform_feedback_separate_attribs_)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "transform feedback separate attribs is too small (" |
| << max_transform_feedback_separate_attribs_ << ", should be " |
| << kMinTransformFeedbackSeparateAttribs << ")."; |
| return false; |
| } |
| |
| const GLint kMinUniformBufferBindings = 24; |
| if (!QueryGLFeatureU(GL_MAX_UNIFORM_BUFFER_BINDINGS, |
| kMinUniformBufferBindings, |
| &max_uniform_buffer_bindings_)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "uniform buffer bindings is too small (" |
| << max_uniform_buffer_bindings_ << ", should be " |
| << kMinUniformBufferBindings << ")."; |
| return false; |
| } |
| |
| // TODO(zmo): Should we check max UNIFORM_BUFFER_OFFSET_ALIGNMENT is 256? |
| GetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, |
| &uniform_buffer_offset_alignment_); |
| } |
| |
| buffer_manager_.reset( |
| new BufferManager(memory_tracker_.get(), feature_info_.get())); |
| framebuffer_manager_.reset(new FramebufferManager( |
| max_draw_buffers_, max_color_attachments_, feature_info_->context_type(), |
| framebuffer_completeness_cache_)); |
| renderbuffer_manager_.reset(new RenderbufferManager( |
| memory_tracker_.get(), max_renderbuffer_size, max_samples, |
| feature_info_.get())); |
| shader_manager_.reset(new ShaderManager()); |
| sampler_manager_.reset(new SamplerManager(feature_info_.get())); |
| |
| // Lookup GL things we need to know. |
| const GLint kGLES2RequiredMinimumVertexAttribs = 8u; |
| if (!QueryGLFeatureU( |
| GL_MAX_VERTEX_ATTRIBS, kGLES2RequiredMinimumVertexAttribs, |
| &max_vertex_attribs_)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because too few " |
| << "vertex attributes supported (" << max_vertex_attribs_ |
| << ", should be " << kGLES2RequiredMinimumVertexAttribs << ")."; |
| return false; |
| } |
| |
| const GLuint kGLES2RequiredMinimumTextureUnits = 8u; |
| if (!QueryGLFeatureU( |
| GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, kGLES2RequiredMinimumTextureUnits, |
| &max_texture_units_)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because too few " |
| << "texture units supported (" << max_texture_units_ |
| << ", should be " << kGLES2RequiredMinimumTextureUnits << ")."; |
| return false; |
| } |
| |
| GLint max_texture_size = 0; |
| GLint max_cube_map_texture_size = 0; |
| GLint max_rectangle_texture_size = 0; |
| GLint max_3d_texture_size = 0; |
| GLint max_array_texture_layers = 0; |
| |
| const GLint kMinTextureSize = 2048; // GL actually says 64!?!? |
| const GLint kMinCubeMapSize = 256; // GL actually says 16!?!? |
| const GLint kMinRectangleTextureSize = 64; |
| const GLint kMin3DTextureSize = 256; |
| const GLint kMinArrayTextureLayers = 256; |
| |
| if (!QueryGLFeature(GL_MAX_TEXTURE_SIZE, kMinTextureSize, |
| &max_texture_size)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "2d texture size is too small (" << max_texture_size |
| << ", should be " << kMinTextureSize << ")."; |
| return false; |
| } |
| if (!QueryGLFeature(GL_MAX_CUBE_MAP_TEXTURE_SIZE, kMinCubeMapSize, |
| &max_cube_map_texture_size)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "cube texture size is too small (" |
| << max_cube_map_texture_size << ", should be " |
| << kMinCubeMapSize << ")."; |
| return false; |
| } |
| if (feature_info_->gl_version_info().is_es3_capable && |
| !QueryGLFeature(GL_MAX_3D_TEXTURE_SIZE, kMin3DTextureSize, |
| &max_3d_texture_size)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "3d texture size is too small (" << max_3d_texture_size |
| << ", should be " << kMin3DTextureSize << ")."; |
| return false; |
| } |
| if (feature_info_->gl_version_info().is_es3_capable && |
| !QueryGLFeature(GL_MAX_ARRAY_TEXTURE_LAYERS, kMinArrayTextureLayers, |
| &max_array_texture_layers)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "array texture layers is too small (" |
| << max_array_texture_layers |
| << ", should be " << kMinArrayTextureLayers << ")."; |
| return false; |
| } |
| if (feature_info_->feature_flags().arb_texture_rectangle && |
| !QueryGLFeature(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, |
| kMinRectangleTextureSize, &max_rectangle_texture_size)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "rectangle texture size is too small (" |
| << max_rectangle_texture_size << ", should be " |
| << kMinRectangleTextureSize << ")."; |
| return false; |
| } |
| |
| if (feature_info_->workarounds().max_texture_size) { |
| max_texture_size = std::min( |
| max_texture_size, |
| feature_info_->workarounds().max_texture_size); |
| max_rectangle_texture_size = std::min( |
| max_rectangle_texture_size, |
| feature_info_->workarounds().max_texture_size); |
| } |
| |
| texture_manager_.reset(new TextureManager(memory_tracker_.get(), |
| feature_info_.get(), |
| max_texture_size, |
| max_cube_map_texture_size, |
| max_rectangle_texture_size, |
| max_3d_texture_size, |
| max_array_texture_layers, |
| bind_generates_resource_)); |
| texture_manager_->set_framebuffer_manager(framebuffer_manager_.get()); |
| |
| const GLint kMinTextureImageUnits = 8; |
| const GLint kMinVertexTextureImageUnits = 0; |
| if (!QueryGLFeatureU(GL_MAX_TEXTURE_IMAGE_UNITS, kMinTextureImageUnits, |
| &max_texture_image_units_)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because too few " |
| << "texture image units supported (" |
| << max_texture_image_units_ |
| << ", should be " << kMinTextureImageUnits << ")."; |
| } |
| if (!QueryGLFeatureU(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, |
| kMinVertexTextureImageUnits, |
| &max_vertex_texture_image_units_)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because too few " |
| << "vertex texture image units supported (" |
| << max_vertex_texture_image_units_ << ", should be " |
| << kMinTextureImageUnits << ")."; |
| return false; |
| } |
| |
| if (feature_info_->gl_version_info().BehavesLikeGLES()) { |
| 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_)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because too few " |
| << "uniforms or varyings supported."; |
| return false; |
| } |
| |
| // Some shaders in Skia need more than the min available vertex and |
| // fragment shader uniform vectors in case of OSMesa GL Implementation |
| if (feature_info_->workarounds().max_fragment_uniform_vectors) { |
| max_fragment_uniform_vectors_ = std::min( |
| max_fragment_uniform_vectors_, |
| static_cast<uint32_t>( |
| feature_info_->workarounds().max_fragment_uniform_vectors)); |
| } |
| if (feature_info_->workarounds().max_varying_vectors) { |
| max_varying_vectors_ = |
| std::min(max_varying_vectors_, |
| static_cast<uint32_t>( |
| feature_info_->workarounds().max_varying_vectors)); |
| } |
| if (feature_info_->workarounds().max_vertex_uniform_vectors) { |
| max_vertex_uniform_vectors_ = |
| std::min(max_vertex_uniform_vectors_, |
| static_cast<uint32_t>( |
| feature_info_->workarounds().max_vertex_uniform_vectors)); |
| } |
| |
| if (context_type != CONTEXT_TYPE_WEBGL1 && |
| context_type != CONTEXT_TYPE_OPENGLES2) { |
| const GLuint kMinVertexOutputComponents = 64; |
| const GLuint kMinFragmentInputComponents = 60; |
| const GLint kMin_MaxProgramTexelOffset = 7; |
| const GLint kMax_MinProgramTexelOffset = -8; |
| |
| if (!QueryGLFeatureU(GL_MAX_VERTEX_OUTPUT_COMPONENTS, |
| kMinVertexOutputComponents, |
| &max_vertex_output_components_)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "vertex output components is too small (" |
| << max_vertex_output_components_ << ", should be " |
| << kMinVertexOutputComponents << ")."; |
| return false; |
| } |
| if (!QueryGLFeatureU(GL_MAX_FRAGMENT_INPUT_COMPONENTS, |
| kMinFragmentInputComponents, |
| &max_fragment_input_components_)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "fragment input components is too small (" |
| << max_fragment_input_components_ << ", should be " |
| << kMinFragmentInputComponents << ")."; |
| return false; |
| } |
| if (!QueryGLFeature(GL_MAX_PROGRAM_TEXEL_OFFSET, kMin_MaxProgramTexelOffset, |
| &max_program_texel_offset_)) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "program texel offset is too small (" |
| << max_program_texel_offset_ << ", should be " |
| << kMin_MaxProgramTexelOffset << ")."; |
| return false; |
| } |
| glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &min_program_texel_offset_); |
| if (enforce_gl_minimums_) { |
| min_program_texel_offset_ = |
| std::max(min_program_texel_offset_, kMax_MinProgramTexelOffset); |
| } |
| if (min_program_texel_offset_ > kMax_MinProgramTexelOffset) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because minimum " |
| << "program texel offset is too big (" |
| << min_program_texel_offset_ << ", should be " |
| << kMax_MinProgramTexelOffset << ")."; |
| return false; |
| } |
| |
| const GLint kES3MinCubeMapSize = 2048; |
| if (max_cube_map_texture_size < kES3MinCubeMapSize) { |
| DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " |
| << "cube texture size is too small (" |
| << max_cube_map_texture_size << ", should be " |
| << kES3MinCubeMapSize << ")."; |
| return false; |
| } |
| } |
| |
| path_manager_.reset(new PathManager()); |
| |
| program_manager_.reset( |
| new ProgramManager(program_cache_, |
| max_varying_vectors_, |
| max_draw_buffers_, |
| max_dual_source_draw_buffers_, |
| max_vertex_attribs_, |
| gpu_preferences_, |
| feature_info_.get())); |
| |
| if (!texture_manager_->Initialize()) { |
| DLOG(ERROR) << "Context::Group::Initialize failed because texture manager " |
| << "failed to initialize."; |
| return false; |
| } |
| |
| decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder)); |
| return true; |
| } |
| |
| namespace { |
| |
| bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) { |
| return !decoder.get(); |
| } |
| |
| template <typename T> |
| class WeakPtrEquals { |
| public: |
| explicit WeakPtrEquals(T* t) : t_(t) {} |
| |
| bool operator()(const base::WeakPtr<T>& t) { |
| return t.get() == t_; |
| } |
| |
| private: |
| T* const t_; |
| }; |
| |
| } // namespace anonymous |
| |
| bool ContextGroup::HaveContexts() { |
| decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), IsNull), |
| decoders_.end()); |
| return !decoders_.empty(); |
| } |
| |
| void ContextGroup::Destroy(GLES2Decoder* decoder, bool have_context) { |
| decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), |
| WeakPtrEquals<gles2::GLES2Decoder>(decoder)), |
| decoders_.end()); |
| // If we still have contexts do nothing. |
| if (HaveContexts()) { |
| return; |
| } |
| |
| if (buffer_manager_ != nullptr) { |
| if (!have_context) { |
| buffer_manager_->MarkContextLost(); |
| } |
| buffer_manager_->Destroy(); |
| buffer_manager_.reset(); |
| } |
| |
| if (framebuffer_manager_ != NULL) { |
| framebuffer_manager_->Destroy(have_context); |
| if (texture_manager_) |
| texture_manager_->set_framebuffer_manager(NULL); |
| framebuffer_manager_.reset(); |
| } |
| |
| if (renderbuffer_manager_ != NULL) { |
| renderbuffer_manager_->Destroy(have_context); |
| renderbuffer_manager_.reset(); |
| } |
| |
| if (texture_manager_ != NULL) { |
| texture_manager_->Destroy(have_context); |
| texture_manager_.reset(); |
| } |
| |
| if (path_manager_ != NULL) { |
| path_manager_->Destroy(have_context); |
| path_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(); |
| } |
| |
| if (sampler_manager_ != NULL) { |
| sampler_manager_->Destroy(have_context); |
| sampler_manager_.reset(); |
| } |
| |
| memory_tracker_ = NULL; |
| } |
| |
| uint32_t ContextGroup::GetMemRepresented() const { |
| uint32_t 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; |
| } |
| |
| void ContextGroup::LoseContexts(error::ContextLostReason reason) { |
| for (size_t ii = 0; ii < decoders_.size(); ++ii) { |
| if (decoders_[ii].get()) { |
| decoders_[ii]->MarkContextLost(reason); |
| } |
| } |
| if (buffer_manager_ != nullptr) { |
| buffer_manager_->MarkContextLost(); |
| } |
| } |
| |
| ContextGroup::~ContextGroup() { |
| CHECK(!HaveContexts()); |
| } |
| |
| 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_t* 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_t* v) { |
| uint32_t value = 0; |
| GetIntegerv(pname, &value); |
| bool result = CheckGLFeatureU(min_required, &value); |
| *v = value; |
| return result; |
| } |
| |
| bool ContextGroup::GetBufferServiceId( |
| GLuint client_id, GLuint* service_id) const { |
| Buffer* buffer = buffer_manager_->GetBuffer(client_id); |
| if (!buffer) |
| return false; |
| *service_id = buffer->service_id(); |
| return true; |
| } |
| |
| } // namespace gles2 |
| } // namespace gpu |