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