aboutsummaryrefslogtreecommitdiffstats
path: root/components/webgl/webgl_limits.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/webgl/webgl_limits.rs')
-rw-r--r--components/webgl/webgl_limits.rs259
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);
+}