1use std::cell::Cell;
6use std::cmp;
7use std::ptr::{self, NonNull};
8#[cfg(feature = "webxr")]
9use std::rc::Rc;
10
11use bitflags::bitflags;
12use dom_struct::dom_struct;
13use euclid::default::{Point2D, Rect, Size2D};
14use js::jsapi::{JSObject, Type};
15use js::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, ObjectValue, UInt32Value};
16use js::rust::{CustomAutoRooterGuard, HandleObject, MutableHandleValue};
17use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array};
18use pixels::{Alpha, Snapshot};
19use script_bindings::conversions::SafeToJSValConvertible;
20use script_bindings::interfaces::WebGL2RenderingContextHelpers;
21use servo_base::generic_channel::{self, GenericSharedMemory};
22use servo_canvas_traits::webgl::WebGLError::*;
23use servo_canvas_traits::webgl::{
24 AlphaTreatment, GLContextAttributes, InternalFormatParameter, TexDataType, TexFormat,
25 WebGLCommand, WebGLContextId, WebGLResult, WebGLVersion, YAxisTreatment, webgl_channel,
26};
27use servo_config::pref;
28use url::Host;
29use webrender_api::ImageKey;
30
31use super::validations::types::TexImageTarget;
32use crate::canvas_context::CanvasContext;
33use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::{
34 WebGL2RenderingContextConstants as constants, WebGL2RenderingContextMethods,
35};
36use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{
37 TexImageSource, WebGLContextAttributes, WebGLRenderingContextMethods,
38};
39use crate::dom::bindings::codegen::UnionTypes::{
40 ArrayBufferViewOrArrayBuffer, Float32ArrayOrUnrestrictedFloatSequence,
41 HTMLCanvasElementOrOffscreenCanvas as RootedHTMLCanvasElementOrOffscreenCanvas,
42 Int32ArrayOrLongSequence, Uint32ArrayOrUnsignedLongSequence,
43};
44use crate::dom::bindings::error::{ErrorResult, Fallible};
45use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
46use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
47use crate::dom::bindings::str::DOMString;
48use crate::dom::globalscope::GlobalScope;
49#[cfg(feature = "webxr")]
50use crate::dom::promise::Promise;
51use crate::dom::webgl::validations::WebGLValidator;
52use crate::dom::webgl::validations::tex_image_2d::{
53 TexImage2DValidator, TexImage2DValidatorResult, TexStorageValidator, TexStorageValidatorResult,
54};
55use crate::dom::webgl::validations::tex_image_3d::{
56 TexImage3DValidator, TexImage3DValidatorResult,
57};
58use crate::dom::webgl::webglactiveinfo::WebGLActiveInfo;
59use crate::dom::webgl::webglbuffer::WebGLBuffer;
60use crate::dom::webgl::webglframebuffer::{WebGLFramebuffer, WebGLFramebufferAttachmentRoot};
61use crate::dom::webgl::webglprogram::WebGLProgram;
62use crate::dom::webgl::webglquery::WebGLQuery;
63use crate::dom::webgl::webglrenderbuffer::WebGLRenderbuffer;
64use crate::dom::webgl::webglrenderingcontext::{
65 Operation, TexPixels, TexSource, VertexAttrib, WebGLRenderingContext, uniform_get,
66 uniform_typed,
67};
68use crate::dom::webgl::webglsampler::{WebGLSampler, WebGLSamplerValue};
69use crate::dom::webgl::webglshader::WebGLShader;
70use crate::dom::webgl::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
71use crate::dom::webgl::webglsync::WebGLSync;
72use crate::dom::webgl::webgltexture::WebGLTexture;
73use crate::dom::webgl::webgltransformfeedback::WebGLTransformFeedback;
74use crate::dom::webgl::webgluniformlocation::WebGLUniformLocation;
75use crate::dom::webgl::webglvertexarrayobject::WebGLVertexArrayObject;
76use crate::dom::window::Window;
77use crate::script_runtime::{CanGc, JSContext};
78
79#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
80#[derive(JSTraceable, MallocSizeOf)]
81struct IndexedBinding {
82 buffer: MutNullableDom<WebGLBuffer>,
83 start: Cell<i64>,
84 size: Cell<i64>,
85}
86
87impl IndexedBinding {
88 fn new() -> IndexedBinding {
89 IndexedBinding {
90 buffer: MutNullableDom::new(None),
91 start: Cell::new(0),
92 size: Cell::new(0),
93 }
94 }
95}
96
97#[dom_struct] pub(crate) struct WebGL2RenderingContext {
99 reflector_: Reflector,
100 base: Dom<WebGLRenderingContext>,
101 occlusion_query: MutNullableDom<WebGLQuery>,
102 primitives_query: MutNullableDom<WebGLQuery>,
103 samplers: Box<[MutNullableDom<WebGLSampler>]>,
104 bound_copy_read_buffer: MutNullableDom<WebGLBuffer>,
105 bound_copy_write_buffer: MutNullableDom<WebGLBuffer>,
106 bound_pixel_pack_buffer: MutNullableDom<WebGLBuffer>,
107 bound_pixel_unpack_buffer: MutNullableDom<WebGLBuffer>,
108 bound_transform_feedback_buffer: MutNullableDom<WebGLBuffer>,
109 bound_uniform_buffer: MutNullableDom<WebGLBuffer>,
110 indexed_uniform_buffer_bindings: Box<[IndexedBinding]>,
111 indexed_transform_feedback_buffer_bindings: Box<[IndexedBinding]>,
112 current_transform_feedback: MutNullableDom<WebGLTransformFeedback>,
113 texture_pack_row_length: Cell<usize>,
114 texture_pack_skip_pixels: Cell<usize>,
115 texture_pack_skip_rows: Cell<usize>,
116 enable_rasterizer_discard: Cell<bool>,
117 default_fb_readbuffer: Cell<u32>,
118 default_fb_drawbuffer: Cell<u32>,
119}
120
121struct ReadPixelsAllowedFormats<'a> {
122 array_types: &'a [Type],
123 channels: usize,
124}
125
126struct ReadPixelsSizes {
127 row_stride: usize,
128 skipped_bytes: usize,
129 size: usize,
130}
131
132impl WebGL2RenderingContext {
133 fn new_inherited(
134 window: &Window,
135 canvas: &RootedHTMLCanvasElementOrOffscreenCanvas,
136 size: Size2D<u32>,
137 attrs: GLContextAttributes,
138 can_gc: CanGc,
139 ) -> Option<WebGL2RenderingContext> {
140 let base =
141 WebGLRenderingContext::new(window, canvas, WebGLVersion::WebGL2, size, attrs, can_gc)?;
142
143 let samplers = (0..base.limits().max_combined_texture_image_units)
144 .map(|_| Default::default())
145 .collect::<Vec<_>>()
146 .into();
147 let indexed_uniform_buffer_bindings = (0..base.limits().max_uniform_buffer_bindings)
148 .map(|_| IndexedBinding::new())
149 .collect::<Vec<_>>()
150 .into();
151 let indexed_transform_feedback_buffer_bindings =
152 (0..base.limits().max_transform_feedback_separate_attribs)
153 .map(|_| IndexedBinding::new())
154 .collect::<Vec<_>>()
155 .into();
156
157 Some(WebGL2RenderingContext {
158 reflector_: Reflector::new(),
159 base: Dom::from_ref(&*base),
160 occlusion_query: MutNullableDom::new(None),
161 primitives_query: MutNullableDom::new(None),
162 samplers,
163 bound_copy_read_buffer: MutNullableDom::new(None),
164 bound_copy_write_buffer: MutNullableDom::new(None),
165 bound_pixel_pack_buffer: MutNullableDom::new(None),
166 bound_pixel_unpack_buffer: MutNullableDom::new(None),
167 bound_transform_feedback_buffer: MutNullableDom::new(None),
168 bound_uniform_buffer: MutNullableDom::new(None),
169 indexed_uniform_buffer_bindings,
170 indexed_transform_feedback_buffer_bindings,
171 current_transform_feedback: MutNullableDom::new(None),
172 texture_pack_row_length: Cell::new(0),
173 texture_pack_skip_pixels: Cell::new(0),
174 texture_pack_skip_rows: Cell::new(0),
175 enable_rasterizer_discard: Cell::new(false),
176 default_fb_readbuffer: Cell::new(constants::BACK),
177 default_fb_drawbuffer: Cell::new(constants::BACK),
178 })
179 }
180
181 pub(crate) fn new(
182 window: &Window,
183 canvas: &RootedHTMLCanvasElementOrOffscreenCanvas,
184 size: Size2D<u32>,
185 attrs: GLContextAttributes,
186 can_gc: CanGc,
187 ) -> Option<DomRoot<WebGL2RenderingContext>> {
188 WebGL2RenderingContext::new_inherited(window, canvas, size, attrs, can_gc)
189 .map(|ctx| reflect_dom_object(Box::new(ctx), window, can_gc))
190 }
191
192 pub(crate) fn set_image_key(&self, image_key: ImageKey) {
193 self.base.set_image_key(image_key);
194 }
195
196 #[expect(unsafe_code)]
197 pub(crate) fn is_webgl2_enabled(_cx: JSContext, global: HandleObject) -> bool {
198 if pref!(dom_webgl2_enabled) {
199 return true;
200 }
201
202 let global = unsafe { GlobalScope::from_object(global.get()) };
203 let origin = global.origin();
204 let host = origin.host();
205 WEBGL2_ORIGINS
206 .iter()
207 .any(|origin| host == Host::parse(origin).ok().as_ref())
208 }
209}
210
211static WEBGL2_ORIGINS: &[&str] = &["www.servoexperiments.com"];
214
215impl WebGL2RenderingContext {
216 pub(crate) fn current_vao(&self) -> DomRoot<WebGLVertexArrayObject> {
217 self.base.current_vao_webgl2()
218 }
219
220 pub(crate) fn validate_uniform_block_for_draw(&self) {
221 let program = match self.base.current_program() {
222 Some(program) => program,
223 None => return,
224 };
225 for uniform_block in program.active_uniform_blocks().iter() {
226 let data_size = uniform_block.size as usize;
227 for block in program.active_uniforms().iter() {
228 let index = match block.bind_index {
229 Some(index) => index,
230 None => continue,
231 };
232 let indexed = &self.indexed_uniform_buffer_bindings[index as usize];
233 let buffer = match indexed.buffer.get() {
234 Some(buffer) => buffer,
235 None => {
236 self.base.webgl_error(InvalidOperation);
237 return;
238 },
239 };
240 if indexed.size.get() == 0 {
241 if data_size > buffer.capacity() {
242 self.base.webgl_error(InvalidOperation);
243 return;
244 }
245 } else {
246 let start = indexed.start.get() as usize;
247 let mut size = indexed.size.get() as usize;
248 if start >= size {
249 self.base.webgl_error(InvalidOperation);
250 return;
251 }
252 size -= start;
253 if data_size > size {
254 self.base.webgl_error(InvalidOperation);
255 return;
256 }
257 }
258 }
259 }
260 }
261
262 fn validate_vertex_attribs_for_draw(&self) {
263 let program = match self.base.current_program() {
264 Some(program) => program,
265 None => return,
266 };
267 let groups = [
268 [
269 constants::INT,
270 constants::INT_VEC2,
271 constants::INT_VEC3,
272 constants::INT_VEC4,
273 ],
274 [
275 constants::UNSIGNED_INT,
276 constants::UNSIGNED_INT_VEC2,
277 constants::UNSIGNED_INT_VEC3,
278 constants::UNSIGNED_INT_VEC4,
279 ],
280 [
281 constants::FLOAT,
282 constants::FLOAT_VEC2,
283 constants::FLOAT_VEC3,
284 constants::FLOAT_VEC4,
285 ],
286 ];
287 let vao = self.current_vao();
288 for prog_attrib in program.active_attribs().iter() {
289 let attrib = handle_potential_webgl_error!(
290 self.base,
291 vao.get_vertex_attrib(prog_attrib.location.unwrap_or(u32::MAX))
293 .ok_or(InvalidOperation),
294 return
295 );
296
297 let current_vertex_attrib = self.base.current_vertex_attribs()[prog_attrib
299 .location
300 .map(|l| l as usize)
301 .unwrap_or(usize::MAX)];
302 let attrib_data_base_type = if !attrib.enabled_as_array {
303 match current_vertex_attrib {
304 VertexAttrib::Int(_, _, _, _) => constants::INT,
305 VertexAttrib::Uint(_, _, _, _) => constants::UNSIGNED_INT,
306 VertexAttrib::Float(_, _, _, _) => constants::FLOAT,
307 }
308 } else {
309 attrib.type_
310 };
311
312 let contains = groups
313 .iter()
314 .find(|g| g.contains(&attrib_data_base_type) && g.contains(&prog_attrib.type_));
315 if contains.is_none() {
316 self.base.webgl_error(InvalidOperation);
317 return;
318 }
319 }
320 }
321
322 pub(crate) fn base_context(&self) -> DomRoot<WebGLRenderingContext> {
323 DomRoot::from_ref(&*self.base)
324 }
325
326 fn bound_buffer(&self, target: u32) -> WebGLResult<Option<DomRoot<WebGLBuffer>>> {
327 match target {
328 constants::COPY_READ_BUFFER => Ok(self.bound_copy_read_buffer.get()),
329 constants::COPY_WRITE_BUFFER => Ok(self.bound_copy_write_buffer.get()),
330 constants::PIXEL_PACK_BUFFER => Ok(self.bound_pixel_pack_buffer.get()),
331 constants::PIXEL_UNPACK_BUFFER => Ok(self.bound_pixel_unpack_buffer.get()),
332 constants::TRANSFORM_FEEDBACK_BUFFER => Ok(self.bound_transform_feedback_buffer.get()),
333 constants::UNIFORM_BUFFER => Ok(self.bound_uniform_buffer.get()),
334 constants::ELEMENT_ARRAY_BUFFER => Ok(self.current_vao().element_array_buffer().get()),
335 _ => self.base.bound_buffer(target),
336 }
337 }
338
339 pub(crate) fn buffer_usage(&self, usage: u32) -> WebGLResult<u32> {
340 match usage {
341 constants::STATIC_READ |
342 constants::DYNAMIC_READ |
343 constants::STREAM_READ |
344 constants::STATIC_COPY |
345 constants::DYNAMIC_COPY |
346 constants::STREAM_COPY => Ok(usage),
347 _ => self.base.buffer_usage(usage),
348 }
349 }
350
351 fn unbind_from(&self, slot: &MutNullableDom<WebGLBuffer>, buffer: &WebGLBuffer) {
352 if slot.get().is_some_and(|b| buffer == &*b) {
353 buffer.decrement_attached_counter(Operation::Infallible);
354 slot.set(None);
355 }
356 }
357
358 fn calc_read_pixel_formats(
359 &self,
360 pixel_type: u32,
361 format: u32,
362 ) -> WebGLResult<ReadPixelsAllowedFormats<'_>> {
363 let array_types = match pixel_type {
364 constants::BYTE => &[Type::Int8][..],
365 constants::SHORT => &[Type::Int16][..],
366 constants::INT => &[Type::Int32][..],
367 constants::UNSIGNED_BYTE => &[Type::Uint8, Type::Uint8Clamped][..],
368 constants::UNSIGNED_SHORT |
369 constants::UNSIGNED_SHORT_4_4_4_4 |
370 constants::UNSIGNED_SHORT_5_5_5_1 |
371 constants::UNSIGNED_SHORT_5_6_5 => &[Type::Uint16][..],
372 constants::UNSIGNED_INT |
373 constants::UNSIGNED_INT_2_10_10_10_REV |
374 constants::UNSIGNED_INT_10F_11F_11F_REV |
375 constants::UNSIGNED_INT_5_9_9_9_REV => &[Type::Uint32][..],
376 constants::FLOAT => &[Type::Float32][..],
377 constants::HALF_FLOAT => &[Type::Uint16][..],
378 _ => return Err(InvalidEnum),
379 };
380 let channels = match format {
381 constants::ALPHA | constants::RED | constants::RED_INTEGER => 1,
382 constants::RG | constants::RG_INTEGER => 2,
383 constants::RGB | constants::RGB_INTEGER => 3,
384 constants::RGBA | constants::RGBA_INTEGER => 4,
385 _ => return Err(InvalidEnum),
386 };
387 Ok(ReadPixelsAllowedFormats {
388 array_types,
389 channels,
390 })
391 }
392
393 fn calc_read_pixel_sizes(
394 &self,
395 width: i32,
396 height: i32,
397 bytes_per_pixel: usize,
398 ) -> WebGLResult<ReadPixelsSizes> {
399 if width < 0 || height < 0 {
400 return Err(InvalidValue);
401 }
402
403 let pixels_per_row = if self.texture_pack_row_length.get() > 0 {
405 self.texture_pack_row_length.get()
406 } else {
407 width as usize
408 };
409 if self.texture_pack_skip_pixels.get() + width as usize > pixels_per_row {
410 return Err(InvalidOperation);
411 }
412
413 let bytes_per_row = pixels_per_row
414 .checked_mul(bytes_per_pixel)
415 .ok_or(InvalidOperation)?;
416 let row_padding_bytes = {
417 let pack_alignment = self.base.get_texture_packing_alignment() as usize;
418 match bytes_per_row % pack_alignment {
419 0 => 0,
420 remainder => pack_alignment - remainder,
421 }
422 };
423 let row_stride = bytes_per_row + row_padding_bytes;
424 let size = if width == 0 || height == 0 {
425 0
426 } else {
427 let full_row_bytes = row_stride
428 .checked_mul(height as usize - 1)
429 .ok_or(InvalidOperation)?;
430 let last_row_bytes = bytes_per_pixel
431 .checked_mul(width as usize)
432 .ok_or(InvalidOperation)?;
433 full_row_bytes
434 .checked_add(last_row_bytes)
435 .ok_or(InvalidOperation)?
436 };
437 let skipped_bytes = {
438 let skipped_row_bytes = self
439 .texture_pack_skip_rows
440 .get()
441 .checked_mul(row_stride)
442 .ok_or(InvalidOperation)?;
443 let skipped_pixel_bytes = self
444 .texture_pack_skip_pixels
445 .get()
446 .checked_mul(bytes_per_pixel)
447 .ok_or(InvalidOperation)?;
448 skipped_row_bytes
449 .checked_add(skipped_pixel_bytes)
450 .ok_or(InvalidOperation)?
451 };
452 Ok(ReadPixelsSizes {
453 row_stride,
454 skipped_bytes,
455 size,
456 })
457 }
458
459 #[expect(unsafe_code)]
460 #[expect(clippy::too_many_arguments)]
461 fn read_pixels_into(
462 &self,
463 x: i32,
464 y: i32,
465 width: i32,
466 height: i32,
467 format: u32,
468 pixel_type: u32,
469 dst: &mut ArrayBufferView,
470 dst_elem_offset: u32,
471 ) {
472 handle_potential_webgl_error!(self.base, self.base.validate_framebuffer(), return);
473
474 if self.bound_pixel_pack_buffer.get().is_some() {
475 return self.base.webgl_error(InvalidOperation);
476 }
477
478 let fb_slot = self.base.get_draw_framebuffer_slot();
479 let fb_readbuffer_valid = match fb_slot.get() {
480 Some(fb) => fb.attachment(fb.read_buffer()).is_some(),
481 None => self.default_fb_readbuffer.get() != constants::NONE,
482 };
483 if !fb_readbuffer_valid {
484 return self.base.webgl_error(InvalidOperation);
485 }
486
487 let dst_byte_offset = {
488 let dst_elem_size = dst.get_array_type().byte_size().unwrap();
489 dst_elem_offset as usize * dst_elem_size
490 };
491 if dst_byte_offset > dst.len() {
492 return self.base.webgl_error(InvalidValue);
493 }
494
495 let dst_array_type = dst.get_array_type();
496 let ReadPixelsAllowedFormats {
497 array_types: allowed_array_types,
498 channels,
499 } = match self.calc_read_pixel_formats(pixel_type, format) {
500 Ok(result) => result,
501 Err(error) => return self.base.webgl_error(error),
502 };
503 if !allowed_array_types.contains(&dst_array_type) {
504 return self.base.webgl_error(InvalidOperation);
505 }
506 if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
507 return self.base.webgl_error(InvalidOperation);
508 }
509
510 let bytes_per_pixel = dst_array_type.byte_size().unwrap() * channels;
511 let ReadPixelsSizes {
512 row_stride,
513 skipped_bytes,
514 size,
515 } = match self.calc_read_pixel_sizes(width, height, bytes_per_pixel) {
516 Ok(result) => result,
517 Err(error) => return self.base.webgl_error(error),
518 };
519 let dst_end = dst_byte_offset + skipped_bytes + size;
520 let dst_pixels = unsafe { dst.as_mut_slice() };
521 if dst_pixels.len() < dst_end {
522 return self.base.webgl_error(InvalidOperation);
523 }
524
525 let dst_byte_offset = {
526 let margin_left = cmp::max(0, -x) as usize;
527 let margin_top = cmp::max(0, -y) as usize;
528 dst_byte_offset +
529 skipped_bytes +
530 margin_left * bytes_per_pixel +
531 margin_top * row_stride
532 };
533 let src_rect = {
534 let (fb_width, fb_height) = handle_potential_webgl_error!(
535 self.base,
536 self.base
537 .get_current_framebuffer_size()
538 .ok_or(InvalidOperation),
539 return
540 );
541 let src_origin = Point2D::new(x, y);
542 let src_size = Size2D::new(width as u32, height as u32);
543 let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
544 match pixels::clip(src_origin, src_size.to_u32(), fb_size.to_u32()) {
545 Some(rect) => rect.to_u32(),
546 None => return,
547 }
548 };
549 let src_row_bytes = handle_potential_webgl_error!(
550 self.base,
551 src_rect
552 .size
553 .width
554 .checked_mul(bytes_per_pixel as u32)
555 .ok_or(InvalidOperation),
556 return
557 );
558
559 let (sender, receiver) = generic_channel::channel().unwrap();
560 self.base.send_command(WebGLCommand::ReadPixels(
561 src_rect, format, pixel_type, sender,
562 ));
563 let (src, _) = receiver.recv().unwrap();
564
565 for i in 0..src_rect.size.height as usize {
566 let src_start = i * src_row_bytes as usize;
567 let dst_start = dst_byte_offset + i * row_stride;
568 dst_pixels[dst_start..dst_start + src_row_bytes as usize]
569 .copy_from_slice(&src[src_start..src_start + src_row_bytes as usize]);
570 }
571 }
572
573 fn uniform_vec_section_uint(
574 &self,
575 vec: Uint32ArrayOrUnsignedLongSequence,
576 offset: u32,
577 length: u32,
578 uniform_size: usize,
579 uniform_location: &WebGLUniformLocation,
580 ) -> WebGLResult<Vec<u32>> {
581 let vec = match vec {
582 Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(),
583 Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v,
584 };
585 self.base
586 .uniform_vec_section::<u32>(vec, offset, length, uniform_size, uniform_location)
587 }
588
589 fn get_default_fb_attachment_param(
590 &self,
591 attachment: u32,
592 pname: u32,
593 mut retval: MutableHandleValue,
594 ) -> WebGLResult<()> {
595 match attachment {
596 constants::BACK | constants::DEPTH | constants::STENCIL => {},
597 _ => return Err(InvalidEnum),
598 }
599
600 if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME {
601 retval.set(NullValue());
602 return Ok(());
603 }
604
605 let attrs = self
606 .GetContextAttributes()
607 .unwrap_or_else(WebGLContextAttributes::empty);
608
609 let intval = match pname {
610 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE => match attachment {
611 constants::DEPTH if !attrs.depth => constants::NONE as _,
612 constants::STENCIL if !attrs.stencil => constants::NONE as _,
613 _ => constants::FRAMEBUFFER_DEFAULT as _,
614 },
615 constants::FRAMEBUFFER_ATTACHMENT_RED_SIZE |
616 constants::FRAMEBUFFER_ATTACHMENT_GREEN_SIZE |
617 constants::FRAMEBUFFER_ATTACHMENT_BLUE_SIZE => match attachment {
618 constants::BACK => 8,
619 _ => 0,
620 },
621 constants::FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE => match attachment {
622 constants::BACK if attrs.alpha => 8,
623 constants::BACK => return Err(InvalidOperation),
624 _ => 0,
625 },
626 constants::FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE => match attachment {
627 constants::DEPTH if attrs.depth => 24,
628 constants::DEPTH => return Err(InvalidOperation),
629 _ => 0,
630 },
631 constants::FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE => match attachment {
632 constants::STENCIL if attrs.stencil => 8,
633 constants::STENCIL => return Err(InvalidOperation),
634 _ => 0,
635 },
636 constants::FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE => match attachment {
637 constants::DEPTH if attrs.depth => constants::UNSIGNED_NORMALIZED as _,
638 constants::STENCIL if attrs.stencil => constants::UNSIGNED_INT as _,
639 constants::DEPTH => return Err(InvalidOperation),
640 constants::STENCIL => return Err(InvalidOperation),
641 _ => constants::UNSIGNED_NORMALIZED as _,
642 },
643 constants::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING => match attachment {
644 constants::DEPTH if !attrs.depth => return Err(InvalidOperation),
645 constants::STENCIL if !attrs.stencil => return Err(InvalidOperation),
646 _ => constants::LINEAR as _,
647 },
648 _ => return Err(InvalidEnum),
649 };
650 retval.set(Int32Value(intval));
651 Ok(())
652 }
653
654 fn get_specific_fb_attachment_param(
655 &self,
656 cx: JSContext,
657 fb: &WebGLFramebuffer,
658 target: u32,
659 attachment: u32,
660 pname: u32,
661 mut rval: MutableHandleValue,
662 ) -> WebGLResult<()> {
663 use crate::dom::webgl::webglframebuffer::WebGLFramebufferAttachmentRoot::{
664 Renderbuffer, Texture,
665 };
666
667 match attachment {
668 constants::DEPTH_ATTACHMENT | constants::STENCIL_ATTACHMENT => {},
669 constants::DEPTH_STENCIL_ATTACHMENT => {
670 if pname == constants::FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE {
671 return Err(InvalidOperation);
672 }
673
674 let a = fb.attachment(constants::DEPTH_ATTACHMENT);
675 let b = fb.attachment(constants::STENCIL_ATTACHMENT);
676 match (a, b) {
677 (Some(Renderbuffer(ref a)), Some(Renderbuffer(ref b))) if a.id() == b.id() => {
678 },
679 (Some(Texture(ref a)), Some(Texture(ref b))) if a.id() == b.id() => {},
680 _ => return Err(InvalidOperation),
681 }
682 },
683 constants::COLOR_ATTACHMENT0..=constants::COLOR_ATTACHMENT15 => {
684 let last_slot =
685 constants::COLOR_ATTACHMENT0 + self.base.limits().max_color_attachments - 1;
686 if last_slot < attachment {
687 return Err(InvalidEnum);
688 }
689 },
690 _ => return Err(InvalidEnum),
691 }
692
693 let attachment = match attachment {
694 constants::DEPTH_STENCIL_ATTACHMENT => constants::DEPTH_ATTACHMENT,
695 _ => attachment,
696 };
697
698 if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME {
699 match fb.attachment(attachment) {
700 Some(Renderbuffer(rb)) => {
701 rb.safe_to_jsval(cx, rval, CanGc::deprecated_note());
702 },
703 Some(Texture(texture)) => {
704 texture.safe_to_jsval(cx, rval, CanGc::deprecated_note());
705 },
706 _ => rval.set(NullValue()),
707 }
708 return Ok(());
709 }
710
711 match pname {
712 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE => {},
713 _ => match fb.attachment(attachment) {
714 Some(webgl_attachment) => match pname {
715 constants::FRAMEBUFFER_ATTACHMENT_RED_SIZE |
716 constants::FRAMEBUFFER_ATTACHMENT_GREEN_SIZE |
717 constants::FRAMEBUFFER_ATTACHMENT_BLUE_SIZE |
718 constants::FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE |
719 constants::FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE |
720 constants::FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE |
721 constants::FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE |
722 constants::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING => {},
723 _ => match webgl_attachment {
724 WebGLFramebufferAttachmentRoot::Renderbuffer(_) => return Err(InvalidEnum),
725 WebGLFramebufferAttachmentRoot::Texture(_) => match pname {
726 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL |
727 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE |
728 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER => {},
729 _ => return Err(InvalidEnum),
730 },
731 },
732 },
733 None => return Err(InvalidOperation),
734 },
735 }
736
737 let (sender, receiver) = webgl_channel().unwrap();
738 self.base
739 .send_command(WebGLCommand::GetFramebufferAttachmentParameter(
740 target, attachment, pname, sender,
741 ));
742
743 let retval = receiver.recv().unwrap();
744 rval.set(Int32Value(retval));
745 Ok(())
746 }
747
748 fn clearbuffer_array_size(&self, buffer: u32, draw_buffer: i32) -> WebGLResult<usize> {
749 match buffer {
750 constants::COLOR => {
751 if draw_buffer < 0 || draw_buffer as u32 >= self.base.limits().max_draw_buffers {
752 return Err(InvalidValue);
753 }
754 Ok(4)
755 },
756 constants::DEPTH | constants::STENCIL | constants::DEPTH_STENCIL => {
757 if draw_buffer != 0 {
758 return Err(InvalidValue);
759 }
760 Ok(1)
761 },
762 _ => unreachable!(),
763 }
764 }
765
766 fn clear_buffer<T: Clone>(
767 &self,
768 buffer: u32,
769 draw_buffer: i32,
770 valid_buffers: &[u32],
771 src_offset: u32,
772 array: Vec<T>,
773 msg: fn(u32, i32, Vec<T>) -> WebGLCommand,
774 ) {
775 if !valid_buffers.contains(&buffer) {
776 return self.base.webgl_error(InvalidEnum);
777 }
778
779 let array_size = handle_potential_webgl_error!(
780 self.base,
781 self.clearbuffer_array_size(buffer, draw_buffer),
782 return
783 );
784 let src_offset = src_offset as usize;
785
786 if array.len() < src_offset + array_size {
787 return self.base.webgl_error(InvalidValue);
788 }
789 let array = array[src_offset..src_offset + array_size].to_vec();
790
791 self.base.send_command(msg(buffer, draw_buffer, array));
792 }
793
794 fn valid_fb_attachment_values(&self, target: u32, attachments: &[u32]) -> bool {
795 let fb_slot = match target {
796 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
797 self.base.get_draw_framebuffer_slot()
798 },
799 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
800 _ => {
801 self.base.webgl_error(InvalidEnum);
802 return false;
803 },
804 };
805
806 if let Some(fb) = fb_slot.get() {
807 if fb.check_status() != constants::FRAMEBUFFER_COMPLETE {
808 return false;
809 }
810
811 for &attachment in attachments {
812 match attachment {
813 constants::DEPTH_ATTACHMENT |
814 constants::STENCIL_ATTACHMENT |
815 constants::DEPTH_STENCIL_ATTACHMENT => {},
816 constants::COLOR_ATTACHMENT0..=constants::COLOR_ATTACHMENT15 => {
817 let last_slot = constants::COLOR_ATTACHMENT0 +
818 self.base.limits().max_color_attachments -
819 1;
820 if last_slot < attachment {
821 return false;
822 }
823 },
824 _ => return false,
825 }
826 }
827 } else {
828 for &attachment in attachments {
829 match attachment {
830 constants::COLOR | constants::DEPTH | constants::STENCIL => {},
831 _ => return false,
832 }
833 }
834 }
835
836 true
837 }
838
839 fn vertex_attrib_i(&self, index: u32, x: i32, y: i32, z: i32, w: i32) {
840 if index >= self.base.limits().max_vertex_attribs {
841 return self.base.webgl_error(InvalidValue);
842 }
843 self.base.current_vertex_attribs()[index as usize] = VertexAttrib::Int(x, y, z, w);
844 self.current_vao()
845 .set_vertex_attrib_type(index, constants::INT);
846 self.base
847 .send_command(WebGLCommand::VertexAttribI(index, x, y, z, w));
848 }
849
850 fn vertex_attrib_u(&self, index: u32, x: u32, y: u32, z: u32, w: u32) {
851 if index >= self.base.limits().max_vertex_attribs {
852 return self.base.webgl_error(InvalidValue);
853 }
854 self.base.current_vertex_attribs()[index as usize] = VertexAttrib::Uint(x, y, z, w);
855 self.current_vao()
856 .set_vertex_attrib_type(index, constants::UNSIGNED_INT);
857 self.base
858 .send_command(WebGLCommand::VertexAttribU(index, x, y, z, w));
859 }
860
861 #[expect(clippy::too_many_arguments)]
862 fn tex_storage(
863 &self,
864 dimensions: u8,
865 target: u32,
866 levels: i32,
867 internal_format: u32,
868 width: i32,
869 height: i32,
870 depth: i32,
871 ) {
872 let expected_dimensions = match target {
873 constants::TEXTURE_2D | constants::TEXTURE_CUBE_MAP => 2,
874 constants::TEXTURE_3D | constants::TEXTURE_2D_ARRAY => 3,
875 _ => return self.base.webgl_error(InvalidEnum),
876 };
877 if dimensions != expected_dimensions {
878 return self.base.webgl_error(InvalidEnum);
879 }
880
881 let validator = TexStorageValidator::new(
882 &self.base,
883 dimensions,
884 target,
885 levels,
886 internal_format,
887 width,
888 height,
889 depth,
890 );
891 let TexStorageValidatorResult {
892 texture,
893 target,
894 levels,
895 internal_format,
896 width,
897 height,
898 depth,
899 } = match validator.validate() {
900 Ok(result) => result,
901 Err(_) => return, };
903
904 handle_potential_webgl_error!(
905 self.base,
906 texture.storage(target, levels, internal_format, width, height, depth)
907 );
908 }
909
910 #[expect(clippy::too_many_arguments)]
911 fn tex_image_3d(
912 &self,
913 texture: &WebGLTexture,
914 target: TexImageTarget,
915 data_type: TexDataType,
916 internal_format: TexFormat,
917 format: TexFormat,
918 level: u32,
919 width: u32,
920 height: u32,
921 depth: u32,
922 _border: u32,
923 unpacking_alignment: u32,
924 data: TexPixels,
925 ) {
926 handle_potential_webgl_error!(
927 self.base,
928 texture.initialize(
929 target,
930 width,
931 height,
932 depth,
933 internal_format,
934 level,
935 Some(data_type)
936 )
937 );
938
939 let internal_format = self
940 .base
941 .extension_manager()
942 .get_effective_tex_internal_format(internal_format, data_type.as_gl_constant());
943 let effective_data_type = self
944 .base
945 .extension_manager()
946 .effective_type(data_type.as_gl_constant());
947
948 self.base.send_command(WebGLCommand::TexImage3D {
949 target: target.as_gl_constant(),
950 level,
951 internal_format,
952 size: data.size(),
953 depth,
954 format,
955 data_type,
956 effective_data_type,
957 unpacking_alignment,
958 alpha_treatment: data.alpha_treatment(),
959 y_axis_treatment: data.y_axis_treatment(),
960 pixel_format: data.pixel_format(),
961 data: data.into_shared_memory().into(),
962 });
963 if let Some(fb) = self.base.bound_draw_framebuffer() {
966 fb.invalidate_texture(texture);
967 }
968 }
969}
970
971impl CanvasContext for WebGL2RenderingContext {
972 type ID = WebGLContextId;
973
974 fn context_id(&self) -> Self::ID {
975 self.base.context_id()
976 }
977
978 fn canvas(&self) -> Option<RootedHTMLCanvasElementOrOffscreenCanvas> {
979 self.base.canvas()
980 }
981
982 fn resize(&self) {
983 self.base.resize();
984 }
985
986 fn reset_bitmap(&self) {
987 self.base.reset_bitmap();
988 }
989
990 fn get_image_data(&self) -> Option<Snapshot> {
991 self.base.get_image_data()
992 }
993
994 fn mark_as_dirty(&self) {
995 self.base.mark_as_dirty()
996 }
997}
998
999impl WebGL2RenderingContextMethods<crate::DomTypeHolder> for WebGL2RenderingContext {
1000 fn Canvas(&self) -> RootedHTMLCanvasElementOrOffscreenCanvas {
1002 self.base.Canvas()
1003 }
1004
1005 fn Flush(&self) {
1007 self.base.Flush()
1008 }
1009
1010 fn Finish(&self) {
1012 self.base.Finish()
1013 }
1014
1015 fn DrawingBufferWidth(&self) -> i32 {
1017 self.base.DrawingBufferWidth()
1018 }
1019
1020 fn DrawingBufferHeight(&self) -> i32 {
1022 self.base.DrawingBufferHeight()
1023 }
1024
1025 fn GetBufferParameter(
1027 &self,
1028 _cx: JSContext,
1029 target: u32,
1030 parameter: u32,
1031 mut retval: MutableHandleValue,
1032 ) {
1033 let buffer = handle_potential_webgl_error!(
1034 self.base,
1035 self.bound_buffer(target),
1036 return retval.set(NullValue())
1037 );
1038 self.base.get_buffer_param(buffer, parameter, retval)
1039 }
1040
1041 fn GetParameter(&self, cx: JSContext, parameter: u32, mut rval: MutableHandleValue) {
1043 match parameter {
1044 constants::VERSION => {
1045 "WebGL 2.0".safe_to_jsval(cx, rval, CanGc::deprecated_note());
1046 return;
1047 },
1048 constants::SHADING_LANGUAGE_VERSION => {
1049 "WebGL GLSL ES 3.00".safe_to_jsval(cx, rval, CanGc::deprecated_note());
1050 return;
1051 },
1052 constants::MAX_CLIENT_WAIT_TIMEOUT_WEBGL => {
1053 rval.set(DoubleValue(
1054 self.base.limits().max_client_wait_timeout_webgl.as_nanos() as f64,
1055 ));
1056 return;
1057 },
1058 constants::MAX_SERVER_WAIT_TIMEOUT => {
1059 rval.set(DoubleValue(
1060 self.base.limits().max_server_wait_timeout.as_nanos() as f64,
1061 ));
1062 return;
1063 },
1064 constants::SAMPLER_BINDING => {
1065 let idx = (self.base.textures().active_unit_enum() - constants::TEXTURE0) as usize;
1066 assert!(idx < self.samplers.len());
1067 let sampler = self.samplers[idx].get();
1068 sampler.safe_to_jsval(cx, rval, CanGc::deprecated_note());
1069 return;
1070 },
1071 constants::COPY_READ_BUFFER_BINDING => {
1072 self.bound_copy_read_buffer
1073 .get()
1074 .safe_to_jsval(cx, rval, CanGc::deprecated_note());
1075 return;
1076 },
1077 constants::COPY_WRITE_BUFFER_BINDING => {
1078 self.bound_copy_write_buffer.get().safe_to_jsval(
1079 cx,
1080 rval,
1081 CanGc::deprecated_note(),
1082 );
1083 return;
1084 },
1085 constants::PIXEL_PACK_BUFFER_BINDING => {
1086 self.bound_pixel_pack_buffer.get().safe_to_jsval(
1087 cx,
1088 rval,
1089 CanGc::deprecated_note(),
1090 );
1091 return;
1092 },
1093 constants::PIXEL_UNPACK_BUFFER_BINDING => {
1094 self.bound_pixel_unpack_buffer.get().safe_to_jsval(
1095 cx,
1096 rval,
1097 CanGc::deprecated_note(),
1098 );
1099 return;
1100 },
1101 constants::TRANSFORM_FEEDBACK_BUFFER_BINDING => {
1102 self.bound_transform_feedback_buffer.get().safe_to_jsval(
1103 cx,
1104 rval,
1105 CanGc::deprecated_note(),
1106 );
1107 return;
1108 },
1109 constants::UNIFORM_BUFFER_BINDING => {
1110 self.bound_uniform_buffer
1111 .get()
1112 .safe_to_jsval(cx, rval, CanGc::deprecated_note());
1113 return;
1114 },
1115 constants::TRANSFORM_FEEDBACK_BINDING => {
1116 self.current_transform_feedback.get().safe_to_jsval(
1117 cx,
1118 rval,
1119 CanGc::deprecated_note(),
1120 );
1121 return;
1122 },
1123 constants::ELEMENT_ARRAY_BUFFER_BINDING => {
1124 let buffer = self.current_vao().element_array_buffer().get();
1125 buffer.safe_to_jsval(cx, rval, CanGc::deprecated_note());
1126 return;
1127 },
1128 constants::VERTEX_ARRAY_BINDING => {
1129 let vao = self.current_vao();
1130 let vao = vao.id().map(|_| &*vao);
1131 vao.safe_to_jsval(cx, rval, CanGc::deprecated_note());
1132 return;
1133 },
1134 constants::READ_FRAMEBUFFER_BINDING => {
1136 self.base.get_read_framebuffer_slot().get().safe_to_jsval(
1137 cx,
1138 rval,
1139 CanGc::deprecated_note(),
1140 );
1141 return;
1142 },
1143 constants::READ_BUFFER => {
1144 let buffer = match self.base.get_read_framebuffer_slot().get() {
1145 Some(fb) => fb.read_buffer(),
1146 None => self.default_fb_readbuffer.get(),
1147 };
1148 rval.set(UInt32Value(buffer));
1149 return;
1150 },
1151 constants::DRAW_BUFFER0..=constants::DRAW_BUFFER15 => {
1152 let buffer = match self.base.get_read_framebuffer_slot().get() {
1153 Some(fb) => {
1154 let idx = parameter - constants::DRAW_BUFFER0;
1155 fb.draw_buffer_i(idx as usize)
1156 },
1157 None if parameter == constants::DRAW_BUFFER0 => {
1158 self.default_fb_readbuffer.get()
1159 },
1160 None => constants::NONE,
1161 };
1162 rval.set(UInt32Value(buffer));
1163 return;
1164 },
1165 constants::MAX_TEXTURE_LOD_BIAS => {
1166 rval.set(DoubleValue(self.base.limits().max_texture_lod_bias as f64));
1167 return;
1168 },
1169 constants::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS => {
1170 rval.set(DoubleValue(
1171 self.base.limits().max_combined_fragment_uniform_components as f64,
1172 ));
1173 return;
1174 },
1175 constants::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS => {
1176 rval.set(DoubleValue(
1177 self.base.limits().max_combined_vertex_uniform_components as f64,
1178 ));
1179 return;
1180 },
1181 constants::MAX_ELEMENT_INDEX => {
1182 rval.set(DoubleValue(self.base.limits().max_element_index as f64));
1183 return;
1184 },
1185 constants::MAX_UNIFORM_BLOCK_SIZE => {
1186 rval.set(DoubleValue(
1187 self.base.limits().max_uniform_block_size as f64,
1188 ));
1189 return;
1190 },
1191 constants::MIN_PROGRAM_TEXEL_OFFSET => {
1192 rval.set(Int32Value(self.base.limits().min_program_texel_offset));
1193 return;
1194 },
1195 _ => {},
1196 }
1197
1198 let limit = match parameter {
1199 constants::MAX_3D_TEXTURE_SIZE => Some(self.base.limits().max_3d_texture_size),
1200 constants::MAX_ARRAY_TEXTURE_LAYERS => {
1201 Some(self.base.limits().max_array_texture_layers)
1202 },
1203 constants::MAX_COLOR_ATTACHMENTS => Some(self.base.limits().max_color_attachments),
1204 constants::MAX_COMBINED_UNIFORM_BLOCKS => {
1205 Some(self.base.limits().max_combined_uniform_blocks)
1206 },
1207 constants::MAX_DRAW_BUFFERS => Some(self.base.limits().max_draw_buffers),
1208 constants::MAX_ELEMENTS_INDICES => Some(self.base.limits().max_elements_indices),
1209 constants::MAX_ELEMENTS_VERTICES => Some(self.base.limits().max_elements_vertices),
1210 constants::MAX_FRAGMENT_INPUT_COMPONENTS => {
1211 Some(self.base.limits().max_fragment_input_components)
1212 },
1213 constants::MAX_FRAGMENT_UNIFORM_BLOCKS => {
1214 Some(self.base.limits().max_fragment_uniform_blocks)
1215 },
1216 constants::MAX_FRAGMENT_UNIFORM_COMPONENTS => {
1217 Some(self.base.limits().max_fragment_uniform_components)
1218 },
1219 constants::MAX_PROGRAM_TEXEL_OFFSET => {
1220 Some(self.base.limits().max_program_texel_offset)
1221 },
1222 constants::MAX_SAMPLES => Some(self.base.limits().max_samples),
1223 constants::MAX_UNIFORM_BUFFER_BINDINGS => {
1224 Some(self.base.limits().max_uniform_buffer_bindings)
1225 },
1226 constants::MAX_VARYING_COMPONENTS => Some(self.base.limits().max_varying_components),
1227 constants::MAX_VERTEX_OUTPUT_COMPONENTS => {
1228 Some(self.base.limits().max_vertex_output_components)
1229 },
1230 constants::MAX_VERTEX_UNIFORM_BLOCKS => {
1231 Some(self.base.limits().max_vertex_uniform_blocks)
1232 },
1233 constants::MAX_VERTEX_UNIFORM_COMPONENTS => {
1234 Some(self.base.limits().max_vertex_uniform_components)
1235 },
1236 constants::UNIFORM_BUFFER_OFFSET_ALIGNMENT => {
1237 Some(self.base.limits().uniform_buffer_offset_alignment)
1238 },
1239 _ => None,
1240 };
1241 if let Some(limit) = limit {
1242 rval.set(UInt32Value(limit));
1243 return;
1244 }
1245
1246 self.base.GetParameter(cx, parameter, rval)
1247 }
1248
1249 fn GetTexParameter(&self, cx: JSContext, target: u32, pname: u32, retval: MutableHandleValue) {
1251 self.base.GetTexParameter(cx, target, pname, retval)
1252 }
1253
1254 fn GetError(&self) -> u32 {
1256 self.base.GetError()
1257 }
1258
1259 fn GetContextAttributes(&self) -> Option<WebGLContextAttributes> {
1261 self.base.GetContextAttributes()
1262 }
1263
1264 fn IsContextLost(&self) -> bool {
1266 self.base.IsContextLost()
1267 }
1268
1269 fn GetSupportedExtensions(&self) -> Option<Vec<DOMString>> {
1271 self.base.GetSupportedExtensions()
1272 }
1273
1274 fn GetExtension(&self, cx: JSContext, name: DOMString) -> Option<NonNull<JSObject>> {
1276 self.base.GetExtension(cx, name)
1277 }
1278
1279 fn GetFramebufferAttachmentParameter(
1281 &self,
1282 cx: JSContext,
1283 target: u32,
1284 attachment: u32,
1285 pname: u32,
1286 mut rval: MutableHandleValue,
1287 ) {
1288 let fb_slot = match target {
1289 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
1290 self.base.get_draw_framebuffer_slot()
1291 },
1292 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
1293 _ => {
1294 self.base.webgl_error(InvalidEnum);
1295 rval.set(NullValue());
1296 return;
1297 },
1298 };
1299
1300 if let Some(fb) = fb_slot.get() {
1301 handle_potential_webgl_error!(
1303 self.base,
1304 fb.validate_transparent(),
1305 return rval.set(NullValue())
1306 );
1307 handle_potential_webgl_error!(
1308 self.base,
1309 self.get_specific_fb_attachment_param(
1310 cx,
1311 &fb,
1312 target,
1313 attachment,
1314 pname,
1315 rval.reborrow()
1316 ),
1317 rval.set(NullValue())
1318 )
1319 } else {
1320 handle_potential_webgl_error!(
1322 self.base,
1323 self.get_default_fb_attachment_param(attachment, pname, rval.reborrow()),
1324 rval.set(NullValue())
1325 )
1326 }
1327 }
1328
1329 fn GetRenderbufferParameter(
1331 &self,
1332 cx: JSContext,
1333 target: u32,
1334 pname: u32,
1335 retval: MutableHandleValue,
1336 ) {
1337 self.base
1338 .GetRenderbufferParameter(cx, target, pname, retval)
1339 }
1340
1341 fn ActiveTexture(&self, texture: u32) {
1343 self.base.ActiveTexture(texture)
1344 }
1345
1346 fn BlendColor(&self, r: f32, g: f32, b: f32, a: f32) {
1348 self.base.BlendColor(r, g, b, a)
1349 }
1350
1351 fn BlendEquation(&self, mode: u32) {
1353 self.base.BlendEquation(mode)
1354 }
1355
1356 fn BlendEquationSeparate(&self, mode_rgb: u32, mode_alpha: u32) {
1358 self.base.BlendEquationSeparate(mode_rgb, mode_alpha)
1359 }
1360
1361 fn BlendFunc(&self, src_factor: u32, dest_factor: u32) {
1363 self.base.BlendFunc(src_factor, dest_factor)
1364 }
1365
1366 fn BlendFuncSeparate(&self, src_rgb: u32, dest_rgb: u32, src_alpha: u32, dest_alpha: u32) {
1368 self.base
1369 .BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha)
1370 }
1371
1372 fn AttachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
1374 self.base.AttachShader(program, shader)
1375 }
1376
1377 fn DetachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
1379 self.base.DetachShader(program, shader)
1380 }
1381
1382 fn BindAttribLocation(&self, program: &WebGLProgram, index: u32, name: DOMString) {
1384 self.base.BindAttribLocation(program, index, name)
1385 }
1386
1387 fn BindBuffer(&self, target: u32, buffer: Option<&WebGLBuffer>) {
1389 let current_vao;
1390 let slot = match target {
1391 constants::COPY_READ_BUFFER => &self.bound_copy_read_buffer,
1392 constants::COPY_WRITE_BUFFER => &self.bound_copy_write_buffer,
1393 constants::PIXEL_PACK_BUFFER => &self.bound_pixel_pack_buffer,
1394 constants::PIXEL_UNPACK_BUFFER => &self.bound_pixel_unpack_buffer,
1395 constants::TRANSFORM_FEEDBACK_BUFFER => &self.bound_transform_feedback_buffer,
1396 constants::UNIFORM_BUFFER => &self.bound_uniform_buffer,
1397 constants::ELEMENT_ARRAY_BUFFER => {
1398 current_vao = self.current_vao();
1399 current_vao.element_array_buffer()
1400 },
1401 _ => return self.base.BindBuffer(target, buffer),
1402 };
1403 self.base.bind_buffer_maybe(slot, target, buffer);
1404 }
1405
1406 fn BindFramebuffer(&self, target: u32, framebuffer: Option<&WebGLFramebuffer>) {
1408 handle_potential_webgl_error!(
1409 self.base,
1410 self.base.validate_new_framebuffer_binding(framebuffer),
1411 return
1412 );
1413
1414 let (bind_read, bind_draw) = match target {
1415 constants::FRAMEBUFFER => (true, true),
1416 constants::READ_FRAMEBUFFER => (true, false),
1417 constants::DRAW_FRAMEBUFFER => (false, true),
1418 _ => return self.base.webgl_error(InvalidEnum),
1419 };
1420 if bind_read {
1421 self.base.bind_framebuffer_to(
1422 target,
1423 framebuffer,
1424 self.base.get_read_framebuffer_slot(),
1425 );
1426 }
1427 if bind_draw {
1428 self.base.bind_framebuffer_to(
1429 target,
1430 framebuffer,
1431 self.base.get_draw_framebuffer_slot(),
1432 );
1433 }
1434 }
1435
1436 fn BindRenderbuffer(&self, target: u32, renderbuffer: Option<&WebGLRenderbuffer>) {
1438 self.base.BindRenderbuffer(target, renderbuffer)
1439 }
1440
1441 fn BindTexture(&self, target: u32, texture: Option<&WebGLTexture>) {
1443 self.base.BindTexture(target, texture)
1444 }
1445
1446 fn GenerateMipmap(&self, target: u32) {
1448 self.base.GenerateMipmap(target)
1449 }
1450
1451 fn BufferData_(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
1453 let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1454 let bound_buffer =
1455 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1456 self.base.buffer_data(target, data, usage, bound_buffer)
1457 }
1458
1459 fn BufferData(&self, target: u32, size: i64, usage: u32) {
1461 let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1462 let bound_buffer =
1463 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1464 self.base.buffer_data_(target, size, usage, bound_buffer)
1465 }
1466
1467 #[expect(unsafe_code)]
1469 fn BufferData__(
1470 &self,
1471 target: u32,
1472 data: CustomAutoRooterGuard<ArrayBufferView>,
1473 usage: u32,
1474 elem_offset: u32,
1475 length: u32,
1476 ) {
1477 let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1478 let bound_buffer =
1479 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1480 let bound_buffer =
1481 handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1482
1483 let elem_size = data.get_array_type().byte_size().unwrap();
1484 let elem_count = data.len() / elem_size;
1485 let elem_offset = elem_offset as usize;
1486 let byte_offset = elem_offset * elem_size;
1487
1488 if byte_offset > data.len() {
1489 return self.base.webgl_error(InvalidValue);
1490 }
1491
1492 let copy_count = if length == 0 {
1493 elem_count - elem_offset
1494 } else {
1495 length as usize
1496 };
1497 if copy_count == 0 {
1498 return;
1499 }
1500 let copy_bytes = copy_count * elem_size;
1501
1502 if byte_offset + copy_bytes > data.len() {
1503 return self.base.webgl_error(InvalidValue);
1504 }
1505
1506 let data_end = byte_offset + copy_bytes;
1507 let data: &[u8] = unsafe { &data.as_slice()[byte_offset..data_end] };
1508 handle_potential_webgl_error!(self.base, bound_buffer.buffer_data(target, data, usage));
1509 }
1510
1511 fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
1513 let bound_buffer =
1514 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1515 self.base
1516 .buffer_sub_data(target, offset, data, bound_buffer)
1517 }
1518
1519 #[expect(unsafe_code)]
1521 fn BufferSubData_(
1522 &self,
1523 target: u32,
1524 dst_byte_offset: i64,
1525 src_data: CustomAutoRooterGuard<ArrayBufferView>,
1526 src_elem_offset: u32,
1527 length: u32,
1528 ) {
1529 let bound_buffer =
1530 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1531 let bound_buffer =
1532 handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1533
1534 let src_elem_size = src_data.get_array_type().byte_size().unwrap();
1535 let src_elem_count = src_data.len() / src_elem_size;
1536 let src_elem_offset = src_elem_offset as usize;
1537 let src_byte_offset = src_elem_offset * src_elem_size;
1538
1539 if dst_byte_offset < 0 || src_byte_offset > src_data.len() {
1540 return self.base.webgl_error(InvalidValue);
1541 }
1542
1543 let copy_count = if length == 0 {
1544 src_elem_count - src_elem_offset
1545 } else {
1546 length as usize
1547 };
1548 if copy_count == 0 {
1549 return;
1550 }
1551 let copy_bytes = copy_count * src_elem_size;
1552
1553 let dst_byte_offset = dst_byte_offset as usize;
1554 if dst_byte_offset + copy_bytes > bound_buffer.capacity() ||
1555 src_byte_offset + copy_bytes > src_data.len()
1556 {
1557 return self.base.webgl_error(InvalidValue);
1558 }
1559
1560 let (sender, receiver) = generic_channel::channel().unwrap();
1561 self.base.send_command(WebGLCommand::BufferSubData(
1562 target,
1563 dst_byte_offset as isize,
1564 receiver,
1565 ));
1566 let src_end = src_byte_offset + copy_bytes;
1567 let data: &[u8] = unsafe { &src_data.as_slice()[src_byte_offset..src_end] };
1568 let buffer = GenericSharedMemory::from_bytes(data);
1569 sender.send(buffer).unwrap();
1570 }
1571
1572 fn CopyBufferSubData(
1574 &self,
1575 read_target: u32,
1576 write_target: u32,
1577 read_offset: i64,
1578 write_offset: i64,
1579 size: i64,
1580 ) {
1581 if read_offset < 0 || write_offset < 0 || size < 0 {
1582 return self.base.webgl_error(InvalidValue);
1583 }
1584
1585 let read_buffer =
1586 handle_potential_webgl_error!(self.base, self.bound_buffer(read_target), return);
1587 let read_buffer =
1588 handle_potential_webgl_error!(self.base, read_buffer.ok_or(InvalidOperation), return);
1589
1590 let write_buffer =
1591 handle_potential_webgl_error!(self.base, self.bound_buffer(write_target), return);
1592 let write_buffer =
1593 handle_potential_webgl_error!(self.base, write_buffer.ok_or(InvalidOperation), return);
1594
1595 let read_until = read_offset + size;
1596 let write_until = write_offset + size;
1597 if read_until as usize > read_buffer.capacity() ||
1598 write_until as usize > write_buffer.capacity()
1599 {
1600 return self.base.webgl_error(InvalidValue);
1601 }
1602
1603 if read_target == write_target {
1604 let is_separate = read_until <= write_offset || write_until <= read_offset;
1605 if !is_separate {
1606 return self.base.webgl_error(InvalidValue);
1607 }
1608 }
1609 let src_is_elemarray = read_buffer
1610 .target()
1611 .is_some_and(|t| t == constants::ELEMENT_ARRAY_BUFFER);
1612 let dst_is_elemarray = write_buffer
1613 .target()
1614 .is_some_and(|t| t == constants::ELEMENT_ARRAY_BUFFER);
1615 if src_is_elemarray != dst_is_elemarray {
1616 return self.base.webgl_error(InvalidOperation);
1617 }
1618
1619 self.base.send_command(WebGLCommand::CopyBufferSubData(
1620 read_target,
1621 write_target,
1622 read_offset,
1623 write_offset,
1624 size,
1625 ));
1626 }
1627
1628 #[expect(unsafe_code)]
1630 fn GetBufferSubData(
1631 &self,
1632 target: u32,
1633 src_byte_offset: i64,
1634 mut dst_buffer: CustomAutoRooterGuard<ArrayBufferView>,
1635 dst_elem_offset: u32,
1636 length: u32,
1637 ) {
1638 let bound_buffer =
1639 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1640 let bound_buffer =
1641 handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1642
1643 let dst_elem_size = dst_buffer.get_array_type().byte_size().unwrap();
1644 let dst_elem_count = dst_buffer.len() / dst_elem_size;
1645 let dst_elem_offset = dst_elem_offset as usize;
1646 let dst_byte_offset = dst_elem_offset * dst_elem_size;
1647
1648 if src_byte_offset < 0 || dst_byte_offset > dst_buffer.len() {
1649 return self.base.webgl_error(InvalidValue);
1650 }
1651
1652 let copy_count = if length == 0 {
1653 dst_elem_count - dst_elem_offset
1654 } else {
1655 length as usize
1656 };
1657 if copy_count == 0 {
1658 return;
1659 }
1660 let copy_bytes = copy_count * dst_elem_size;
1661
1662 let src_byte_offset = src_byte_offset as usize;
1665 if src_byte_offset + copy_bytes > bound_buffer.capacity() ||
1666 dst_byte_offset + copy_bytes > dst_buffer.len()
1667 {
1668 return self.base.webgl_error(InvalidValue);
1669 }
1670
1671 let (sender, receiver) = generic_channel::channel().unwrap();
1672 self.base.send_command(WebGLCommand::GetBufferSubData(
1673 target,
1674 src_byte_offset,
1675 copy_bytes,
1676 sender,
1677 ));
1678 let data = receiver.recv().unwrap();
1679 let dst_end = dst_byte_offset + copy_bytes;
1680 unsafe {
1681 dst_buffer.as_mut_slice()[dst_byte_offset..dst_end].copy_from_slice(&data);
1682 }
1683 }
1684
1685 #[expect(unsafe_code)]
1687 fn CompressedTexImage2D(
1688 &self,
1689 target: u32,
1690 level: i32,
1691 internal_format: u32,
1692 width: i32,
1693 height: i32,
1694 border: i32,
1695 pixels: CustomAutoRooterGuard<ArrayBufferView>,
1696 src_offset: u32,
1697 src_length_override: u32,
1698 ) {
1699 let mut data = unsafe { pixels.as_slice() };
1700 let start = src_offset as usize;
1701 let end = (src_offset + src_length_override) as usize;
1702 if start > data.len() || end > data.len() {
1703 self.base.webgl_error(InvalidValue);
1704 return;
1705 }
1706 if src_length_override != 0 {
1707 data = &data[start..end];
1708 }
1709 self.base.compressed_tex_image_2d(
1710 target,
1711 level,
1712 internal_format,
1713 width,
1714 height,
1715 border,
1716 data,
1717 )
1718 }
1719
1720 #[expect(unsafe_code)]
1722 fn CompressedTexSubImage2D(
1723 &self,
1724 target: u32,
1725 level: i32,
1726 xoffset: i32,
1727 yoffset: i32,
1728 width: i32,
1729 height: i32,
1730 format: u32,
1731 pixels: CustomAutoRooterGuard<ArrayBufferView>,
1732 src_offset: u32,
1733 src_length_override: u32,
1734 ) {
1735 let mut data = unsafe { pixels.as_slice() };
1736 let start = src_offset as usize;
1737 let end = (src_offset + src_length_override) as usize;
1738 if start > data.len() || end > data.len() {
1739 self.base.webgl_error(InvalidValue);
1740 return;
1741 }
1742 if src_length_override != 0 {
1743 data = &data[start..end];
1744 }
1745 self.base.compressed_tex_sub_image_2d(
1746 target, level, xoffset, yoffset, width, height, format, data,
1747 )
1748 }
1749
1750 fn CopyTexImage2D(
1752 &self,
1753 target: u32,
1754 level: i32,
1755 internal_format: u32,
1756 x: i32,
1757 y: i32,
1758 width: i32,
1759 height: i32,
1760 border: i32,
1761 ) {
1762 self.base
1763 .CopyTexImage2D(target, level, internal_format, x, y, width, height, border)
1764 }
1765
1766 fn CopyTexSubImage2D(
1768 &self,
1769 target: u32,
1770 level: i32,
1771 xoffset: i32,
1772 yoffset: i32,
1773 x: i32,
1774 y: i32,
1775 width: i32,
1776 height: i32,
1777 ) {
1778 self.base
1779 .CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height)
1780 }
1781
1782 fn Clear(&self, mask: u32) {
1784 self.base.Clear(mask)
1785 }
1786
1787 fn ClearColor(&self, red: f32, green: f32, blue: f32, alpha: f32) {
1789 self.base.ClearColor(red, green, blue, alpha)
1790 }
1791
1792 fn ClearDepth(&self, depth: f32) {
1794 self.base.ClearDepth(depth)
1795 }
1796
1797 fn ClearStencil(&self, stencil: i32) {
1799 self.base.ClearStencil(stencil)
1800 }
1801
1802 fn ColorMask(&self, r: bool, g: bool, b: bool, a: bool) {
1804 self.base.ColorMask(r, g, b, a)
1805 }
1806
1807 fn CullFace(&self, mode: u32) {
1809 self.base.CullFace(mode)
1810 }
1811
1812 fn FrontFace(&self, mode: u32) {
1814 self.base.FrontFace(mode)
1815 }
1816 fn DepthFunc(&self, func: u32) {
1818 self.base.DepthFunc(func)
1819 }
1820
1821 fn DepthMask(&self, flag: bool) {
1823 self.base.DepthMask(flag)
1824 }
1825
1826 fn DepthRange(&self, near: f32, far: f32) {
1828 self.base.DepthRange(near, far)
1829 }
1830
1831 fn Enable(&self, cap: u32) {
1833 match cap {
1834 constants::RASTERIZER_DISCARD => {
1835 self.enable_rasterizer_discard.set(true);
1836 self.base.send_command(WebGLCommand::Enable(cap));
1837 },
1838 _ => self.base.Enable(cap),
1839 }
1840 }
1841
1842 fn Disable(&self, cap: u32) {
1844 match cap {
1845 constants::RASTERIZER_DISCARD => {
1846 self.enable_rasterizer_discard.set(false);
1847 self.base.send_command(WebGLCommand::Disable(cap));
1848 },
1849 _ => self.base.Disable(cap),
1850 }
1851 }
1852
1853 fn CompileShader(&self, shader: &WebGLShader) {
1855 self.base.CompileShader(shader)
1856 }
1857
1858 fn CreateBuffer(&self) -> Option<DomRoot<WebGLBuffer>> {
1860 self.base.CreateBuffer()
1861 }
1862
1863 fn CreateFramebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
1865 self.base.CreateFramebuffer()
1866 }
1867
1868 fn CreateRenderbuffer(&self) -> Option<DomRoot<WebGLRenderbuffer>> {
1870 self.base.CreateRenderbuffer()
1871 }
1872
1873 fn CreateTexture(&self) -> Option<DomRoot<WebGLTexture>> {
1875 self.base.CreateTexture()
1876 }
1877
1878 fn CreateProgram(&self) -> Option<DomRoot<WebGLProgram>> {
1880 self.base.CreateProgram()
1881 }
1882
1883 fn CreateShader(&self, shader_type: u32) -> Option<DomRoot<WebGLShader>> {
1885 self.base.CreateShader(shader_type)
1886 }
1887
1888 fn CreateVertexArray(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
1890 self.base.create_vertex_array_webgl2()
1891 }
1892
1893 fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) {
1895 let buffer = match buffer {
1896 Some(buffer) => buffer,
1897 None => return,
1898 };
1899 handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
1900 if buffer.is_marked_for_deletion() {
1901 return;
1902 }
1903 self.current_vao().unbind_buffer(buffer);
1904 self.unbind_from(self.base.array_buffer_slot(), buffer);
1905 self.unbind_from(&self.bound_copy_read_buffer, buffer);
1906 self.unbind_from(&self.bound_copy_write_buffer, buffer);
1907 self.unbind_from(&self.bound_pixel_pack_buffer, buffer);
1908 self.unbind_from(&self.bound_pixel_unpack_buffer, buffer);
1909 self.unbind_from(&self.bound_transform_feedback_buffer, buffer);
1910 self.unbind_from(&self.bound_uniform_buffer, buffer);
1911
1912 for binding in self.indexed_uniform_buffer_bindings.iter() {
1913 self.unbind_from(&binding.buffer, buffer);
1914 }
1915 for binding in self.indexed_transform_feedback_buffer_bindings.iter() {
1916 self.unbind_from(&binding.buffer, buffer);
1917 }
1918
1919 buffer.mark_for_deletion(Operation::Infallible);
1920 }
1921
1922 fn DeleteFramebuffer(&self, framebuffer: Option<&WebGLFramebuffer>) {
1924 self.base.DeleteFramebuffer(framebuffer)
1925 }
1926
1927 fn DeleteRenderbuffer(&self, renderbuffer: Option<&WebGLRenderbuffer>) {
1929 self.base.DeleteRenderbuffer(renderbuffer)
1930 }
1931
1932 fn DeleteTexture(&self, texture: Option<&WebGLTexture>) {
1934 self.base.DeleteTexture(texture)
1935 }
1936
1937 fn DeleteProgram(&self, program: Option<&WebGLProgram>) {
1939 self.base.DeleteProgram(program)
1940 }
1941
1942 fn DeleteShader(&self, shader: Option<&WebGLShader>) {
1944 self.base.DeleteShader(shader)
1945 }
1946
1947 fn DeleteVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) {
1949 self.base.delete_vertex_array_webgl2(vertex_array);
1950 }
1951
1952 fn DrawArrays(&self, mode: u32, first: i32, count: i32) {
1954 self.validate_uniform_block_for_draw();
1955 self.validate_vertex_attribs_for_draw();
1956 self.base.DrawArrays(mode, first, count)
1957 }
1958
1959 fn DrawElements(&self, mode: u32, count: i32, type_: u32, offset: i64) {
1961 self.validate_uniform_block_for_draw();
1962 self.validate_vertex_attribs_for_draw();
1963 self.base.DrawElements(mode, count, type_, offset)
1964 }
1965
1966 fn EnableVertexAttribArray(&self, attrib_id: u32) {
1968 self.base.EnableVertexAttribArray(attrib_id)
1969 }
1970
1971 fn DisableVertexAttribArray(&self, attrib_id: u32) {
1973 self.base.DisableVertexAttribArray(attrib_id)
1974 }
1975
1976 fn GetActiveUniform(
1978 &self,
1979 program: &WebGLProgram,
1980 index: u32,
1981 ) -> Option<DomRoot<WebGLActiveInfo>> {
1982 self.base.GetActiveUniform(program, index)
1983 }
1984
1985 fn GetActiveAttrib(
1987 &self,
1988 program: &WebGLProgram,
1989 index: u32,
1990 ) -> Option<DomRoot<WebGLActiveInfo>> {
1991 self.base.GetActiveAttrib(program, index)
1992 }
1993
1994 fn GetAttribLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
1996 self.base.GetAttribLocation(program, name)
1997 }
1998
1999 fn GetFragDataLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
2001 handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return -1);
2002 handle_potential_webgl_error!(self.base, program.get_frag_data_location(name), -1)
2003 }
2004
2005 fn GetProgramInfoLog(&self, program: &WebGLProgram) -> Option<DOMString> {
2007 self.base.GetProgramInfoLog(program)
2008 }
2009
2010 fn GetProgramParameter(
2012 &self,
2013 cx: JSContext,
2014 program: &WebGLProgram,
2015 param_id: u32,
2016 mut retval: MutableHandleValue,
2017 ) {
2018 handle_potential_webgl_error!(
2019 self.base,
2020 self.base.validate_ownership(program),
2021 return retval.set(NullValue())
2022 );
2023 if program.is_deleted() {
2024 self.base.webgl_error(InvalidOperation);
2025 return retval.set(NullValue());
2026 }
2027 match param_id {
2028 constants::TRANSFORM_FEEDBACK_VARYINGS => {
2029 retval.set(Int32Value(program.transform_feedback_varyings_length()))
2030 },
2031 constants::TRANSFORM_FEEDBACK_BUFFER_MODE => {
2032 retval.set(Int32Value(program.transform_feedback_buffer_mode()))
2033 },
2034 _ => self.base.GetProgramParameter(cx, program, param_id, retval),
2035 }
2036 }
2037
2038 fn GetShaderInfoLog(&self, shader: &WebGLShader) -> Option<DOMString> {
2040 self.base.GetShaderInfoLog(shader)
2041 }
2042
2043 fn GetShaderParameter(
2045 &self,
2046 cx: JSContext,
2047 shader: &WebGLShader,
2048 param_id: u32,
2049 retval: MutableHandleValue,
2050 ) {
2051 self.base.GetShaderParameter(cx, shader, param_id, retval)
2052 }
2053
2054 fn GetShaderPrecisionFormat(
2056 &self,
2057 shader_type: u32,
2058 precision_type: u32,
2059 ) -> Option<DomRoot<WebGLShaderPrecisionFormat>> {
2060 self.base
2061 .GetShaderPrecisionFormat(shader_type, precision_type)
2062 }
2063
2064 fn GetIndexedParameter(
2066 &self,
2067 cx: JSContext,
2068 target: u32,
2069 index: u32,
2070 mut retval: MutableHandleValue,
2071 ) {
2072 let bindings = match target {
2073 constants::TRANSFORM_FEEDBACK_BUFFER_BINDING |
2074 constants::TRANSFORM_FEEDBACK_BUFFER_SIZE |
2075 constants::TRANSFORM_FEEDBACK_BUFFER_START => {
2076 &self.indexed_transform_feedback_buffer_bindings
2077 },
2078 constants::UNIFORM_BUFFER_BINDING |
2079 constants::UNIFORM_BUFFER_SIZE |
2080 constants::UNIFORM_BUFFER_START => &self.indexed_uniform_buffer_bindings,
2081 _ => {
2082 self.base.webgl_error(InvalidEnum);
2083 return retval.set(NullValue());
2084 },
2085 };
2086
2087 let binding = match bindings.get(index as usize) {
2088 Some(binding) => binding,
2089 None => {
2090 self.base.webgl_error(InvalidValue);
2091 return retval.set(NullValue());
2092 },
2093 };
2094
2095 match target {
2096 constants::TRANSFORM_FEEDBACK_BUFFER_BINDING | constants::UNIFORM_BUFFER_BINDING => {
2097 binding
2098 .buffer
2099 .get()
2100 .safe_to_jsval(cx, retval, CanGc::deprecated_note())
2101 },
2102 constants::TRANSFORM_FEEDBACK_BUFFER_START | constants::UNIFORM_BUFFER_START => {
2103 retval.set(Int32Value(binding.start.get() as _))
2104 },
2105 constants::TRANSFORM_FEEDBACK_BUFFER_SIZE | constants::UNIFORM_BUFFER_SIZE => {
2106 retval.set(Int32Value(binding.size.get() as _))
2107 },
2108 _ => unreachable!(),
2109 }
2110 }
2111
2112 fn GetUniformLocation(
2114 &self,
2115 program: &WebGLProgram,
2116 name: DOMString,
2117 ) -> Option<DomRoot<WebGLUniformLocation>> {
2118 self.base.GetUniformLocation(program, name)
2119 }
2120
2121 fn GetVertexAttrib(&self, cx: JSContext, index: u32, pname: u32, retval: MutableHandleValue) {
2123 self.base.GetVertexAttrib(cx, index, pname, retval)
2124 }
2125
2126 fn GetVertexAttribOffset(&self, index: u32, pname: u32) -> i64 {
2128 self.base.GetVertexAttribOffset(index, pname)
2129 }
2130
2131 fn Hint(&self, target: u32, mode: u32) {
2133 self.base.Hint(target, mode)
2134 }
2135
2136 fn IsBuffer(&self, buffer: Option<&WebGLBuffer>) -> bool {
2138 self.base.IsBuffer(buffer)
2139 }
2140
2141 fn IsEnabled(&self, cap: u32) -> bool {
2144 match cap {
2145 constants::RASTERIZER_DISCARD => self.enable_rasterizer_discard.get(),
2146 _ => self.base.IsEnabled(cap),
2147 }
2148 }
2149
2150 fn IsFramebuffer(&self, frame_buffer: Option<&WebGLFramebuffer>) -> bool {
2152 self.base.IsFramebuffer(frame_buffer)
2153 }
2154
2155 fn IsProgram(&self, program: Option<&WebGLProgram>) -> bool {
2157 self.base.IsProgram(program)
2158 }
2159
2160 fn IsRenderbuffer(&self, render_buffer: Option<&WebGLRenderbuffer>) -> bool {
2162 self.base.IsRenderbuffer(render_buffer)
2163 }
2164
2165 fn IsShader(&self, shader: Option<&WebGLShader>) -> bool {
2167 self.base.IsShader(shader)
2168 }
2169
2170 fn IsTexture(&self, texture: Option<&WebGLTexture>) -> bool {
2172 self.base.IsTexture(texture)
2173 }
2174
2175 fn IsVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) -> bool {
2177 self.base.is_vertex_array_webgl2(vertex_array)
2178 }
2179
2180 fn LineWidth(&self, width: f32) {
2182 self.base.LineWidth(width)
2183 }
2184
2185 fn PixelStorei(&self, param_name: u32, param_value: i32) {
2187 if param_value < 0 {
2188 return self.base.webgl_error(InvalidValue);
2189 }
2190
2191 match param_name {
2192 constants::PACK_ROW_LENGTH => self.texture_pack_row_length.set(param_value as _),
2193 constants::PACK_SKIP_PIXELS => self.texture_pack_skip_pixels.set(param_value as _),
2194 constants::PACK_SKIP_ROWS => self.texture_pack_skip_rows.set(param_value as _),
2195 _ => self.base.PixelStorei(param_name, param_value),
2196 }
2197 }
2198
2199 fn PolygonOffset(&self, factor: f32, units: f32) {
2201 self.base.PolygonOffset(factor, units)
2202 }
2203
2204 fn ReadPixels(
2206 &self,
2207 x: i32,
2208 y: i32,
2209 width: i32,
2210 height: i32,
2211 format: u32,
2212 pixel_type: u32,
2213 mut pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
2214 ) {
2215 let pixels =
2216 handle_potential_webgl_error!(self.base, pixels.as_mut().ok_or(InvalidValue), return);
2217
2218 self.read_pixels_into(x, y, width, height, format, pixel_type, pixels, 0)
2219 }
2220
2221 fn ReadPixels_(
2223 &self,
2224 x: i32,
2225 y: i32,
2226 width: i32,
2227 height: i32,
2228 format: u32,
2229 pixel_type: u32,
2230 dst_byte_offset: i64,
2231 ) {
2232 handle_potential_webgl_error!(self.base, self.base.validate_framebuffer(), return);
2233
2234 let dst = match self.bound_pixel_pack_buffer.get() {
2235 Some(buffer) => buffer,
2236 None => return self.base.webgl_error(InvalidOperation),
2237 };
2238
2239 if dst_byte_offset < 0 {
2240 return self.base.webgl_error(InvalidValue);
2241 }
2242 let dst_byte_offset = dst_byte_offset as usize;
2243 if dst_byte_offset > dst.capacity() {
2244 return self.base.webgl_error(InvalidOperation);
2245 }
2246
2247 let ReadPixelsAllowedFormats {
2248 array_types: _,
2249 channels: bytes_per_pixel,
2250 } = match self.calc_read_pixel_formats(pixel_type, format) {
2251 Ok(result) => result,
2252 Err(error) => return self.base.webgl_error(error),
2253 };
2254 if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
2255 return self.base.webgl_error(InvalidOperation);
2256 }
2257
2258 let ReadPixelsSizes {
2259 row_stride: _,
2260 skipped_bytes,
2261 size,
2262 } = match self.calc_read_pixel_sizes(width, height, bytes_per_pixel) {
2263 Ok(result) => result,
2264 Err(error) => return self.base.webgl_error(error),
2265 };
2266 let dst_end = dst_byte_offset + skipped_bytes + size;
2267 if dst.capacity() < dst_end {
2268 return self.base.webgl_error(InvalidOperation);
2269 }
2270
2271 {
2272 let (fb_width, fb_height) = handle_potential_webgl_error!(
2273 self.base,
2274 self.base
2275 .get_current_framebuffer_size()
2276 .ok_or(InvalidOperation),
2277 return
2278 );
2279 let src_origin = Point2D::new(x, y);
2280 let src_size = Size2D::new(width as u32, height as u32);
2281 let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
2282 if pixels::clip(src_origin, src_size.to_u32(), fb_size.to_u32()).is_none() {
2283 return;
2284 }
2285 }
2286 let src_rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height));
2287
2288 self.base.send_command(WebGLCommand::PixelStorei(
2289 constants::PACK_ALIGNMENT,
2290 self.base.get_texture_packing_alignment() as _,
2291 ));
2292 self.base.send_command(WebGLCommand::PixelStorei(
2293 constants::PACK_ROW_LENGTH,
2294 self.texture_pack_row_length.get() as _,
2295 ));
2296 self.base.send_command(WebGLCommand::PixelStorei(
2297 constants::PACK_SKIP_ROWS,
2298 self.texture_pack_skip_rows.get() as _,
2299 ));
2300 self.base.send_command(WebGLCommand::PixelStorei(
2301 constants::PACK_SKIP_PIXELS,
2302 self.texture_pack_skip_pixels.get() as _,
2303 ));
2304 self.base.send_command(WebGLCommand::ReadPixelsPP(
2305 src_rect,
2306 format,
2307 pixel_type,
2308 dst_byte_offset,
2309 ));
2310 }
2311
2312 fn ReadPixels__(
2314 &self,
2315 x: i32,
2316 y: i32,
2317 width: i32,
2318 height: i32,
2319 format: u32,
2320 pixel_type: u32,
2321 mut dst: CustomAutoRooterGuard<ArrayBufferView>,
2322 dst_elem_offset: u32,
2323 ) {
2324 self.read_pixels_into(
2325 x,
2326 y,
2327 width,
2328 height,
2329 format,
2330 pixel_type,
2331 &mut dst,
2332 dst_elem_offset,
2333 )
2334 }
2335
2336 fn SampleCoverage(&self, value: f32, invert: bool) {
2338 self.base.SampleCoverage(value, invert)
2339 }
2340
2341 fn Scissor(&self, x: i32, y: i32, width: i32, height: i32) {
2343 self.base.Scissor(x, y, width, height)
2344 }
2345
2346 fn StencilFunc(&self, func: u32, ref_: i32, mask: u32) {
2348 self.base.StencilFunc(func, ref_, mask)
2349 }
2350
2351 fn StencilFuncSeparate(&self, face: u32, func: u32, ref_: i32, mask: u32) {
2353 self.base.StencilFuncSeparate(face, func, ref_, mask)
2354 }
2355
2356 fn StencilMask(&self, mask: u32) {
2358 self.base.StencilMask(mask)
2359 }
2360
2361 fn StencilMaskSeparate(&self, face: u32, mask: u32) {
2363 self.base.StencilMaskSeparate(face, mask)
2364 }
2365
2366 fn StencilOp(&self, fail: u32, zfail: u32, zpass: u32) {
2368 self.base.StencilOp(fail, zfail, zpass)
2369 }
2370
2371 fn StencilOpSeparate(&self, face: u32, fail: u32, zfail: u32, zpass: u32) {
2373 self.base.StencilOpSeparate(face, fail, zfail, zpass)
2374 }
2375
2376 fn LinkProgram(&self, program: &WebGLProgram) {
2378 self.base.LinkProgram(program)
2379 }
2380
2381 fn ShaderSource(&self, shader: &WebGLShader, source: DOMString) {
2383 self.base.ShaderSource(shader, source)
2384 }
2385
2386 fn GetShaderSource(&self, shader: &WebGLShader) -> Option<DOMString> {
2388 self.base.GetShaderSource(shader)
2389 }
2390
2391 fn Uniform1f(&self, location: Option<&WebGLUniformLocation>, val: f32) {
2393 self.base.Uniform1f(location, val)
2394 }
2395
2396 fn Uniform1i(&self, location: Option<&WebGLUniformLocation>, val: i32) {
2398 self.base.Uniform1i(location, val)
2399 }
2400
2401 fn Uniform1iv(
2403 &self,
2404 location: Option<&WebGLUniformLocation>,
2405 v: Int32ArrayOrLongSequence,
2406 src_offset: u32,
2407 src_length: u32,
2408 ) {
2409 self.base.uniform1iv(location, v, src_offset, src_length)
2410 }
2411
2412 fn Uniform1ui(&self, location: Option<&WebGLUniformLocation>, val: u32) {
2414 self.base.with_location(location, |location| {
2415 match location.type_() {
2416 constants::BOOL | constants::UNSIGNED_INT => (),
2417 _ => return Err(InvalidOperation),
2418 }
2419 self.base
2420 .send_command(WebGLCommand::Uniform1ui(location.id(), val));
2421 Ok(())
2422 });
2423 }
2424
2425 fn Uniform1uiv(
2427 &self,
2428 location: Option<&WebGLUniformLocation>,
2429 val: Uint32ArrayOrUnsignedLongSequence,
2430 src_offset: u32,
2431 src_length: u32,
2432 ) {
2433 self.base.with_location(location, |location| {
2434 match location.type_() {
2435 constants::BOOL |
2436 constants::UNSIGNED_INT |
2437 constants::SAMPLER_2D |
2438 constants::SAMPLER_2D_ARRAY |
2439 constants::SAMPLER_3D |
2440 constants::SAMPLER_CUBE => {},
2441 _ => return Err(InvalidOperation),
2442 }
2443
2444 let val = self.uniform_vec_section_uint(val, src_offset, src_length, 1, location)?;
2445
2446 match location.type_() {
2447 constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
2448 for &v in val
2449 .iter()
2450 .take(cmp::min(location.size().unwrap_or(1) as usize, val.len()))
2451 {
2452 if v >= self.base.limits().max_combined_texture_image_units {
2453 return Err(InvalidValue);
2454 }
2455 }
2456 },
2457 _ => {},
2458 }
2459 self.base
2460 .send_command(WebGLCommand::Uniform1uiv(location.id(), val));
2461 Ok(())
2462 });
2463 }
2464
2465 fn Uniform1fv(
2467 &self,
2468 location: Option<&WebGLUniformLocation>,
2469 v: Float32ArrayOrUnrestrictedFloatSequence,
2470 src_offset: u32,
2471 src_length: u32,
2472 ) {
2473 self.base.uniform1fv(location, v, src_offset, src_length);
2474 }
2475
2476 fn Uniform2f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32) {
2478 self.base.Uniform2f(location, x, y)
2479 }
2480
2481 fn Uniform2fv(
2483 &self,
2484 location: Option<&WebGLUniformLocation>,
2485 v: Float32ArrayOrUnrestrictedFloatSequence,
2486 src_offset: u32,
2487 src_length: u32,
2488 ) {
2489 self.base.uniform2fv(location, v, src_offset, src_length);
2490 }
2491
2492 fn Uniform2i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32) {
2494 self.base.Uniform2i(location, x, y)
2495 }
2496
2497 fn Uniform2iv(
2499 &self,
2500 location: Option<&WebGLUniformLocation>,
2501 v: Int32ArrayOrLongSequence,
2502 src_offset: u32,
2503 src_length: u32,
2504 ) {
2505 self.base.uniform2iv(location, v, src_offset, src_length)
2506 }
2507
2508 fn Uniform2ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32) {
2510 self.base.with_location(location, |location| {
2511 match location.type_() {
2512 constants::BOOL_VEC2 | constants::UNSIGNED_INT_VEC2 => {},
2513 _ => return Err(InvalidOperation),
2514 }
2515 self.base
2516 .send_command(WebGLCommand::Uniform2ui(location.id(), x, y));
2517 Ok(())
2518 });
2519 }
2520
2521 fn Uniform2uiv(
2523 &self,
2524 location: Option<&WebGLUniformLocation>,
2525 val: Uint32ArrayOrUnsignedLongSequence,
2526 src_offset: u32,
2527 src_length: u32,
2528 ) {
2529 self.base.with_location(location, |location| {
2530 match location.type_() {
2531 constants::BOOL_VEC2 | constants::UNSIGNED_INT_VEC2 => {},
2532 _ => return Err(InvalidOperation),
2533 }
2534 let val = self.uniform_vec_section_uint(val, src_offset, src_length, 2, location)?;
2535 self.base
2536 .send_command(WebGLCommand::Uniform2uiv(location.id(), val));
2537 Ok(())
2538 });
2539 }
2540
2541 fn Uniform3f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32) {
2543 self.base.Uniform3f(location, x, y, z)
2544 }
2545
2546 fn Uniform3fv(
2548 &self,
2549 location: Option<&WebGLUniformLocation>,
2550 v: Float32ArrayOrUnrestrictedFloatSequence,
2551 src_offset: u32,
2552 src_length: u32,
2553 ) {
2554 self.base.uniform3fv(location, v, src_offset, src_length);
2555 }
2556
2557 fn Uniform3i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32) {
2559 self.base.Uniform3i(location, x, y, z)
2560 }
2561
2562 fn Uniform3iv(
2564 &self,
2565 location: Option<&WebGLUniformLocation>,
2566 v: Int32ArrayOrLongSequence,
2567 src_offset: u32,
2568 src_length: u32,
2569 ) {
2570 self.base.uniform3iv(location, v, src_offset, src_length)
2571 }
2572
2573 fn Uniform3ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32, z: u32) {
2575 self.base.with_location(location, |location| {
2576 match location.type_() {
2577 constants::BOOL_VEC3 | constants::UNSIGNED_INT_VEC3 => {},
2578 _ => return Err(InvalidOperation),
2579 }
2580 self.base
2581 .send_command(WebGLCommand::Uniform3ui(location.id(), x, y, z));
2582 Ok(())
2583 });
2584 }
2585
2586 fn Uniform3uiv(
2588 &self,
2589 location: Option<&WebGLUniformLocation>,
2590 val: Uint32ArrayOrUnsignedLongSequence,
2591 src_offset: u32,
2592 src_length: u32,
2593 ) {
2594 self.base.with_location(location, |location| {
2595 match location.type_() {
2596 constants::BOOL_VEC3 | constants::UNSIGNED_INT_VEC3 => {},
2597 _ => return Err(InvalidOperation),
2598 }
2599 let val = self.uniform_vec_section_uint(val, src_offset, src_length, 3, location)?;
2600 self.base
2601 .send_command(WebGLCommand::Uniform3uiv(location.id(), val));
2602 Ok(())
2603 });
2604 }
2605
2606 fn Uniform4i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32, w: i32) {
2608 self.base.Uniform4i(location, x, y, z, w)
2609 }
2610
2611 fn Uniform4iv(
2613 &self,
2614 location: Option<&WebGLUniformLocation>,
2615 v: Int32ArrayOrLongSequence,
2616 src_offset: u32,
2617 src_length: u32,
2618 ) {
2619 self.base.uniform4iv(location, v, src_offset, src_length)
2620 }
2621
2622 fn Uniform4ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32, z: u32, w: u32) {
2624 self.base.with_location(location, |location| {
2625 match location.type_() {
2626 constants::BOOL_VEC4 | constants::UNSIGNED_INT_VEC4 => {},
2627 _ => return Err(InvalidOperation),
2628 }
2629 self.base
2630 .send_command(WebGLCommand::Uniform4ui(location.id(), x, y, z, w));
2631 Ok(())
2632 });
2633 }
2634
2635 fn Uniform4uiv(
2637 &self,
2638 location: Option<&WebGLUniformLocation>,
2639 val: Uint32ArrayOrUnsignedLongSequence,
2640 src_offset: u32,
2641 src_length: u32,
2642 ) {
2643 self.base.with_location(location, |location| {
2644 match location.type_() {
2645 constants::BOOL_VEC4 | constants::UNSIGNED_INT_VEC4 => {},
2646 _ => return Err(InvalidOperation),
2647 }
2648 let val = self.uniform_vec_section_uint(val, src_offset, src_length, 4, location)?;
2649 self.base
2650 .send_command(WebGLCommand::Uniform4uiv(location.id(), val));
2651 Ok(())
2652 });
2653 }
2654
2655 fn Uniform4f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32, w: f32) {
2657 self.base.Uniform4f(location, x, y, z, w)
2658 }
2659
2660 fn Uniform4fv(
2662 &self,
2663 location: Option<&WebGLUniformLocation>,
2664 v: Float32ArrayOrUnrestrictedFloatSequence,
2665 src_offset: u32,
2666 src_length: u32,
2667 ) {
2668 self.base.uniform4fv(location, v, src_offset, src_length);
2669 }
2670
2671 fn UniformMatrix2fv(
2673 &self,
2674 location: Option<&WebGLUniformLocation>,
2675 transpose: bool,
2676 v: Float32ArrayOrUnrestrictedFloatSequence,
2677 src_offset: u32,
2678 src_length: u32,
2679 ) {
2680 self.base
2681 .uniform_matrix_2fv(location, transpose, v, src_offset, src_length)
2682 }
2683
2684 fn UniformMatrix3fv(
2686 &self,
2687 location: Option<&WebGLUniformLocation>,
2688 transpose: bool,
2689 v: Float32ArrayOrUnrestrictedFloatSequence,
2690 src_offset: u32,
2691 src_length: u32,
2692 ) {
2693 self.base
2694 .uniform_matrix_3fv(location, transpose, v, src_offset, src_length)
2695 }
2696
2697 fn UniformMatrix4fv(
2699 &self,
2700 location: Option<&WebGLUniformLocation>,
2701 transpose: bool,
2702 v: Float32ArrayOrUnrestrictedFloatSequence,
2703 src_offset: u32,
2704 src_length: u32,
2705 ) {
2706 self.base
2707 .uniform_matrix_4fv(location, transpose, v, src_offset, src_length)
2708 }
2709
2710 fn UniformMatrix3x2fv(
2712 &self,
2713 location: Option<&WebGLUniformLocation>,
2714 transpose: bool,
2715 val: Float32ArrayOrUnrestrictedFloatSequence,
2716 src_offset: u32,
2717 src_length: u32,
2718 ) {
2719 self.base.with_location(location, |location| {
2720 match location.type_() {
2721 constants::FLOAT_MAT3x2 => {},
2722 _ => return Err(InvalidOperation),
2723 }
2724 let val = self.base.uniform_matrix_section(
2725 val,
2726 src_offset,
2727 src_length,
2728 transpose,
2729 3 * 2,
2730 location,
2731 )?;
2732 self.base
2733 .send_command(WebGLCommand::UniformMatrix3x2fv(location.id(), val));
2734 Ok(())
2735 });
2736 }
2737
2738 fn UniformMatrix4x2fv(
2740 &self,
2741 location: Option<&WebGLUniformLocation>,
2742 transpose: bool,
2743 val: Float32ArrayOrUnrestrictedFloatSequence,
2744 src_offset: u32,
2745 src_length: u32,
2746 ) {
2747 self.base.with_location(location, |location| {
2748 match location.type_() {
2749 constants::FLOAT_MAT4x2 => {},
2750 _ => return Err(InvalidOperation),
2751 }
2752 let val = self.base.uniform_matrix_section(
2753 val,
2754 src_offset,
2755 src_length,
2756 transpose,
2757 4 * 2,
2758 location,
2759 )?;
2760 self.base
2761 .send_command(WebGLCommand::UniformMatrix4x2fv(location.id(), val));
2762 Ok(())
2763 });
2764 }
2765
2766 fn UniformMatrix2x3fv(
2768 &self,
2769 location: Option<&WebGLUniformLocation>,
2770 transpose: bool,
2771 val: Float32ArrayOrUnrestrictedFloatSequence,
2772 src_offset: u32,
2773 src_length: u32,
2774 ) {
2775 self.base.with_location(location, |location| {
2776 match location.type_() {
2777 constants::FLOAT_MAT2x3 => {},
2778 _ => return Err(InvalidOperation),
2779 }
2780 let val = self.base.uniform_matrix_section(
2781 val,
2782 src_offset,
2783 src_length,
2784 transpose,
2785 2 * 3,
2786 location,
2787 )?;
2788 self.base
2789 .send_command(WebGLCommand::UniformMatrix2x3fv(location.id(), val));
2790 Ok(())
2791 });
2792 }
2793
2794 fn UniformMatrix4x3fv(
2796 &self,
2797 location: Option<&WebGLUniformLocation>,
2798 transpose: bool,
2799 val: Float32ArrayOrUnrestrictedFloatSequence,
2800 src_offset: u32,
2801 src_length: u32,
2802 ) {
2803 self.base.with_location(location, |location| {
2804 match location.type_() {
2805 constants::FLOAT_MAT4x3 => {},
2806 _ => return Err(InvalidOperation),
2807 }
2808 let val = self.base.uniform_matrix_section(
2809 val,
2810 src_offset,
2811 src_length,
2812 transpose,
2813 4 * 3,
2814 location,
2815 )?;
2816 self.base
2817 .send_command(WebGLCommand::UniformMatrix4x3fv(location.id(), val));
2818 Ok(())
2819 });
2820 }
2821
2822 fn UniformMatrix2x4fv(
2824 &self,
2825 location: Option<&WebGLUniformLocation>,
2826 transpose: bool,
2827 val: Float32ArrayOrUnrestrictedFloatSequence,
2828 src_offset: u32,
2829 src_length: u32,
2830 ) {
2831 self.base.with_location(location, |location| {
2832 match location.type_() {
2833 constants::FLOAT_MAT2x4 => {},
2834 _ => return Err(InvalidOperation),
2835 }
2836 let val = self.base.uniform_matrix_section(
2837 val,
2838 src_offset,
2839 src_length,
2840 transpose,
2841 2 * 4,
2842 location,
2843 )?;
2844 self.base
2845 .send_command(WebGLCommand::UniformMatrix2x4fv(location.id(), val));
2846 Ok(())
2847 });
2848 }
2849
2850 fn UniformMatrix3x4fv(
2852 &self,
2853 location: Option<&WebGLUniformLocation>,
2854 transpose: bool,
2855 val: Float32ArrayOrUnrestrictedFloatSequence,
2856 src_offset: u32,
2857 src_length: u32,
2858 ) {
2859 self.base.with_location(location, |location| {
2860 match location.type_() {
2861 constants::FLOAT_MAT3x4 => {},
2862 _ => return Err(InvalidOperation),
2863 }
2864 let val = self.base.uniform_matrix_section(
2865 val,
2866 src_offset,
2867 src_length,
2868 transpose,
2869 3 * 4,
2870 location,
2871 )?;
2872 self.base
2873 .send_command(WebGLCommand::UniformMatrix3x4fv(location.id(), val));
2874 Ok(())
2875 });
2876 }
2877
2878 #[expect(unsafe_code)]
2880 fn GetUniform(
2881 &self,
2882 cx: JSContext,
2883 program: &WebGLProgram,
2884 location: &WebGLUniformLocation,
2885 mut retval: MutableHandleValue,
2886 ) {
2887 handle_potential_webgl_error!(
2888 self.base,
2889 self.base.uniform_check_program(program, location),
2890 return retval.set(NullValue())
2891 );
2892
2893 let triple = (&*self.base, program.id(), location.id());
2894
2895 match location.type_() {
2896 constants::UNSIGNED_INT => retval.set(UInt32Value(uniform_get(
2897 triple,
2898 WebGLCommand::GetUniformUint,
2899 ))),
2900 constants::UNSIGNED_INT_VEC2 => unsafe {
2901 uniform_typed::<Uint32>(
2902 *cx,
2903 &uniform_get(triple, WebGLCommand::GetUniformUint2),
2904 retval,
2905 )
2906 },
2907 constants::UNSIGNED_INT_VEC3 => unsafe {
2908 uniform_typed::<Uint32>(
2909 *cx,
2910 &uniform_get(triple, WebGLCommand::GetUniformUint3),
2911 retval,
2912 )
2913 },
2914 constants::UNSIGNED_INT_VEC4 => unsafe {
2915 uniform_typed::<Uint32>(
2916 *cx,
2917 &uniform_get(triple, WebGLCommand::GetUniformUint4),
2918 retval,
2919 )
2920 },
2921 constants::FLOAT_MAT2x3 => unsafe {
2922 uniform_typed::<Float32>(
2923 *cx,
2924 &uniform_get(triple, WebGLCommand::GetUniformFloat2x3),
2925 retval,
2926 )
2927 },
2928 constants::FLOAT_MAT2x4 => unsafe {
2929 uniform_typed::<Float32>(
2930 *cx,
2931 &uniform_get(triple, WebGLCommand::GetUniformFloat2x4),
2932 retval,
2933 )
2934 },
2935 constants::FLOAT_MAT3x2 => unsafe {
2936 uniform_typed::<Float32>(
2937 *cx,
2938 &uniform_get(triple, WebGLCommand::GetUniformFloat3x2),
2939 retval,
2940 )
2941 },
2942 constants::FLOAT_MAT3x4 => unsafe {
2943 uniform_typed::<Float32>(
2944 *cx,
2945 &uniform_get(triple, WebGLCommand::GetUniformFloat3x4),
2946 retval,
2947 )
2948 },
2949 constants::FLOAT_MAT4x2 => unsafe {
2950 uniform_typed::<Float32>(
2951 *cx,
2952 &uniform_get(triple, WebGLCommand::GetUniformFloat4x2),
2953 retval,
2954 )
2955 },
2956 constants::FLOAT_MAT4x3 => unsafe {
2957 uniform_typed::<Float32>(
2958 *cx,
2959 &uniform_get(triple, WebGLCommand::GetUniformFloat4x3),
2960 retval,
2961 )
2962 },
2963 constants::SAMPLER_3D | constants::SAMPLER_2D_ARRAY => {
2964 retval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)))
2965 },
2966 _ => self.base.GetUniform(cx, program, location, retval),
2967 }
2968 }
2969
2970 fn UseProgram(&self, program: Option<&WebGLProgram>) {
2972 self.base.UseProgram(program)
2973 }
2974
2975 fn ValidateProgram(&self, program: &WebGLProgram) {
2977 self.base.ValidateProgram(program)
2978 }
2979
2980 fn VertexAttrib1f(&self, indx: u32, x: f32) {
2982 self.base.VertexAttrib1f(indx, x)
2983 }
2984
2985 fn VertexAttrib1fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2987 self.base.VertexAttrib1fv(indx, v)
2988 }
2989
2990 fn VertexAttrib2f(&self, indx: u32, x: f32, y: f32) {
2992 self.base.VertexAttrib2f(indx, x, y)
2993 }
2994
2995 fn VertexAttrib2fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2997 self.base.VertexAttrib2fv(indx, v)
2998 }
2999
3000 fn VertexAttrib3f(&self, indx: u32, x: f32, y: f32, z: f32) {
3002 self.base.VertexAttrib3f(indx, x, y, z)
3003 }
3004
3005 fn VertexAttrib3fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
3007 self.base.VertexAttrib3fv(indx, v)
3008 }
3009
3010 fn VertexAttrib4f(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) {
3012 self.base.VertexAttrib4f(indx, x, y, z, w)
3013 }
3014
3015 fn VertexAttrib4fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
3017 self.base.VertexAttrib4fv(indx, v)
3018 }
3019
3020 fn VertexAttribI4i(&self, index: u32, x: i32, y: i32, z: i32, w: i32) {
3022 self.vertex_attrib_i(index, x, y, z, w)
3023 }
3024
3025 fn VertexAttribI4iv(&self, index: u32, v: Int32ArrayOrLongSequence) {
3027 let values = match v {
3028 Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
3029 Int32ArrayOrLongSequence::LongSequence(v) => v,
3030 };
3031 if values.len() < 4 {
3032 return self.base.webgl_error(InvalidValue);
3033 }
3034 self.vertex_attrib_i(index, values[0], values[1], values[2], values[3]);
3035 }
3036
3037 fn VertexAttribI4ui(&self, index: u32, x: u32, y: u32, z: u32, w: u32) {
3039 self.vertex_attrib_u(index, x, y, z, w)
3040 }
3041
3042 fn VertexAttribI4uiv(&self, index: u32, v: Uint32ArrayOrUnsignedLongSequence) {
3044 let values = match v {
3045 Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(),
3046 Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v,
3047 };
3048 if values.len() < 4 {
3049 return self.base.webgl_error(InvalidValue);
3050 }
3051 self.vertex_attrib_u(index, values[0], values[1], values[2], values[3]);
3052 }
3053
3054 fn VertexAttribPointer(
3056 &self,
3057 attrib_id: u32,
3058 size: i32,
3059 data_type: u32,
3060 normalized: bool,
3061 stride: i32,
3062 offset: i64,
3063 ) {
3064 self.base
3065 .VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset)
3066 }
3067
3068 fn VertexAttribIPointer(&self, index: u32, size: i32, type_: u32, stride: i32, offset: i64) {
3070 match type_ {
3071 constants::BYTE |
3072 constants::UNSIGNED_BYTE |
3073 constants::SHORT |
3074 constants::UNSIGNED_SHORT |
3075 constants::INT |
3076 constants::UNSIGNED_INT => {},
3077 _ => return self.base.webgl_error(InvalidEnum),
3078 };
3079 self.base
3080 .VertexAttribPointer(index, size, type_, false, stride, offset)
3081 }
3082
3083 fn Viewport(&self, x: i32, y: i32, width: i32, height: i32) {
3085 self.base.Viewport(x, y, width, height)
3086 }
3087
3088 #[expect(unsafe_code)]
3093 fn TexImage3D(
3094 &self,
3095 target: u32,
3096 level: i32,
3097 internal_format: i32,
3098 width: i32,
3099 height: i32,
3100 depth: i32,
3101 border: i32,
3102 format: u32,
3103 type_: u32,
3104 src_data: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3105 ) -> Fallible<()> {
3106 if self.bound_pixel_unpack_buffer.get().is_some() {
3109 self.base.webgl_error(InvalidOperation);
3110 return Ok(());
3111 }
3112
3113 if type_ == constants::FLOAT_32_UNSIGNED_INT_24_8_REV && src_data.is_some() {
3116 self.base.webgl_error(InvalidOperation);
3117 return Ok(());
3118 }
3119
3120 if border != 0 {
3121 self.base.webgl_error(InvalidValue);
3122 return Ok(());
3123 }
3124
3125 let Ok(TexImage3DValidatorResult {
3126 width,
3127 height,
3128 depth,
3129 level,
3130 border,
3131 texture,
3132 target,
3133 internal_format,
3134 format,
3135 data_type,
3136 }) = TexImage3DValidator::new(
3137 &self.base,
3138 target,
3139 level,
3140 internal_format as u32,
3141 width,
3142 height,
3143 depth,
3144 border,
3145 format,
3146 type_,
3147 &src_data,
3148 )
3149 .validate()
3150 else {
3151 return Ok(());
3152 };
3153
3154 let unpacking_alignment = self.base.texture_unpacking_alignment();
3157 let element_size = data_type.element_size();
3158 let components_per_element = data_type.components_per_element();
3159 let components = format.components();
3160 let expected_byte_len = if height == 0 {
3162 0
3163 } else {
3164 let cpp = element_size * components / components_per_element;
3169 let mut padding_bytes = (cpp * width) % unpacking_alignment;
3170 if padding_bytes > 0 {
3171 padding_bytes = unpacking_alignment - padding_bytes;
3172 }
3173 let bytes_per_row = cpp * width + padding_bytes;
3174 let bytes_last_row = cpp * width;
3175 let bytes_per_image = bytes_per_row * height;
3176 let bytes_last_image = bytes_per_row * (height - 1) + bytes_last_row;
3177 bytes_per_image * (depth - 1) + bytes_last_image
3178 };
3179
3180 let buff = match *src_data {
3182 Some(ref data) => GenericSharedMemory::from_bytes(unsafe { data.as_slice() }),
3183 None => GenericSharedMemory::from_bytes(&vec![0u8; expected_byte_len as usize]),
3184 };
3185 if buff.len() < expected_byte_len as usize {
3186 return {
3187 self.base.webgl_error(InvalidOperation);
3188 Ok(())
3189 };
3190 }
3191 let (alpha_treatment, y_axis_treatment) =
3192 self.base.get_current_unpack_state(Alpha::NotPremultiplied);
3193 if let (Some(AlphaTreatment::Premultiply), YAxisTreatment::Flipped) =
3197 (alpha_treatment, y_axis_treatment)
3198 {
3199 if src_data.is_some() {
3200 self.base.webgl_error(InvalidOperation);
3201 return Ok(());
3202 }
3203 }
3204 let tex_source = TexPixels::from_array(
3205 buff,
3206 Size2D::new(width, height),
3207 alpha_treatment,
3208 y_axis_treatment,
3209 );
3210
3211 self.tex_image_3d(
3212 &texture,
3213 target,
3214 data_type,
3215 internal_format,
3216 format,
3217 level,
3218 width,
3219 height,
3220 depth,
3221 border,
3222 unpacking_alignment,
3223 tex_source,
3224 );
3225 Ok(())
3226 }
3227
3228 fn TexImage2D(
3230 &self,
3231 target: u32,
3232 level: i32,
3233 internal_format: i32,
3234 width: i32,
3235 height: i32,
3236 border: i32,
3237 format: u32,
3238 data_type: u32,
3239 pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3240 ) -> Fallible<()> {
3241 self.base.TexImage2D(
3242 target,
3243 level,
3244 internal_format,
3245 width,
3246 height,
3247 border,
3248 format,
3249 data_type,
3250 pixels,
3251 )
3252 }
3253
3254 fn TexImage2D_(
3256 &self,
3257 target: u32,
3258 level: i32,
3259 internal_format: i32,
3260 format: u32,
3261 data_type: u32,
3262 source: TexImageSource,
3263 ) -> ErrorResult {
3264 self.base
3265 .TexImage2D_(target, level, internal_format, format, data_type, source)
3266 }
3267
3268 fn TexImage2D__(
3270 &self,
3271 target: u32,
3272 level: i32,
3273 internalformat: i32,
3274 width: i32,
3275 height: i32,
3276 border: i32,
3277 format: u32,
3278 type_: u32,
3279 pbo_offset: i64,
3280 ) -> Fallible<()> {
3281 let pixel_unpack_buffer = match self.bound_pixel_unpack_buffer.get() {
3282 Some(pixel_unpack_buffer) => pixel_unpack_buffer,
3283 None => {
3284 self.base.webgl_error(InvalidOperation);
3285 return Ok(());
3286 },
3287 };
3288
3289 if let Some(tf_buffer) = self.bound_transform_feedback_buffer.get() {
3290 if pixel_unpack_buffer == tf_buffer {
3291 self.base.webgl_error(InvalidOperation);
3292 return Ok(());
3293 }
3294 }
3295
3296 if pbo_offset < 0 || pbo_offset as usize > pixel_unpack_buffer.capacity() {
3297 self.base.webgl_error(InvalidValue);
3298 return Ok(());
3299 }
3300
3301 let unpacking_alignment = self.base.texture_unpacking_alignment();
3302
3303 let validator = TexImage2DValidator::new(
3304 &self.base,
3305 target,
3306 level,
3307 internalformat as u32,
3308 width,
3309 height,
3310 border,
3311 format,
3312 type_,
3313 );
3314
3315 let TexImage2DValidatorResult {
3316 texture,
3317 target,
3318 width,
3319 height,
3320 level,
3321 border,
3322 internal_format,
3323 format,
3324 data_type,
3325 } = match validator.validate() {
3326 Ok(result) => result,
3327 Err(_) => return Ok(()),
3328 };
3329
3330 self.base.tex_image_2d(
3331 &texture,
3332 target,
3333 data_type,
3334 internal_format,
3335 format,
3336 level,
3337 border,
3338 unpacking_alignment,
3339 Size2D::new(width, height),
3340 TexSource::BufferOffset(pbo_offset),
3341 );
3342
3343 Ok(())
3344 }
3345
3346 fn TexImage2D___(
3348 &self,
3349 target: u32,
3350 level: i32,
3351 internalformat: i32,
3352 width: i32,
3353 height: i32,
3354 border: i32,
3355 format: u32,
3356 type_: u32,
3357 source: TexImageSource,
3358 ) -> Fallible<()> {
3359 if self.bound_pixel_unpack_buffer.get().is_some() {
3360 self.base.webgl_error(InvalidOperation);
3361 return Ok(());
3362 }
3363
3364 let validator = TexImage2DValidator::new(
3365 &self.base,
3366 target,
3367 level,
3368 internalformat as u32,
3369 width,
3370 height,
3371 border,
3372 format,
3373 type_,
3374 );
3375
3376 let TexImage2DValidatorResult {
3377 texture,
3378 target,
3379 width: _,
3380 height: _,
3381 level,
3382 border,
3383 internal_format,
3384 format,
3385 data_type,
3386 } = match validator.validate() {
3387 Ok(result) => result,
3388 Err(_) => return Ok(()),
3389 };
3390
3391 let unpacking_alignment = self.base.texture_unpacking_alignment();
3392
3393 let pixels = match self.base.get_image_pixels(source)? {
3394 Some(pixels) => pixels,
3395 None => return Ok(()),
3396 };
3397
3398 self.base.tex_image_2d(
3399 &texture,
3400 target,
3401 data_type,
3402 internal_format,
3403 format,
3404 level,
3405 border,
3406 unpacking_alignment,
3407 pixels.size(),
3408 TexSource::Pixels(pixels),
3409 );
3410
3411 Ok(())
3412 }
3413
3414 #[expect(unsafe_code)]
3416 fn TexImage2D____(
3417 &self,
3418 target: u32,
3419 level: i32,
3420 internalformat: i32,
3421 width: i32,
3422 height: i32,
3423 border: i32,
3424 format: u32,
3425 type_: u32,
3426 src_data: CustomAutoRooterGuard<ArrayBufferView>,
3427 src_offset: u32,
3428 ) -> Fallible<()> {
3429 if self.bound_pixel_unpack_buffer.get().is_some() {
3430 self.base.webgl_error(InvalidOperation);
3431 return Ok(());
3432 }
3433
3434 if type_ == constants::FLOAT_32_UNSIGNED_INT_24_8_REV {
3435 self.base.webgl_error(InvalidOperation);
3436 return Ok(());
3437 }
3438
3439 let validator = TexImage2DValidator::new(
3440 &self.base,
3441 target,
3442 level,
3443 internalformat as u32,
3444 width,
3445 height,
3446 border,
3447 format,
3448 type_,
3449 );
3450
3451 let TexImage2DValidatorResult {
3452 texture,
3453 target,
3454 width,
3455 height,
3456 level,
3457 border,
3458 internal_format,
3459 format,
3460 data_type,
3461 } = match validator.validate() {
3462 Ok(result) => result,
3463 Err(_) => return Ok(()),
3464 };
3465
3466 let unpacking_alignment = self.base.texture_unpacking_alignment();
3467
3468 let src_elem_size = src_data.get_array_type().byte_size().unwrap();
3469 let src_byte_offset = src_offset as usize * src_elem_size;
3470
3471 if src_data.len() <= src_byte_offset {
3472 self.base.webgl_error(InvalidOperation);
3473 return Ok(());
3474 }
3475
3476 let buff =
3477 GenericSharedMemory::from_bytes(unsafe { &src_data.as_slice()[src_byte_offset..] });
3478
3479 let expected_byte_length = match self.base.validate_tex_image_2d_data(
3480 width,
3481 height,
3482 format,
3483 data_type,
3484 unpacking_alignment,
3485 Some(&*src_data),
3486 ) {
3487 Ok(byte_length) => byte_length,
3488 Err(()) => return Ok(()),
3489 };
3490
3491 if expected_byte_length as usize > buff.len() {
3492 self.base.webgl_error(InvalidOperation);
3493 return Ok(());
3494 }
3495
3496 let size = Size2D::new(width, height);
3497
3498 let (alpha_treatment, y_axis_treatment) =
3499 self.base.get_current_unpack_state(Alpha::NotPremultiplied);
3500
3501 self.base.tex_image_2d(
3502 &texture,
3503 target,
3504 data_type,
3505 internal_format,
3506 format,
3507 level,
3508 border,
3509 unpacking_alignment,
3510 size,
3511 TexSource::Pixels(TexPixels::from_array(
3512 buff,
3513 size,
3514 alpha_treatment,
3515 y_axis_treatment,
3516 )),
3517 );
3518
3519 Ok(())
3520 }
3521
3522 fn TexSubImage2D(
3524 &self,
3525 target: u32,
3526 level: i32,
3527 xoffset: i32,
3528 yoffset: i32,
3529 width: i32,
3530 height: i32,
3531 format: u32,
3532 data_type: u32,
3533 pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3534 ) -> Fallible<()> {
3535 self.base.TexSubImage2D(
3536 target, level, xoffset, yoffset, width, height, format, data_type, pixels,
3537 )
3538 }
3539
3540 fn TexSubImage2D_(
3542 &self,
3543 target: u32,
3544 level: i32,
3545 xoffset: i32,
3546 yoffset: i32,
3547 format: u32,
3548 data_type: u32,
3549 source: TexImageSource,
3550 ) -> ErrorResult {
3551 self.base
3552 .TexSubImage2D_(target, level, xoffset, yoffset, format, data_type, source)
3553 }
3554
3555 fn TexParameterf(&self, target: u32, name: u32, value: f32) {
3557 self.base.TexParameterf(target, name, value)
3558 }
3559
3560 fn TexParameteri(&self, target: u32, name: u32, value: i32) {
3562 self.base.TexParameteri(target, name, value)
3563 }
3564
3565 fn CheckFramebufferStatus(&self, target: u32) -> u32 {
3567 let fb_slot = match target {
3568 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3569 self.base.get_draw_framebuffer_slot()
3570 },
3571 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3572 _ => {
3573 self.base.webgl_error(InvalidEnum);
3574 return 0;
3575 },
3576 };
3577 match fb_slot.get() {
3578 Some(fb) => fb.check_status(),
3579 None => constants::FRAMEBUFFER_COMPLETE,
3580 }
3581 }
3582
3583 fn RenderbufferStorage(&self, target: u32, internal_format: u32, width: i32, height: i32) {
3585 self.base
3586 .RenderbufferStorage(target, internal_format, width, height)
3587 }
3588
3589 fn BlitFramebuffer(
3591 &self,
3592 src_x0: i32,
3593 src_y0: i32,
3594 src_x1: i32,
3595 src_y1: i32,
3596 dst_x0: i32,
3597 dst_y0: i32,
3598 dst_x1: i32,
3599 dst_y1: i32,
3600 mask: u32,
3601 filter: u32,
3602 ) {
3603 bitflags! {
3604 struct BlitFrameBufferFlags: u32 {
3605 const DEPTH = constants::DEPTH_BUFFER_BIT;
3606 const COLOR = constants::COLOR_BUFFER_BIT;
3607 const STENCIL = constants::STENCIL_BUFFER_BIT;
3608 const DEPTH_STENCIL = constants::DEPTH_BUFFER_BIT | constants::STENCIL_BUFFER_BIT;
3609 }
3610 };
3611 let Some(bits) = BlitFrameBufferFlags::from_bits(mask) else {
3612 return self.base.webgl_error(InvalidValue);
3613 };
3614 let attributes = self.base.GetContextAttributes().unwrap();
3615
3616 if bits.intersects(BlitFrameBufferFlags::DEPTH_STENCIL) {
3617 match filter {
3618 constants::LINEAR => return self.base.webgl_error(InvalidOperation),
3619 constants::NEAREST => {},
3620 _ => return self.base.webgl_error(InvalidOperation),
3621 }
3622 }
3623
3624 let src_fb = self.base.get_read_framebuffer_slot().get();
3625 let dst_fb = self.base.get_draw_framebuffer_slot().get();
3626
3627 let get_default_formats = || -> WebGLResult<(Option<u32>, Option<u32>, Option<u32>)> {
3628 if attributes.antialias {
3630 return Err(InvalidOperation);
3631 };
3632 let color = if attributes.alpha {
3633 Some(constants::RGBA8)
3634 } else {
3635 Some(constants::RGB8)
3636 };
3637 let (depth, stencil) = match (attributes.depth, attributes.stencil) {
3638 (true, true) => (
3639 Some(constants::DEPTH24_STENCIL8),
3640 Some(constants::DEPTH24_STENCIL8),
3641 ),
3642 (true, false) => (Some(constants::DEPTH_COMPONENT16), None),
3643 (false, true) => (None, Some(constants::STENCIL_INDEX8)),
3644 _ => (None, None),
3645 };
3646 Ok((color, depth, stencil))
3647 };
3648
3649 let (src_color, src_depth, src_stencil) = match src_fb {
3650 Some(fb) => {
3651 handle_potential_webgl_error!(self.base, fb.get_attachment_formats(), return)
3652 },
3653 None => handle_potential_webgl_error!(self.base, get_default_formats(), return),
3654 };
3655 let (dst_color, dst_depth, dst_stencil) = match dst_fb {
3656 Some(fb) => {
3657 handle_potential_webgl_error!(self.base, fb.get_attachment_formats(), return)
3658 },
3659 None => handle_potential_webgl_error!(self.base, get_default_formats(), return),
3660 };
3661
3662 if bits.intersects(BlitFrameBufferFlags::COLOR) && src_color != dst_color {
3663 return self.base.webgl_error(InvalidOperation);
3664 }
3665 if bits.intersects(BlitFrameBufferFlags::DEPTH) && src_depth != dst_depth {
3666 return self.base.webgl_error(InvalidOperation);
3667 }
3668 if bits.intersects(BlitFrameBufferFlags::STENCIL) && src_stencil != dst_stencil {
3669 return self.base.webgl_error(InvalidOperation);
3670 }
3671
3672 let src_width = src_x1.checked_sub(src_x0);
3673 let dst_width = dst_x1.checked_sub(dst_x0);
3674 let src_height = src_y1.checked_sub(src_y0);
3675 let dst_height = dst_y1.checked_sub(dst_y0);
3676
3677 if src_width.is_none() ||
3678 dst_width.is_none() ||
3679 src_height.is_none() ||
3680 dst_height.is_none()
3681 {
3682 return self.base.webgl_error(InvalidOperation);
3683 }
3684
3685 self.base.send_command(WebGLCommand::BlitFrameBuffer(
3686 src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter,
3687 ));
3688 }
3689
3690 fn FramebufferRenderbuffer(
3692 &self,
3693 target: u32,
3694 attachment: u32,
3695 renderbuffertarget: u32,
3696 rb: Option<&WebGLRenderbuffer>,
3697 ) {
3698 if let Some(rb) = rb {
3699 handle_potential_webgl_error!(self.base, self.base.validate_ownership(rb), return);
3700 }
3701
3702 let fb_slot = match target {
3703 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3704 self.base.get_draw_framebuffer_slot()
3705 },
3706 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3707 _ => return self.base.webgl_error(InvalidEnum),
3708 };
3709
3710 if renderbuffertarget != constants::RENDERBUFFER {
3711 return self.base.webgl_error(InvalidEnum);
3712 }
3713
3714 match fb_slot.get() {
3715 Some(fb) => match attachment {
3716 constants::DEPTH_STENCIL_ATTACHMENT => {
3717 handle_potential_webgl_error!(
3718 self.base,
3719 fb.renderbuffer(constants::DEPTH_ATTACHMENT, rb)
3720 );
3721 handle_potential_webgl_error!(
3722 self.base,
3723 fb.renderbuffer(constants::STENCIL_ATTACHMENT, rb)
3724 );
3725 },
3726 _ => handle_potential_webgl_error!(self.base, fb.renderbuffer(attachment, rb)),
3727 },
3728 None => self.base.webgl_error(InvalidOperation),
3729 };
3730 }
3731
3732 fn FramebufferTexture2D(
3734 &self,
3735 target: u32,
3736 attachment: u32,
3737 textarget: u32,
3738 texture: Option<&WebGLTexture>,
3739 level: i32,
3740 ) {
3741 if let Some(texture) = texture {
3742 handle_potential_webgl_error!(self.base, self.base.validate_ownership(texture), return);
3743 }
3744
3745 let fb_slot = match target {
3746 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3747 self.base.get_draw_framebuffer_slot()
3748 },
3749 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3750 _ => return self.base.webgl_error(InvalidEnum),
3751 };
3752 match fb_slot.get() {
3753 Some(fb) => handle_potential_webgl_error!(
3754 self.base,
3755 fb.texture2d(attachment, textarget, texture, level)
3756 ),
3757 None => self.base.webgl_error(InvalidOperation),
3758 }
3759 }
3760
3761 fn GetAttachedShaders(&self, program: &WebGLProgram) -> Option<Vec<DomRoot<WebGLShader>>> {
3763 self.base.GetAttachedShaders(program)
3764 }
3765
3766 fn DrawArraysInstanced(&self, mode: u32, first: i32, count: i32, primcount: i32) {
3768 self.validate_uniform_block_for_draw();
3769 self.validate_vertex_attribs_for_draw();
3770 handle_potential_webgl_error!(
3771 self.base,
3772 self.base
3773 .draw_arrays_instanced(mode, first, count, primcount)
3774 )
3775 }
3776
3777 fn DrawElementsInstanced(
3779 &self,
3780 mode: u32,
3781 count: i32,
3782 type_: u32,
3783 offset: i64,
3784 primcount: i32,
3785 ) {
3786 self.validate_uniform_block_for_draw();
3787 self.validate_vertex_attribs_for_draw();
3788 handle_potential_webgl_error!(
3789 self.base,
3790 self.base
3791 .draw_elements_instanced(mode, count, type_, offset, primcount)
3792 )
3793 }
3794
3795 fn DrawRangeElements(
3797 &self,
3798 mode: u32,
3799 start: u32,
3800 end: u32,
3801 count: i32,
3802 type_: u32,
3803 offset: i64,
3804 ) {
3805 if end < start {
3806 self.base.webgl_error(InvalidValue);
3807 return;
3808 }
3809 self.validate_uniform_block_for_draw();
3810 self.validate_vertex_attribs_for_draw();
3811 handle_potential_webgl_error!(
3812 self.base,
3813 self.base
3814 .draw_elements_instanced(mode, count, type_, offset, 1)
3815 )
3816 }
3817
3818 fn VertexAttribDivisor(&self, index: u32, divisor: u32) {
3820 self.base.vertex_attrib_divisor(index, divisor);
3821 }
3822
3823 fn CreateQuery(&self) -> Option<DomRoot<WebGLQuery>> {
3825 Some(WebGLQuery::new(&self.base, CanGc::deprecated_note()))
3826 }
3827
3828 #[rustfmt::skip]
3830 fn DeleteQuery(&self, query: Option<&WebGLQuery>) {
3831 if let Some(query) = query {
3832 handle_potential_webgl_error!(self.base, self.base.validate_ownership(query), return);
3833
3834 if let Some(query_target) = query.target() {
3835 let slot = match query_target {
3836 constants::ANY_SAMPLES_PASSED |
3837 constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3838 &self.occlusion_query
3839 },
3840 constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3841 &self.primitives_query
3842 },
3843 _ => unreachable!(),
3844 };
3845 if let Some(stored_query) = slot.get() {
3846 if stored_query.target() == query.target() {
3847 slot.set(None);
3848 }
3849 }
3850 }
3851
3852 query.delete(Operation::Infallible);
3853 }
3854 }
3855
3856 fn IsQuery(&self, query: Option<&WebGLQuery>) -> bool {
3858 match query {
3859 Some(query) => self.base.validate_ownership(query).is_ok() && query.is_valid(),
3860 None => false,
3861 }
3862 }
3863
3864 fn CreateSampler(&self) -> Option<DomRoot<WebGLSampler>> {
3866 Some(WebGLSampler::new(&self.base, CanGc::deprecated_note()))
3867 }
3868
3869 fn DeleteSampler(&self, sampler: Option<&WebGLSampler>) {
3871 if let Some(sampler) = sampler {
3872 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
3873 for slot in self.samplers.iter() {
3874 if slot.get().is_some_and(|s| sampler == &*s) {
3875 slot.set(None);
3876 }
3877 }
3878 sampler.delete(Operation::Infallible);
3879 }
3880 }
3881
3882 fn IsSampler(&self, sampler: Option<&WebGLSampler>) -> bool {
3884 match sampler {
3885 Some(sampler) => self.base.validate_ownership(sampler).is_ok() && sampler.is_valid(),
3886 None => false,
3887 }
3888 }
3889
3890 #[rustfmt::skip]
3892 fn BeginQuery(&self, target: u32, query: &WebGLQuery) {
3893 handle_potential_webgl_error!(self.base, self.base.validate_ownership(query), return);
3894
3895 let active_query = match target {
3896 constants::ANY_SAMPLES_PASSED |
3897 constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3898 &self.occlusion_query
3899 },
3900 constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3901 &self.primitives_query
3902 },
3903 _ => {
3904 self.base.webgl_error(InvalidEnum);
3905 return;
3906 },
3907 };
3908 if active_query.get().is_some() {
3909 self.base.webgl_error(InvalidOperation);
3910 return;
3911 }
3912 let result = query.begin(&self.base, target);
3913 match result {
3914 Ok(_) => active_query.set(Some(query)),
3915 Err(error) => self.base.webgl_error(error),
3916 }
3917 }
3918
3919 #[rustfmt::skip]
3921 fn EndQuery(&self, target: u32) {
3922 let active_query = match target {
3923 constants::ANY_SAMPLES_PASSED |
3924 constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3925 self.occlusion_query.take()
3926 },
3927 constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3928 self.primitives_query.take()
3929 },
3930 _ => {
3931 self.base.webgl_error(InvalidEnum);
3932 return;
3933 },
3934 };
3935 match active_query {
3936 None => self.base.webgl_error(InvalidOperation),
3937 Some(query) => {
3938 let result = query.end(&self.base, target);
3939 if let Err(error) = result {
3940 self.base.webgl_error(error);
3941 }
3942 },
3943 }
3944 }
3945
3946 #[rustfmt::skip]
3948 fn GetQuery(&self, target: u32, pname: u32) -> Option<DomRoot<WebGLQuery>> {
3949 if pname != constants::CURRENT_QUERY {
3950 self.base.webgl_error(InvalidEnum);
3951 return None;
3952 }
3953 let active_query = match target {
3954 constants::ANY_SAMPLES_PASSED |
3955 constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3956 self.occlusion_query.get()
3957 },
3958 constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3959 self.primitives_query.get()
3960 },
3961 _ => {
3962 self.base.webgl_error(InvalidEnum);
3963 None
3964 },
3965 };
3966 if let Some(query) = active_query.as_ref() {
3967 if query.target() != Some(target) {
3968 return None;
3969 }
3970 }
3971 active_query
3972 }
3973
3974 #[rustfmt::skip]
3976 fn GetQueryParameter(&self, _cx: JSContext, query: &WebGLQuery, pname: u32, mut retval: MutableHandleValue) {
3977 handle_potential_webgl_error!(
3978 self.base,
3979 self.base.validate_ownership(query),
3980 return retval.set(NullValue())
3981 );
3982 match query.get_parameter(&self.base, pname) {
3983 Ok(value) => match pname {
3984 constants::QUERY_RESULT => retval.set(UInt32Value(value)),
3985 constants::QUERY_RESULT_AVAILABLE => retval.set(BooleanValue(value != 0)),
3986 _ => unreachable!(),
3987 },
3988 Err(error) => {
3989 self.base.webgl_error(error);
3990 retval.set(NullValue())
3991 },
3992 }
3993 }
3994
3995 fn FenceSync(&self, condition: u32, flags: u32) -> Option<DomRoot<WebGLSync>> {
3997 if flags != 0 {
3998 self.base.webgl_error(InvalidValue);
3999 return None;
4000 }
4001 if condition != constants::SYNC_GPU_COMMANDS_COMPLETE {
4002 self.base.webgl_error(InvalidEnum);
4003 return None;
4004 }
4005
4006 Some(WebGLSync::new(&self.base, CanGc::deprecated_note()))
4007 }
4008
4009 fn IsSync(&self, sync: Option<&WebGLSync>) -> bool {
4011 match sync {
4012 Some(sync) => {
4013 if self.base.validate_ownership(sync).is_err() {
4016 return false;
4017 }
4018
4019 if !sync.is_valid() {
4021 return false;
4022 }
4023
4024 handle_potential_webgl_error!(
4026 self.base,
4027 self.base.validate_ownership(sync),
4028 return false
4029 );
4030 let (sender, receiver) = webgl_channel().unwrap();
4031 self.base
4032 .send_command(WebGLCommand::IsSync(sync.id(), sender));
4033 receiver.recv().unwrap()
4034 },
4035 None => false,
4036 }
4037 }
4038
4039 fn ClientWaitSync(&self, sync: &WebGLSync, flags: u32, timeout: u64) -> u32 {
4041 if !sync.is_valid() {
4042 self.base.webgl_error(InvalidOperation);
4043 return constants::WAIT_FAILED;
4044 }
4045 handle_potential_webgl_error!(
4046 self.base,
4047 self.base.validate_ownership(sync),
4048 return constants::WAIT_FAILED
4049 );
4050 if flags != 0 && flags != constants::SYNC_FLUSH_COMMANDS_BIT {
4051 self.base.webgl_error(InvalidValue);
4052 return constants::WAIT_FAILED;
4053 }
4054 if timeout > self.base.limits().max_client_wait_timeout_webgl.as_nanos() as u64 {
4055 self.base.webgl_error(InvalidOperation);
4056 return constants::WAIT_FAILED;
4057 }
4058
4059 match sync.client_wait_sync(&self.base, flags, timeout) {
4060 Some(status) => status,
4061 None => constants::WAIT_FAILED,
4062 }
4063 }
4064
4065 fn WaitSync(&self, sync: &WebGLSync, flags: u32, timeout: i64) {
4067 if !sync.is_valid() {
4068 self.base.webgl_error(InvalidOperation);
4069 return;
4070 }
4071 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
4072 if flags != 0 {
4073 self.base.webgl_error(InvalidValue);
4074 return;
4075 }
4076 if timeout != constants::TIMEOUT_IGNORED {
4077 self.base.webgl_error(InvalidValue);
4078 return;
4079 }
4080
4081 self.base
4082 .send_command(WebGLCommand::WaitSync(sync.id(), flags, timeout));
4083 }
4084
4085 fn GetSyncParameter(
4087 &self,
4088 _cx: JSContext,
4089 sync: &WebGLSync,
4090 pname: u32,
4091 mut retval: MutableHandleValue,
4092 ) {
4093 if !sync.is_valid() {
4094 self.base.webgl_error(InvalidOperation);
4095 return retval.set(NullValue());
4096 }
4097 handle_potential_webgl_error!(
4098 self.base,
4099 self.base.validate_ownership(sync),
4100 return retval.set(NullValue())
4101 );
4102 match pname {
4103 constants::OBJECT_TYPE | constants::SYNC_CONDITION | constants::SYNC_FLAGS => {
4104 let (sender, receiver) = webgl_channel().unwrap();
4105 self.base
4106 .send_command(WebGLCommand::GetSyncParameter(sync.id(), pname, sender));
4107 retval.set(UInt32Value(receiver.recv().unwrap()))
4108 },
4109 constants::SYNC_STATUS => match sync.get_sync_status(pname, &self.base) {
4110 Some(status) => retval.set(UInt32Value(status)),
4111 None => retval.set(UInt32Value(constants::UNSIGNALED)),
4112 },
4113 _ => {
4114 self.base.webgl_error(InvalidEnum);
4115 retval.set(NullValue())
4116 },
4117 }
4118 }
4119
4120 fn DeleteSync(&self, sync: Option<&WebGLSync>) {
4122 if let Some(sync) = sync {
4123 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
4124 sync.delete(Operation::Infallible);
4125 }
4126 }
4127
4128 fn BindSampler(&self, unit: u32, sampler: Option<&WebGLSampler>) {
4130 if let Some(sampler) = sampler {
4131 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4132
4133 if unit as usize >= self.samplers.len() {
4134 self.base.webgl_error(InvalidValue);
4135 return;
4136 }
4137
4138 let result = sampler.bind(&self.base, unit);
4139 match result {
4140 Ok(_) => self.samplers[unit as usize].set(Some(sampler)),
4141 Err(error) => self.base.webgl_error(error),
4142 }
4143 }
4144 }
4145
4146 fn BindVertexArray(&self, array: Option<&WebGLVertexArrayObject>) {
4148 self.base.bind_vertex_array_webgl2(array);
4149 }
4150
4151 fn SamplerParameteri(&self, sampler: &WebGLSampler, pname: u32, param: i32) {
4153 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4154 let param = WebGLSamplerValue::GLenum(param as u32);
4155 let result = sampler.set_parameter(&self.base, pname, param);
4156 if let Err(error) = result {
4157 self.base.webgl_error(error);
4158 }
4159 }
4160
4161 fn SamplerParameterf(&self, sampler: &WebGLSampler, pname: u32, param: f32) {
4163 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4164 let param = WebGLSamplerValue::Float(param);
4165 let result = sampler.set_parameter(&self.base, pname, param);
4166 if let Err(error) = result {
4167 self.base.webgl_error(error);
4168 }
4169 }
4170
4171 fn GetSamplerParameter(
4173 &self,
4174 _cx: JSContext,
4175 sampler: &WebGLSampler,
4176 pname: u32,
4177 mut retval: MutableHandleValue,
4178 ) {
4179 handle_potential_webgl_error!(
4180 self.base,
4181 self.base.validate_ownership(sampler),
4182 return retval.set(NullValue())
4183 );
4184 match sampler.get_parameter(&self.base, pname) {
4185 Ok(value) => match value {
4186 WebGLSamplerValue::GLenum(value) => retval.set(UInt32Value(value)),
4187 WebGLSamplerValue::Float(value) => retval.set(DoubleValue(value as f64)),
4188 },
4189 Err(error) => {
4190 self.base.webgl_error(error);
4191 retval.set(NullValue())
4192 },
4193 }
4194 }
4195
4196 fn CreateTransformFeedback(&self) -> Option<DomRoot<WebGLTransformFeedback>> {
4198 Some(WebGLTransformFeedback::new(
4199 &self.base,
4200 CanGc::deprecated_note(),
4201 ))
4202 }
4203
4204 fn DeleteTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) {
4206 if let Some(tf) = tf {
4207 handle_potential_webgl_error!(self.base, self.base.validate_ownership(tf), return);
4208 if tf.is_active() {
4209 self.base.webgl_error(InvalidOperation);
4210 return;
4211 }
4212 tf.delete(Operation::Infallible);
4213 self.current_transform_feedback.set(None);
4214 }
4215 }
4216
4217 fn IsTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) -> bool {
4219 match tf {
4220 Some(tf) => {
4221 if self.base.validate_ownership(tf).is_err() {
4224 return false;
4225 }
4226
4227 if !tf.is_valid() {
4229 return false;
4230 }
4231
4232 handle_potential_webgl_error!(
4234 self.base,
4235 self.base.validate_ownership(tf),
4236 return false
4237 );
4238 let (sender, receiver) = webgl_channel().unwrap();
4239 self.base
4240 .send_command(WebGLCommand::IsTransformFeedback(tf.id(), sender));
4241 receiver.recv().unwrap()
4242 },
4243 None => false,
4245 }
4246 }
4247
4248 fn BindTransformFeedback(&self, target: u32, tf: Option<&WebGLTransformFeedback>) {
4250 if target != constants::TRANSFORM_FEEDBACK {
4251 self.base.webgl_error(InvalidEnum);
4252 return;
4253 }
4254 match tf {
4255 Some(transform_feedback) => {
4256 handle_potential_webgl_error!(
4257 self.base,
4258 self.base.validate_ownership(transform_feedback),
4259 return
4260 );
4261 if !transform_feedback.is_valid() {
4262 self.base.webgl_error(InvalidOperation);
4263 return;
4264 }
4265 if let Some(current_tf) = self.current_transform_feedback.get() {
4266 if current_tf.is_active() && !current_tf.is_paused() {
4267 self.base.webgl_error(InvalidOperation);
4268 return;
4269 }
4270 }
4271 transform_feedback.bind(&self.base, target);
4272 self.current_transform_feedback
4273 .set(Some(transform_feedback));
4274 },
4275 None => self
4276 .base
4277 .send_command(WebGLCommand::BindTransformFeedback(target, 0)),
4278 }
4279 }
4280
4281 #[expect(non_snake_case)]
4283 fn BeginTransformFeedback(&self, primitiveMode: u32) {
4284 match primitiveMode {
4285 constants::POINTS | constants::LINES | constants::TRIANGLES => {},
4286 _ => {
4287 self.base.webgl_error(InvalidEnum);
4288 return;
4289 },
4290 };
4291 let current_tf = match self.current_transform_feedback.get() {
4292 Some(current_tf) => current_tf,
4293 None => {
4294 self.base.webgl_error(InvalidOperation);
4295 return;
4296 },
4297 };
4298 if current_tf.is_active() {
4299 self.base.webgl_error(InvalidOperation);
4300 return;
4301 };
4302 let program = match self.base.current_program() {
4303 Some(program) => program,
4304 None => {
4305 self.base.webgl_error(InvalidOperation);
4306 return;
4307 },
4308 };
4309 if !program.is_linked() || program.transform_feedback_varyings_length() == 0 {
4310 self.base.webgl_error(InvalidOperation);
4311 return;
4312 };
4313 current_tf.begin(&self.base, primitiveMode);
4314 }
4315
4316 fn EndTransformFeedback(&self) {
4318 if let Some(current_tf) = self.current_transform_feedback.get() {
4319 if !current_tf.is_active() {
4320 self.base.webgl_error(InvalidOperation);
4321 return;
4322 }
4323 current_tf.end(&self.base);
4324 }
4325 }
4326
4327 fn ResumeTransformFeedback(&self) {
4329 if let Some(current_tf) = self.current_transform_feedback.get() {
4330 if !current_tf.is_active() || !current_tf.is_paused() {
4331 self.base.webgl_error(InvalidOperation);
4332 return;
4333 }
4334 current_tf.resume(&self.base);
4335 }
4336 }
4337
4338 fn PauseTransformFeedback(&self) {
4340 if let Some(current_tf) = self.current_transform_feedback.get() {
4341 if !current_tf.is_active() || current_tf.is_paused() {
4342 self.base.webgl_error(InvalidOperation);
4343 return;
4344 }
4345 current_tf.pause(&self.base);
4346 }
4347 }
4348
4349 #[expect(non_snake_case)]
4351 fn TransformFeedbackVaryings(
4352 &self,
4353 program: &WebGLProgram,
4354 varyings: Vec<DOMString>,
4355 bufferMode: u32,
4356 ) {
4357 if let Err(error) = self.base.validate_ownership(program) {
4360 self.base.webgl_error(error);
4361 return;
4362 }
4363 handle_potential_webgl_error!(self.base, program.validate(), return);
4364 let strs = varyings
4365 .iter()
4366 .map(|name| String::from(name.to_owned()))
4367 .collect::<Vec<String>>();
4368 match bufferMode {
4369 constants::INTERLEAVED_ATTRIBS => {
4370 self.base
4371 .send_command(WebGLCommand::TransformFeedbackVaryings(
4372 program.id(),
4373 strs,
4374 bufferMode,
4375 ));
4376 },
4377 constants::SEPARATE_ATTRIBS => {
4378 let max_tf_sp_att =
4379 self.base.limits().max_transform_feedback_separate_attribs as usize;
4380 if strs.len() >= max_tf_sp_att {
4381 self.base.webgl_error(InvalidValue);
4382 return;
4383 }
4384 self.base
4385 .send_command(WebGLCommand::TransformFeedbackVaryings(
4386 program.id(),
4387 strs,
4388 bufferMode,
4389 ));
4390 },
4391 _ => self.base.webgl_error(InvalidEnum),
4392 }
4393 }
4394
4395 fn GetTransformFeedbackVarying(
4397 &self,
4398 program: &WebGLProgram,
4399 index: u32,
4400 ) -> Option<DomRoot<WebGLActiveInfo>> {
4401 if let Err(error) = self.base.validate_ownership(program) {
4404 self.base.webgl_error(error);
4405 return None;
4406 }
4407
4408 handle_potential_webgl_error!(self.base, program.validate(), return None);
4409
4410 if index >= program.transform_feedback_varyings_length() as u32 {
4411 self.base.webgl_error(InvalidValue);
4412 return None;
4413 }
4414
4415 let (sender, receiver) = webgl_channel().unwrap();
4416 self.base
4417 .send_command(WebGLCommand::GetTransformFeedbackVarying(
4418 program.id(),
4419 index,
4420 sender,
4421 ));
4422 let (size, ty, name) = receiver.recv().unwrap();
4423 Some(WebGLActiveInfo::new(
4424 self.base.global().as_window(),
4425 size,
4426 ty,
4427 DOMString::from(name),
4428 CanGc::deprecated_note(),
4429 ))
4430 }
4431
4432 fn BindBufferBase(&self, target: u32, index: u32, buffer: Option<&WebGLBuffer>) {
4434 let (generic_slot, indexed_bindings) = match target {
4435 constants::TRANSFORM_FEEDBACK_BUFFER => (
4436 &self.bound_transform_feedback_buffer,
4437 &self.indexed_transform_feedback_buffer_bindings,
4438 ),
4439 constants::UNIFORM_BUFFER => (
4440 &self.bound_uniform_buffer,
4441 &self.indexed_uniform_buffer_bindings,
4442 ),
4443 _ => return self.base.webgl_error(InvalidEnum),
4444 };
4445 let indexed_binding = match indexed_bindings.get(index as usize) {
4446 Some(slot) => slot,
4447 None => return self.base.webgl_error(InvalidValue),
4448 };
4449
4450 if let Some(buffer) = buffer {
4451 handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
4452
4453 if buffer.is_marked_for_deletion() {
4454 return self.base.webgl_error(InvalidOperation);
4455 }
4456 handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
4457
4458 buffer.increment_attached_counter();
4460 buffer.increment_attached_counter();
4461 }
4462
4463 self.base.send_command(WebGLCommand::BindBufferBase(
4464 target,
4465 index,
4466 buffer.map(|b| b.id()),
4467 ));
4468
4469 for slot in &[generic_slot, &indexed_binding.buffer] {
4470 if let Some(old) = slot.get() {
4471 old.decrement_attached_counter(Operation::Infallible);
4472 }
4473 slot.set(buffer);
4474 }
4475 indexed_binding.start.set(0);
4476 indexed_binding.size.set(0);
4477 }
4478
4479 fn BindBufferRange(
4481 &self,
4482 target: u32,
4483 index: u32,
4484 buffer: Option<&WebGLBuffer>,
4485 offset: i64,
4486 size: i64,
4487 ) {
4488 let (generic_slot, indexed_bindings) = match target {
4489 constants::TRANSFORM_FEEDBACK_BUFFER => (
4490 &self.bound_transform_feedback_buffer,
4491 &self.indexed_transform_feedback_buffer_bindings,
4492 ),
4493 constants::UNIFORM_BUFFER => (
4494 &self.bound_uniform_buffer,
4495 &self.indexed_uniform_buffer_bindings,
4496 ),
4497 _ => return self.base.webgl_error(InvalidEnum),
4498 };
4499 let indexed_binding = match indexed_bindings.get(index as usize) {
4500 Some(slot) => slot,
4501 None => return self.base.webgl_error(InvalidValue),
4502 };
4503
4504 if offset < 0 || size < 0 {
4505 return self.base.webgl_error(InvalidValue);
4506 }
4507 if buffer.is_some() && size == 0 {
4508 return self.base.webgl_error(InvalidValue);
4509 }
4510
4511 match target {
4512 constants::TRANSFORM_FEEDBACK_BUFFER => {
4513 if size % 4 != 0 && offset % 4 != 0 {
4514 return self.base.webgl_error(InvalidValue);
4515 }
4516 },
4517 constants::UNIFORM_BUFFER => {
4518 let offset_alignment = self.base.limits().uniform_buffer_offset_alignment;
4519 if offset % offset_alignment as i64 != 0 {
4520 return self.base.webgl_error(InvalidValue);
4521 }
4522 },
4523 _ => unreachable!(),
4524 }
4525
4526 if let Some(buffer) = buffer {
4527 handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
4528
4529 if buffer.is_marked_for_deletion() {
4530 return self.base.webgl_error(InvalidOperation);
4531 }
4532 handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
4533
4534 buffer.increment_attached_counter();
4536 buffer.increment_attached_counter();
4537 }
4538
4539 self.base.send_command(WebGLCommand::BindBufferRange(
4540 target,
4541 index,
4542 buffer.map(|b| b.id()),
4543 offset,
4544 size,
4545 ));
4546
4547 for slot in &[generic_slot, &indexed_binding.buffer] {
4548 if let Some(old) = slot.get() {
4549 old.decrement_attached_counter(Operation::Infallible);
4550 }
4551 slot.set(buffer);
4552 }
4553 indexed_binding.start.set(offset);
4554 indexed_binding.size.set(size);
4555 }
4556
4557 fn GetUniformIndices(&self, program: &WebGLProgram, names: Vec<DOMString>) -> Option<Vec<u32>> {
4559 handle_potential_webgl_error!(
4560 self.base,
4561 self.base.validate_ownership(program),
4562 return None
4563 );
4564 let indices = handle_potential_webgl_error!(
4565 self.base,
4566 program.get_uniform_indices(names),
4567 return None
4568 );
4569 Some(indices)
4570 }
4571
4572 fn GetActiveUniforms(
4574 &self,
4575 cx: JSContext,
4576 program: &WebGLProgram,
4577 indices: Vec<u32>,
4578 pname: u32,
4579 mut rval: MutableHandleValue,
4580 ) {
4581 handle_potential_webgl_error!(
4582 self.base,
4583 self.base.validate_ownership(program),
4584 return rval.set(NullValue())
4585 );
4586 let values = handle_potential_webgl_error!(
4587 self.base,
4588 program.get_active_uniforms(indices, pname),
4589 return rval.set(NullValue())
4590 );
4591
4592 match pname {
4593 constants::UNIFORM_SIZE |
4594 constants::UNIFORM_TYPE |
4595 constants::UNIFORM_BLOCK_INDEX |
4596 constants::UNIFORM_OFFSET |
4597 constants::UNIFORM_ARRAY_STRIDE |
4598 constants::UNIFORM_MATRIX_STRIDE => {
4599 values.safe_to_jsval(cx, rval, CanGc::deprecated_note());
4600 },
4601 constants::UNIFORM_IS_ROW_MAJOR => {
4602 let values = values.iter().map(|&v| v != 0).collect::<Vec<_>>();
4603 values.safe_to_jsval(cx, rval, CanGc::deprecated_note());
4604 },
4605 _ => unreachable!(),
4606 }
4607 }
4608
4609 fn GetUniformBlockIndex(&self, program: &WebGLProgram, block_name: DOMString) -> u32 {
4611 handle_potential_webgl_error!(
4612 self.base,
4613 self.base.validate_ownership(program),
4614 return constants::INVALID_INDEX
4615 );
4616 handle_potential_webgl_error!(
4617 self.base,
4618 program.get_uniform_block_index(block_name),
4619 constants::INVALID_INDEX
4620 )
4621 }
4622
4623 #[expect(unsafe_code)]
4625 fn GetActiveUniformBlockParameter(
4626 &self,
4627 cx: JSContext,
4628 program: &WebGLProgram,
4629 block_index: u32,
4630 pname: u32,
4631 mut retval: MutableHandleValue,
4632 ) {
4633 handle_potential_webgl_error!(
4634 self.base,
4635 self.base.validate_ownership(program),
4636 return retval.set(NullValue())
4637 );
4638 let values = handle_potential_webgl_error!(
4639 self.base,
4640 program.get_active_uniform_block_parameter(block_index, pname),
4641 return retval.set(NullValue())
4642 );
4643 match pname {
4644 constants::UNIFORM_BLOCK_BINDING |
4645 constants::UNIFORM_BLOCK_DATA_SIZE |
4646 constants::UNIFORM_BLOCK_ACTIVE_UNIFORMS => {
4647 assert!(values.len() == 1);
4648 retval.set(UInt32Value(values[0] as u32))
4649 },
4650 constants::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES => unsafe {
4651 let values = values.iter().map(|&v| v as u32).collect::<Vec<_>>();
4652 rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
4653 Uint32Array::create(*cx, CreateWith::Slice(&values), result.handle_mut()).unwrap();
4654 retval.set(ObjectValue(result.get()))
4655 },
4656 constants::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER |
4657 constants::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => {
4658 assert!(values.len() == 1);
4659 retval.set(BooleanValue(values[0] != 0))
4660 },
4661 _ => unreachable!(),
4662 }
4663 }
4664
4665 fn GetActiveUniformBlockName(
4667 &self,
4668 program: &WebGLProgram,
4669 block_index: u32,
4670 ) -> Option<DOMString> {
4671 handle_potential_webgl_error!(
4672 self.base,
4673 self.base.validate_ownership(program),
4674 return None
4675 );
4676 let name = handle_potential_webgl_error!(
4677 self.base,
4678 program.get_active_uniform_block_name(block_index),
4679 return None
4680 );
4681 Some(DOMString::from(name))
4682 }
4683
4684 fn UniformBlockBinding(&self, program: &WebGLProgram, block_index: u32, block_binding: u32) {
4686 handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return);
4687
4688 if block_binding >= self.base.limits().max_uniform_buffer_bindings {
4689 return self.base.webgl_error(InvalidValue);
4690 }
4691
4692 handle_potential_webgl_error!(
4693 self.base,
4694 program.bind_uniform_block(block_index, block_binding)
4695 )
4696 }
4697
4698 fn ClearBufferfv(
4700 &self,
4701 buffer: u32,
4702 draw_buffer: i32,
4703 values: Float32ArrayOrUnrestrictedFloatSequence,
4704 src_offset: u32,
4705 ) {
4706 let array = match values {
4707 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4708 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4709 };
4710 self.clear_buffer::<f32>(
4711 buffer,
4712 draw_buffer,
4713 &[constants::COLOR, constants::DEPTH],
4714 src_offset,
4715 array,
4716 WebGLCommand::ClearBufferfv,
4717 )
4718 }
4719
4720 fn ClearBufferiv(
4722 &self,
4723 buffer: u32,
4724 draw_buffer: i32,
4725 values: Int32ArrayOrLongSequence,
4726 src_offset: u32,
4727 ) {
4728 let array = match values {
4729 Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
4730 Int32ArrayOrLongSequence::LongSequence(v) => v,
4731 };
4732 self.clear_buffer::<i32>(
4733 buffer,
4734 draw_buffer,
4735 &[constants::COLOR, constants::STENCIL],
4736 src_offset,
4737 array,
4738 WebGLCommand::ClearBufferiv,
4739 )
4740 }
4741
4742 fn ClearBufferuiv(
4744 &self,
4745 buffer: u32,
4746 draw_buffer: i32,
4747 values: Uint32ArrayOrUnsignedLongSequence,
4748 src_offset: u32,
4749 ) {
4750 let array = match values {
4751 Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(),
4752 Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v,
4753 };
4754 self.clear_buffer::<u32>(
4755 buffer,
4756 draw_buffer,
4757 &[constants::COLOR],
4758 src_offset,
4759 array,
4760 WebGLCommand::ClearBufferuiv,
4761 )
4762 }
4763
4764 fn ClearBufferfi(&self, buffer: u32, draw_buffer: i32, depth: f32, stencil: i32) {
4766 if buffer != constants::DEPTH_STENCIL {
4767 return self.base.webgl_error(InvalidEnum);
4768 }
4769
4770 handle_potential_webgl_error!(
4771 self.base,
4772 self.clearbuffer_array_size(buffer, draw_buffer),
4773 return
4774 );
4775
4776 self.base.send_command(WebGLCommand::ClearBufferfi(
4777 buffer,
4778 draw_buffer,
4779 depth,
4780 stencil,
4781 ));
4782 }
4783
4784 fn InvalidateFramebuffer(&self, target: u32, attachments: Vec<u32>) {
4786 if !self.valid_fb_attachment_values(target, &attachments) {
4787 return;
4788 }
4789
4790 self.base
4791 .send_command(WebGLCommand::InvalidateFramebuffer(target, attachments))
4792 }
4793
4794 fn InvalidateSubFramebuffer(
4796 &self,
4797 target: u32,
4798 attachments: Vec<u32>,
4799 x: i32,
4800 y: i32,
4801 width: i32,
4802 height: i32,
4803 ) {
4804 if !self.valid_fb_attachment_values(target, &attachments) {
4805 return;
4806 }
4807
4808 if width < 0 || height < 0 {
4809 return self.base.webgl_error(InvalidValue);
4810 }
4811
4812 self.base
4813 .send_command(WebGLCommand::InvalidateSubFramebuffer(
4814 target,
4815 attachments,
4816 x,
4817 y,
4818 width,
4819 height,
4820 ))
4821 }
4822
4823 fn FramebufferTextureLayer(
4825 &self,
4826 target: u32,
4827 attachment: u32,
4828 texture: Option<&WebGLTexture>,
4829 level: i32,
4830 layer: i32,
4831 ) {
4832 if let Some(tex) = texture {
4833 handle_potential_webgl_error!(self.base, self.base.validate_ownership(tex), return);
4834 }
4835
4836 let fb_slot = match target {
4837 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
4838 self.base.get_draw_framebuffer_slot()
4839 },
4840 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
4841 _ => return self.base.webgl_error(InvalidEnum),
4842 };
4843
4844 match fb_slot.get() {
4845 Some(fb) => handle_potential_webgl_error!(
4846 self.base,
4847 fb.texture_layer(attachment, texture, level, layer)
4848 ),
4849 None => self.base.webgl_error(InvalidOperation),
4850 }
4851 }
4852
4853 #[expect(unsafe_code)]
4855 fn GetInternalformatParameter(
4856 &self,
4857 cx: JSContext,
4858 target: u32,
4859 internal_format: u32,
4860 pname: u32,
4861 mut retval: MutableHandleValue,
4862 ) {
4863 if target != constants::RENDERBUFFER {
4864 self.base.webgl_error(InvalidEnum);
4865 return retval.set(NullValue());
4866 }
4867
4868 match handle_potential_webgl_error!(
4869 self.base,
4870 InternalFormatParameter::from_u32(pname),
4871 return retval.set(NullValue())
4872 ) {
4873 InternalFormatParameter::IntVec(param) => unsafe {
4874 let (sender, receiver) = webgl_channel().unwrap();
4875 self.base
4876 .send_command(WebGLCommand::GetInternalFormatIntVec(
4877 target,
4878 internal_format,
4879 param,
4880 sender,
4881 ));
4882
4883 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
4884 Int32Array::create(
4885 *cx,
4886 CreateWith::Slice(&receiver.recv().unwrap()),
4887 rval.handle_mut(),
4888 )
4889 .unwrap();
4890 retval.set(ObjectValue(rval.get()))
4891 },
4892 }
4893 }
4894
4895 fn RenderbufferStorageMultisample(
4897 &self,
4898 target: u32,
4899 samples: i32,
4900 internal_format: u32,
4901 width: i32,
4902 height: i32,
4903 ) {
4904 self.base
4905 .renderbuffer_storage(target, samples, internal_format, width, height)
4906 }
4907
4908 fn ReadBuffer(&self, src: u32) {
4910 match src {
4911 constants::BACK | constants::NONE => {},
4912 _ if self.base.valid_color_attachment_enum(src) => {},
4913 _ => return self.base.webgl_error(InvalidEnum),
4914 }
4915
4916 if let Some(fb) = self.base.get_read_framebuffer_slot().get() {
4917 handle_potential_webgl_error!(self.base, fb.set_read_buffer(src))
4918 } else {
4919 match src {
4920 constants::NONE | constants::BACK => {},
4921 _ => return self.base.webgl_error(InvalidOperation),
4922 }
4923
4924 self.default_fb_readbuffer.set(src);
4925 self.base.send_command(WebGLCommand::ReadBuffer(src));
4926 }
4927 }
4928
4929 fn DrawBuffers(&self, buffers: Vec<u32>) {
4931 if let Some(fb) = self.base.get_draw_framebuffer_slot().get() {
4932 handle_potential_webgl_error!(self.base, fb.set_draw_buffers(buffers))
4933 } else {
4934 if buffers.len() != 1 {
4935 return self.base.webgl_error(InvalidOperation);
4936 }
4937
4938 match buffers[0] {
4939 constants::NONE | constants::BACK => {},
4940 _ => return self.base.webgl_error(InvalidOperation),
4941 }
4942
4943 self.default_fb_drawbuffer.set(buffers[0]);
4944 self.base.send_command(WebGLCommand::DrawBuffers(buffers));
4945 }
4946 }
4947
4948 fn TexStorage2D(
4950 &self,
4951 target: u32,
4952 levels: i32,
4953 internal_format: u32,
4954 width: i32,
4955 height: i32,
4956 ) {
4957 self.tex_storage(2, target, levels, internal_format, width, height, 1)
4958 }
4959
4960 fn TexStorage3D(
4962 &self,
4963 target: u32,
4964 levels: i32,
4965 internal_format: u32,
4966 width: i32,
4967 height: i32,
4968 depth: i32,
4969 ) {
4970 self.tex_storage(3, target, levels, internal_format, width, height, depth)
4971 }
4972
4973 #[cfg(feature = "webxr")]
4975 fn MakeXRCompatible(&self, can_gc: CanGc) -> Rc<Promise> {
4976 let p = Promise::new(&self.global(), can_gc);
4978 p.resolve_native(&(), can_gc);
4979 p
4980 }
4981}
4982
4983impl WebGL2RenderingContextHelpers for WebGL2RenderingContext {
4984 fn is_webgl2_enabled(cx: JSContext, global: HandleObject) -> bool {
4985 Self::is_webgl2_enabled(cx, global)
4986 }
4987}