diff options
Diffstat (limited to 'components/webgl/webgl_limits.rs')
-rw-r--r-- | components/webgl/webgl_limits.rs | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/components/webgl/webgl_limits.rs b/components/webgl/webgl_limits.rs new file mode 100644 index 00000000000..f683b6efff6 --- /dev/null +++ b/components/webgl/webgl_limits.rs @@ -0,0 +1,259 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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, WebGLVersion}; +use glow::{self as gl, Context as Gl, HasContext}; +type GLenum = u32; + +pub trait GLLimitsDetect { + fn detect(gl: &Gl, webgl_version: WebGLVersion) -> Self; +} + +impl GLLimitsDetect for 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); + let max_combined_texture_image_units = gl.get_integer(gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS); + 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); + + // 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, + max_vertex_output_vectors, + max_fragment_input_vectors, + ); + if gl.version().is_embedded { + 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; + + 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); + }; + + let ( + max_uniform_block_size, + max_uniform_buffer_bindings, + min_program_texel_offset, + max_program_texel_offset, + max_transform_feedback_separate_attribs, + max_draw_buffers, + max_color_attachments, + max_combined_uniform_blocks, + max_combined_vertex_uniform_components, + max_combined_fragment_uniform_components, + max_vertex_uniform_blocks, + max_vertex_uniform_components, + max_fragment_uniform_blocks, + max_fragment_uniform_components, + max_3d_texture_size, + max_array_texture_layers, + uniform_buffer_offset_alignment, + max_element_index, + max_elements_indices, + max_elements_vertices, + max_fragment_input_components, + max_samples, + max_server_wait_timeout, + max_texture_lod_bias, + max_varying_components, + max_vertex_output_components, + ); + if webgl_version == WebGLVersion::WebGL2 { + max_uniform_block_size = gl.get_integer64(gl::MAX_UNIFORM_BLOCK_SIZE); + max_uniform_buffer_bindings = gl.get_integer(gl::MAX_UNIFORM_BUFFER_BINDINGS); + min_program_texel_offset = gl.get_signed_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); + max_combined_uniform_blocks = gl.get_integer(gl::MAX_COMBINED_UNIFORM_BLOCKS); + max_combined_vertex_uniform_components = + gl.get_integer64(gl::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS); + max_combined_fragment_uniform_components = + gl.get_integer64(gl::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS); + max_vertex_uniform_blocks = gl.get_integer(gl::MAX_VERTEX_UNIFORM_BLOCKS); + max_vertex_uniform_components = gl.get_integer(gl::MAX_VERTEX_UNIFORM_COMPONENTS); + max_fragment_uniform_blocks = gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_BLOCKS); + max_fragment_uniform_components = gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_COMPONENTS); + uniform_buffer_offset_alignment = gl.get_integer(gl::UNIFORM_BUFFER_OFFSET_ALIGNMENT); + max_3d_texture_size = gl.get_integer(gl::MAX_3D_TEXTURE_SIZE); + max_array_texture_layers = gl.get_integer(gl::MAX_ARRAY_TEXTURE_LAYERS); + max_element_index = gl + .try_get_integer64(gl::MAX_ELEMENT_INDEX) + .unwrap_or(u32::MAX as u64); // requires GL 4.3 + max_elements_indices = gl.get_integer(gl::MAX_ELEMENTS_INDICES); + max_elements_vertices = gl.get_integer(gl::MAX_ELEMENTS_VERTICES); + max_fragment_input_components = gl.get_integer(gl::MAX_FRAGMENT_INPUT_COMPONENTS); + max_samples = gl.get_integer(gl::MAX_SAMPLES); + max_server_wait_timeout = + std::time::Duration::from_nanos(gl.get_integer64(gl::MAX_SERVER_WAIT_TIMEOUT)); + max_texture_lod_bias = gl.get_float(gl::MAX_TEXTURE_LOD_BIAS); + max_varying_components = gl.try_get_integer(gl::MAX_VARYING_COMPONENTS).unwrap_or( + // macOS Core Profile is buggy. The spec says this value is 4 * MAX_VARYING_VECTORS. + max_varying_vectors * 4, + ); + max_vertex_output_components = gl.get_integer(gl::MAX_VERTEX_OUTPUT_COMPONENTS); + } else { + max_uniform_block_size = 0; + 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; + max_combined_uniform_blocks = 0; + max_combined_vertex_uniform_components = 0; + max_combined_fragment_uniform_components = 0; + max_vertex_uniform_blocks = 0; + max_vertex_uniform_components = 0; + max_fragment_uniform_blocks = 0; + max_fragment_uniform_components = 0; + uniform_buffer_offset_alignment = 0; + max_3d_texture_size = 0; + max_array_texture_layers = 0; + max_element_index = 0; + max_elements_indices = 0; + max_elements_vertices = 0; + max_fragment_input_components = 0; + max_samples = 0; + max_server_wait_timeout = std::time::Duration::default(); + max_texture_lod_bias = 0.0; + max_varying_components = 0; + max_vertex_output_components = 0; + } + + GLLimits { + max_vertex_attribs, + max_tex_size, + max_cube_map_tex_size, + max_combined_texture_image_units, + max_fragment_uniform_vectors, + max_renderbuffer_size, + max_texture_image_units, + max_varying_vectors, + max_vertex_texture_image_units, + 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, + max_uniform_block_size, + max_combined_uniform_blocks, + max_combined_vertex_uniform_components, + max_combined_fragment_uniform_components, + max_vertex_uniform_blocks, + max_vertex_uniform_components, + max_fragment_uniform_blocks, + max_fragment_uniform_components, + max_3d_texture_size, + max_array_texture_layers, + uniform_buffer_offset_alignment, + max_element_index, + max_elements_indices, + max_elements_vertices, + max_fragment_input_components, + max_samples, + max_server_wait_timeout, + max_texture_lod_bias, + max_varying_components, + max_vertex_output_components, + } + } +} + +trait GLExt { + fn try_get_integer(self, parameter: GLenum) -> Option<u32>; + fn try_get_integer64(self, parameter: GLenum) -> Option<u64>; + fn try_get_signed_integer(self, parameter: GLenum) -> Option<i32>; + fn try_get_float(self, parameter: GLenum) -> Option<f32>; + fn get_integer(self, parameter: GLenum) -> u32; + fn get_integer64(self, parameter: GLenum) -> u64; + fn get_signed_integer(self, parameter: GLenum) -> i32; + fn get_float(self, parameter: GLenum) -> f32; +} + +macro_rules! create_fun { + ($tryer:ident, $getter:ident, $gltype:ty, $glcall:ident, $rstype:ty) => { + #[allow(unsafe_code)] + fn $tryer(self, parameter: GLenum) -> Option<$rstype> { + let mut value = [<$gltype>::default()]; + unsafe { + self.$glcall(parameter, &mut value); + } + if unsafe { self.get_error() } != gl::NO_ERROR { + None + } else { + Some(value[0] as $rstype) + } + } + + fn $getter(self, parameter: GLenum) -> $rstype { + self.$tryer(parameter).unwrap() + } + }; +} + +impl GLExt for &Gl { + create_fun!( + try_get_integer, + get_integer, + i32, + get_parameter_i32_slice, + u32 + ); + create_fun!( + try_get_integer64, + get_integer64, + i64, + get_parameter_i64_slice, + u64 + ); + create_fun!( + try_get_signed_integer, + get_signed_integer, + i32, + get_parameter_i32_slice, + i32 + ); + create_fun!(try_get_float, get_float, f32, get_parameter_f32_slice, f32); +} |