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