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);
let max_client_wait_timeout_webgl = std::time::Duration::new(1, 0);
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); 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(
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<'a> GLExt for &'a 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);
}