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