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