script/dom/webgl/
webgl2renderingcontext.rs

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