// Copyright (c) 2010 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 #include #include "app/gfx/gl/gl_implementation.h" #include "gpu/command_buffer/service/feature_info.h" #include "gpu/command_buffer/service/gl_utils.h" #include "gpu/GLES2/gles2_command_buffer.h" namespace gpu { namespace gles2 { FeatureInfo::FeatureInfo() { } // Helps query for extensions. class ExtensionHelper { public: ExtensionHelper(const char* extensions, const char* desired_features) : desire_all_features_(false) { // Check for "*" if (desired_features && desired_features[0] == '*' && desired_features[1] == '\0') { desired_features = NULL; } InitStringSet(extensions, &have_extensions_); InitStringSet(desired_features, &desired_extensions_); if (!desired_features) { desire_all_features_ = true; } } // Returns true if extension exists. bool Have(const char* extension) { return have_extensions_.find(extension) != have_extensions_.end(); } // Returns true of an extension is desired. It may not exist. bool Desire(const char* extension) { return desire_all_features_ || desired_extensions_.find(extension) != desired_extensions_.end(); } // Returns true if an extension exists and is desired. bool HaveAndDesire(const char* extension) { return Have(extension) && Desire(extension); } private: void InitStringSet(const char* s, std::set* string_set) { std::string str(s ? s : ""); std::string::size_type lastPos = 0; while (true) { std::string::size_type pos = str.find_first_of(" ", lastPos); if (pos != std::string::npos) { if (pos - lastPos) { string_set->insert(str.substr(lastPos, pos - lastPos)); } lastPos = pos + 1; } else { string_set->insert(str.substr(lastPos)); break; } } } bool desire_all_features_; // Extensions that exist. std::set have_extensions_; // Extensions that are desired but may not exist. std::set desired_extensions_; }; bool FeatureInfo::Initialize(const char* allowed_features) { AddFeatures(allowed_features); return true; } void FeatureInfo::AddFeatures(const char* desired_features) { // Figure out what extensions to turn on. ExtensionHelper ext( reinterpret_cast(glGetString(GL_EXTENSIONS)), desired_features); bool npot_ok = false; AddExtensionString("GL_CHROMIUM_map_sub"); AddExtensionString("GL_CHROMIUM_copy_texture_to_parent_texture"); AddExtensionString("GL_CHROMIUM_resource_safe"); AddExtensionString("GL_CHROMIUM_resize"); AddExtensionString("GL_CHROMIUM_strict_attribs"); // Only turn this feature on if it is requested. Not by default. if (desired_features && ext.Desire("GL_CHROMIUM_webglsl")) { AddExtensionString("GL_CHROMIUM_webglsl"); feature_flags_.chromium_webglsl = true; } // Check if we should allow GL_EXT_texture_compression_dxt1 and // GL_EXT_texture_compression_s3tc. bool enable_dxt1 = false; bool enable_s3tc = false; if (ext.HaveAndDesire("GL_EXT_texture_compression_dxt1")) { enable_dxt1 = true; } if (ext.HaveAndDesire("GL_EXT_texture_compression_s3tc")) { enable_dxt1 = true; enable_s3tc = true; } if (enable_dxt1) { AddExtensionString("GL_EXT_texture_compression_dxt1"); validators_.compressed_texture_format.AddValue( GL_COMPRESSED_RGB_S3TC_DXT1_EXT); validators_.compressed_texture_format.AddValue( GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); } if (enable_s3tc) { AddExtensionString("GL_EXT_texture_compression_s3tc"); validators_.compressed_texture_format.AddValue( GL_COMPRESSED_RGBA_S3TC_DXT3_EXT); validators_.compressed_texture_format.AddValue( GL_COMPRESSED_RGBA_S3TC_DXT5_EXT); } // Check if we should enable GL_EXT_texture_filter_anisotropic. if (ext.HaveAndDesire("GL_EXT_texture_filter_anisotropic")) { AddExtensionString("GL_EXT_texture_filter_anisotropic"); validators_.texture_parameter.AddValue( GL_TEXTURE_MAX_ANISOTROPY_EXT); validators_.g_l_state.AddValue( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT); } // Check if we should support GL_OES_packed_depth_stencil and/or // GL_GOOGLE_depth_texture. // NOTE: GL_OES_depth_texture requires support for depth // cubemaps. GL_ARB_depth_texture requires other features that // GL_OES_packed_depth_stencil does not provide. Therefore we made up // GL_GOOGLE_depth_texture. bool enable_depth_texture = false; if (ext.Desire("GL_GOOGLE_depth_texture") && (ext.Have("GL_ARB_depth_texture") || ext.Have("GL_OES_depth_texture"))) { enable_depth_texture = true; AddExtensionString("GL_GOOGLE_depth_texture"); validators_.texture_internal_format.AddValue(GL_DEPTH_COMPONENT); validators_.texture_format.AddValue(GL_DEPTH_COMPONENT); validators_.pixel_type.AddValue(GL_UNSIGNED_SHORT); validators_.pixel_type.AddValue(GL_UNSIGNED_INT); } // TODO(gman): Add depth types fo ElementsPerGroup and BytesPerElement if (ext.Desire("GL_OES_packed_depth_stencil") && (ext.Have("GL_EXT_packed_depth_stencil") || ext.Have("GL_OES_packed_depth_stencil"))) { AddExtensionString("GL_OES_packed_depth_stencil"); if (enable_depth_texture) { validators_.texture_internal_format.AddValue(GL_DEPTH_STENCIL); validators_.texture_format.AddValue(GL_DEPTH_STENCIL); validators_.pixel_type.AddValue(GL_UNSIGNED_INT_24_8); } validators_.render_buffer_format.AddValue(GL_DEPTH24_STENCIL8); } bool enable_texture_format_bgra8888 = false; bool enable_read_format_bgra = false; // Check if we should allow GL_EXT_texture_format_BGRA8888 if (ext.Desire("GL_EXT_texture_format_BGRA8888") && (ext.Have("GL_EXT_texture_format_BGRA8888") || ext.Have("GL_APPLE_texture_format_BGRA8888") || ext.Have("GL_EXT_bgra"))) { enable_texture_format_bgra8888 = true; } if (ext.HaveAndDesire("GL_EXT_bgra")) { enable_texture_format_bgra8888 = true; enable_read_format_bgra = true; } if (ext.Desire("GL_EXT_read_format_bgra") && (ext.Have("GL_EXT_read_format_bgra") || ext.Have("GL_EXT_bgra"))) { enable_read_format_bgra = true; } if (enable_texture_format_bgra8888) { AddExtensionString("GL_EXT_texture_format_BGRA8888"); validators_.texture_internal_format.AddValue(GL_BGRA_EXT); validators_.texture_format.AddValue(GL_BGRA_EXT); } if (enable_read_format_bgra) { AddExtensionString("GL_EXT_read_format_bgra"); validators_.read_pixel_format.AddValue(GL_BGRA_EXT); } if (ext.Desire("GL_OES_rgb8_rgba8")) { if (ext.Have("GL_OES_rgb8_rgba8") || gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL) { AddExtensionString("GL_OES_rgb8_rgba8"); validators_.render_buffer_format.AddValue(GL_RGB8_OES); validators_.render_buffer_format.AddValue(GL_RGBA8_OES); } } // Check if we should allow GL_OES_texture_npot if (ext.Desire("GL_OES_texture_npot") && (ext.Have("GL_ARB_texture_non_power_of_two") || ext.Have("GL_OES_texture_npot"))) { AddExtensionString("GL_OES_texture_npot"); npot_ok = true; } // Check if we should allow GL_OES_texture_float, GL_OES_texture_half_float, // GL_OES_texture_float_linear, GL_OES_texture_half_float_linear bool enable_texture_float = false; bool enable_texture_float_linear = false; bool enable_texture_half_float = false; bool enable_texture_half_float_linear = false; bool have_arb_texture_float = ext.Have("GL_ARB_texture_float"); if (have_arb_texture_float && ext.Desire("GL_ARB_texture_float")) { enable_texture_float = true; enable_texture_float_linear = true; enable_texture_half_float = true; enable_texture_half_float_linear = true; } else { if (ext.HaveAndDesire("GL_OES_texture_float") || (have_arb_texture_float && ext.Desire("GL_OES_texture_float"))) { enable_texture_float = true; if (ext.HaveAndDesire("GL_OES_texture_float_linear") || (have_arb_texture_float && ext.Desire("GL_OES_texture_float_linear"))) { enable_texture_float_linear = true; } } if (ext.HaveAndDesire("GL_OES_texture_half_float") || (have_arb_texture_float && ext.Desire("GL_OES_texture_half_float"))) { enable_texture_half_float = true; if (ext.HaveAndDesire("GL_OES_texture_half_float_linear") || (have_arb_texture_float && ext.Desire("GL_OES_texture_half_float_linear"))) { enable_texture_half_float_linear = true; } } } if (enable_texture_float) { validators_.pixel_type.AddValue(GL_FLOAT); AddExtensionString("GL_OES_texture_float"); if (enable_texture_float_linear) { AddExtensionString("GL_OES_texture_float_linear"); } } if (enable_texture_half_float) { validators_.pixel_type.AddValue(GL_HALF_FLOAT_OES); AddExtensionString("GL_OES_texture_half_float"); if (enable_texture_half_float_linear) { AddExtensionString("GL_OES_texture_half_float_linear"); } } // Check for multisample support if (ext.Desire("GL_CHROMIUM_framebuffer_multisample") && (ext.Have("GL_EXT_framebuffer_multisample") || ext.Have("GL_ANGLE_framebuffer_multisample"))) { feature_flags_.chromium_framebuffer_multisample = true; validators_.frame_buffer_target.AddValue(GL_READ_FRAMEBUFFER_EXT); validators_.frame_buffer_target.AddValue(GL_DRAW_FRAMEBUFFER_EXT); validators_.g_l_state.AddValue(GL_READ_FRAMEBUFFER_BINDING_EXT); validators_.g_l_state.AddValue(GL_MAX_SAMPLES_EXT); validators_.render_buffer_parameter.AddValue(GL_RENDERBUFFER_SAMPLES_EXT); AddExtensionString("GL_CHROMIUM_framebuffer_multisample"); } if (ext.HaveAndDesire("GL_OES_depth24") || (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL && ext.Desire("GL_OES_depth24"))) { AddExtensionString("GL_OES_depth24"); validators_.render_buffer_format.AddValue(GL_DEPTH_COMPONENT24); } if (ext.HaveAndDesire("GL_OES_standard_derivatives") || (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL && ext.Desire("GL_OES_standard_derivatives"))) { AddExtensionString("GL_OES_standard_derivatives"); feature_flags_.oes_standard_derivatives = true; validators_.hint_target.AddValue(GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES); validators_.g_l_state.AddValue(GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES); } // TODO(gman): Add support for these extensions. // GL_OES_depth32 // GL_OES_element_index_uint feature_flags_.enable_texture_float_linear = enable_texture_float_linear; feature_flags_.enable_texture_half_float_linear = enable_texture_half_float_linear; feature_flags_.npot_ok = npot_ok; } void FeatureInfo::AddExtensionString(const std::string& str) { if (extensions_.find(str) == std::string::npos) { extensions_ += (extensions_.empty() ? "" : " ") + str; } } } // namespace gles2 } // namespace gpu