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