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