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