michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: #include "GLContext.h" michael@0: #include "nsPrintfCString.h" michael@0: michael@0: #ifdef XP_MACOSX michael@0: #include "nsCocoaFeatures.h" michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: namespace gl { michael@0: michael@0: const size_t kMAX_EXTENSION_GROUP_SIZE = 5; michael@0: michael@0: // ARB_ES2_compatibility is natively supported in OpenGL 4.1. michael@0: static const unsigned int kGLCoreVersionForES2Compat = 410; michael@0: michael@0: // ARB_ES3_compatibility is natively supported in OpenGL 4.3. michael@0: static const unsigned int kGLCoreVersionForES3Compat = 430; michael@0: michael@0: struct FeatureInfo michael@0: { michael@0: const char* mName; michael@0: unsigned int mOpenGLVersion; michael@0: unsigned int mOpenGLESVersion; michael@0: GLContext::GLExtensions mExtensions[kMAX_EXTENSION_GROUP_SIZE]; michael@0: }; michael@0: michael@0: static const FeatureInfo sFeatureInfoArr[] = { michael@0: { michael@0: "bind_buffer_offset", michael@0: 0, // OpenGL version michael@0: 0, // OpenGL ES version michael@0: { michael@0: GLContext::EXT_transform_feedback, michael@0: GLContext::NV_transform_feedback, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "blend_minmax", michael@0: 200, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::EXT_blend_minmax, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "depth_texture", michael@0: 200, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_depth_texture, michael@0: GLContext::OES_depth_texture, michael@0: // Intentionally avoid putting ANGLE_depth_texture here, michael@0: // it does not offer quite the same functionality. michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "draw_buffers", michael@0: 200, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_draw_buffers, michael@0: GLContext::EXT_draw_buffers, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "draw_instanced", michael@0: 310, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_draw_instanced, michael@0: GLContext::EXT_draw_instanced, michael@0: GLContext::NV_draw_instanced, michael@0: GLContext::ANGLE_instanced_arrays, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "draw_range_elements", michael@0: 120, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::EXT_draw_range_elements, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "element_index_uint", michael@0: 200, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::OES_element_index_uint, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "ES2_compatibility", michael@0: kGLCoreVersionForES2Compat, michael@0: 200, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_ES2_compatibility, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "ES3_compatibility", michael@0: kGLCoreVersionForES3Compat, michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_ES3_compatibility, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: // Removes clamping for float color outputs from frag shaders. michael@0: "frag_color_float", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_color_buffer_float, michael@0: GLContext::EXT_color_buffer_float, michael@0: GLContext::EXT_color_buffer_half_float, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "frag_depth", michael@0: 200, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::EXT_frag_depth, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "framebuffer_blit", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::EXT_framebuffer_blit, michael@0: GLContext::ANGLE_framebuffer_blit, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "framebuffer_multisample", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::EXT_framebuffer_multisample, michael@0: GLContext::ANGLE_framebuffer_multisample, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "framebuffer_object", michael@0: 300, // OpenGL version michael@0: 200, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_framebuffer_object, michael@0: GLContext::EXT_framebuffer_object, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "get_query_object_iv", michael@0: 200, // OpenGL version michael@0: 0, // OpenGL ES version michael@0: { michael@0: GLContext::Extensions_End michael@0: } michael@0: /* michael@0: * XXX_get_query_object_iv only provide GetQueryObjectiv provided by michael@0: * ARB_occlusion_query (added by OpenGL 2.0). michael@0: */ michael@0: }, michael@0: { michael@0: "instanced_arrays", michael@0: 330, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_instanced_arrays, michael@0: GLContext::NV_instanced_arrays, michael@0: GLContext::ANGLE_instanced_arrays, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "instanced_non_arrays", michael@0: 330, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_instanced_arrays, michael@0: GLContext::Extensions_End michael@0: } michael@0: /* This is an expanded version of `instanced_arrays` that allows for all michael@0: * enabled active attrib arrays to have non-zero divisors. michael@0: * ANGLE_instanced_arrays and NV_instanced_arrays forbid this, but GLES3 michael@0: * has no such restriction. michael@0: */ michael@0: }, michael@0: { michael@0: "occlusion_query", michael@0: 200, // OpenGL version michael@0: 0, // OpenGL ES version michael@0: { michael@0: GLContext::Extensions_End michael@0: } michael@0: // XXX_occlusion_query depend on ARB_occlusion_query (added in OpenGL 2.0) michael@0: }, michael@0: { michael@0: "occlusion_query_boolean", michael@0: kGLCoreVersionForES3Compat, michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_ES3_compatibility, michael@0: GLContext::EXT_occlusion_query_boolean, michael@0: GLContext::Extensions_End michael@0: } michael@0: /* michael@0: * XXX_occlusion_query_boolean provide ANY_SAMPLES_PASSED_CONSERVATIVE, michael@0: * but EXT_occlusion_query_boolean is only a OpenGL ES extension. But michael@0: * it is supported on desktop if ARB_ES3_compatibility because michael@0: * EXT_occlusion_query_boolean (added in OpenGL ES 3.0). michael@0: */ michael@0: }, michael@0: { michael@0: "occlusion_query2", michael@0: 330, // = min(330, kGLCoreVersionForES3Compat), michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_occlusion_query2, michael@0: GLContext::ARB_ES3_compatibility, michael@0: GLContext::EXT_occlusion_query_boolean, michael@0: GLContext::Extensions_End michael@0: } michael@0: /* michael@0: * XXX_occlusion_query2 (add in OpenGL 3.3) provide ANY_SAMPLES_PASSED, michael@0: * which is provided by ARB_occlusion_query2, EXT_occlusion_query_boolean michael@0: * (added in OpenGL ES 3.0) and ARB_ES3_compatibility michael@0: */ michael@0: }, michael@0: { michael@0: "packed_depth_stencil", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::EXT_packed_depth_stencil, michael@0: GLContext::OES_packed_depth_stencil, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "query_objects", michael@0: 200, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::EXT_occlusion_query_boolean, michael@0: GLContext::Extensions_End michael@0: } michael@0: /* michael@0: * XXX_query_objects only provide entry points commonly supported by michael@0: * ARB_occlusion_query (added in OpenGL 2.0) and EXT_occlusion_query_boolean michael@0: * (added in OpenGL ES 3.0) michael@0: */ michael@0: }, michael@0: { michael@0: "renderbuffer_float", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_texture_float, michael@0: GLContext::EXT_color_buffer_float, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "renderbuffer_half_float", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_texture_float, michael@0: GLContext::EXT_color_buffer_half_float, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "robustness", michael@0: 0, // OpenGL version michael@0: 0, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_robustness, michael@0: GLContext::EXT_robustness, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "sRGB", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::EXT_sRGB, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "standard_derivatives", michael@0: 200, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::OES_standard_derivatives, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "texture_float", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_texture_float, michael@0: GLContext::OES_texture_float, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "texture_float_linear", michael@0: 310, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_texture_float, michael@0: GLContext::OES_texture_float_linear, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "texture_half_float", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_half_float_pixel, michael@0: GLContext::ARB_texture_float, michael@0: GLContext::NV_half_float, michael@0: GLContext::Extensions_End michael@0: } michael@0: /** michael@0: * We are not including OES_texture_half_float in this feature, because: michael@0: * GL_HALF_FLOAT = 0x140B michael@0: * GL_HALF_FLOAT_ARB = 0x140B == GL_HALF_FLOAT michael@0: * GL_HALF_FLOAT_NV = 0x140B == GL_HALF_FLOAT michael@0: * GL_HALF_FLOAT_OES = 0x8D61 != GL_HALF_FLOAT michael@0: * WebGL handles this specifically with an OES_texture_half_float check. michael@0: */ michael@0: }, michael@0: { michael@0: "texture_half_float_linear", michael@0: 310, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_half_float_pixel, michael@0: GLContext::ARB_texture_float, michael@0: GLContext::NV_half_float, michael@0: GLContext::OES_texture_half_float_linear, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "texture_non_power_of_two", michael@0: 200, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_texture_non_power_of_two, michael@0: GLContext::OES_texture_npot, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "transform_feedback", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::EXT_transform_feedback, michael@0: GLContext::NV_transform_feedback, michael@0: GLContext::Extensions_End michael@0: } michael@0: }, michael@0: { michael@0: "vertex_array_object", michael@0: 300, // OpenGL version michael@0: 300, // OpenGL ES version michael@0: { michael@0: GLContext::ARB_vertex_array_object, michael@0: GLContext::OES_vertex_array_object, michael@0: GLContext::APPLE_vertex_array_object, michael@0: GLContext::Extensions_End michael@0: } michael@0: } michael@0: }; michael@0: michael@0: static inline const FeatureInfo& michael@0: GetFeatureInfo(GLFeature feature) michael@0: { michael@0: static_assert(MOZ_ARRAY_LENGTH(sFeatureInfoArr) == size_t(GLFeature::EnumMax), michael@0: "Mismatched lengths for sFeatureInfoInfos and GLFeature enums"); michael@0: michael@0: MOZ_ASSERT(feature < GLFeature::EnumMax, michael@0: "GLContext::GetFeatureInfoInfo : unknown "); michael@0: michael@0: return sFeatureInfoArr[size_t(feature)]; michael@0: } michael@0: michael@0: static inline uint32_t michael@0: ProfileVersionForFeature(GLFeature feature, ContextProfile profile) michael@0: { michael@0: MOZ_ASSERT(profile != ContextProfile::Unknown, michael@0: "GLContext::ProfileVersionForFeature : unknown "); michael@0: michael@0: const FeatureInfo& featureInfo = GetFeatureInfo(feature); michael@0: michael@0: if (profile == ContextProfile::OpenGLES) { michael@0: return featureInfo.mOpenGLESVersion; michael@0: } michael@0: michael@0: return featureInfo.mOpenGLVersion; michael@0: } michael@0: michael@0: static inline bool michael@0: IsFeatureIsPartOfProfileVersion(GLFeature feature, michael@0: ContextProfile profile, unsigned int version) michael@0: { michael@0: unsigned int profileVersion = ProfileVersionForFeature(feature, profile); michael@0: michael@0: /** michael@0: * if `profileVersion` is zero, it means that no version of the profile michael@0: * added support for the feature. michael@0: */ michael@0: return profileVersion && version >= profileVersion; michael@0: } michael@0: michael@0: const char* michael@0: GLContext::GetFeatureName(GLFeature feature) michael@0: { michael@0: return GetFeatureInfo(feature).mName; michael@0: } michael@0: michael@0: static bool michael@0: CanReadSRGBFromFBOTexture(GLContext* gl) michael@0: { michael@0: if (!gl->WorkAroundDriverBugs()) michael@0: return true; michael@0: michael@0: #ifdef XP_MACOSX michael@0: // Bug 843668: michael@0: // MacOSX 10.6 reports to support EXT_framebuffer_sRGB and michael@0: // EXT_texture_sRGB but fails to convert from sRGB to linear michael@0: // when writing to an sRGB texture attached to an FBO. michael@0: if (!nsCocoaFeatures::OnLionOrLater()) { michael@0: return false; michael@0: } michael@0: #endif // XP_MACOSX michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: GLContext::InitFeatures() michael@0: { michael@0: for (size_t feature_index = 0; feature_index < size_t(GLFeature::EnumMax); feature_index++) michael@0: { michael@0: GLFeature feature = GLFeature(feature_index); michael@0: michael@0: if (IsFeatureIsPartOfProfileVersion(feature, mProfile, mVersion)) { michael@0: mAvailableFeatures[feature_index] = true; michael@0: continue; michael@0: } michael@0: michael@0: mAvailableFeatures[feature_index] = false; michael@0: michael@0: const FeatureInfo& featureInfo = GetFeatureInfo(feature); michael@0: michael@0: for (size_t j = 0; true; j++) michael@0: { michael@0: MOZ_ASSERT(j < kMAX_EXTENSION_GROUP_SIZE, "kMAX_EXTENSION_GROUP_SIZE too small"); michael@0: michael@0: if (featureInfo.mExtensions[j] == GLContext::Extensions_End) { michael@0: break; michael@0: } michael@0: michael@0: if (IsExtensionSupported(featureInfo.mExtensions[j])) { michael@0: mAvailableFeatures[feature_index] = true; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Bug 843668: Work around limitation of the feature system. michael@0: // For sRGB support under OpenGL to match OpenGL ES spec, check for both michael@0: // EXT_texture_sRGB and EXT_framebuffer_sRGB is required. michael@0: const bool aresRGBExtensionsAvailable = michael@0: IsExtensionSupported(EXT_texture_sRGB) && michael@0: (IsExtensionSupported(ARB_framebuffer_sRGB) || michael@0: IsExtensionSupported(EXT_framebuffer_sRGB)); michael@0: michael@0: mAvailableFeatures[size_t(GLFeature::sRGB)] = michael@0: aresRGBExtensionsAvailable && michael@0: CanReadSRGBFromFBOTexture(this); michael@0: } michael@0: michael@0: void michael@0: GLContext::MarkUnsupported(GLFeature feature) michael@0: { michael@0: mAvailableFeatures[size_t(feature)] = false; michael@0: michael@0: const FeatureInfo& featureInfo = GetFeatureInfo(feature); michael@0: michael@0: for (size_t i = 0; true; i++) michael@0: { michael@0: MOZ_ASSERT(i < kMAX_EXTENSION_GROUP_SIZE, "kMAX_EXTENSION_GROUP_SIZE too small"); michael@0: michael@0: if (featureInfo.mExtensions[i] == GLContext::Extensions_End) { michael@0: break; michael@0: } michael@0: michael@0: MarkExtensionUnsupported(featureInfo.mExtensions[i]); michael@0: } michael@0: michael@0: MOZ_ASSERT(!IsSupported(feature), "GLContext::MarkUnsupported has failed!"); michael@0: michael@0: NS_WARNING(nsPrintfCString("%s marked as unsupported", GetFeatureName(feature)).get()); michael@0: } michael@0: michael@0: } /* namespace gl */ michael@0: } /* namespace mozilla */