Split webgl into separate crate (#36718)

canvas crate was home for both webgl and 2dcanvas impl, but it makes
more sense to separate these two, by splitting webgl into standalone
crate (like we already have for webgpu).

Testing: Rust for fearless refactoring (but there are WPT tests just in
case)

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
sagudev 2025-04-30 07:27:44 +02:00 committed by GitHub
parent 0c0ee04b8e
commit 955149b194
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 79 additions and 33 deletions

View file

@ -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);
}