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