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