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