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, CanGc::note());
698 },
699 Some(Texture(texture)) => {
700 texture.safe_to_jsval(cx, rval, CanGc::note());
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, CanGc::note());
1046 return;
1047 },
1048 constants::SHADING_LANGUAGE_VERSION => {
1049 "WebGL GLSL ES 3.00".safe_to_jsval(cx, rval, CanGc::note());
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, CanGc::note());
1069 return;
1070 },
1071 constants::COPY_READ_BUFFER_BINDING => {
1072 self.bound_copy_read_buffer
1073 .get()
1074 .safe_to_jsval(cx, rval, CanGc::note());
1075 return;
1076 },
1077 constants::COPY_WRITE_BUFFER_BINDING => {
1078 self.bound_copy_write_buffer
1079 .get()
1080 .safe_to_jsval(cx, rval, CanGc::note());
1081 return;
1082 },
1083 constants::PIXEL_PACK_BUFFER_BINDING => {
1084 self.bound_pixel_pack_buffer
1085 .get()
1086 .safe_to_jsval(cx, rval, CanGc::note());
1087 return;
1088 },
1089 constants::PIXEL_UNPACK_BUFFER_BINDING => {
1090 self.bound_pixel_unpack_buffer
1091 .get()
1092 .safe_to_jsval(cx, rval, CanGc::note());
1093 return;
1094 },
1095 constants::TRANSFORM_FEEDBACK_BUFFER_BINDING => {
1096 self.bound_transform_feedback_buffer
1097 .get()
1098 .safe_to_jsval(cx, rval, CanGc::note());
1099 return;
1100 },
1101 constants::UNIFORM_BUFFER_BINDING => {
1102 self.bound_uniform_buffer
1103 .get()
1104 .safe_to_jsval(cx, rval, CanGc::note());
1105 return;
1106 },
1107 constants::TRANSFORM_FEEDBACK_BINDING => {
1108 self.current_transform_feedback
1109 .get()
1110 .safe_to_jsval(cx, rval, CanGc::note());
1111 return;
1112 },
1113 constants::ELEMENT_ARRAY_BUFFER_BINDING => {
1114 let buffer = self.current_vao().element_array_buffer().get();
1115 buffer.safe_to_jsval(cx, rval, CanGc::note());
1116 return;
1117 },
1118 constants::VERTEX_ARRAY_BINDING => {
1119 let vao = self.current_vao();
1120 let vao = vao.id().map(|_| &*vao);
1121 vao.safe_to_jsval(cx, rval, CanGc::note());
1122 return;
1123 },
1124 constants::READ_FRAMEBUFFER_BINDING => {
1126 self.base
1127 .get_read_framebuffer_slot()
1128 .get()
1129 .safe_to_jsval(cx, rval, CanGc::note());
1130 return;
1131 },
1132 constants::READ_BUFFER => {
1133 let buffer = match self.base.get_read_framebuffer_slot().get() {
1134 Some(fb) => fb.read_buffer(),
1135 None => self.default_fb_readbuffer.get(),
1136 };
1137 rval.set(UInt32Value(buffer));
1138 return;
1139 },
1140 constants::DRAW_BUFFER0..=constants::DRAW_BUFFER15 => {
1141 let buffer = match self.base.get_read_framebuffer_slot().get() {
1142 Some(fb) => {
1143 let idx = parameter - constants::DRAW_BUFFER0;
1144 fb.draw_buffer_i(idx as usize)
1145 },
1146 None if parameter == constants::DRAW_BUFFER0 => {
1147 self.default_fb_readbuffer.get()
1148 },
1149 None => constants::NONE,
1150 };
1151 rval.set(UInt32Value(buffer));
1152 return;
1153 },
1154 constants::MAX_TEXTURE_LOD_BIAS => {
1155 rval.set(DoubleValue(self.base.limits().max_texture_lod_bias as f64));
1156 return;
1157 },
1158 constants::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS => {
1159 rval.set(DoubleValue(
1160 self.base.limits().max_combined_fragment_uniform_components as f64,
1161 ));
1162 return;
1163 },
1164 constants::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS => {
1165 rval.set(DoubleValue(
1166 self.base.limits().max_combined_vertex_uniform_components as f64,
1167 ));
1168 return;
1169 },
1170 constants::MAX_ELEMENT_INDEX => {
1171 rval.set(DoubleValue(self.base.limits().max_element_index as f64));
1172 return;
1173 },
1174 constants::MAX_UNIFORM_BLOCK_SIZE => {
1175 rval.set(DoubleValue(
1176 self.base.limits().max_uniform_block_size as f64,
1177 ));
1178 return;
1179 },
1180 constants::MIN_PROGRAM_TEXEL_OFFSET => {
1181 rval.set(Int32Value(self.base.limits().min_program_texel_offset));
1182 return;
1183 },
1184 _ => {},
1185 }
1186
1187 let limit = match parameter {
1188 constants::MAX_3D_TEXTURE_SIZE => Some(self.base.limits().max_3d_texture_size),
1189 constants::MAX_ARRAY_TEXTURE_LAYERS => {
1190 Some(self.base.limits().max_array_texture_layers)
1191 },
1192 constants::MAX_COLOR_ATTACHMENTS => Some(self.base.limits().max_color_attachments),
1193 constants::MAX_COMBINED_UNIFORM_BLOCKS => {
1194 Some(self.base.limits().max_combined_uniform_blocks)
1195 },
1196 constants::MAX_DRAW_BUFFERS => Some(self.base.limits().max_draw_buffers),
1197 constants::MAX_ELEMENTS_INDICES => Some(self.base.limits().max_elements_indices),
1198 constants::MAX_ELEMENTS_VERTICES => Some(self.base.limits().max_elements_vertices),
1199 constants::MAX_FRAGMENT_INPUT_COMPONENTS => {
1200 Some(self.base.limits().max_fragment_input_components)
1201 },
1202 constants::MAX_FRAGMENT_UNIFORM_BLOCKS => {
1203 Some(self.base.limits().max_fragment_uniform_blocks)
1204 },
1205 constants::MAX_FRAGMENT_UNIFORM_COMPONENTS => {
1206 Some(self.base.limits().max_fragment_uniform_components)
1207 },
1208 constants::MAX_PROGRAM_TEXEL_OFFSET => {
1209 Some(self.base.limits().max_program_texel_offset)
1210 },
1211 constants::MAX_SAMPLES => Some(self.base.limits().max_samples),
1212 constants::MAX_UNIFORM_BUFFER_BINDINGS => {
1213 Some(self.base.limits().max_uniform_buffer_bindings)
1214 },
1215 constants::MAX_VARYING_COMPONENTS => Some(self.base.limits().max_varying_components),
1216 constants::MAX_VERTEX_OUTPUT_COMPONENTS => {
1217 Some(self.base.limits().max_vertex_output_components)
1218 },
1219 constants::MAX_VERTEX_UNIFORM_BLOCKS => {
1220 Some(self.base.limits().max_vertex_uniform_blocks)
1221 },
1222 constants::MAX_VERTEX_UNIFORM_COMPONENTS => {
1223 Some(self.base.limits().max_vertex_uniform_components)
1224 },
1225 constants::UNIFORM_BUFFER_OFFSET_ALIGNMENT => {
1226 Some(self.base.limits().uniform_buffer_offset_alignment)
1227 },
1228 _ => None,
1229 };
1230 if let Some(limit) = limit {
1231 rval.set(UInt32Value(limit));
1232 return;
1233 }
1234
1235 self.base.GetParameter(cx, parameter, rval)
1236 }
1237
1238 fn GetTexParameter(&self, cx: JSContext, target: u32, pname: u32, retval: MutableHandleValue) {
1240 self.base.GetTexParameter(cx, target, pname, retval)
1241 }
1242
1243 fn GetError(&self) -> u32 {
1245 self.base.GetError()
1246 }
1247
1248 fn GetContextAttributes(&self) -> Option<WebGLContextAttributes> {
1250 self.base.GetContextAttributes()
1251 }
1252
1253 fn IsContextLost(&self) -> bool {
1255 self.base.IsContextLost()
1256 }
1257
1258 fn GetSupportedExtensions(&self) -> Option<Vec<DOMString>> {
1260 self.base.GetSupportedExtensions()
1261 }
1262
1263 fn GetExtension(&self, cx: JSContext, name: DOMString) -> Option<NonNull<JSObject>> {
1265 self.base.GetExtension(cx, name)
1266 }
1267
1268 fn GetFramebufferAttachmentParameter(
1270 &self,
1271 cx: JSContext,
1272 target: u32,
1273 attachment: u32,
1274 pname: u32,
1275 mut rval: MutableHandleValue,
1276 ) {
1277 let fb_slot = match target {
1278 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
1279 self.base.get_draw_framebuffer_slot()
1280 },
1281 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
1282 _ => {
1283 self.base.webgl_error(InvalidEnum);
1284 rval.set(NullValue());
1285 return;
1286 },
1287 };
1288
1289 if let Some(fb) = fb_slot.get() {
1290 handle_potential_webgl_error!(
1292 self.base,
1293 fb.validate_transparent(),
1294 return rval.set(NullValue())
1295 );
1296 handle_potential_webgl_error!(
1297 self.base,
1298 self.get_specific_fb_attachment_param(
1299 cx,
1300 &fb,
1301 target,
1302 attachment,
1303 pname,
1304 rval.reborrow()
1305 ),
1306 rval.set(NullValue())
1307 )
1308 } else {
1309 handle_potential_webgl_error!(
1311 self.base,
1312 self.get_default_fb_attachment_param(attachment, pname, rval.reborrow()),
1313 rval.set(NullValue())
1314 )
1315 }
1316 }
1317
1318 fn GetRenderbufferParameter(
1320 &self,
1321 cx: JSContext,
1322 target: u32,
1323 pname: u32,
1324 retval: MutableHandleValue,
1325 ) {
1326 self.base
1327 .GetRenderbufferParameter(cx, target, pname, retval)
1328 }
1329
1330 fn ActiveTexture(&self, texture: u32) {
1332 self.base.ActiveTexture(texture)
1333 }
1334
1335 fn BlendColor(&self, r: f32, g: f32, b: f32, a: f32) {
1337 self.base.BlendColor(r, g, b, a)
1338 }
1339
1340 fn BlendEquation(&self, mode: u32) {
1342 self.base.BlendEquation(mode)
1343 }
1344
1345 fn BlendEquationSeparate(&self, mode_rgb: u32, mode_alpha: u32) {
1347 self.base.BlendEquationSeparate(mode_rgb, mode_alpha)
1348 }
1349
1350 fn BlendFunc(&self, src_factor: u32, dest_factor: u32) {
1352 self.base.BlendFunc(src_factor, dest_factor)
1353 }
1354
1355 fn BlendFuncSeparate(&self, src_rgb: u32, dest_rgb: u32, src_alpha: u32, dest_alpha: u32) {
1357 self.base
1358 .BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha)
1359 }
1360
1361 fn AttachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
1363 self.base.AttachShader(program, shader)
1364 }
1365
1366 fn DetachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
1368 self.base.DetachShader(program, shader)
1369 }
1370
1371 fn BindAttribLocation(&self, program: &WebGLProgram, index: u32, name: DOMString) {
1373 self.base.BindAttribLocation(program, index, name)
1374 }
1375
1376 fn BindBuffer(&self, target: u32, buffer: Option<&WebGLBuffer>) {
1378 let current_vao;
1379 let slot = match target {
1380 constants::COPY_READ_BUFFER => &self.bound_copy_read_buffer,
1381 constants::COPY_WRITE_BUFFER => &self.bound_copy_write_buffer,
1382 constants::PIXEL_PACK_BUFFER => &self.bound_pixel_pack_buffer,
1383 constants::PIXEL_UNPACK_BUFFER => &self.bound_pixel_unpack_buffer,
1384 constants::TRANSFORM_FEEDBACK_BUFFER => &self.bound_transform_feedback_buffer,
1385 constants::UNIFORM_BUFFER => &self.bound_uniform_buffer,
1386 constants::ELEMENT_ARRAY_BUFFER => {
1387 current_vao = self.current_vao();
1388 current_vao.element_array_buffer()
1389 },
1390 _ => return self.base.BindBuffer(target, buffer),
1391 };
1392 self.base.bind_buffer_maybe(slot, target, buffer);
1393 }
1394
1395 fn BindFramebuffer(&self, target: u32, framebuffer: Option<&WebGLFramebuffer>) {
1397 handle_potential_webgl_error!(
1398 self.base,
1399 self.base.validate_new_framebuffer_binding(framebuffer),
1400 return
1401 );
1402
1403 let (bind_read, bind_draw) = match target {
1404 constants::FRAMEBUFFER => (true, true),
1405 constants::READ_FRAMEBUFFER => (true, false),
1406 constants::DRAW_FRAMEBUFFER => (false, true),
1407 _ => return self.base.webgl_error(InvalidEnum),
1408 };
1409 if bind_read {
1410 self.base.bind_framebuffer_to(
1411 target,
1412 framebuffer,
1413 self.base.get_read_framebuffer_slot(),
1414 );
1415 }
1416 if bind_draw {
1417 self.base.bind_framebuffer_to(
1418 target,
1419 framebuffer,
1420 self.base.get_draw_framebuffer_slot(),
1421 );
1422 }
1423 }
1424
1425 fn BindRenderbuffer(&self, target: u32, renderbuffer: Option<&WebGLRenderbuffer>) {
1427 self.base.BindRenderbuffer(target, renderbuffer)
1428 }
1429
1430 fn BindTexture(&self, target: u32, texture: Option<&WebGLTexture>) {
1432 self.base.BindTexture(target, texture)
1433 }
1434
1435 fn GenerateMipmap(&self, target: u32) {
1437 self.base.GenerateMipmap(target)
1438 }
1439
1440 fn BufferData_(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
1442 let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1443 let bound_buffer =
1444 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1445 self.base.buffer_data(target, data, usage, bound_buffer)
1446 }
1447
1448 fn BufferData(&self, target: u32, size: i64, usage: u32) {
1450 let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1451 let bound_buffer =
1452 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1453 self.base.buffer_data_(target, size, usage, bound_buffer)
1454 }
1455
1456 #[allow(unsafe_code)]
1458 fn BufferData__(
1459 &self,
1460 target: u32,
1461 data: CustomAutoRooterGuard<ArrayBufferView>,
1462 usage: u32,
1463 elem_offset: u32,
1464 length: u32,
1465 ) {
1466 let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1467 let bound_buffer =
1468 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1469 let bound_buffer =
1470 handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1471
1472 let elem_size = data.get_array_type().byte_size().unwrap();
1473 let elem_count = data.len() / elem_size;
1474 let elem_offset = elem_offset as usize;
1475 let byte_offset = elem_offset * elem_size;
1476
1477 if byte_offset > data.len() {
1478 return self.base.webgl_error(InvalidValue);
1479 }
1480
1481 let copy_count = if length == 0 {
1482 elem_count - elem_offset
1483 } else {
1484 length as usize
1485 };
1486 if copy_count == 0 {
1487 return;
1488 }
1489 let copy_bytes = copy_count * elem_size;
1490
1491 if byte_offset + copy_bytes > data.len() {
1492 return self.base.webgl_error(InvalidValue);
1493 }
1494
1495 let data_end = byte_offset + copy_bytes;
1496 let data: &[u8] = unsafe { &data.as_slice()[byte_offset..data_end] };
1497 handle_potential_webgl_error!(self.base, bound_buffer.buffer_data(target, data, usage));
1498 }
1499
1500 fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
1502 let bound_buffer =
1503 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1504 self.base
1505 .buffer_sub_data(target, offset, data, bound_buffer)
1506 }
1507
1508 #[allow(unsafe_code)]
1510 fn BufferSubData_(
1511 &self,
1512 target: u32,
1513 dst_byte_offset: i64,
1514 src_data: CustomAutoRooterGuard<ArrayBufferView>,
1515 src_elem_offset: u32,
1516 length: u32,
1517 ) {
1518 let bound_buffer =
1519 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1520 let bound_buffer =
1521 handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1522
1523 let src_elem_size = src_data.get_array_type().byte_size().unwrap();
1524 let src_elem_count = src_data.len() / src_elem_size;
1525 let src_elem_offset = src_elem_offset as usize;
1526 let src_byte_offset = src_elem_offset * src_elem_size;
1527
1528 if dst_byte_offset < 0 || src_byte_offset > src_data.len() {
1529 return self.base.webgl_error(InvalidValue);
1530 }
1531
1532 let copy_count = if length == 0 {
1533 src_elem_count - src_elem_offset
1534 } else {
1535 length as usize
1536 };
1537 if copy_count == 0 {
1538 return;
1539 }
1540 let copy_bytes = copy_count * src_elem_size;
1541
1542 let dst_byte_offset = dst_byte_offset as usize;
1543 if dst_byte_offset + copy_bytes > bound_buffer.capacity() ||
1544 src_byte_offset + copy_bytes > src_data.len()
1545 {
1546 return self.base.webgl_error(InvalidValue);
1547 }
1548
1549 let (sender, receiver) = ipc::bytes_channel().unwrap();
1550 self.base.send_command(WebGLCommand::BufferSubData(
1551 target,
1552 dst_byte_offset as isize,
1553 receiver,
1554 ));
1555 let src_end = src_byte_offset + copy_bytes;
1556 let data: &[u8] = unsafe { &src_data.as_slice()[src_byte_offset..src_end] };
1557 sender.send(data).unwrap();
1558 }
1559
1560 fn CopyBufferSubData(
1562 &self,
1563 read_target: u32,
1564 write_target: u32,
1565 read_offset: i64,
1566 write_offset: i64,
1567 size: i64,
1568 ) {
1569 if read_offset < 0 || write_offset < 0 || size < 0 {
1570 return self.base.webgl_error(InvalidValue);
1571 }
1572
1573 let read_buffer =
1574 handle_potential_webgl_error!(self.base, self.bound_buffer(read_target), return);
1575 let read_buffer =
1576 handle_potential_webgl_error!(self.base, read_buffer.ok_or(InvalidOperation), return);
1577
1578 let write_buffer =
1579 handle_potential_webgl_error!(self.base, self.bound_buffer(write_target), return);
1580 let write_buffer =
1581 handle_potential_webgl_error!(self.base, write_buffer.ok_or(InvalidOperation), return);
1582
1583 let read_until = read_offset + size;
1584 let write_until = write_offset + size;
1585 if read_until as usize > read_buffer.capacity() ||
1586 write_until as usize > write_buffer.capacity()
1587 {
1588 return self.base.webgl_error(InvalidValue);
1589 }
1590
1591 if read_target == write_target {
1592 let is_separate = read_until <= write_offset || write_until <= read_offset;
1593 if !is_separate {
1594 return self.base.webgl_error(InvalidValue);
1595 }
1596 }
1597 let src_is_elemarray = read_buffer
1598 .target()
1599 .is_some_and(|t| t == constants::ELEMENT_ARRAY_BUFFER);
1600 let dst_is_elemarray = write_buffer
1601 .target()
1602 .is_some_and(|t| t == constants::ELEMENT_ARRAY_BUFFER);
1603 if src_is_elemarray != dst_is_elemarray {
1604 return self.base.webgl_error(InvalidOperation);
1605 }
1606
1607 self.base.send_command(WebGLCommand::CopyBufferSubData(
1608 read_target,
1609 write_target,
1610 read_offset,
1611 write_offset,
1612 size,
1613 ));
1614 }
1615
1616 #[allow(unsafe_code)]
1618 fn GetBufferSubData(
1619 &self,
1620 target: u32,
1621 src_byte_offset: i64,
1622 mut dst_buffer: CustomAutoRooterGuard<ArrayBufferView>,
1623 dst_elem_offset: u32,
1624 length: u32,
1625 ) {
1626 let bound_buffer =
1627 handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1628 let bound_buffer =
1629 handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1630
1631 let dst_elem_size = dst_buffer.get_array_type().byte_size().unwrap();
1632 let dst_elem_count = dst_buffer.len() / dst_elem_size;
1633 let dst_elem_offset = dst_elem_offset as usize;
1634 let dst_byte_offset = dst_elem_offset * dst_elem_size;
1635
1636 if src_byte_offset < 0 || dst_byte_offset > dst_buffer.len() {
1637 return self.base.webgl_error(InvalidValue);
1638 }
1639
1640 let copy_count = if length == 0 {
1641 dst_elem_count - dst_elem_offset
1642 } else {
1643 length as usize
1644 };
1645 if copy_count == 0 {
1646 return;
1647 }
1648 let copy_bytes = copy_count * dst_elem_size;
1649
1650 let src_byte_offset = src_byte_offset as usize;
1653 if src_byte_offset + copy_bytes > bound_buffer.capacity() ||
1654 dst_byte_offset + copy_bytes > dst_buffer.len()
1655 {
1656 return self.base.webgl_error(InvalidValue);
1657 }
1658
1659 let (sender, receiver) = ipc::bytes_channel().unwrap();
1660 self.base.send_command(WebGLCommand::GetBufferSubData(
1661 target,
1662 src_byte_offset,
1663 copy_bytes,
1664 sender,
1665 ));
1666 let data = receiver.recv().unwrap();
1667 let dst_end = dst_byte_offset + copy_bytes;
1668 unsafe {
1669 dst_buffer.as_mut_slice()[dst_byte_offset..dst_end].copy_from_slice(&data);
1670 }
1671 }
1672
1673 #[allow(unsafe_code)]
1675 fn CompressedTexImage2D(
1676 &self,
1677 target: u32,
1678 level: i32,
1679 internal_format: u32,
1680 width: i32,
1681 height: i32,
1682 border: i32,
1683 pixels: CustomAutoRooterGuard<ArrayBufferView>,
1684 src_offset: u32,
1685 src_length_override: u32,
1686 ) {
1687 let mut data = unsafe { pixels.as_slice() };
1688 let start = src_offset as usize;
1689 let end = (src_offset + src_length_override) as usize;
1690 if start > data.len() || end > data.len() {
1691 self.base.webgl_error(InvalidValue);
1692 return;
1693 }
1694 if src_length_override != 0 {
1695 data = &data[start..end];
1696 }
1697 self.base.compressed_tex_image_2d(
1698 target,
1699 level,
1700 internal_format,
1701 width,
1702 height,
1703 border,
1704 data,
1705 )
1706 }
1707
1708 #[allow(unsafe_code)]
1710 fn CompressedTexSubImage2D(
1711 &self,
1712 target: u32,
1713 level: i32,
1714 xoffset: i32,
1715 yoffset: i32,
1716 width: i32,
1717 height: i32,
1718 format: u32,
1719 pixels: CustomAutoRooterGuard<ArrayBufferView>,
1720 src_offset: u32,
1721 src_length_override: u32,
1722 ) {
1723 let mut data = unsafe { pixels.as_slice() };
1724 let start = src_offset as usize;
1725 let end = (src_offset + src_length_override) as usize;
1726 if start > data.len() || end > data.len() {
1727 self.base.webgl_error(InvalidValue);
1728 return;
1729 }
1730 if src_length_override != 0 {
1731 data = &data[start..end];
1732 }
1733 self.base.compressed_tex_sub_image_2d(
1734 target, level, xoffset, yoffset, width, height, format, data,
1735 )
1736 }
1737
1738 fn CopyTexImage2D(
1740 &self,
1741 target: u32,
1742 level: i32,
1743 internal_format: u32,
1744 x: i32,
1745 y: i32,
1746 width: i32,
1747 height: i32,
1748 border: i32,
1749 ) {
1750 self.base
1751 .CopyTexImage2D(target, level, internal_format, x, y, width, height, border)
1752 }
1753
1754 fn CopyTexSubImage2D(
1756 &self,
1757 target: u32,
1758 level: i32,
1759 xoffset: i32,
1760 yoffset: i32,
1761 x: i32,
1762 y: i32,
1763 width: i32,
1764 height: i32,
1765 ) {
1766 self.base
1767 .CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height)
1768 }
1769
1770 fn Clear(&self, mask: u32) {
1772 self.base.Clear(mask)
1773 }
1774
1775 fn ClearColor(&self, red: f32, green: f32, blue: f32, alpha: f32) {
1777 self.base.ClearColor(red, green, blue, alpha)
1778 }
1779
1780 fn ClearDepth(&self, depth: f32) {
1782 self.base.ClearDepth(depth)
1783 }
1784
1785 fn ClearStencil(&self, stencil: i32) {
1787 self.base.ClearStencil(stencil)
1788 }
1789
1790 fn ColorMask(&self, r: bool, g: bool, b: bool, a: bool) {
1792 self.base.ColorMask(r, g, b, a)
1793 }
1794
1795 fn CullFace(&self, mode: u32) {
1797 self.base.CullFace(mode)
1798 }
1799
1800 fn FrontFace(&self, mode: u32) {
1802 self.base.FrontFace(mode)
1803 }
1804 fn DepthFunc(&self, func: u32) {
1806 self.base.DepthFunc(func)
1807 }
1808
1809 fn DepthMask(&self, flag: bool) {
1811 self.base.DepthMask(flag)
1812 }
1813
1814 fn DepthRange(&self, near: f32, far: f32) {
1816 self.base.DepthRange(near, far)
1817 }
1818
1819 fn Enable(&self, cap: u32) {
1821 match cap {
1822 constants::RASTERIZER_DISCARD => {
1823 self.enable_rasterizer_discard.set(true);
1824 self.base.send_command(WebGLCommand::Enable(cap));
1825 },
1826 _ => self.base.Enable(cap),
1827 }
1828 }
1829
1830 fn Disable(&self, cap: u32) {
1832 match cap {
1833 constants::RASTERIZER_DISCARD => {
1834 self.enable_rasterizer_discard.set(false);
1835 self.base.send_command(WebGLCommand::Disable(cap));
1836 },
1837 _ => self.base.Disable(cap),
1838 }
1839 }
1840
1841 fn CompileShader(&self, shader: &WebGLShader) {
1843 self.base.CompileShader(shader)
1844 }
1845
1846 fn CreateBuffer(&self) -> Option<DomRoot<WebGLBuffer>> {
1848 self.base.CreateBuffer()
1849 }
1850
1851 fn CreateFramebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
1853 self.base.CreateFramebuffer()
1854 }
1855
1856 fn CreateRenderbuffer(&self) -> Option<DomRoot<WebGLRenderbuffer>> {
1858 self.base.CreateRenderbuffer()
1859 }
1860
1861 fn CreateTexture(&self) -> Option<DomRoot<WebGLTexture>> {
1863 self.base.CreateTexture()
1864 }
1865
1866 fn CreateProgram(&self) -> Option<DomRoot<WebGLProgram>> {
1868 self.base.CreateProgram()
1869 }
1870
1871 fn CreateShader(&self, shader_type: u32) -> Option<DomRoot<WebGLShader>> {
1873 self.base.CreateShader(shader_type)
1874 }
1875
1876 fn CreateVertexArray(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
1878 self.base.create_vertex_array_webgl2()
1879 }
1880
1881 fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) {
1883 let buffer = match buffer {
1884 Some(buffer) => buffer,
1885 None => return,
1886 };
1887 handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
1888 if buffer.is_marked_for_deletion() {
1889 return;
1890 }
1891 self.current_vao().unbind_buffer(buffer);
1892 self.unbind_from(self.base.array_buffer_slot(), buffer);
1893 self.unbind_from(&self.bound_copy_read_buffer, buffer);
1894 self.unbind_from(&self.bound_copy_write_buffer, buffer);
1895 self.unbind_from(&self.bound_pixel_pack_buffer, buffer);
1896 self.unbind_from(&self.bound_pixel_unpack_buffer, buffer);
1897 self.unbind_from(&self.bound_transform_feedback_buffer, buffer);
1898 self.unbind_from(&self.bound_uniform_buffer, buffer);
1899
1900 for binding in self.indexed_uniform_buffer_bindings.iter() {
1901 self.unbind_from(&binding.buffer, buffer);
1902 }
1903 for binding in self.indexed_transform_feedback_buffer_bindings.iter() {
1904 self.unbind_from(&binding.buffer, buffer);
1905 }
1906
1907 buffer.mark_for_deletion(Operation::Infallible);
1908 }
1909
1910 fn DeleteFramebuffer(&self, framebuffer: Option<&WebGLFramebuffer>) {
1912 self.base.DeleteFramebuffer(framebuffer)
1913 }
1914
1915 fn DeleteRenderbuffer(&self, renderbuffer: Option<&WebGLRenderbuffer>) {
1917 self.base.DeleteRenderbuffer(renderbuffer)
1918 }
1919
1920 fn DeleteTexture(&self, texture: Option<&WebGLTexture>) {
1922 self.base.DeleteTexture(texture)
1923 }
1924
1925 fn DeleteProgram(&self, program: Option<&WebGLProgram>) {
1927 self.base.DeleteProgram(program)
1928 }
1929
1930 fn DeleteShader(&self, shader: Option<&WebGLShader>) {
1932 self.base.DeleteShader(shader)
1933 }
1934
1935 fn DeleteVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) {
1937 self.base.delete_vertex_array_webgl2(vertex_array);
1938 }
1939
1940 fn DrawArrays(&self, mode: u32, first: i32, count: i32) {
1942 self.validate_uniform_block_for_draw();
1943 self.validate_vertex_attribs_for_draw();
1944 self.base.DrawArrays(mode, first, count)
1945 }
1946
1947 fn DrawElements(&self, mode: u32, count: i32, type_: u32, offset: i64) {
1949 self.validate_uniform_block_for_draw();
1950 self.validate_vertex_attribs_for_draw();
1951 self.base.DrawElements(mode, count, type_, offset)
1952 }
1953
1954 fn EnableVertexAttribArray(&self, attrib_id: u32) {
1956 self.base.EnableVertexAttribArray(attrib_id)
1957 }
1958
1959 fn DisableVertexAttribArray(&self, attrib_id: u32) {
1961 self.base.DisableVertexAttribArray(attrib_id)
1962 }
1963
1964 fn GetActiveUniform(
1966 &self,
1967 program: &WebGLProgram,
1968 index: u32,
1969 ) -> Option<DomRoot<WebGLActiveInfo>> {
1970 self.base.GetActiveUniform(program, index)
1971 }
1972
1973 fn GetActiveAttrib(
1975 &self,
1976 program: &WebGLProgram,
1977 index: u32,
1978 ) -> Option<DomRoot<WebGLActiveInfo>> {
1979 self.base.GetActiveAttrib(program, index)
1980 }
1981
1982 fn GetAttribLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
1984 self.base.GetAttribLocation(program, name)
1985 }
1986
1987 fn GetFragDataLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
1989 handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return -1);
1990 handle_potential_webgl_error!(self.base, program.get_frag_data_location(name), -1)
1991 }
1992
1993 fn GetProgramInfoLog(&self, program: &WebGLProgram) -> Option<DOMString> {
1995 self.base.GetProgramInfoLog(program)
1996 }
1997
1998 fn GetProgramParameter(
2000 &self,
2001 cx: JSContext,
2002 program: &WebGLProgram,
2003 param_id: u32,
2004 mut retval: MutableHandleValue,
2005 ) {
2006 handle_potential_webgl_error!(
2007 self.base,
2008 self.base.validate_ownership(program),
2009 return retval.set(NullValue())
2010 );
2011 if program.is_deleted() {
2012 self.base.webgl_error(InvalidOperation);
2013 return retval.set(NullValue());
2014 }
2015 match param_id {
2016 constants::TRANSFORM_FEEDBACK_VARYINGS => {
2017 retval.set(Int32Value(program.transform_feedback_varyings_length()))
2018 },
2019 constants::TRANSFORM_FEEDBACK_BUFFER_MODE => {
2020 retval.set(Int32Value(program.transform_feedback_buffer_mode()))
2021 },
2022 _ => self.base.GetProgramParameter(cx, program, param_id, retval),
2023 }
2024 }
2025
2026 fn GetShaderInfoLog(&self, shader: &WebGLShader) -> Option<DOMString> {
2028 self.base.GetShaderInfoLog(shader)
2029 }
2030
2031 fn GetShaderParameter(
2033 &self,
2034 cx: JSContext,
2035 shader: &WebGLShader,
2036 param_id: u32,
2037 retval: MutableHandleValue,
2038 ) {
2039 self.base.GetShaderParameter(cx, shader, param_id, retval)
2040 }
2041
2042 fn GetShaderPrecisionFormat(
2044 &self,
2045 shader_type: u32,
2046 precision_type: u32,
2047 ) -> Option<DomRoot<WebGLShaderPrecisionFormat>> {
2048 self.base
2049 .GetShaderPrecisionFormat(shader_type, precision_type)
2050 }
2051
2052 fn GetIndexedParameter(
2054 &self,
2055 cx: JSContext,
2056 target: u32,
2057 index: u32,
2058 mut retval: MutableHandleValue,
2059 ) {
2060 let bindings = match target {
2061 constants::TRANSFORM_FEEDBACK_BUFFER_BINDING |
2062 constants::TRANSFORM_FEEDBACK_BUFFER_SIZE |
2063 constants::TRANSFORM_FEEDBACK_BUFFER_START => {
2064 &self.indexed_transform_feedback_buffer_bindings
2065 },
2066 constants::UNIFORM_BUFFER_BINDING |
2067 constants::UNIFORM_BUFFER_SIZE |
2068 constants::UNIFORM_BUFFER_START => &self.indexed_uniform_buffer_bindings,
2069 _ => {
2070 self.base.webgl_error(InvalidEnum);
2071 return retval.set(NullValue());
2072 },
2073 };
2074
2075 let binding = match bindings.get(index as usize) {
2076 Some(binding) => binding,
2077 None => {
2078 self.base.webgl_error(InvalidValue);
2079 return retval.set(NullValue());
2080 },
2081 };
2082
2083 match target {
2084 constants::TRANSFORM_FEEDBACK_BUFFER_BINDING | constants::UNIFORM_BUFFER_BINDING => {
2085 binding
2086 .buffer
2087 .get()
2088 .safe_to_jsval(cx, retval, CanGc::note())
2089 },
2090 constants::TRANSFORM_FEEDBACK_BUFFER_START | constants::UNIFORM_BUFFER_START => {
2091 retval.set(Int32Value(binding.start.get() as _))
2092 },
2093 constants::TRANSFORM_FEEDBACK_BUFFER_SIZE | constants::UNIFORM_BUFFER_SIZE => {
2094 retval.set(Int32Value(binding.size.get() as _))
2095 },
2096 _ => unreachable!(),
2097 }
2098 }
2099
2100 fn GetUniformLocation(
2102 &self,
2103 program: &WebGLProgram,
2104 name: DOMString,
2105 ) -> Option<DomRoot<WebGLUniformLocation>> {
2106 self.base.GetUniformLocation(program, name)
2107 }
2108
2109 fn GetVertexAttrib(&self, cx: JSContext, index: u32, pname: u32, retval: MutableHandleValue) {
2111 self.base.GetVertexAttrib(cx, index, pname, retval)
2112 }
2113
2114 fn GetVertexAttribOffset(&self, index: u32, pname: u32) -> i64 {
2116 self.base.GetVertexAttribOffset(index, pname)
2117 }
2118
2119 fn Hint(&self, target: u32, mode: u32) {
2121 self.base.Hint(target, mode)
2122 }
2123
2124 fn IsBuffer(&self, buffer: Option<&WebGLBuffer>) -> bool {
2126 self.base.IsBuffer(buffer)
2127 }
2128
2129 fn IsEnabled(&self, cap: u32) -> bool {
2132 match cap {
2133 constants::RASTERIZER_DISCARD => self.enable_rasterizer_discard.get(),
2134 _ => self.base.IsEnabled(cap),
2135 }
2136 }
2137
2138 fn IsFramebuffer(&self, frame_buffer: Option<&WebGLFramebuffer>) -> bool {
2140 self.base.IsFramebuffer(frame_buffer)
2141 }
2142
2143 fn IsProgram(&self, program: Option<&WebGLProgram>) -> bool {
2145 self.base.IsProgram(program)
2146 }
2147
2148 fn IsRenderbuffer(&self, render_buffer: Option<&WebGLRenderbuffer>) -> bool {
2150 self.base.IsRenderbuffer(render_buffer)
2151 }
2152
2153 fn IsShader(&self, shader: Option<&WebGLShader>) -> bool {
2155 self.base.IsShader(shader)
2156 }
2157
2158 fn IsTexture(&self, texture: Option<&WebGLTexture>) -> bool {
2160 self.base.IsTexture(texture)
2161 }
2162
2163 fn IsVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) -> bool {
2165 self.base.is_vertex_array_webgl2(vertex_array)
2166 }
2167
2168 fn LineWidth(&self, width: f32) {
2170 self.base.LineWidth(width)
2171 }
2172
2173 fn PixelStorei(&self, param_name: u32, param_value: i32) {
2175 if param_value < 0 {
2176 return self.base.webgl_error(InvalidValue);
2177 }
2178
2179 match param_name {
2180 constants::PACK_ROW_LENGTH => self.texture_pack_row_length.set(param_value as _),
2181 constants::PACK_SKIP_PIXELS => self.texture_pack_skip_pixels.set(param_value as _),
2182 constants::PACK_SKIP_ROWS => self.texture_pack_skip_rows.set(param_value as _),
2183 _ => self.base.PixelStorei(param_name, param_value),
2184 }
2185 }
2186
2187 fn PolygonOffset(&self, factor: f32, units: f32) {
2189 self.base.PolygonOffset(factor, units)
2190 }
2191
2192 fn ReadPixels(
2194 &self,
2195 x: i32,
2196 y: i32,
2197 width: i32,
2198 height: i32,
2199 format: u32,
2200 pixel_type: u32,
2201 mut pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
2202 ) {
2203 let pixels =
2204 handle_potential_webgl_error!(self.base, pixels.as_mut().ok_or(InvalidValue), return);
2205
2206 self.read_pixels_into(x, y, width, height, format, pixel_type, pixels, 0)
2207 }
2208
2209 fn ReadPixels_(
2211 &self,
2212 x: i32,
2213 y: i32,
2214 width: i32,
2215 height: i32,
2216 format: u32,
2217 pixel_type: u32,
2218 dst_byte_offset: i64,
2219 ) {
2220 handle_potential_webgl_error!(self.base, self.base.validate_framebuffer(), return);
2221
2222 let dst = match self.bound_pixel_pack_buffer.get() {
2223 Some(buffer) => buffer,
2224 None => return self.base.webgl_error(InvalidOperation),
2225 };
2226
2227 if dst_byte_offset < 0 {
2228 return self.base.webgl_error(InvalidValue);
2229 }
2230 let dst_byte_offset = dst_byte_offset as usize;
2231 if dst_byte_offset > dst.capacity() {
2232 return self.base.webgl_error(InvalidOperation);
2233 }
2234
2235 let ReadPixelsAllowedFormats {
2236 array_types: _,
2237 channels: bytes_per_pixel,
2238 } = match self.calc_read_pixel_formats(pixel_type, format) {
2239 Ok(result) => result,
2240 Err(error) => return self.base.webgl_error(error),
2241 };
2242 if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
2243 return self.base.webgl_error(InvalidOperation);
2244 }
2245
2246 let ReadPixelsSizes {
2247 row_stride: _,
2248 skipped_bytes,
2249 size,
2250 } = match self.calc_read_pixel_sizes(width, height, bytes_per_pixel) {
2251 Ok(result) => result,
2252 Err(error) => return self.base.webgl_error(error),
2253 };
2254 let dst_end = dst_byte_offset + skipped_bytes + size;
2255 if dst.capacity() < dst_end {
2256 return self.base.webgl_error(InvalidOperation);
2257 }
2258
2259 {
2260 let (fb_width, fb_height) = handle_potential_webgl_error!(
2261 self.base,
2262 self.base
2263 .get_current_framebuffer_size()
2264 .ok_or(InvalidOperation),
2265 return
2266 );
2267 let src_origin = Point2D::new(x, y);
2268 let src_size = Size2D::new(width as u32, height as u32);
2269 let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
2270 if pixels::clip(src_origin, src_size.to_u32(), fb_size.to_u32()).is_none() {
2271 return;
2272 }
2273 }
2274 let src_rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height));
2275
2276 self.base.send_command(WebGLCommand::PixelStorei(
2277 constants::PACK_ALIGNMENT,
2278 self.base.get_texture_packing_alignment() as _,
2279 ));
2280 self.base.send_command(WebGLCommand::PixelStorei(
2281 constants::PACK_ROW_LENGTH,
2282 self.texture_pack_row_length.get() as _,
2283 ));
2284 self.base.send_command(WebGLCommand::PixelStorei(
2285 constants::PACK_SKIP_ROWS,
2286 self.texture_pack_skip_rows.get() as _,
2287 ));
2288 self.base.send_command(WebGLCommand::PixelStorei(
2289 constants::PACK_SKIP_PIXELS,
2290 self.texture_pack_skip_pixels.get() as _,
2291 ));
2292 self.base.send_command(WebGLCommand::ReadPixelsPP(
2293 src_rect,
2294 format,
2295 pixel_type,
2296 dst_byte_offset,
2297 ));
2298 }
2299
2300 #[allow(unsafe_code)]
2302 fn ReadPixels__(
2303 &self,
2304 x: i32,
2305 y: i32,
2306 width: i32,
2307 height: i32,
2308 format: u32,
2309 pixel_type: u32,
2310 mut dst: CustomAutoRooterGuard<ArrayBufferView>,
2311 dst_elem_offset: u32,
2312 ) {
2313 self.read_pixels_into(
2314 x,
2315 y,
2316 width,
2317 height,
2318 format,
2319 pixel_type,
2320 &mut dst,
2321 dst_elem_offset,
2322 )
2323 }
2324
2325 fn SampleCoverage(&self, value: f32, invert: bool) {
2327 self.base.SampleCoverage(value, invert)
2328 }
2329
2330 fn Scissor(&self, x: i32, y: i32, width: i32, height: i32) {
2332 self.base.Scissor(x, y, width, height)
2333 }
2334
2335 fn StencilFunc(&self, func: u32, ref_: i32, mask: u32) {
2337 self.base.StencilFunc(func, ref_, mask)
2338 }
2339
2340 fn StencilFuncSeparate(&self, face: u32, func: u32, ref_: i32, mask: u32) {
2342 self.base.StencilFuncSeparate(face, func, ref_, mask)
2343 }
2344
2345 fn StencilMask(&self, mask: u32) {
2347 self.base.StencilMask(mask)
2348 }
2349
2350 fn StencilMaskSeparate(&self, face: u32, mask: u32) {
2352 self.base.StencilMaskSeparate(face, mask)
2353 }
2354
2355 fn StencilOp(&self, fail: u32, zfail: u32, zpass: u32) {
2357 self.base.StencilOp(fail, zfail, zpass)
2358 }
2359
2360 fn StencilOpSeparate(&self, face: u32, fail: u32, zfail: u32, zpass: u32) {
2362 self.base.StencilOpSeparate(face, fail, zfail, zpass)
2363 }
2364
2365 fn LinkProgram(&self, program: &WebGLProgram) {
2367 self.base.LinkProgram(program)
2368 }
2369
2370 fn ShaderSource(&self, shader: &WebGLShader, source: DOMString) {
2372 self.base.ShaderSource(shader, source)
2373 }
2374
2375 fn GetShaderSource(&self, shader: &WebGLShader) -> Option<DOMString> {
2377 self.base.GetShaderSource(shader)
2378 }
2379
2380 fn Uniform1f(&self, location: Option<&WebGLUniformLocation>, val: f32) {
2382 self.base.Uniform1f(location, val)
2383 }
2384
2385 fn Uniform1i(&self, location: Option<&WebGLUniformLocation>, val: i32) {
2387 self.base.Uniform1i(location, val)
2388 }
2389
2390 fn Uniform1iv(
2392 &self,
2393 location: Option<&WebGLUniformLocation>,
2394 v: Int32ArrayOrLongSequence,
2395 src_offset: u32,
2396 src_length: u32,
2397 ) {
2398 self.base.uniform1iv(location, v, src_offset, src_length)
2399 }
2400
2401 fn Uniform1ui(&self, location: Option<&WebGLUniformLocation>, val: u32) {
2403 self.base.with_location(location, |location| {
2404 match location.type_() {
2405 constants::BOOL | constants::UNSIGNED_INT => (),
2406 _ => return Err(InvalidOperation),
2407 }
2408 self.base
2409 .send_command(WebGLCommand::Uniform1ui(location.id(), val));
2410 Ok(())
2411 });
2412 }
2413
2414 fn Uniform1uiv(
2416 &self,
2417 location: Option<&WebGLUniformLocation>,
2418 val: Uint32ArrayOrUnsignedLongSequence,
2419 src_offset: u32,
2420 src_length: u32,
2421 ) {
2422 self.base.with_location(location, |location| {
2423 match location.type_() {
2424 constants::BOOL |
2425 constants::UNSIGNED_INT |
2426 constants::SAMPLER_2D |
2427 constants::SAMPLER_2D_ARRAY |
2428 constants::SAMPLER_3D |
2429 constants::SAMPLER_CUBE => {},
2430 _ => return Err(InvalidOperation),
2431 }
2432
2433 let val = self.uniform_vec_section_uint(val, src_offset, src_length, 1, location)?;
2434
2435 match location.type_() {
2436 constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
2437 for &v in val
2438 .iter()
2439 .take(cmp::min(location.size().unwrap_or(1) as usize, val.len()))
2440 {
2441 if v >= self.base.limits().max_combined_texture_image_units {
2442 return Err(InvalidValue);
2443 }
2444 }
2445 },
2446 _ => {},
2447 }
2448 self.base
2449 .send_command(WebGLCommand::Uniform1uiv(location.id(), val));
2450 Ok(())
2451 });
2452 }
2453
2454 fn Uniform1fv(
2456 &self,
2457 location: Option<&WebGLUniformLocation>,
2458 v: Float32ArrayOrUnrestrictedFloatSequence,
2459 src_offset: u32,
2460 src_length: u32,
2461 ) {
2462 self.base.uniform1fv(location, v, src_offset, src_length);
2463 }
2464
2465 fn Uniform2f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32) {
2467 self.base.Uniform2f(location, x, y)
2468 }
2469
2470 fn Uniform2fv(
2472 &self,
2473 location: Option<&WebGLUniformLocation>,
2474 v: Float32ArrayOrUnrestrictedFloatSequence,
2475 src_offset: u32,
2476 src_length: u32,
2477 ) {
2478 self.base.uniform2fv(location, v, src_offset, src_length);
2479 }
2480
2481 fn Uniform2i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32) {
2483 self.base.Uniform2i(location, x, y)
2484 }
2485
2486 fn Uniform2iv(
2488 &self,
2489 location: Option<&WebGLUniformLocation>,
2490 v: Int32ArrayOrLongSequence,
2491 src_offset: u32,
2492 src_length: u32,
2493 ) {
2494 self.base.uniform2iv(location, v, src_offset, src_length)
2495 }
2496
2497 fn Uniform2ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32) {
2499 self.base.with_location(location, |location| {
2500 match location.type_() {
2501 constants::BOOL_VEC2 | constants::UNSIGNED_INT_VEC2 => {},
2502 _ => return Err(InvalidOperation),
2503 }
2504 self.base
2505 .send_command(WebGLCommand::Uniform2ui(location.id(), x, y));
2506 Ok(())
2507 });
2508 }
2509
2510 fn Uniform2uiv(
2512 &self,
2513 location: Option<&WebGLUniformLocation>,
2514 val: Uint32ArrayOrUnsignedLongSequence,
2515 src_offset: u32,
2516 src_length: u32,
2517 ) {
2518 self.base.with_location(location, |location| {
2519 match location.type_() {
2520 constants::BOOL_VEC2 | constants::UNSIGNED_INT_VEC2 => {},
2521 _ => return Err(InvalidOperation),
2522 }
2523 let val = self.uniform_vec_section_uint(val, src_offset, src_length, 2, location)?;
2524 self.base
2525 .send_command(WebGLCommand::Uniform2uiv(location.id(), val));
2526 Ok(())
2527 });
2528 }
2529
2530 fn Uniform3f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32) {
2532 self.base.Uniform3f(location, x, y, z)
2533 }
2534
2535 fn Uniform3fv(
2537 &self,
2538 location: Option<&WebGLUniformLocation>,
2539 v: Float32ArrayOrUnrestrictedFloatSequence,
2540 src_offset: u32,
2541 src_length: u32,
2542 ) {
2543 self.base.uniform3fv(location, v, src_offset, src_length);
2544 }
2545
2546 fn Uniform3i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32) {
2548 self.base.Uniform3i(location, x, y, z)
2549 }
2550
2551 fn Uniform3iv(
2553 &self,
2554 location: Option<&WebGLUniformLocation>,
2555 v: Int32ArrayOrLongSequence,
2556 src_offset: u32,
2557 src_length: u32,
2558 ) {
2559 self.base.uniform3iv(location, v, src_offset, src_length)
2560 }
2561
2562 fn Uniform3ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32, z: u32) {
2564 self.base.with_location(location, |location| {
2565 match location.type_() {
2566 constants::BOOL_VEC3 | constants::UNSIGNED_INT_VEC3 => {},
2567 _ => return Err(InvalidOperation),
2568 }
2569 self.base
2570 .send_command(WebGLCommand::Uniform3ui(location.id(), x, y, z));
2571 Ok(())
2572 });
2573 }
2574
2575 fn Uniform3uiv(
2577 &self,
2578 location: Option<&WebGLUniformLocation>,
2579 val: Uint32ArrayOrUnsignedLongSequence,
2580 src_offset: u32,
2581 src_length: u32,
2582 ) {
2583 self.base.with_location(location, |location| {
2584 match location.type_() {
2585 constants::BOOL_VEC3 | constants::UNSIGNED_INT_VEC3 => {},
2586 _ => return Err(InvalidOperation),
2587 }
2588 let val = self.uniform_vec_section_uint(val, src_offset, src_length, 3, location)?;
2589 self.base
2590 .send_command(WebGLCommand::Uniform3uiv(location.id(), val));
2591 Ok(())
2592 });
2593 }
2594
2595 fn Uniform4i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32, w: i32) {
2597 self.base.Uniform4i(location, x, y, z, w)
2598 }
2599
2600 fn Uniform4iv(
2602 &self,
2603 location: Option<&WebGLUniformLocation>,
2604 v: Int32ArrayOrLongSequence,
2605 src_offset: u32,
2606 src_length: u32,
2607 ) {
2608 self.base.uniform4iv(location, v, src_offset, src_length)
2609 }
2610
2611 fn Uniform4ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32, z: u32, w: u32) {
2613 self.base.with_location(location, |location| {
2614 match location.type_() {
2615 constants::BOOL_VEC4 | constants::UNSIGNED_INT_VEC4 => {},
2616 _ => return Err(InvalidOperation),
2617 }
2618 self.base
2619 .send_command(WebGLCommand::Uniform4ui(location.id(), x, y, z, w));
2620 Ok(())
2621 });
2622 }
2623
2624 fn Uniform4uiv(
2626 &self,
2627 location: Option<&WebGLUniformLocation>,
2628 val: Uint32ArrayOrUnsignedLongSequence,
2629 src_offset: u32,
2630 src_length: u32,
2631 ) {
2632 self.base.with_location(location, |location| {
2633 match location.type_() {
2634 constants::BOOL_VEC4 | constants::UNSIGNED_INT_VEC4 => {},
2635 _ => return Err(InvalidOperation),
2636 }
2637 let val = self.uniform_vec_section_uint(val, src_offset, src_length, 4, location)?;
2638 self.base
2639 .send_command(WebGLCommand::Uniform4uiv(location.id(), val));
2640 Ok(())
2641 });
2642 }
2643
2644 fn Uniform4f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32, w: f32) {
2646 self.base.Uniform4f(location, x, y, z, w)
2647 }
2648
2649 fn Uniform4fv(
2651 &self,
2652 location: Option<&WebGLUniformLocation>,
2653 v: Float32ArrayOrUnrestrictedFloatSequence,
2654 src_offset: u32,
2655 src_length: u32,
2656 ) {
2657 self.base.uniform4fv(location, v, src_offset, src_length);
2658 }
2659
2660 fn UniformMatrix2fv(
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_2fv(location, transpose, v, src_offset, src_length)
2671 }
2672
2673 fn UniformMatrix3fv(
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_3fv(location, transpose, v, src_offset, src_length)
2684 }
2685
2686 fn UniformMatrix4fv(
2688 &self,
2689 location: Option<&WebGLUniformLocation>,
2690 transpose: bool,
2691 v: Float32ArrayOrUnrestrictedFloatSequence,
2692 src_offset: u32,
2693 src_length: u32,
2694 ) {
2695 self.base
2696 .uniform_matrix_4fv(location, transpose, v, src_offset, src_length)
2697 }
2698
2699 fn UniformMatrix3x2fv(
2701 &self,
2702 location: Option<&WebGLUniformLocation>,
2703 transpose: bool,
2704 val: Float32ArrayOrUnrestrictedFloatSequence,
2705 src_offset: u32,
2706 src_length: u32,
2707 ) {
2708 self.base.with_location(location, |location| {
2709 match location.type_() {
2710 constants::FLOAT_MAT3x2 => {},
2711 _ => return Err(InvalidOperation),
2712 }
2713 let val = self.base.uniform_matrix_section(
2714 val,
2715 src_offset,
2716 src_length,
2717 transpose,
2718 3 * 2,
2719 location,
2720 )?;
2721 self.base
2722 .send_command(WebGLCommand::UniformMatrix3x2fv(location.id(), val));
2723 Ok(())
2724 });
2725 }
2726
2727 fn UniformMatrix4x2fv(
2729 &self,
2730 location: Option<&WebGLUniformLocation>,
2731 transpose: bool,
2732 val: Float32ArrayOrUnrestrictedFloatSequence,
2733 src_offset: u32,
2734 src_length: u32,
2735 ) {
2736 self.base.with_location(location, |location| {
2737 match location.type_() {
2738 constants::FLOAT_MAT4x2 => {},
2739 _ => return Err(InvalidOperation),
2740 }
2741 let val = self.base.uniform_matrix_section(
2742 val,
2743 src_offset,
2744 src_length,
2745 transpose,
2746 4 * 2,
2747 location,
2748 )?;
2749 self.base
2750 .send_command(WebGLCommand::UniformMatrix4x2fv(location.id(), val));
2751 Ok(())
2752 });
2753 }
2754
2755 fn UniformMatrix2x3fv(
2757 &self,
2758 location: Option<&WebGLUniformLocation>,
2759 transpose: bool,
2760 val: Float32ArrayOrUnrestrictedFloatSequence,
2761 src_offset: u32,
2762 src_length: u32,
2763 ) {
2764 self.base.with_location(location, |location| {
2765 match location.type_() {
2766 constants::FLOAT_MAT2x3 => {},
2767 _ => return Err(InvalidOperation),
2768 }
2769 let val = self.base.uniform_matrix_section(
2770 val,
2771 src_offset,
2772 src_length,
2773 transpose,
2774 2 * 3,
2775 location,
2776 )?;
2777 self.base
2778 .send_command(WebGLCommand::UniformMatrix2x3fv(location.id(), val));
2779 Ok(())
2780 });
2781 }
2782
2783 fn UniformMatrix4x3fv(
2785 &self,
2786 location: Option<&WebGLUniformLocation>,
2787 transpose: bool,
2788 val: Float32ArrayOrUnrestrictedFloatSequence,
2789 src_offset: u32,
2790 src_length: u32,
2791 ) {
2792 self.base.with_location(location, |location| {
2793 match location.type_() {
2794 constants::FLOAT_MAT4x3 => {},
2795 _ => return Err(InvalidOperation),
2796 }
2797 let val = self.base.uniform_matrix_section(
2798 val,
2799 src_offset,
2800 src_length,
2801 transpose,
2802 4 * 3,
2803 location,
2804 )?;
2805 self.base
2806 .send_command(WebGLCommand::UniformMatrix4x3fv(location.id(), val));
2807 Ok(())
2808 });
2809 }
2810
2811 fn UniformMatrix2x4fv(
2813 &self,
2814 location: Option<&WebGLUniformLocation>,
2815 transpose: bool,
2816 val: Float32ArrayOrUnrestrictedFloatSequence,
2817 src_offset: u32,
2818 src_length: u32,
2819 ) {
2820 self.base.with_location(location, |location| {
2821 match location.type_() {
2822 constants::FLOAT_MAT2x4 => {},
2823 _ => return Err(InvalidOperation),
2824 }
2825 let val = self.base.uniform_matrix_section(
2826 val,
2827 src_offset,
2828 src_length,
2829 transpose,
2830 2 * 4,
2831 location,
2832 )?;
2833 self.base
2834 .send_command(WebGLCommand::UniformMatrix2x4fv(location.id(), val));
2835 Ok(())
2836 });
2837 }
2838
2839 fn UniformMatrix3x4fv(
2841 &self,
2842 location: Option<&WebGLUniformLocation>,
2843 transpose: bool,
2844 val: Float32ArrayOrUnrestrictedFloatSequence,
2845 src_offset: u32,
2846 src_length: u32,
2847 ) {
2848 self.base.with_location(location, |location| {
2849 match location.type_() {
2850 constants::FLOAT_MAT3x4 => {},
2851 _ => return Err(InvalidOperation),
2852 }
2853 let val = self.base.uniform_matrix_section(
2854 val,
2855 src_offset,
2856 src_length,
2857 transpose,
2858 3 * 4,
2859 location,
2860 )?;
2861 self.base
2862 .send_command(WebGLCommand::UniformMatrix3x4fv(location.id(), val));
2863 Ok(())
2864 });
2865 }
2866
2867 #[allow(unsafe_code)]
2869 fn GetUniform(
2870 &self,
2871 cx: JSContext,
2872 program: &WebGLProgram,
2873 location: &WebGLUniformLocation,
2874 mut retval: MutableHandleValue,
2875 ) {
2876 handle_potential_webgl_error!(
2877 self.base,
2878 self.base.uniform_check_program(program, location),
2879 return retval.set(NullValue())
2880 );
2881
2882 let triple = (&*self.base, program.id(), location.id());
2883
2884 match location.type_() {
2885 constants::UNSIGNED_INT => retval.set(UInt32Value(uniform_get(
2886 triple,
2887 WebGLCommand::GetUniformUint,
2888 ))),
2889 constants::UNSIGNED_INT_VEC2 => unsafe {
2890 uniform_typed::<Uint32>(
2891 *cx,
2892 &uniform_get(triple, WebGLCommand::GetUniformUint2),
2893 retval,
2894 )
2895 },
2896 constants::UNSIGNED_INT_VEC3 => unsafe {
2897 uniform_typed::<Uint32>(
2898 *cx,
2899 &uniform_get(triple, WebGLCommand::GetUniformUint3),
2900 retval,
2901 )
2902 },
2903 constants::UNSIGNED_INT_VEC4 => unsafe {
2904 uniform_typed::<Uint32>(
2905 *cx,
2906 &uniform_get(triple, WebGLCommand::GetUniformUint4),
2907 retval,
2908 )
2909 },
2910 constants::FLOAT_MAT2x3 => unsafe {
2911 uniform_typed::<Float32>(
2912 *cx,
2913 &uniform_get(triple, WebGLCommand::GetUniformFloat2x3),
2914 retval,
2915 )
2916 },
2917 constants::FLOAT_MAT2x4 => unsafe {
2918 uniform_typed::<Float32>(
2919 *cx,
2920 &uniform_get(triple, WebGLCommand::GetUniformFloat2x4),
2921 retval,
2922 )
2923 },
2924 constants::FLOAT_MAT3x2 => unsafe {
2925 uniform_typed::<Float32>(
2926 *cx,
2927 &uniform_get(triple, WebGLCommand::GetUniformFloat3x2),
2928 retval,
2929 )
2930 },
2931 constants::FLOAT_MAT3x4 => unsafe {
2932 uniform_typed::<Float32>(
2933 *cx,
2934 &uniform_get(triple, WebGLCommand::GetUniformFloat3x4),
2935 retval,
2936 )
2937 },
2938 constants::FLOAT_MAT4x2 => unsafe {
2939 uniform_typed::<Float32>(
2940 *cx,
2941 &uniform_get(triple, WebGLCommand::GetUniformFloat4x2),
2942 retval,
2943 )
2944 },
2945 constants::FLOAT_MAT4x3 => unsafe {
2946 uniform_typed::<Float32>(
2947 *cx,
2948 &uniform_get(triple, WebGLCommand::GetUniformFloat4x3),
2949 retval,
2950 )
2951 },
2952 constants::SAMPLER_3D | constants::SAMPLER_2D_ARRAY => {
2953 retval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)))
2954 },
2955 _ => self.base.GetUniform(cx, program, location, retval),
2956 }
2957 }
2958
2959 fn UseProgram(&self, program: Option<&WebGLProgram>) {
2961 self.base.UseProgram(program)
2962 }
2963
2964 fn ValidateProgram(&self, program: &WebGLProgram) {
2966 self.base.ValidateProgram(program)
2967 }
2968
2969 fn VertexAttrib1f(&self, indx: u32, x: f32) {
2971 self.base.VertexAttrib1f(indx, x)
2972 }
2973
2974 fn VertexAttrib1fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2976 self.base.VertexAttrib1fv(indx, v)
2977 }
2978
2979 fn VertexAttrib2f(&self, indx: u32, x: f32, y: f32) {
2981 self.base.VertexAttrib2f(indx, x, y)
2982 }
2983
2984 fn VertexAttrib2fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2986 self.base.VertexAttrib2fv(indx, v)
2987 }
2988
2989 fn VertexAttrib3f(&self, indx: u32, x: f32, y: f32, z: f32) {
2991 self.base.VertexAttrib3f(indx, x, y, z)
2992 }
2993
2994 fn VertexAttrib3fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2996 self.base.VertexAttrib3fv(indx, v)
2997 }
2998
2999 fn VertexAttrib4f(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) {
3001 self.base.VertexAttrib4f(indx, x, y, z, w)
3002 }
3003
3004 fn VertexAttrib4fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
3006 self.base.VertexAttrib4fv(indx, v)
3007 }
3008
3009 fn VertexAttribI4i(&self, index: u32, x: i32, y: i32, z: i32, w: i32) {
3011 self.vertex_attrib_i(index, x, y, z, w)
3012 }
3013
3014 fn VertexAttribI4iv(&self, index: u32, v: Int32ArrayOrLongSequence) {
3016 let values = match v {
3017 Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
3018 Int32ArrayOrLongSequence::LongSequence(v) => v,
3019 };
3020 if values.len() < 4 {
3021 return self.base.webgl_error(InvalidValue);
3022 }
3023 self.vertex_attrib_i(index, values[0], values[1], values[2], values[3]);
3024 }
3025
3026 fn VertexAttribI4ui(&self, index: u32, x: u32, y: u32, z: u32, w: u32) {
3028 self.vertex_attrib_u(index, x, y, z, w)
3029 }
3030
3031 fn VertexAttribI4uiv(&self, index: u32, v: Uint32ArrayOrUnsignedLongSequence) {
3033 let values = match v {
3034 Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(),
3035 Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v,
3036 };
3037 if values.len() < 4 {
3038 return self.base.webgl_error(InvalidValue);
3039 }
3040 self.vertex_attrib_u(index, values[0], values[1], values[2], values[3]);
3041 }
3042
3043 fn VertexAttribPointer(
3045 &self,
3046 attrib_id: u32,
3047 size: i32,
3048 data_type: u32,
3049 normalized: bool,
3050 stride: i32,
3051 offset: i64,
3052 ) {
3053 self.base
3054 .VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset)
3055 }
3056
3057 fn VertexAttribIPointer(&self, index: u32, size: i32, type_: u32, stride: i32, offset: i64) {
3059 match type_ {
3060 constants::BYTE |
3061 constants::UNSIGNED_BYTE |
3062 constants::SHORT |
3063 constants::UNSIGNED_SHORT |
3064 constants::INT |
3065 constants::UNSIGNED_INT => {},
3066 _ => return self.base.webgl_error(InvalidEnum),
3067 };
3068 self.base
3069 .VertexAttribPointer(index, size, type_, false, stride, offset)
3070 }
3071
3072 fn Viewport(&self, x: i32, y: i32, width: i32, height: i32) {
3074 self.base.Viewport(x, y, width, height)
3075 }
3076
3077 #[allow(unsafe_code)]
3082 fn TexImage3D(
3083 &self,
3084 target: u32,
3085 level: i32,
3086 internal_format: i32,
3087 width: i32,
3088 height: i32,
3089 depth: i32,
3090 border: i32,
3091 format: u32,
3092 type_: u32,
3093 src_data: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3094 ) -> Fallible<()> {
3095 if self.bound_pixel_unpack_buffer.get().is_some() {
3098 self.base.webgl_error(InvalidOperation);
3099 return Ok(());
3100 }
3101
3102 if type_ == constants::FLOAT_32_UNSIGNED_INT_24_8_REV && src_data.is_some() {
3105 self.base.webgl_error(InvalidOperation);
3106 return Ok(());
3107 }
3108
3109 if border != 0 {
3110 self.base.webgl_error(InvalidValue);
3111 return Ok(());
3112 }
3113
3114 let Ok(TexImage3DValidatorResult {
3115 width,
3116 height,
3117 depth,
3118 level,
3119 border,
3120 texture,
3121 target,
3122 internal_format,
3123 format,
3124 data_type,
3125 }) = TexImage3DValidator::new(
3126 &self.base,
3127 target,
3128 level,
3129 internal_format as u32,
3130 width,
3131 height,
3132 depth,
3133 border,
3134 format,
3135 type_,
3136 &src_data,
3137 )
3138 .validate()
3139 else {
3140 return Ok(());
3141 };
3142
3143 let unpacking_alignment = self.base.texture_unpacking_alignment();
3147 let buff = match *src_data {
3148 Some(ref data) => IpcSharedMemory::from_bytes(unsafe { data.as_slice() }),
3149 None => {
3150 let element_size = data_type.element_size();
3151 let components = format.components();
3152 let components_per_element = format.components();
3153 let expected_byte_len = if height == 0 {
3156 0
3157 } else {
3158 let cpp = element_size * components / components_per_element;
3163 let stride =
3164 (width * cpp + unpacking_alignment - 1) & !(unpacking_alignment - 1);
3165 stride * (height - 1) + width * cpp
3166 };
3167 IpcSharedMemory::from_bytes(&vec![0u8; expected_byte_len as usize])
3168 },
3169 };
3170 let (alpha_treatment, y_axis_treatment) =
3171 self.base.get_current_unpack_state(Alpha::NotPremultiplied);
3172 if let (Some(AlphaTreatment::Premultiply), YAxisTreatment::Flipped) =
3176 (alpha_treatment, y_axis_treatment)
3177 {
3178 if src_data.is_some() {
3179 self.base.webgl_error(InvalidOperation);
3180 return Ok(());
3181 }
3182 }
3183 let tex_source = TexPixels::from_array(
3184 buff,
3185 Size2D::new(width, height),
3186 alpha_treatment,
3187 y_axis_treatment,
3188 );
3189
3190 self.tex_image_3d(
3191 &texture,
3192 target,
3193 data_type,
3194 internal_format,
3195 format,
3196 level,
3197 width,
3198 height,
3199 depth,
3200 border,
3201 unpacking_alignment,
3202 tex_source,
3203 );
3204 Ok(())
3205 }
3206
3207 fn TexImage2D(
3209 &self,
3210 target: u32,
3211 level: i32,
3212 internal_format: i32,
3213 width: i32,
3214 height: i32,
3215 border: i32,
3216 format: u32,
3217 data_type: u32,
3218 pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3219 ) -> Fallible<()> {
3220 self.base.TexImage2D(
3221 target,
3222 level,
3223 internal_format,
3224 width,
3225 height,
3226 border,
3227 format,
3228 data_type,
3229 pixels,
3230 )
3231 }
3232
3233 fn TexImage2D_(
3235 &self,
3236 target: u32,
3237 level: i32,
3238 internal_format: i32,
3239 format: u32,
3240 data_type: u32,
3241 source: TexImageSource,
3242 ) -> ErrorResult {
3243 self.base
3244 .TexImage2D_(target, level, internal_format, format, data_type, source)
3245 }
3246
3247 fn TexImage2D__(
3249 &self,
3250 target: u32,
3251 level: i32,
3252 internalformat: i32,
3253 width: i32,
3254 height: i32,
3255 border: i32,
3256 format: u32,
3257 type_: u32,
3258 pbo_offset: i64,
3259 ) -> Fallible<()> {
3260 let pixel_unpack_buffer = match self.bound_pixel_unpack_buffer.get() {
3261 Some(pixel_unpack_buffer) => pixel_unpack_buffer,
3262 None => {
3263 self.base.webgl_error(InvalidOperation);
3264 return Ok(());
3265 },
3266 };
3267
3268 if let Some(tf_buffer) = self.bound_transform_feedback_buffer.get() {
3269 if pixel_unpack_buffer == tf_buffer {
3270 self.base.webgl_error(InvalidOperation);
3271 return Ok(());
3272 }
3273 }
3274
3275 if pbo_offset < 0 || pbo_offset as usize > pixel_unpack_buffer.capacity() {
3276 self.base.webgl_error(InvalidValue);
3277 return Ok(());
3278 }
3279
3280 let unpacking_alignment = self.base.texture_unpacking_alignment();
3281
3282 let validator = TexImage2DValidator::new(
3283 &self.base,
3284 target,
3285 level,
3286 internalformat as u32,
3287 width,
3288 height,
3289 border,
3290 format,
3291 type_,
3292 );
3293
3294 let TexImage2DValidatorResult {
3295 texture,
3296 target,
3297 width,
3298 height,
3299 level,
3300 border,
3301 internal_format,
3302 format,
3303 data_type,
3304 } = match validator.validate() {
3305 Ok(result) => result,
3306 Err(_) => return Ok(()),
3307 };
3308
3309 self.base.tex_image_2d(
3310 &texture,
3311 target,
3312 data_type,
3313 internal_format,
3314 format,
3315 level,
3316 border,
3317 unpacking_alignment,
3318 Size2D::new(width, height),
3319 TexSource::BufferOffset(pbo_offset),
3320 );
3321
3322 Ok(())
3323 }
3324
3325 fn TexImage2D___(
3327 &self,
3328 target: u32,
3329 level: i32,
3330 internalformat: i32,
3331 width: i32,
3332 height: i32,
3333 border: i32,
3334 format: u32,
3335 type_: u32,
3336 source: TexImageSource,
3337 ) -> Fallible<()> {
3338 if self.bound_pixel_unpack_buffer.get().is_some() {
3339 self.base.webgl_error(InvalidOperation);
3340 return Ok(());
3341 }
3342
3343 let validator = TexImage2DValidator::new(
3344 &self.base,
3345 target,
3346 level,
3347 internalformat as u32,
3348 width,
3349 height,
3350 border,
3351 format,
3352 type_,
3353 );
3354
3355 let TexImage2DValidatorResult {
3356 texture,
3357 target,
3358 width: _,
3359 height: _,
3360 level,
3361 border,
3362 internal_format,
3363 format,
3364 data_type,
3365 } = match validator.validate() {
3366 Ok(result) => result,
3367 Err(_) => return Ok(()),
3368 };
3369
3370 let unpacking_alignment = self.base.texture_unpacking_alignment();
3371
3372 let pixels = match self.base.get_image_pixels(source)? {
3373 Some(pixels) => pixels,
3374 None => return Ok(()),
3375 };
3376
3377 self.base.tex_image_2d(
3378 &texture,
3379 target,
3380 data_type,
3381 internal_format,
3382 format,
3383 level,
3384 border,
3385 unpacking_alignment,
3386 pixels.size(),
3387 TexSource::Pixels(pixels),
3388 );
3389
3390 Ok(())
3391 }
3392
3393 #[allow(unsafe_code)]
3395 fn TexImage2D____(
3396 &self,
3397 target: u32,
3398 level: i32,
3399 internalformat: i32,
3400 width: i32,
3401 height: i32,
3402 border: i32,
3403 format: u32,
3404 type_: u32,
3405 src_data: CustomAutoRooterGuard<ArrayBufferView>,
3406 src_offset: u32,
3407 ) -> Fallible<()> {
3408 if self.bound_pixel_unpack_buffer.get().is_some() {
3409 self.base.webgl_error(InvalidOperation);
3410 return Ok(());
3411 }
3412
3413 if type_ == constants::FLOAT_32_UNSIGNED_INT_24_8_REV {
3414 self.base.webgl_error(InvalidOperation);
3415 return Ok(());
3416 }
3417
3418 let validator = TexImage2DValidator::new(
3419 &self.base,
3420 target,
3421 level,
3422 internalformat as u32,
3423 width,
3424 height,
3425 border,
3426 format,
3427 type_,
3428 );
3429
3430 let TexImage2DValidatorResult {
3431 texture,
3432 target,
3433 width,
3434 height,
3435 level,
3436 border,
3437 internal_format,
3438 format,
3439 data_type,
3440 } = match validator.validate() {
3441 Ok(result) => result,
3442 Err(_) => return Ok(()),
3443 };
3444
3445 let unpacking_alignment = self.base.texture_unpacking_alignment();
3446
3447 let src_elem_size = src_data.get_array_type().byte_size().unwrap();
3448 let src_byte_offset = src_offset as usize * src_elem_size;
3449
3450 if src_data.len() <= src_byte_offset {
3451 self.base.webgl_error(InvalidOperation);
3452 return Ok(());
3453 }
3454
3455 let buff = IpcSharedMemory::from_bytes(unsafe { &src_data.as_slice()[src_byte_offset..] });
3456
3457 let expected_byte_length = match self.base.validate_tex_image_2d_data(
3458 width,
3459 height,
3460 format,
3461 data_type,
3462 unpacking_alignment,
3463 Some(&*src_data),
3464 ) {
3465 Ok(byte_length) => byte_length,
3466 Err(()) => return Ok(()),
3467 };
3468
3469 if expected_byte_length as usize > buff.len() {
3470 self.base.webgl_error(InvalidOperation);
3471 return Ok(());
3472 }
3473
3474 let size = Size2D::new(width, height);
3475
3476 let (alpha_treatment, y_axis_treatment) =
3477 self.base.get_current_unpack_state(Alpha::NotPremultiplied);
3478
3479 self.base.tex_image_2d(
3480 &texture,
3481 target,
3482 data_type,
3483 internal_format,
3484 format,
3485 level,
3486 border,
3487 unpacking_alignment,
3488 size,
3489 TexSource::Pixels(TexPixels::from_array(
3490 buff,
3491 size,
3492 alpha_treatment,
3493 y_axis_treatment,
3494 )),
3495 );
3496
3497 Ok(())
3498 }
3499
3500 fn TexSubImage2D(
3502 &self,
3503 target: u32,
3504 level: i32,
3505 xoffset: i32,
3506 yoffset: i32,
3507 width: i32,
3508 height: i32,
3509 format: u32,
3510 data_type: u32,
3511 pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3512 ) -> Fallible<()> {
3513 self.base.TexSubImage2D(
3514 target, level, xoffset, yoffset, width, height, format, data_type, pixels,
3515 )
3516 }
3517
3518 fn TexSubImage2D_(
3520 &self,
3521 target: u32,
3522 level: i32,
3523 xoffset: i32,
3524 yoffset: i32,
3525 format: u32,
3526 data_type: u32,
3527 source: TexImageSource,
3528 ) -> ErrorResult {
3529 self.base
3530 .TexSubImage2D_(target, level, xoffset, yoffset, format, data_type, source)
3531 }
3532
3533 fn TexParameterf(&self, target: u32, name: u32, value: f32) {
3535 self.base.TexParameterf(target, name, value)
3536 }
3537
3538 fn TexParameteri(&self, target: u32, name: u32, value: i32) {
3540 self.base.TexParameteri(target, name, value)
3541 }
3542
3543 fn CheckFramebufferStatus(&self, target: u32) -> u32 {
3545 let fb_slot = match target {
3546 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3547 self.base.get_draw_framebuffer_slot()
3548 },
3549 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3550 _ => {
3551 self.base.webgl_error(InvalidEnum);
3552 return 0;
3553 },
3554 };
3555 match fb_slot.get() {
3556 Some(fb) => fb.check_status(),
3557 None => constants::FRAMEBUFFER_COMPLETE,
3558 }
3559 }
3560
3561 fn RenderbufferStorage(&self, target: u32, internal_format: u32, width: i32, height: i32) {
3563 self.base
3564 .RenderbufferStorage(target, internal_format, width, height)
3565 }
3566
3567 fn BlitFramebuffer(
3569 &self,
3570 src_x0: i32,
3571 src_y0: i32,
3572 src_x1: i32,
3573 src_y1: i32,
3574 dst_x0: i32,
3575 dst_y0: i32,
3576 dst_x1: i32,
3577 dst_y1: i32,
3578 mask: u32,
3579 filter: u32,
3580 ) {
3581 bitflags! {
3582 struct BlitFrameBufferFlags: u32 {
3583 const DEPTH = constants::DEPTH_BUFFER_BIT;
3584 const COLOR = constants::COLOR_BUFFER_BIT;
3585 const STENCIL = constants::STENCIL_BUFFER_BIT;
3586 const DEPTH_STENCIL = constants::DEPTH_BUFFER_BIT | constants::STENCIL_BUFFER_BIT;
3587 }
3588 };
3589 let Some(bits) = BlitFrameBufferFlags::from_bits(mask) else {
3590 return self.base.webgl_error(InvalidValue);
3591 };
3592 let attributes = self.base.GetContextAttributes().unwrap();
3593
3594 if bits.intersects(BlitFrameBufferFlags::DEPTH_STENCIL) {
3595 match filter {
3596 constants::LINEAR => return self.base.webgl_error(InvalidOperation),
3597 constants::NEAREST => {},
3598 _ => return self.base.webgl_error(InvalidOperation),
3599 }
3600 }
3601
3602 let src_fb = self.base.get_read_framebuffer_slot().get();
3603 let dst_fb = self.base.get_draw_framebuffer_slot().get();
3604
3605 let get_default_formats = || -> WebGLResult<(Option<u32>, Option<u32>, Option<u32>)> {
3606 if attributes.antialias {
3608 return Err(InvalidOperation);
3609 };
3610 let color = if attributes.alpha {
3611 Some(constants::RGBA8)
3612 } else {
3613 Some(constants::RGB8)
3614 };
3615 let (depth, stencil) = match (attributes.depth, attributes.stencil) {
3616 (true, true) => (
3617 Some(constants::DEPTH24_STENCIL8),
3618 Some(constants::DEPTH24_STENCIL8),
3619 ),
3620 (true, false) => (Some(constants::DEPTH_COMPONENT16), None),
3621 (false, true) => (None, Some(constants::STENCIL_INDEX8)),
3622 _ => (None, None),
3623 };
3624 Ok((color, depth, stencil))
3625 };
3626
3627 let (src_color, src_depth, src_stencil) = match src_fb {
3628 Some(fb) => {
3629 handle_potential_webgl_error!(self.base, fb.get_attachment_formats(), return)
3630 },
3631 None => handle_potential_webgl_error!(self.base, get_default_formats(), return),
3632 };
3633 let (dst_color, dst_depth, dst_stencil) = match dst_fb {
3634 Some(fb) => {
3635 handle_potential_webgl_error!(self.base, fb.get_attachment_formats(), return)
3636 },
3637 None => handle_potential_webgl_error!(self.base, get_default_formats(), return),
3638 };
3639
3640 if bits.intersects(BlitFrameBufferFlags::COLOR) && src_color != dst_color {
3641 return self.base.webgl_error(InvalidOperation);
3642 }
3643 if bits.intersects(BlitFrameBufferFlags::DEPTH) && src_depth != dst_depth {
3644 return self.base.webgl_error(InvalidOperation);
3645 }
3646 if bits.intersects(BlitFrameBufferFlags::STENCIL) && src_stencil != dst_stencil {
3647 return self.base.webgl_error(InvalidOperation);
3648 }
3649
3650 let src_width = src_x1.checked_sub(src_x0);
3651 let dst_width = dst_x1.checked_sub(dst_x0);
3652 let src_height = src_y1.checked_sub(src_y0);
3653 let dst_height = dst_y1.checked_sub(dst_y0);
3654
3655 if src_width.is_none() ||
3656 dst_width.is_none() ||
3657 src_height.is_none() ||
3658 dst_height.is_none()
3659 {
3660 return self.base.webgl_error(InvalidOperation);
3661 }
3662
3663 self.base.send_command(WebGLCommand::BlitFrameBuffer(
3664 src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter,
3665 ));
3666 }
3667
3668 fn FramebufferRenderbuffer(
3670 &self,
3671 target: u32,
3672 attachment: u32,
3673 renderbuffertarget: u32,
3674 rb: Option<&WebGLRenderbuffer>,
3675 ) {
3676 if let Some(rb) = rb {
3677 handle_potential_webgl_error!(self.base, self.base.validate_ownership(rb), return);
3678 }
3679
3680 let fb_slot = match target {
3681 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3682 self.base.get_draw_framebuffer_slot()
3683 },
3684 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3685 _ => return self.base.webgl_error(InvalidEnum),
3686 };
3687
3688 if renderbuffertarget != constants::RENDERBUFFER {
3689 return self.base.webgl_error(InvalidEnum);
3690 }
3691
3692 match fb_slot.get() {
3693 Some(fb) => match attachment {
3694 constants::DEPTH_STENCIL_ATTACHMENT => {
3695 handle_potential_webgl_error!(
3696 self.base,
3697 fb.renderbuffer(constants::DEPTH_ATTACHMENT, rb)
3698 );
3699 handle_potential_webgl_error!(
3700 self.base,
3701 fb.renderbuffer(constants::STENCIL_ATTACHMENT, rb)
3702 );
3703 },
3704 _ => handle_potential_webgl_error!(self.base, fb.renderbuffer(attachment, rb)),
3705 },
3706 None => self.base.webgl_error(InvalidOperation),
3707 };
3708 }
3709
3710 fn FramebufferTexture2D(
3712 &self,
3713 target: u32,
3714 attachment: u32,
3715 textarget: u32,
3716 texture: Option<&WebGLTexture>,
3717 level: i32,
3718 ) {
3719 if let Some(texture) = texture {
3720 handle_potential_webgl_error!(self.base, self.base.validate_ownership(texture), return);
3721 }
3722
3723 let fb_slot = match target {
3724 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3725 self.base.get_draw_framebuffer_slot()
3726 },
3727 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3728 _ => return self.base.webgl_error(InvalidEnum),
3729 };
3730 match fb_slot.get() {
3731 Some(fb) => handle_potential_webgl_error!(
3732 self.base,
3733 fb.texture2d(attachment, textarget, texture, level)
3734 ),
3735 None => self.base.webgl_error(InvalidOperation),
3736 }
3737 }
3738
3739 fn GetAttachedShaders(&self, program: &WebGLProgram) -> Option<Vec<DomRoot<WebGLShader>>> {
3741 self.base.GetAttachedShaders(program)
3742 }
3743
3744 fn DrawArraysInstanced(&self, mode: u32, first: i32, count: i32, primcount: i32) {
3746 self.validate_uniform_block_for_draw();
3747 self.validate_vertex_attribs_for_draw();
3748 handle_potential_webgl_error!(
3749 self.base,
3750 self.base
3751 .draw_arrays_instanced(mode, first, count, primcount)
3752 )
3753 }
3754
3755 fn DrawElementsInstanced(
3757 &self,
3758 mode: u32,
3759 count: i32,
3760 type_: u32,
3761 offset: i64,
3762 primcount: i32,
3763 ) {
3764 self.validate_uniform_block_for_draw();
3765 self.validate_vertex_attribs_for_draw();
3766 handle_potential_webgl_error!(
3767 self.base,
3768 self.base
3769 .draw_elements_instanced(mode, count, type_, offset, primcount)
3770 )
3771 }
3772
3773 fn DrawRangeElements(
3775 &self,
3776 mode: u32,
3777 start: u32,
3778 end: u32,
3779 count: i32,
3780 type_: u32,
3781 offset: i64,
3782 ) {
3783 if end < start {
3784 self.base.webgl_error(InvalidValue);
3785 return;
3786 }
3787 self.validate_uniform_block_for_draw();
3788 self.validate_vertex_attribs_for_draw();
3789 handle_potential_webgl_error!(
3790 self.base,
3791 self.base
3792 .draw_elements_instanced(mode, count, type_, offset, 1)
3793 )
3794 }
3795
3796 fn VertexAttribDivisor(&self, index: u32, divisor: u32) {
3798 self.base.vertex_attrib_divisor(index, divisor);
3799 }
3800
3801 fn CreateQuery(&self) -> Option<DomRoot<WebGLQuery>> {
3803 Some(WebGLQuery::new(&self.base, CanGc::note()))
3804 }
3805
3806 #[rustfmt::skip]
3808 fn DeleteQuery(&self, query: Option<&WebGLQuery>) {
3809 if let Some(query) = query {
3810 handle_potential_webgl_error!(self.base, self.base.validate_ownership(query), return);
3811
3812 if let Some(query_target) = query.target() {
3813 let slot = match query_target {
3814 constants::ANY_SAMPLES_PASSED |
3815 constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3816 &self.occlusion_query
3817 },
3818 constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3819 &self.primitives_query
3820 },
3821 _ => unreachable!(),
3822 };
3823 if let Some(stored_query) = slot.get() {
3824 if stored_query.target() == query.target() {
3825 slot.set(None);
3826 }
3827 }
3828 }
3829
3830 query.delete(Operation::Infallible);
3831 }
3832 }
3833
3834 fn IsQuery(&self, query: Option<&WebGLQuery>) -> bool {
3836 match query {
3837 Some(query) => self.base.validate_ownership(query).is_ok() && query.is_valid(),
3838 None => false,
3839 }
3840 }
3841
3842 fn CreateSampler(&self) -> Option<DomRoot<WebGLSampler>> {
3844 Some(WebGLSampler::new(&self.base, CanGc::note()))
3845 }
3846
3847 fn DeleteSampler(&self, sampler: Option<&WebGLSampler>) {
3849 if let Some(sampler) = sampler {
3850 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
3851 for slot in self.samplers.iter() {
3852 if slot.get().is_some_and(|s| sampler == &*s) {
3853 slot.set(None);
3854 }
3855 }
3856 sampler.delete(Operation::Infallible);
3857 }
3858 }
3859
3860 fn IsSampler(&self, sampler: Option<&WebGLSampler>) -> bool {
3862 match sampler {
3863 Some(sampler) => self.base.validate_ownership(sampler).is_ok() && sampler.is_valid(),
3864 None => false,
3865 }
3866 }
3867
3868 #[rustfmt::skip]
3870 fn BeginQuery(&self, target: u32, query: &WebGLQuery) {
3871 handle_potential_webgl_error!(self.base, self.base.validate_ownership(query), return);
3872
3873 let active_query = match target {
3874 constants::ANY_SAMPLES_PASSED |
3875 constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3876 &self.occlusion_query
3877 },
3878 constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3879 &self.primitives_query
3880 },
3881 _ => {
3882 self.base.webgl_error(InvalidEnum);
3883 return;
3884 },
3885 };
3886 if active_query.get().is_some() {
3887 self.base.webgl_error(InvalidOperation);
3888 return;
3889 }
3890 let result = query.begin(&self.base, target);
3891 match result {
3892 Ok(_) => active_query.set(Some(query)),
3893 Err(error) => self.base.webgl_error(error),
3894 }
3895 }
3896
3897 #[rustfmt::skip]
3899 fn EndQuery(&self, target: u32) {
3900 let active_query = match target {
3901 constants::ANY_SAMPLES_PASSED |
3902 constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3903 self.occlusion_query.take()
3904 },
3905 constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3906 self.primitives_query.take()
3907 },
3908 _ => {
3909 self.base.webgl_error(InvalidEnum);
3910 return;
3911 },
3912 };
3913 match active_query {
3914 None => self.base.webgl_error(InvalidOperation),
3915 Some(query) => {
3916 let result = query.end(&self.base, target);
3917 if let Err(error) = result {
3918 self.base.webgl_error(error);
3919 }
3920 },
3921 }
3922 }
3923
3924 #[rustfmt::skip]
3926 fn GetQuery(&self, target: u32, pname: u32) -> Option<DomRoot<WebGLQuery>> {
3927 if pname != constants::CURRENT_QUERY {
3928 self.base.webgl_error(InvalidEnum);
3929 return None;
3930 }
3931 let active_query = match target {
3932 constants::ANY_SAMPLES_PASSED |
3933 constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3934 self.occlusion_query.get()
3935 },
3936 constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3937 self.primitives_query.get()
3938 },
3939 _ => {
3940 self.base.webgl_error(InvalidEnum);
3941 None
3942 },
3943 };
3944 if let Some(query) = active_query.as_ref() {
3945 if query.target() != Some(target) {
3946 return None;
3947 }
3948 }
3949 active_query
3950 }
3951
3952 #[rustfmt::skip]
3954 fn GetQueryParameter(&self, _cx: JSContext, query: &WebGLQuery, pname: u32, mut retval: MutableHandleValue) {
3955 handle_potential_webgl_error!(
3956 self.base,
3957 self.base.validate_ownership(query),
3958 return retval.set(NullValue())
3959 );
3960 match query.get_parameter(&self.base, pname) {
3961 Ok(value) => match pname {
3962 constants::QUERY_RESULT => retval.set(UInt32Value(value)),
3963 constants::QUERY_RESULT_AVAILABLE => retval.set(BooleanValue(value != 0)),
3964 _ => unreachable!(),
3965 },
3966 Err(error) => {
3967 self.base.webgl_error(error);
3968 retval.set(NullValue())
3969 },
3970 }
3971 }
3972
3973 fn FenceSync(&self, condition: u32, flags: u32) -> Option<DomRoot<WebGLSync>> {
3975 if flags != 0 {
3976 self.base.webgl_error(InvalidValue);
3977 return None;
3978 }
3979 if condition != constants::SYNC_GPU_COMMANDS_COMPLETE {
3980 self.base.webgl_error(InvalidEnum);
3981 return None;
3982 }
3983
3984 Some(WebGLSync::new(&self.base, CanGc::note()))
3985 }
3986
3987 fn IsSync(&self, sync: Option<&WebGLSync>) -> bool {
3989 match sync {
3990 Some(sync) => {
3991 if !sync.is_valid() {
3992 return false;
3993 }
3994 handle_potential_webgl_error!(
3995 self.base,
3996 self.base.validate_ownership(sync),
3997 return false
3998 );
3999 let (sender, receiver) = webgl_channel().unwrap();
4000 self.base
4001 .send_command(WebGLCommand::IsSync(sync.id(), sender));
4002 receiver.recv().unwrap()
4003 },
4004 None => false,
4005 }
4006 }
4007
4008 fn ClientWaitSync(&self, sync: &WebGLSync, flags: u32, timeout: u64) -> u32 {
4010 if !sync.is_valid() {
4011 self.base.webgl_error(InvalidOperation);
4012 return constants::WAIT_FAILED;
4013 }
4014 handle_potential_webgl_error!(
4015 self.base,
4016 self.base.validate_ownership(sync),
4017 return constants::WAIT_FAILED
4018 );
4019 if flags != 0 && flags != constants::SYNC_FLUSH_COMMANDS_BIT {
4020 self.base.webgl_error(InvalidValue);
4021 return constants::WAIT_FAILED;
4022 }
4023 if timeout > self.base.limits().max_client_wait_timeout_webgl.as_nanos() as u64 {
4024 self.base.webgl_error(InvalidOperation);
4025 return constants::WAIT_FAILED;
4026 }
4027
4028 match sync.client_wait_sync(&self.base, flags, timeout) {
4029 Some(status) => status,
4030 None => constants::WAIT_FAILED,
4031 }
4032 }
4033
4034 fn WaitSync(&self, sync: &WebGLSync, flags: u32, timeout: i64) {
4036 if !sync.is_valid() {
4037 self.base.webgl_error(InvalidOperation);
4038 return;
4039 }
4040 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
4041 if flags != 0 {
4042 self.base.webgl_error(InvalidValue);
4043 return;
4044 }
4045 if timeout != constants::TIMEOUT_IGNORED {
4046 self.base.webgl_error(InvalidValue);
4047 return;
4048 }
4049
4050 self.base
4051 .send_command(WebGLCommand::WaitSync(sync.id(), flags, timeout));
4052 }
4053
4054 fn GetSyncParameter(
4056 &self,
4057 _cx: JSContext,
4058 sync: &WebGLSync,
4059 pname: u32,
4060 mut retval: MutableHandleValue,
4061 ) {
4062 if !sync.is_valid() {
4063 self.base.webgl_error(InvalidOperation);
4064 return retval.set(NullValue());
4065 }
4066 handle_potential_webgl_error!(
4067 self.base,
4068 self.base.validate_ownership(sync),
4069 return retval.set(NullValue())
4070 );
4071 match pname {
4072 constants::OBJECT_TYPE | constants::SYNC_CONDITION | constants::SYNC_FLAGS => {
4073 let (sender, receiver) = webgl_channel().unwrap();
4074 self.base
4075 .send_command(WebGLCommand::GetSyncParameter(sync.id(), pname, sender));
4076 retval.set(UInt32Value(receiver.recv().unwrap()))
4077 },
4078 constants::SYNC_STATUS => match sync.get_sync_status(pname, &self.base) {
4079 Some(status) => retval.set(UInt32Value(status)),
4080 None => retval.set(UInt32Value(constants::UNSIGNALED)),
4081 },
4082 _ => {
4083 self.base.webgl_error(InvalidEnum);
4084 retval.set(NullValue())
4085 },
4086 }
4087 }
4088
4089 fn DeleteSync(&self, sync: Option<&WebGLSync>) {
4091 if let Some(sync) = sync {
4092 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
4093 sync.delete(Operation::Infallible);
4094 }
4095 }
4096
4097 fn BindSampler(&self, unit: u32, sampler: Option<&WebGLSampler>) {
4099 if let Some(sampler) = sampler {
4100 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4101
4102 if unit as usize >= self.samplers.len() {
4103 self.base.webgl_error(InvalidValue);
4104 return;
4105 }
4106
4107 let result = sampler.bind(&self.base, unit);
4108 match result {
4109 Ok(_) => self.samplers[unit as usize].set(Some(sampler)),
4110 Err(error) => self.base.webgl_error(error),
4111 }
4112 }
4113 }
4114
4115 fn BindVertexArray(&self, array: Option<&WebGLVertexArrayObject>) {
4117 self.base.bind_vertex_array_webgl2(array);
4118 }
4119
4120 fn SamplerParameteri(&self, sampler: &WebGLSampler, pname: u32, param: i32) {
4122 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4123 let param = WebGLSamplerValue::GLenum(param as u32);
4124 let result = sampler.set_parameter(&self.base, pname, param);
4125 if let Err(error) = result {
4126 self.base.webgl_error(error);
4127 }
4128 }
4129
4130 fn SamplerParameterf(&self, sampler: &WebGLSampler, pname: u32, param: f32) {
4132 handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4133 let param = WebGLSamplerValue::Float(param);
4134 let result = sampler.set_parameter(&self.base, pname, param);
4135 if let Err(error) = result {
4136 self.base.webgl_error(error);
4137 }
4138 }
4139
4140 fn GetSamplerParameter(
4142 &self,
4143 _cx: JSContext,
4144 sampler: &WebGLSampler,
4145 pname: u32,
4146 mut retval: MutableHandleValue,
4147 ) {
4148 handle_potential_webgl_error!(
4149 self.base,
4150 self.base.validate_ownership(sampler),
4151 return retval.set(NullValue())
4152 );
4153 match sampler.get_parameter(&self.base, pname) {
4154 Ok(value) => match value {
4155 WebGLSamplerValue::GLenum(value) => retval.set(UInt32Value(value)),
4156 WebGLSamplerValue::Float(value) => retval.set(DoubleValue(value as f64)),
4157 },
4158 Err(error) => {
4159 self.base.webgl_error(error);
4160 retval.set(NullValue())
4161 },
4162 }
4163 }
4164
4165 fn CreateTransformFeedback(&self) -> Option<DomRoot<WebGLTransformFeedback>> {
4167 Some(WebGLTransformFeedback::new(&self.base, CanGc::note()))
4168 }
4169
4170 fn DeleteTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) {
4172 if let Some(tf) = tf {
4173 handle_potential_webgl_error!(self.base, self.base.validate_ownership(tf), return);
4174 if tf.is_active() {
4175 self.base.webgl_error(InvalidOperation);
4176 return;
4177 }
4178 tf.delete(Operation::Infallible);
4179 self.current_transform_feedback.set(None);
4180 }
4181 }
4182
4183 fn IsTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) -> bool {
4185 match tf {
4186 Some(tf) => {
4187 if !tf.is_valid() {
4188 return false;
4189 }
4190 handle_potential_webgl_error!(
4191 self.base,
4192 self.base.validate_ownership(tf),
4193 return false
4194 );
4195 let (sender, receiver) = webgl_channel().unwrap();
4196 self.base
4197 .send_command(WebGLCommand::IsTransformFeedback(tf.id(), sender));
4198 receiver.recv().unwrap()
4199 },
4200 None => false,
4201 }
4202 }
4203
4204 fn BindTransformFeedback(&self, target: u32, tf: Option<&WebGLTransformFeedback>) {
4206 if target != constants::TRANSFORM_FEEDBACK {
4207 self.base.webgl_error(InvalidEnum);
4208 return;
4209 }
4210 match tf {
4211 Some(transform_feedback) => {
4212 handle_potential_webgl_error!(
4213 self.base,
4214 self.base.validate_ownership(transform_feedback),
4215 return
4216 );
4217 if !transform_feedback.is_valid() {
4218 self.base.webgl_error(InvalidOperation);
4219 return;
4220 }
4221 if let Some(current_tf) = self.current_transform_feedback.get() {
4222 if current_tf.is_active() && !current_tf.is_paused() {
4223 self.base.webgl_error(InvalidOperation);
4224 return;
4225 }
4226 }
4227 transform_feedback.bind(&self.base, target);
4228 self.current_transform_feedback
4229 .set(Some(transform_feedback));
4230 },
4231 None => self
4232 .base
4233 .send_command(WebGLCommand::BindTransformFeedback(target, 0)),
4234 }
4235 }
4236
4237 #[allow(non_snake_case)]
4239 fn BeginTransformFeedback(&self, primitiveMode: u32) {
4240 match primitiveMode {
4241 constants::POINTS | constants::LINES | constants::TRIANGLES => {},
4242 _ => {
4243 self.base.webgl_error(InvalidEnum);
4244 return;
4245 },
4246 };
4247 let current_tf = match self.current_transform_feedback.get() {
4248 Some(current_tf) => current_tf,
4249 None => {
4250 self.base.webgl_error(InvalidOperation);
4251 return;
4252 },
4253 };
4254 if current_tf.is_active() {
4255 self.base.webgl_error(InvalidOperation);
4256 return;
4257 };
4258 let program = match self.base.current_program() {
4259 Some(program) => program,
4260 None => {
4261 self.base.webgl_error(InvalidOperation);
4262 return;
4263 },
4264 };
4265 if !program.is_linked() || program.transform_feedback_varyings_length() == 0 {
4266 self.base.webgl_error(InvalidOperation);
4267 return;
4268 };
4269 current_tf.begin(&self.base, primitiveMode);
4270 }
4271
4272 fn EndTransformFeedback(&self) {
4274 if let Some(current_tf) = self.current_transform_feedback.get() {
4275 if !current_tf.is_active() {
4276 self.base.webgl_error(InvalidOperation);
4277 return;
4278 }
4279 current_tf.end(&self.base);
4280 }
4281 }
4282
4283 fn ResumeTransformFeedback(&self) {
4285 if let Some(current_tf) = self.current_transform_feedback.get() {
4286 if !current_tf.is_active() || !current_tf.is_paused() {
4287 self.base.webgl_error(InvalidOperation);
4288 return;
4289 }
4290 current_tf.resume(&self.base);
4291 }
4292 }
4293
4294 fn PauseTransformFeedback(&self) {
4296 if let Some(current_tf) = self.current_transform_feedback.get() {
4297 if !current_tf.is_active() || current_tf.is_paused() {
4298 self.base.webgl_error(InvalidOperation);
4299 return;
4300 }
4301 current_tf.pause(&self.base);
4302 }
4303 }
4304
4305 #[allow(non_snake_case)]
4307 fn TransformFeedbackVaryings(
4308 &self,
4309 program: &WebGLProgram,
4310 varyings: Vec<DOMString>,
4311 bufferMode: u32,
4312 ) {
4313 handle_potential_webgl_error!(self.base, program.validate(), return);
4314 let strs = varyings
4315 .iter()
4316 .map(|name| String::from(name.to_owned()))
4317 .collect::<Vec<String>>();
4318 match bufferMode {
4319 constants::INTERLEAVED_ATTRIBS => {
4320 self.base
4321 .send_command(WebGLCommand::TransformFeedbackVaryings(
4322 program.id(),
4323 strs,
4324 bufferMode,
4325 ));
4326 },
4327 constants::SEPARATE_ATTRIBS => {
4328 let max_tf_sp_att =
4329 self.base.limits().max_transform_feedback_separate_attribs as usize;
4330 if strs.len() >= max_tf_sp_att {
4331 self.base.webgl_error(InvalidValue);
4332 return;
4333 }
4334 self.base
4335 .send_command(WebGLCommand::TransformFeedbackVaryings(
4336 program.id(),
4337 strs,
4338 bufferMode,
4339 ));
4340 },
4341 _ => self.base.webgl_error(InvalidEnum),
4342 }
4343 }
4344
4345 fn GetTransformFeedbackVarying(
4347 &self,
4348 program: &WebGLProgram,
4349 index: u32,
4350 ) -> Option<DomRoot<WebGLActiveInfo>> {
4351 handle_potential_webgl_error!(self.base, program.validate(), return None);
4352 if index >= program.transform_feedback_varyings_length() as u32 {
4353 self.base.webgl_error(InvalidValue);
4354 return None;
4355 }
4356
4357 let (sender, receiver) = webgl_channel().unwrap();
4358 self.base
4359 .send_command(WebGLCommand::GetTransformFeedbackVarying(
4360 program.id(),
4361 index,
4362 sender,
4363 ));
4364 let (size, ty, name) = receiver.recv().unwrap();
4365 Some(WebGLActiveInfo::new(
4366 self.base.global().as_window(),
4367 size,
4368 ty,
4369 DOMString::from(name),
4370 CanGc::note(),
4371 ))
4372 }
4373
4374 fn BindBufferBase(&self, target: u32, index: u32, buffer: Option<&WebGLBuffer>) {
4376 let (generic_slot, indexed_bindings) = match target {
4377 constants::TRANSFORM_FEEDBACK_BUFFER => (
4378 &self.bound_transform_feedback_buffer,
4379 &self.indexed_transform_feedback_buffer_bindings,
4380 ),
4381 constants::UNIFORM_BUFFER => (
4382 &self.bound_uniform_buffer,
4383 &self.indexed_uniform_buffer_bindings,
4384 ),
4385 _ => return self.base.webgl_error(InvalidEnum),
4386 };
4387 let indexed_binding = match indexed_bindings.get(index as usize) {
4388 Some(slot) => slot,
4389 None => return self.base.webgl_error(InvalidValue),
4390 };
4391
4392 if let Some(buffer) = buffer {
4393 handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
4394
4395 if buffer.is_marked_for_deletion() {
4396 return self.base.webgl_error(InvalidOperation);
4397 }
4398 handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
4399
4400 buffer.increment_attached_counter();
4402 buffer.increment_attached_counter();
4403 }
4404
4405 self.base.send_command(WebGLCommand::BindBufferBase(
4406 target,
4407 index,
4408 buffer.map(|b| b.id()),
4409 ));
4410
4411 for slot in &[generic_slot, &indexed_binding.buffer] {
4412 if let Some(old) = slot.get() {
4413 old.decrement_attached_counter(Operation::Infallible);
4414 }
4415 slot.set(buffer);
4416 }
4417 indexed_binding.start.set(0);
4418 indexed_binding.size.set(0);
4419 }
4420
4421 fn BindBufferRange(
4423 &self,
4424 target: u32,
4425 index: u32,
4426 buffer: Option<&WebGLBuffer>,
4427 offset: i64,
4428 size: i64,
4429 ) {
4430 let (generic_slot, indexed_bindings) = match target {
4431 constants::TRANSFORM_FEEDBACK_BUFFER => (
4432 &self.bound_transform_feedback_buffer,
4433 &self.indexed_transform_feedback_buffer_bindings,
4434 ),
4435 constants::UNIFORM_BUFFER => (
4436 &self.bound_uniform_buffer,
4437 &self.indexed_uniform_buffer_bindings,
4438 ),
4439 _ => return self.base.webgl_error(InvalidEnum),
4440 };
4441 let indexed_binding = match indexed_bindings.get(index as usize) {
4442 Some(slot) => slot,
4443 None => return self.base.webgl_error(InvalidValue),
4444 };
4445
4446 if offset < 0 || size < 0 {
4447 return self.base.webgl_error(InvalidValue);
4448 }
4449 if buffer.is_some() && size == 0 {
4450 return self.base.webgl_error(InvalidValue);
4451 }
4452
4453 match target {
4454 constants::TRANSFORM_FEEDBACK_BUFFER => {
4455 if size % 4 != 0 && offset % 4 != 0 {
4456 return self.base.webgl_error(InvalidValue);
4457 }
4458 },
4459 constants::UNIFORM_BUFFER => {
4460 let offset_alignment = self.base.limits().uniform_buffer_offset_alignment;
4461 if offset % offset_alignment as i64 != 0 {
4462 return self.base.webgl_error(InvalidValue);
4463 }
4464 },
4465 _ => unreachable!(),
4466 }
4467
4468 if let Some(buffer) = buffer {
4469 handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
4470
4471 if buffer.is_marked_for_deletion() {
4472 return self.base.webgl_error(InvalidOperation);
4473 }
4474 handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
4475
4476 buffer.increment_attached_counter();
4478 buffer.increment_attached_counter();
4479 }
4480
4481 self.base.send_command(WebGLCommand::BindBufferRange(
4482 target,
4483 index,
4484 buffer.map(|b| b.id()),
4485 offset,
4486 size,
4487 ));
4488
4489 for slot in &[generic_slot, &indexed_binding.buffer] {
4490 if let Some(old) = slot.get() {
4491 old.decrement_attached_counter(Operation::Infallible);
4492 }
4493 slot.set(buffer);
4494 }
4495 indexed_binding.start.set(offset);
4496 indexed_binding.size.set(size);
4497 }
4498
4499 fn GetUniformIndices(&self, program: &WebGLProgram, names: Vec<DOMString>) -> Option<Vec<u32>> {
4501 handle_potential_webgl_error!(
4502 self.base,
4503 self.base.validate_ownership(program),
4504 return None
4505 );
4506 let indices = handle_potential_webgl_error!(
4507 self.base,
4508 program.get_uniform_indices(names),
4509 return None
4510 );
4511 Some(indices)
4512 }
4513
4514 fn GetActiveUniforms(
4516 &self,
4517 cx: JSContext,
4518 program: &WebGLProgram,
4519 indices: Vec<u32>,
4520 pname: u32,
4521 mut rval: MutableHandleValue,
4522 ) {
4523 handle_potential_webgl_error!(
4524 self.base,
4525 self.base.validate_ownership(program),
4526 return rval.set(NullValue())
4527 );
4528 let values = handle_potential_webgl_error!(
4529 self.base,
4530 program.get_active_uniforms(indices, pname),
4531 return rval.set(NullValue())
4532 );
4533
4534 match pname {
4535 constants::UNIFORM_SIZE |
4536 constants::UNIFORM_TYPE |
4537 constants::UNIFORM_BLOCK_INDEX |
4538 constants::UNIFORM_OFFSET |
4539 constants::UNIFORM_ARRAY_STRIDE |
4540 constants::UNIFORM_MATRIX_STRIDE => {
4541 values.safe_to_jsval(cx, rval, CanGc::note());
4542 },
4543 constants::UNIFORM_IS_ROW_MAJOR => {
4544 let values = values.iter().map(|&v| v != 0).collect::<Vec<_>>();
4545 values.safe_to_jsval(cx, rval, CanGc::note());
4546 },
4547 _ => unreachable!(),
4548 }
4549 }
4550
4551 fn GetUniformBlockIndex(&self, program: &WebGLProgram, block_name: DOMString) -> u32 {
4553 handle_potential_webgl_error!(
4554 self.base,
4555 self.base.validate_ownership(program),
4556 return constants::INVALID_INDEX
4557 );
4558 handle_potential_webgl_error!(
4559 self.base,
4560 program.get_uniform_block_index(block_name),
4561 constants::INVALID_INDEX
4562 )
4563 }
4564
4565 #[allow(unsafe_code)]
4567 fn GetActiveUniformBlockParameter(
4568 &self,
4569 cx: JSContext,
4570 program: &WebGLProgram,
4571 block_index: u32,
4572 pname: u32,
4573 mut retval: MutableHandleValue,
4574 ) {
4575 handle_potential_webgl_error!(
4576 self.base,
4577 self.base.validate_ownership(program),
4578 return retval.set(NullValue())
4579 );
4580 let values = handle_potential_webgl_error!(
4581 self.base,
4582 program.get_active_uniform_block_parameter(block_index, pname),
4583 return retval.set(NullValue())
4584 );
4585 match pname {
4586 constants::UNIFORM_BLOCK_BINDING |
4587 constants::UNIFORM_BLOCK_DATA_SIZE |
4588 constants::UNIFORM_BLOCK_ACTIVE_UNIFORMS => {
4589 assert!(values.len() == 1);
4590 retval.set(UInt32Value(values[0] as u32))
4591 },
4592 constants::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES => unsafe {
4593 let values = values.iter().map(|&v| v as u32).collect::<Vec<_>>();
4594 rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
4595 Uint32Array::create(*cx, CreateWith::Slice(&values), result.handle_mut()).unwrap();
4596 retval.set(ObjectValue(result.get()))
4597 },
4598 constants::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER |
4599 constants::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => {
4600 assert!(values.len() == 1);
4601 retval.set(BooleanValue(values[0] != 0))
4602 },
4603 _ => unreachable!(),
4604 }
4605 }
4606
4607 fn GetActiveUniformBlockName(
4609 &self,
4610 program: &WebGLProgram,
4611 block_index: u32,
4612 ) -> Option<DOMString> {
4613 handle_potential_webgl_error!(
4614 self.base,
4615 self.base.validate_ownership(program),
4616 return None
4617 );
4618 let name = handle_potential_webgl_error!(
4619 self.base,
4620 program.get_active_uniform_block_name(block_index),
4621 return None
4622 );
4623 Some(DOMString::from(name))
4624 }
4625
4626 fn UniformBlockBinding(&self, program: &WebGLProgram, block_index: u32, block_binding: u32) {
4628 handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return);
4629
4630 if block_binding >= self.base.limits().max_uniform_buffer_bindings {
4631 return self.base.webgl_error(InvalidValue);
4632 }
4633
4634 handle_potential_webgl_error!(
4635 self.base,
4636 program.bind_uniform_block(block_index, block_binding)
4637 )
4638 }
4639
4640 fn ClearBufferfv(
4642 &self,
4643 buffer: u32,
4644 draw_buffer: i32,
4645 values: Float32ArrayOrUnrestrictedFloatSequence,
4646 src_offset: u32,
4647 ) {
4648 let array = match values {
4649 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4650 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4651 };
4652 self.clear_buffer::<f32>(
4653 buffer,
4654 draw_buffer,
4655 &[constants::COLOR, constants::DEPTH],
4656 src_offset,
4657 array,
4658 WebGLCommand::ClearBufferfv,
4659 )
4660 }
4661
4662 fn ClearBufferiv(
4664 &self,
4665 buffer: u32,
4666 draw_buffer: i32,
4667 values: Int32ArrayOrLongSequence,
4668 src_offset: u32,
4669 ) {
4670 let array = match values {
4671 Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
4672 Int32ArrayOrLongSequence::LongSequence(v) => v,
4673 };
4674 self.clear_buffer::<i32>(
4675 buffer,
4676 draw_buffer,
4677 &[constants::COLOR, constants::STENCIL],
4678 src_offset,
4679 array,
4680 WebGLCommand::ClearBufferiv,
4681 )
4682 }
4683
4684 fn ClearBufferuiv(
4686 &self,
4687 buffer: u32,
4688 draw_buffer: i32,
4689 values: Uint32ArrayOrUnsignedLongSequence,
4690 src_offset: u32,
4691 ) {
4692 let array = match values {
4693 Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(),
4694 Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v,
4695 };
4696 self.clear_buffer::<u32>(
4697 buffer,
4698 draw_buffer,
4699 &[constants::COLOR],
4700 src_offset,
4701 array,
4702 WebGLCommand::ClearBufferuiv,
4703 )
4704 }
4705
4706 fn ClearBufferfi(&self, buffer: u32, draw_buffer: i32, depth: f32, stencil: i32) {
4708 if buffer != constants::DEPTH_STENCIL {
4709 return self.base.webgl_error(InvalidEnum);
4710 }
4711
4712 handle_potential_webgl_error!(
4713 self.base,
4714 self.clearbuffer_array_size(buffer, draw_buffer),
4715 return
4716 );
4717
4718 self.base.send_command(WebGLCommand::ClearBufferfi(
4719 buffer,
4720 draw_buffer,
4721 depth,
4722 stencil,
4723 ));
4724 }
4725
4726 fn InvalidateFramebuffer(&self, target: u32, attachments: Vec<u32>) {
4728 if !self.valid_fb_attachment_values(target, &attachments) {
4729 return;
4730 }
4731
4732 self.base
4733 .send_command(WebGLCommand::InvalidateFramebuffer(target, attachments))
4734 }
4735
4736 fn InvalidateSubFramebuffer(
4738 &self,
4739 target: u32,
4740 attachments: Vec<u32>,
4741 x: i32,
4742 y: i32,
4743 width: i32,
4744 height: i32,
4745 ) {
4746 if !self.valid_fb_attachment_values(target, &attachments) {
4747 return;
4748 }
4749
4750 if width < 0 || height < 0 {
4751 return self.base.webgl_error(InvalidValue);
4752 }
4753
4754 self.base
4755 .send_command(WebGLCommand::InvalidateSubFramebuffer(
4756 target,
4757 attachments,
4758 x,
4759 y,
4760 width,
4761 height,
4762 ))
4763 }
4764
4765 fn FramebufferTextureLayer(
4767 &self,
4768 target: u32,
4769 attachment: u32,
4770 texture: Option<&WebGLTexture>,
4771 level: i32,
4772 layer: i32,
4773 ) {
4774 if let Some(tex) = texture {
4775 handle_potential_webgl_error!(self.base, self.base.validate_ownership(tex), return);
4776 }
4777
4778 let fb_slot = match target {
4779 constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
4780 self.base.get_draw_framebuffer_slot()
4781 },
4782 constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
4783 _ => return self.base.webgl_error(InvalidEnum),
4784 };
4785
4786 match fb_slot.get() {
4787 Some(fb) => handle_potential_webgl_error!(
4788 self.base,
4789 fb.texture_layer(attachment, texture, level, layer)
4790 ),
4791 None => self.base.webgl_error(InvalidOperation),
4792 }
4793 }
4794
4795 #[allow(unsafe_code)]
4797 fn GetInternalformatParameter(
4798 &self,
4799 cx: JSContext,
4800 target: u32,
4801 internal_format: u32,
4802 pname: u32,
4803 mut retval: MutableHandleValue,
4804 ) {
4805 if target != constants::RENDERBUFFER {
4806 self.base.webgl_error(InvalidEnum);
4807 return retval.set(NullValue());
4808 }
4809
4810 match handle_potential_webgl_error!(
4811 self.base,
4812 InternalFormatParameter::from_u32(pname),
4813 return retval.set(NullValue())
4814 ) {
4815 InternalFormatParameter::IntVec(param) => unsafe {
4816 let (sender, receiver) = webgl_channel().unwrap();
4817 self.base
4818 .send_command(WebGLCommand::GetInternalFormatIntVec(
4819 target,
4820 internal_format,
4821 param,
4822 sender,
4823 ));
4824
4825 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
4826 Int32Array::create(
4827 *cx,
4828 CreateWith::Slice(&receiver.recv().unwrap()),
4829 rval.handle_mut(),
4830 )
4831 .unwrap();
4832 retval.set(ObjectValue(rval.get()))
4833 },
4834 }
4835 }
4836
4837 fn RenderbufferStorageMultisample(
4839 &self,
4840 target: u32,
4841 samples: i32,
4842 internal_format: u32,
4843 width: i32,
4844 height: i32,
4845 ) {
4846 self.base
4847 .renderbuffer_storage(target, samples, internal_format, width, height)
4848 }
4849
4850 fn ReadBuffer(&self, src: u32) {
4852 match src {
4853 constants::BACK | constants::NONE => {},
4854 _ if self.base.valid_color_attachment_enum(src) => {},
4855 _ => return self.base.webgl_error(InvalidEnum),
4856 }
4857
4858 if let Some(fb) = self.base.get_read_framebuffer_slot().get() {
4859 handle_potential_webgl_error!(self.base, fb.set_read_buffer(src))
4860 } else {
4861 match src {
4862 constants::NONE | constants::BACK => {},
4863 _ => return self.base.webgl_error(InvalidOperation),
4864 }
4865
4866 self.default_fb_readbuffer.set(src);
4867 self.base.send_command(WebGLCommand::ReadBuffer(src));
4868 }
4869 }
4870
4871 fn DrawBuffers(&self, buffers: Vec<u32>) {
4873 if let Some(fb) = self.base.get_draw_framebuffer_slot().get() {
4874 handle_potential_webgl_error!(self.base, fb.set_draw_buffers(buffers))
4875 } else {
4876 if buffers.len() != 1 {
4877 return self.base.webgl_error(InvalidOperation);
4878 }
4879
4880 match buffers[0] {
4881 constants::NONE | constants::BACK => {},
4882 _ => return self.base.webgl_error(InvalidOperation),
4883 }
4884
4885 self.default_fb_drawbuffer.set(buffers[0]);
4886 self.base.send_command(WebGLCommand::DrawBuffers(buffers));
4887 }
4888 }
4889
4890 fn TexStorage2D(
4892 &self,
4893 target: u32,
4894 levels: i32,
4895 internal_format: u32,
4896 width: i32,
4897 height: i32,
4898 ) {
4899 self.tex_storage(2, target, levels, internal_format, width, height, 1)
4900 }
4901
4902 fn TexStorage3D(
4904 &self,
4905 target: u32,
4906 levels: i32,
4907 internal_format: u32,
4908 width: i32,
4909 height: i32,
4910 depth: i32,
4911 ) {
4912 self.tex_storage(3, target, levels, internal_format, width, height, depth)
4913 }
4914
4915 #[cfg(feature = "webxr")]
4917 fn MakeXRCompatible(&self, can_gc: CanGc) -> Rc<Promise> {
4918 let p = Promise::new(&self.global(), can_gc);
4920 p.resolve_native(&(), can_gc);
4921 p
4922 }
4923}
4924
4925impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGL2RenderingContext> {
4926 #[allow(unsafe_code)]
4927 fn canvas_data_source(self) -> Option<ImageKey> {
4928 let this = self.unsafe_get();
4929 unsafe { (*this.base.to_layout().unsafe_get()).layout_handle() }
4930 }
4931}
4932
4933impl WebGL2RenderingContextHelpers for WebGL2RenderingContext {
4934 fn is_webgl2_enabled(cx: JSContext, global: HandleObject) -> bool {
4935 Self::is_webgl2_enabled(cx, global)
4936 }
4937}