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