diff --git a/components/canvas/webgl_limits.rs b/components/canvas/webgl_limits.rs index 0add74b3082..d910be71d99 100644 --- a/components/canvas/webgl_limits.rs +++ b/components/canvas/webgl_limits.rs @@ -2,17 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use canvas_traits::webgl::GLLimits; +use canvas_traits::webgl::{GLLimits, WebGLVersion}; use sparkle::gl; use sparkle::gl::GLenum; use sparkle::gl::Gl; +use sparkle::gl::GlType; pub trait GLLimitsDetect { - fn detect(gl: &Gl) -> Self; + fn detect(gl: &Gl, webgl_version: WebGLVersion) -> Self; } impl GLLimitsDetect for GLLimits { - fn detect(gl: &Gl) -> GLLimits { + fn detect(gl: &Gl, webgl_version: WebGLVersion) -> GLLimits { let max_vertex_attribs = gl.get_integer(gl::MAX_VERTEX_ATTRIBS); let max_tex_size = gl.get_integer(gl::MAX_TEXTURE_SIZE); let max_cube_map_tex_size = gl.get_integer(gl::MAX_CUBE_MAP_TEXTURE_SIZE); @@ -20,41 +21,74 @@ impl GLLimitsDetect for GLLimits { let max_renderbuffer_size = gl.get_integer(gl::MAX_RENDERBUFFER_SIZE); let max_texture_image_units = gl.get_integer(gl::MAX_TEXTURE_IMAGE_UNITS); let max_vertex_texture_image_units = gl.get_integer(gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS); - let max_transform_feedback_separate_attribs = - gl.get_integer(gl::MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS); // TODO: better value for this? let max_client_wait_timeout_webgl = std::time::Duration::new(1, 0); // Based on: // https://searchfox.org/mozilla-central/rev/5a744713370ec47969595e369fd5125f123e6d24/dom/canvas/WebGLContextValidate.cpp#523-558 - let (max_fragment_uniform_vectors, max_varying_vectors, max_vertex_uniform_vectors); - match gl.try_get_integer(gl::MAX_FRAGMENT_UNIFORM_VECTORS) { - Some(max_vectors) => { - max_fragment_uniform_vectors = max_vectors; - max_varying_vectors = gl.get_integer(gl::MAX_VARYING_VECTORS); - max_vertex_uniform_vectors = gl.get_integer(gl::MAX_VERTEX_UNIFORM_VECTORS); - }, - None => { - let max_fragment_uniform_components = - gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_COMPONENTS); - let max_vertex_uniform_components = - gl.get_integer(gl::MAX_VERTEX_UNIFORM_COMPONENTS); + let ( + max_fragment_uniform_vectors, + max_varying_vectors, + max_vertex_uniform_vectors, + max_vertex_output_vectors, + max_fragment_input_vectors, + ); + if gl.get_type() == GlType::Gles { + max_fragment_uniform_vectors = gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_VECTORS); + max_varying_vectors = gl.get_integer(gl::MAX_VARYING_VECTORS); + max_vertex_uniform_vectors = gl.get_integer(gl::MAX_VERTEX_UNIFORM_VECTORS); + max_vertex_output_vectors = gl + .try_get_integer(gl::MAX_VERTEX_OUTPUT_COMPONENTS) + .map(|c| c / 4) + .unwrap_or(max_varying_vectors); + max_fragment_input_vectors = gl + .try_get_integer(gl::MAX_FRAGMENT_INPUT_COMPONENTS) + .map(|c| c / 4) + .unwrap_or(max_vertex_output_vectors); + } else { + max_fragment_uniform_vectors = gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_COMPONENTS) / 4; + max_vertex_uniform_vectors = gl.get_integer(gl::MAX_VERTEX_UNIFORM_COMPONENTS) / 4; - let max_vertex_output_components = gl - .try_get_integer(gl::MAX_VERTEX_OUTPUT_COMPONENTS) - .unwrap_or(0); - let max_fragment_input_components = gl - .try_get_integer(gl::MAX_FRAGMENT_INPUT_COMPONENTS) - .unwrap_or(0); - let max_varying_components = max_vertex_output_components - .min(max_fragment_input_components) - .max(16); + max_fragment_input_vectors = gl + .try_get_integer(gl::MAX_FRAGMENT_INPUT_COMPONENTS) + .or_else(|| gl.try_get_integer(gl::MAX_VARYING_COMPONENTS)) + .map(|c| c / 4) + .unwrap_or_else(|| gl.get_integer(gl::MAX_VARYING_VECTORS)); + max_vertex_output_vectors = gl + .try_get_integer(gl::MAX_VERTEX_OUTPUT_COMPONENTS) + .map(|c| c / 4) + .unwrap_or(max_fragment_input_vectors); + max_varying_vectors = max_vertex_output_vectors + .min(max_fragment_input_vectors) + .max(4); + }; - max_fragment_uniform_vectors = max_fragment_uniform_components / 4; - max_varying_vectors = max_varying_components / 4; - max_vertex_uniform_vectors = max_vertex_uniform_components / 4; - }, + let ( + max_uniform_buffer_bindings, + min_program_texel_offset, + max_program_texel_offset, + max_transform_feedback_separate_attribs, + max_draw_buffers, + max_color_attachments, + ); + if webgl_version == WebGLVersion::WebGL2 { + max_uniform_buffer_bindings = gl.get_integer(gl::MAX_UNIFORM_BUFFER_BINDINGS); + min_program_texel_offset = gl.get_integer(gl::MIN_PROGRAM_TEXEL_OFFSET); + max_program_texel_offset = gl.get_integer(gl::MAX_PROGRAM_TEXEL_OFFSET); + max_transform_feedback_separate_attribs = + gl.get_integer(gl::MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS); + max_color_attachments = gl.get_integer(gl::MAX_COLOR_ATTACHMENTS); + max_draw_buffers = gl + .get_integer(gl::MAX_DRAW_BUFFERS) + .min(max_color_attachments) + } else { + max_uniform_buffer_bindings = 0; + min_program_texel_offset = 0; + max_program_texel_offset = 0; + max_transform_feedback_separate_attribs = 0; + max_color_attachments = 1; + max_draw_buffers = 1; } GLLimits { @@ -70,6 +104,13 @@ impl GLLimitsDetect for GLLimits { max_vertex_uniform_vectors, max_client_wait_timeout_webgl, max_transform_feedback_separate_attribs, + max_vertex_output_vectors, + max_fragment_input_vectors, + max_uniform_buffer_bindings, + min_program_texel_offset, + max_program_texel_offset, + max_color_attachments, + max_draw_buffers, } } } diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index aece9e410a8..b9a4533f134 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -421,7 +421,7 @@ impl WebGLThread { let context_attributes = &ContextAttributes { version: webgl_version.to_surfman_version(), - flags: attributes.to_surfman_context_attribute_flags(), + flags: attributes.to_surfman_context_attribute_flags(webgl_version), }; let context_descriptor = self @@ -486,7 +486,7 @@ impl WebGLThread { })), }; - let limits = GLLimits::detect(&*gl); + let limits = GLLimits::detect(&*gl, webgl_version); let size = clamp_viewport(&gl, requested_size); if safe_size != size { @@ -2659,17 +2659,24 @@ impl ToSurfmanVersion for WebGLVersion { } trait SurfmanContextAttributeFlagsConvert { - fn to_surfman_context_attribute_flags(&self) -> ContextAttributeFlags; + fn to_surfman_context_attribute_flags( + &self, + webgl_version: WebGLVersion, + ) -> ContextAttributeFlags; } impl SurfmanContextAttributeFlagsConvert for GLContextAttributes { - fn to_surfman_context_attribute_flags(&self) -> ContextAttributeFlags { + fn to_surfman_context_attribute_flags( + &self, + webgl_version: WebGLVersion, + ) -> ContextAttributeFlags { let mut flags = ContextAttributeFlags::empty(); flags.set(ContextAttributeFlags::ALPHA, self.alpha); flags.set(ContextAttributeFlags::DEPTH, self.depth); flags.set(ContextAttributeFlags::STENCIL, self.stencil); - // TODO: should we always set this to true? - flags.set(ContextAttributeFlags::COMPATIBILITY_PROFILE, true); + if webgl_version == WebGLVersion::WebGL1 { + flags.set(ContextAttributeFlags::COMPATIBILITY_PROFILE, true); + } flags } } diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 29e02db2725..63ee46c108c 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -992,4 +992,11 @@ pub struct GLLimits { pub max_vertex_uniform_vectors: u32, pub max_client_wait_timeout_webgl: std::time::Duration, pub max_transform_feedback_separate_attribs: u32, + pub max_vertex_output_vectors: u32, + pub max_fragment_input_vectors: u32, + pub max_draw_buffers: u32, + pub max_color_attachments: u32, + pub max_uniform_buffer_bindings: u32, + pub min_program_texel_offset: u32, + pub max_program_texel_offset: u32, } diff --git a/components/script/dom/webglshader.rs b/components/script/dom/webglshader.rs index eae89fe3dcb..d8278b1ee5a 100644 --- a/components/script/dom/webglshader.rs +++ b/components/script/dom/webglshader.rs @@ -18,7 +18,7 @@ use canvas_traits::webgl::{webgl_channel, GlType, WebGLVersion}; use canvas_traits::webgl::{GLLimits, WebGLCommand, WebGLError}; use canvas_traits::webgl::{WebGLResult, WebGLSLVersion, WebGLShaderId}; use dom_struct::dom_struct; -use mozangle::shaders::{BuiltInResources, Output, ShaderValidator}; +use mozangle::shaders::{ffi, BuiltInResources, Output, ShaderValidator}; use std::cell::Cell; use std::os::raw::c_int; use std::sync::Once; @@ -81,6 +81,121 @@ impl WebGLShader { } } +// Based on https://searchfox.org/mozilla-central/rev/efdf9bb55789ea782ae3a431bda6be74a87b041e/gfx/angle/checkout/src/compiler/translator/ShaderLang.cpp#173 +fn default_validator() -> BuiltInResources { + BuiltInResources { + // Constants. + MaxVertexAttribs: 8, + MaxVertexUniformVectors: 128, + MaxVaryingVectors: 8, + MaxVertexTextureImageUnits: 0, + MaxCombinedTextureImageUnits: 8, + MaxTextureImageUnits: 8, + MaxFragmentUniformVectors: 16, + MaxDrawBuffers: 1, + + // Extensions. + OES_standard_derivatives: 0, + OES_EGL_image_external: 0, + OES_EGL_image_external_essl3: 0, + NV_EGL_stream_consumer_external: 0, + ARB_texture_rectangle: 0, + EXT_blend_func_extended: 0, + EXT_draw_buffers: 0, + EXT_frag_depth: 0, + EXT_shader_texture_lod: 0, + WEBGL_debug_shader_precision: 0, + EXT_shader_framebuffer_fetch: 0, + NV_shader_framebuffer_fetch: 0, + NV_draw_buffers: 0, + ARM_shader_framebuffer_fetch: 0, + //OVR_multiview: 0, + OVR_multiview2: 0, + EXT_YUV_target: 0, + EXT_geometry_shader: 0, + OES_texture_storage_multisample_2d_array: 0, + //OES_texture_3d: 0, + ANGLE_texture_multisample: 0, + ANGLE_multi_draw: 0, + + // Disable highp precision in fragment shader by default. + FragmentPrecisionHigh: 0, + + // GLSL ES 3.0 constants. + MaxVertexOutputVectors: 16, + MaxFragmentInputVectors: 15, + MinProgramTexelOffset: -8, + MaxProgramTexelOffset: 7, + + // Extension constants. + MaxDualSourceDrawBuffers: 0, + MaxViewsOVR: 4, + + // Disable name hashing by default. + HashFunction: None, + ArrayIndexClampingStrategy: + ffi::ShArrayIndexClampingStrategy::SH_CLAMP_WITH_CLAMP_INTRINSIC, + + MaxExpressionComplexity: 256, + MaxCallStackDepth: 256, + MaxFunctionParameters: 1024, + + // ES 3.1 Revision 4, 7.2 Built-in Constants + + // ES 3.1, Revision 4, 8.13 Texture minification + // "The value of MIN_PROGRAM_TEXTURE_GATHER_OFFSET must be less than or equal to the value of + // MIN_PROGRAM_TEXEL_OFFSET. The value of MAX_PROGRAM_TEXTURE_GATHER_OFFSET must be greater than + // or equal to the value of MAX_PROGRAM_TEXEL_OFFSET" + MinProgramTextureGatherOffset: -8, + MaxProgramTextureGatherOffset: 7, + + MaxImageUnits: 4, + MaxVertexImageUniforms: 0, + MaxFragmentImageUniforms: 0, + MaxComputeImageUniforms: 0, + MaxCombinedImageUniforms: 0, + + MaxUniformLocations: 1024, + + MaxCombinedShaderOutputResources: 4, + + MaxComputeWorkGroupCount: [65535, 65535, 65535], + MaxComputeWorkGroupSize: [128, 128, 64], + MaxComputeUniformComponents: 512, + MaxComputeTextureImageUnits: 16, + + MaxComputeAtomicCounters: 8, + MaxComputeAtomicCounterBuffers: 1, + + MaxVertexAtomicCounters: 0, + MaxFragmentAtomicCounters: 0, + MaxCombinedAtomicCounters: 8, + MaxAtomicCounterBindings: 1, + + MaxVertexAtomicCounterBuffers: 0, + MaxFragmentAtomicCounterBuffers: 0, + MaxCombinedAtomicCounterBuffers: 1, + MaxAtomicCounterBufferSize: 32, + + MaxUniformBufferBindings: 32, + MaxShaderStorageBufferBindings: 4, + MaxPointSize: 0.0, + + MaxGeometryUniformComponents: 1024, + MaxGeometryUniformBlocks: 12, + MaxGeometryInputComponents: 64, + MaxGeometryOutputComponents: 64, + MaxGeometryOutputVertices: 256, + MaxGeometryTotalOutputComponents: 1024, + MaxGeometryTextureImageUnits: 16, + MaxGeometryAtomicCounterBuffers: 0, + MaxGeometryAtomicCounters: 0, + MaxGeometryShaderStorageBlocks: 0, + MaxGeometryShaderInvocations: 32, + MaxGeometryImageUniforms: 0, + } +} + impl WebGLShader { pub fn id(&self) -> WebGLShaderId { self.id @@ -108,19 +223,31 @@ impl WebGLShader { let source = self.source.borrow(); - let params = BuiltInResources { + let mut params = BuiltInResources { MaxVertexAttribs: limits.max_vertex_attribs as c_int, MaxVertexUniformVectors: limits.max_vertex_uniform_vectors as c_int, - MaxVaryingVectors: limits.max_varying_vectors as c_int, MaxVertexTextureImageUnits: limits.max_vertex_texture_image_units as c_int, MaxCombinedTextureImageUnits: limits.max_combined_texture_image_units as c_int, MaxTextureImageUnits: limits.max_texture_image_units as c_int, MaxFragmentUniformVectors: limits.max_fragment_uniform_vectors as c_int, + + MaxVertexOutputVectors: limits.max_vertex_output_vectors as c_int, + MaxFragmentInputVectors: limits.max_fragment_input_vectors as c_int, + MaxVaryingVectors: limits.max_varying_vectors as c_int, + OES_standard_derivatives: ext.is_enabled::() as c_int, EXT_shader_texture_lod: ext.is_enabled::() as c_int, + FragmentPrecisionHigh: 1, - ..BuiltInResources::default() + ..default_validator() }; + + if webgl_version == WebGLVersion::WebGL2 { + params.MinProgramTexelOffset = limits.min_program_texel_offset as c_int; + params.MaxProgramTexelOffset = limits.max_program_texel_offset as c_int; + params.MaxDrawBuffers = limits.max_draw_buffers as c_int; + } + let validator = match webgl_version { WebGLVersion::WebGL1 => { let output_format = if api_type == GlType::Gles { diff --git a/tests/wpt/webgl/meta/conformance2/programs/gl-get-frag-data-location.html.ini b/tests/wpt/webgl/meta/conformance2/programs/gl-get-frag-data-location.html.ini index 3f6cf9b8e22..9ee2a3ac166 100644 --- a/tests/wpt/webgl/meta/conformance2/programs/gl-get-frag-data-location.html.ini +++ b/tests/wpt/webgl/meta/conformance2/programs/gl-get-frag-data-location.html.ini @@ -1,4 +1,4 @@ [gl-get-frag-data-location.html] - [WebGL test #1: Set up program failed] + expected: ERROR + [WebGL test #2: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] expected: FAIL - diff --git a/tests/wpt/webgl/meta/conformance2/uniforms/incompatible-texture-type-for-sampler.html.ini b/tests/wpt/webgl/meta/conformance2/uniforms/incompatible-texture-type-for-sampler.html.ini index ead79e969c8..6bbc467ede7 100644 --- a/tests/wpt/webgl/meta/conformance2/uniforms/incompatible-texture-type-for-sampler.html.ini +++ b/tests/wpt/webgl/meta/conformance2/uniforms/incompatible-texture-type-for-sampler.html.ini @@ -1,5 +1,5 @@ [incompatible-texture-type-for-sampler.html] - expected: ERROR + expected: CRASH [WebGL test #45: getError expected: NO_ERROR. Was INVALID_ENUM : No errors from setup for TEXTURE_2D RGBA16UI] expected: FAIL