1use canvas_traits::webgl::{GLLimits, WebGLVersion};
6use glow::{self as gl, Context as Gl, HasContext};
7type GLenum = u32;
8
9pub trait GLLimitsDetect {
10 fn detect(gl: &Gl, webgl_version: WebGLVersion) -> Self;
11}
12
13impl GLLimitsDetect for GLLimits {
14 fn detect(gl: &Gl, webgl_version: WebGLVersion) -> GLLimits {
15 let max_vertex_attribs = gl.get_integer(gl::MAX_VERTEX_ATTRIBS);
16 let max_tex_size = gl.get_integer(gl::MAX_TEXTURE_SIZE);
17 let max_3d_tex_size = gl.get_integer(gl::MAX_3D_TEXTURE_SIZE);
18 let max_cube_map_tex_size = gl.get_integer(gl::MAX_CUBE_MAP_TEXTURE_SIZE);
19 let max_combined_texture_image_units = gl.get_integer(gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS);
20 let max_renderbuffer_size = gl.get_integer(gl::MAX_RENDERBUFFER_SIZE);
21 let max_texture_image_units = gl.get_integer(gl::MAX_TEXTURE_IMAGE_UNITS);
22 let max_vertex_texture_image_units = gl.get_integer(gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS);
23
24 let max_client_wait_timeout_webgl = std::time::Duration::new(1, 0);
26
27 let (
30 max_fragment_uniform_vectors,
31 max_varying_vectors,
32 max_vertex_uniform_vectors,
33 max_vertex_output_vectors,
34 max_fragment_input_vectors,
35 );
36 if gl.version().is_embedded {
37 max_fragment_uniform_vectors = gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_VECTORS);
38 max_varying_vectors = gl.get_integer(gl::MAX_VARYING_VECTORS);
39 max_vertex_uniform_vectors = gl.get_integer(gl::MAX_VERTEX_UNIFORM_VECTORS);
40 max_vertex_output_vectors = gl
41 .try_get_integer(gl::MAX_VERTEX_OUTPUT_COMPONENTS)
42 .map(|c| c / 4)
43 .unwrap_or(max_varying_vectors);
44 max_fragment_input_vectors = gl
45 .try_get_integer(gl::MAX_FRAGMENT_INPUT_COMPONENTS)
46 .map(|c| c / 4)
47 .unwrap_or(max_vertex_output_vectors);
48 } else {
49 max_fragment_uniform_vectors = gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_COMPONENTS) / 4;
50 max_vertex_uniform_vectors = gl.get_integer(gl::MAX_VERTEX_UNIFORM_COMPONENTS) / 4;
51
52 max_fragment_input_vectors = gl
53 .try_get_integer(gl::MAX_FRAGMENT_INPUT_COMPONENTS)
54 .or_else(|| gl.try_get_integer(gl::MAX_VARYING_COMPONENTS))
55 .map(|c| c / 4)
56 .unwrap_or_else(|| gl.get_integer(gl::MAX_VARYING_VECTORS));
57 max_vertex_output_vectors = gl
58 .try_get_integer(gl::MAX_VERTEX_OUTPUT_COMPONENTS)
59 .map(|c| c / 4)
60 .unwrap_or(max_fragment_input_vectors);
61 max_varying_vectors = max_vertex_output_vectors
62 .min(max_fragment_input_vectors)
63 .max(4);
64 };
65
66 let (
67 max_uniform_block_size,
68 max_uniform_buffer_bindings,
69 min_program_texel_offset,
70 max_program_texel_offset,
71 max_transform_feedback_separate_attribs,
72 max_draw_buffers,
73 max_color_attachments,
74 max_combined_uniform_blocks,
75 max_combined_vertex_uniform_components,
76 max_combined_fragment_uniform_components,
77 max_vertex_uniform_blocks,
78 max_vertex_uniform_components,
79 max_fragment_uniform_blocks,
80 max_fragment_uniform_components,
81 max_3d_texture_size,
82 max_array_texture_layers,
83 uniform_buffer_offset_alignment,
84 max_element_index,
85 max_elements_indices,
86 max_elements_vertices,
87 max_fragment_input_components,
88 max_samples,
89 max_server_wait_timeout,
90 max_texture_lod_bias,
91 max_varying_components,
92 max_vertex_output_components,
93 );
94 if webgl_version == WebGLVersion::WebGL2 {
95 max_uniform_block_size = gl.get_integer64(gl::MAX_UNIFORM_BLOCK_SIZE);
96 max_uniform_buffer_bindings = gl.get_integer(gl::MAX_UNIFORM_BUFFER_BINDINGS);
97 min_program_texel_offset = gl.get_signed_integer(gl::MIN_PROGRAM_TEXEL_OFFSET);
98 max_program_texel_offset = gl.get_integer(gl::MAX_PROGRAM_TEXEL_OFFSET);
99 max_transform_feedback_separate_attribs =
100 gl.get_integer(gl::MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
101 max_color_attachments = gl.get_integer(gl::MAX_COLOR_ATTACHMENTS);
102 max_draw_buffers = gl
103 .get_integer(gl::MAX_DRAW_BUFFERS)
104 .min(max_color_attachments);
105 max_combined_uniform_blocks = gl.get_integer(gl::MAX_COMBINED_UNIFORM_BLOCKS);
106 max_combined_vertex_uniform_components =
107 gl.get_integer64(gl::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS);
108 max_combined_fragment_uniform_components =
109 gl.get_integer64(gl::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS);
110 max_vertex_uniform_blocks = gl.get_integer(gl::MAX_VERTEX_UNIFORM_BLOCKS);
111 max_vertex_uniform_components = gl.get_integer(gl::MAX_VERTEX_UNIFORM_COMPONENTS);
112 max_fragment_uniform_blocks = gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_BLOCKS);
113 max_fragment_uniform_components = gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_COMPONENTS);
114 uniform_buffer_offset_alignment = gl.get_integer(gl::UNIFORM_BUFFER_OFFSET_ALIGNMENT);
115 max_3d_texture_size = gl.get_integer(gl::MAX_3D_TEXTURE_SIZE);
116 max_array_texture_layers = gl.get_integer(gl::MAX_ARRAY_TEXTURE_LAYERS);
117 max_element_index = gl
118 .try_get_integer64(gl::MAX_ELEMENT_INDEX)
119 .unwrap_or(u32::MAX as u64); max_elements_indices = gl.get_integer(gl::MAX_ELEMENTS_INDICES);
121 max_elements_vertices = gl.get_integer(gl::MAX_ELEMENTS_VERTICES);
122 max_fragment_input_components = gl.get_integer(gl::MAX_FRAGMENT_INPUT_COMPONENTS);
123 max_samples = gl.get_integer(gl::MAX_SAMPLES);
124 max_server_wait_timeout =
125 std::time::Duration::from_nanos(gl.get_integer64(gl::MAX_SERVER_WAIT_TIMEOUT));
126 max_texture_lod_bias = gl.get_float(gl::MAX_TEXTURE_LOD_BIAS);
127 max_varying_components = gl.try_get_integer(gl::MAX_VARYING_COMPONENTS).unwrap_or(
128 max_varying_vectors * 4,
130 );
131 max_vertex_output_components = gl.get_integer(gl::MAX_VERTEX_OUTPUT_COMPONENTS);
132 } else {
133 max_uniform_block_size = 0;
134 max_uniform_buffer_bindings = 0;
135 min_program_texel_offset = 0;
136 max_program_texel_offset = 0;
137 max_transform_feedback_separate_attribs = 0;
138 max_color_attachments = 1;
139 max_draw_buffers = 1;
140 max_combined_uniform_blocks = 0;
141 max_combined_vertex_uniform_components = 0;
142 max_combined_fragment_uniform_components = 0;
143 max_vertex_uniform_blocks = 0;
144 max_vertex_uniform_components = 0;
145 max_fragment_uniform_blocks = 0;
146 max_fragment_uniform_components = 0;
147 uniform_buffer_offset_alignment = 0;
148 max_3d_texture_size = 0;
149 max_array_texture_layers = 0;
150 max_element_index = 0;
151 max_elements_indices = 0;
152 max_elements_vertices = 0;
153 max_fragment_input_components = 0;
154 max_samples = 0;
155 max_server_wait_timeout = std::time::Duration::default();
156 max_texture_lod_bias = 0.0;
157 max_varying_components = 0;
158 max_vertex_output_components = 0;
159 }
160
161 GLLimits {
162 max_vertex_attribs,
163 max_tex_size,
164 max_3d_tex_size,
165 max_cube_map_tex_size,
166 max_combined_texture_image_units,
167 max_fragment_uniform_vectors,
168 max_renderbuffer_size,
169 max_texture_image_units,
170 max_varying_vectors,
171 max_vertex_texture_image_units,
172 max_vertex_uniform_vectors,
173 max_client_wait_timeout_webgl,
174 max_transform_feedback_separate_attribs,
175 max_vertex_output_vectors,
176 max_fragment_input_vectors,
177 max_uniform_buffer_bindings,
178 min_program_texel_offset,
179 max_program_texel_offset,
180 max_color_attachments,
181 max_draw_buffers,
182 max_uniform_block_size,
183 max_combined_uniform_blocks,
184 max_combined_vertex_uniform_components,
185 max_combined_fragment_uniform_components,
186 max_vertex_uniform_blocks,
187 max_vertex_uniform_components,
188 max_fragment_uniform_blocks,
189 max_fragment_uniform_components,
190 max_3d_texture_size,
191 max_array_texture_layers,
192 uniform_buffer_offset_alignment,
193 max_element_index,
194 max_elements_indices,
195 max_elements_vertices,
196 max_fragment_input_components,
197 max_samples,
198 max_server_wait_timeout,
199 max_texture_lod_bias,
200 max_varying_components,
201 max_vertex_output_components,
202 }
203 }
204}
205
206trait GLExt {
207 fn try_get_integer(self, parameter: GLenum) -> Option<u32>;
208 fn try_get_integer64(self, parameter: GLenum) -> Option<u64>;
209 fn try_get_signed_integer(self, parameter: GLenum) -> Option<i32>;
210 fn try_get_float(self, parameter: GLenum) -> Option<f32>;
211 fn get_integer(self, parameter: GLenum) -> u32;
212 fn get_integer64(self, parameter: GLenum) -> u64;
213 fn get_signed_integer(self, parameter: GLenum) -> i32;
214 fn get_float(self, parameter: GLenum) -> f32;
215}
216
217macro_rules! create_fun {
218 ($tryer:ident, $getter:ident, $gltype:ty, $glcall:ident, $rstype:ty) => {
219 #[expect(unsafe_code)]
220 fn $tryer(self, parameter: GLenum) -> Option<$rstype> {
221 let mut value = [<$gltype>::default()];
222 unsafe {
223 self.$glcall(parameter, &mut value);
224 }
225 if unsafe { self.get_error() } != gl::NO_ERROR {
226 None
227 } else {
228 Some(value[0] as $rstype)
229 }
230 }
231
232 fn $getter(self, parameter: GLenum) -> $rstype {
233 self.$tryer(parameter).unwrap()
234 }
235 };
236}
237
238impl GLExt for &Gl {
239 create_fun!(
240 try_get_integer,
241 get_integer,
242 i32,
243 get_parameter_i32_slice,
244 u32
245 );
246 create_fun!(
247 try_get_integer64,
248 get_integer64,
249 i64,
250 get_parameter_i64_slice,
251 u64
252 );
253 create_fun!(
254 try_get_signed_integer,
255 get_signed_integer,
256 i32,
257 get_parameter_i32_slice,
258 i32
259 );
260 create_fun!(try_get_float, get_float, f32, get_parameter_f32_slice, f32);
261}