1use std::cell::Cell;
6use std::cmp;
7use std::ptr::{self, NonNull};
8#[cfg(feature = "webxr")]
9use std::rc::Rc;
10
11#[cfg(feature = "webgl_backtrace")]
12use backtrace::Backtrace;
13use bitflags::bitflags;
14use canvas_traits::webgl::WebGLError::*;
15use canvas_traits::webgl::{
16 AlphaTreatment, GLContextAttributes, GLLimits, GlType, Parameter, SizedDataType, TexDataType,
17 TexFormat, TexParameter, WebGLChan, WebGLCommand, WebGLCommandBacktrace, WebGLContextId,
18 WebGLError, WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId,
19 WebGLResult, WebGLSLVersion, WebGLSendResult, WebGLSender, WebGLVersion, YAxisTreatment,
20 webgl_channel,
21};
22use dom_struct::dom_struct;
23use euclid::default::{Point2D, Rect, Size2D};
24use ipc_channel::ipc::{self, IpcSharedMemory};
25use js::jsapi::{JSContext, JSObject, Type};
26use js::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, ObjectValue, UInt32Value};
27use js::rust::{CustomAutoRooterGuard, MutableHandleValue};
28use js::typedarray::{
29 ArrayBufferView, CreateWith, Float32, Float32Array, Int32, Int32Array, TypedArray,
30 TypedArrayElementCreator, Uint32Array,
31};
32use pixels::{self, Alpha, PixelFormat, Snapshot, SnapshotPixelFormat};
33use script_bindings::conversions::SafeToJSValConvertible;
34use serde::{Deserialize, Serialize};
35use servo_config::pref;
36use webrender_api::ImageKey;
37
38use crate::canvas_context::CanvasContext;
39use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
40use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
41use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants;
42use crate::dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants;
43use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants;
44use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{
45 TexImageSource, WebGLContextAttributes, WebGLRenderingContextConstants as constants,
46 WebGLRenderingContextMethods,
47};
48use crate::dom::bindings::codegen::UnionTypes::{
49 ArrayBufferViewOrArrayBuffer, Float32ArrayOrUnrestrictedFloatSequence,
50 HTMLCanvasElementOrOffscreenCanvas, Int32ArrayOrLongSequence,
51};
52use crate::dom::bindings::conversions::DerivedFrom;
53use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
54use crate::dom::bindings::inheritance::Castable;
55use crate::dom::bindings::reflector::{DomGlobal, DomObject, Reflector, reflect_dom_object};
56use crate::dom::bindings::root::{DomOnceCell, DomRoot, LayoutDom, MutNullableDom};
57use crate::dom::bindings::str::DOMString;
58use crate::dom::event::{Event, EventBubbles, EventCancelable};
59use crate::dom::html::htmlcanvaselement::LayoutCanvasRenderingContextHelpers;
60use crate::dom::node::{Node, NodeDamage, NodeTraits};
61#[cfg(feature = "webxr")]
62use crate::dom::promise::Promise;
63use crate::dom::webgl::extensions::WebGLExtensions;
64use crate::dom::webgl::validations::WebGLValidator;
65use crate::dom::webgl::validations::tex_image_2d::{
66 CommonCompressedTexImage2DValidatorResult, CommonTexImage2DValidator,
67 CommonTexImage2DValidatorResult, CompressedTexImage2DValidator,
68 CompressedTexSubImage2DValidator, TexImage2DValidator, TexImage2DValidatorResult,
69};
70use crate::dom::webgl::validations::types::TexImageTarget;
71use crate::dom::webgl::vertexarrayobject::VertexAttribData;
72use crate::dom::webgl::webglactiveinfo::WebGLActiveInfo;
73use crate::dom::webgl::webglbuffer::WebGLBuffer;
74use crate::dom::webgl::webglcontextevent::WebGLContextEvent;
75use crate::dom::webgl::webglframebuffer::{
76 CompleteForRendering, WebGLFramebuffer, WebGLFramebufferAttachmentRoot,
77};
78use crate::dom::webgl::webglobject::WebGLObject;
79use crate::dom::webgl::webglprogram::WebGLProgram;
80use crate::dom::webgl::webglrenderbuffer::WebGLRenderbuffer;
81use crate::dom::webgl::webglshader::WebGLShader;
82use crate::dom::webgl::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
83use crate::dom::webgl::webgltexture::{TexParameterValue, WebGLTexture};
84use crate::dom::webgl::webgluniformlocation::WebGLUniformLocation;
85use crate::dom::webgl::webglvertexarrayobject::WebGLVertexArrayObject;
86use crate::dom::webgl::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES;
87use crate::dom::window::Window;
88use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
89
90macro_rules! handle_object_deletion {
99 ($self_:expr, $binding:expr, $object:ident, $unbind_command:expr) => {
100 if let Some(bound_object) = $binding.get() {
101 if bound_object.id() == $object.id() {
102 $binding.set(None);
103 if let Some(command) = $unbind_command {
104 $self_.send_command(command);
105 }
106 }
107 }
108 };
109}
110
111fn has_invalid_blend_constants(arg1: u32, arg2: u32) -> bool {
112 match (arg1, arg2) {
113 (constants::CONSTANT_COLOR, constants::CONSTANT_ALPHA) => true,
114 (constants::ONE_MINUS_CONSTANT_COLOR, constants::ONE_MINUS_CONSTANT_ALPHA) => true,
115 (constants::ONE_MINUS_CONSTANT_COLOR, constants::CONSTANT_ALPHA) => true,
116 (constants::CONSTANT_COLOR, constants::ONE_MINUS_CONSTANT_ALPHA) => true,
117 (_, _) => false,
118 }
119}
120
121pub(crate) fn uniform_get<T, F>(triple: (&WebGLRenderingContext, WebGLProgramId, i32), f: F) -> T
122where
123 F: FnOnce(WebGLProgramId, i32, WebGLSender<T>) -> WebGLCommand,
124 T: for<'de> Deserialize<'de> + Serialize,
125{
126 let (sender, receiver) = webgl_channel().unwrap();
127 triple.0.send_command(f(triple.1, triple.2, sender));
128 receiver.recv().unwrap()
129}
130
131#[allow(unsafe_code)]
132pub(crate) unsafe fn uniform_typed<T>(
133 cx: *mut JSContext,
134 value: &[T::Element],
135 mut retval: MutableHandleValue,
136) where
137 T: TypedArrayElementCreator,
138{
139 rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>());
140 <TypedArray<T, *mut JSObject>>::create(cx, CreateWith::Slice(value), rval.handle_mut())
141 .unwrap();
142 retval.set(ObjectValue(rval.get()));
143}
144
145#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
147pub(crate) struct TextureUnpacking(u8);
148
149bitflags! {
150 impl TextureUnpacking: u8 {
151 const FLIP_Y_AXIS = 0x01;
152 const PREMULTIPLY_ALPHA = 0x02;
153 const CONVERT_COLORSPACE = 0x04;
154 }
155}
156
157#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
158pub(crate) enum VertexAttrib {
159 Float(f32, f32, f32, f32),
160 Int(i32, i32, i32, i32),
161 Uint(u32, u32, u32, u32),
162}
163
164#[derive(Clone, Copy, Debug)]
165pub(crate) enum Operation {
166 Fallible,
167 Infallible,
168}
169
170#[dom_struct]
171pub(crate) struct WebGLRenderingContext {
172 reflector_: Reflector,
173 #[ignore_malloc_size_of = "Channels are hard"]
174 webgl_sender: WebGLMessageSender,
175 #[ignore_malloc_size_of = "Defined in webrender"]
176 #[no_trace]
177 webrender_image: ImageKey,
178 #[no_trace]
179 webgl_version: WebGLVersion,
180 #[no_trace]
181 glsl_version: WebGLSLVersion,
182 #[ignore_malloc_size_of = "Defined in surfman"]
183 #[no_trace]
184 limits: GLLimits,
185 canvas: HTMLCanvasElementOrOffscreenCanvas,
186 #[ignore_malloc_size_of = "Defined in canvas_traits"]
187 #[no_trace]
188 last_error: Cell<Option<WebGLError>>,
189 texture_packing_alignment: Cell<u8>,
190 texture_unpacking_settings: Cell<TextureUnpacking>,
191 texture_unpacking_alignment: Cell<u32>,
193 bound_draw_framebuffer: MutNullableDom<WebGLFramebuffer>,
194 bound_read_framebuffer: MutNullableDom<WebGLFramebuffer>,
197 bound_renderbuffer: MutNullableDom<WebGLRenderbuffer>,
198 bound_buffer_array: MutNullableDom<WebGLBuffer>,
199 current_program: MutNullableDom<WebGLProgram>,
200 current_vertex_attribs: DomRefCell<Box<[VertexAttrib]>>,
201 #[ignore_malloc_size_of = "Because it's small"]
202 current_scissor: Cell<(i32, i32, u32, u32)>,
203 #[ignore_malloc_size_of = "Because it's small"]
204 current_clear_color: Cell<(f32, f32, f32, f32)>,
205 #[no_trace]
206 size: Cell<Size2D<u32>>,
207 extension_manager: WebGLExtensions,
208 capabilities: Capabilities,
209 default_vao: DomOnceCell<WebGLVertexArrayObjectOES>,
210 current_vao: MutNullableDom<WebGLVertexArrayObjectOES>,
211 default_vao_webgl2: DomOnceCell<WebGLVertexArrayObject>,
212 current_vao_webgl2: MutNullableDom<WebGLVertexArrayObject>,
213 textures: Textures,
214 #[no_trace]
215 api_type: GlType,
216}
217
218impl WebGLRenderingContext {
219 pub(crate) fn new_inherited(
220 window: &Window,
221 canvas: &HTMLCanvasElementOrOffscreenCanvas,
222 webgl_version: WebGLVersion,
223 size: Size2D<u32>,
224 attrs: GLContextAttributes,
225 ) -> Result<WebGLRenderingContext, String> {
226 if pref!(webgl_testing_context_creation_error) {
227 return Err("WebGL context creation error forced by pref `webgl.testing.context_creation_error`".into());
228 }
229
230 let webgl_chan = match window.webgl_chan() {
231 Some(chan) => chan,
232 None => return Err("WebGL initialization failed early on".into()),
233 };
234
235 let (sender, receiver) = webgl_channel().unwrap();
236 webgl_chan
237 .send(WebGLMsg::CreateContext(webgl_version, size, attrs, sender))
238 .unwrap();
239 let result = receiver.recv().unwrap();
240
241 result.map(|ctx_data| {
242 let max_combined_texture_image_units = ctx_data.limits.max_combined_texture_image_units;
243 let max_vertex_attribs = ctx_data.limits.max_vertex_attribs as usize;
244 Self {
245 reflector_: Reflector::new(),
246 webgl_sender: WebGLMessageSender::new(ctx_data.sender),
247 webrender_image: ctx_data.image_key,
248 webgl_version,
249 glsl_version: ctx_data.glsl_version,
250 limits: ctx_data.limits,
251 canvas: canvas.clone(),
252 last_error: Cell::new(None),
253 texture_packing_alignment: Cell::new(4),
254 texture_unpacking_settings: Cell::new(TextureUnpacking::CONVERT_COLORSPACE),
255 texture_unpacking_alignment: Cell::new(4),
256 bound_draw_framebuffer: MutNullableDom::new(None),
257 bound_read_framebuffer: MutNullableDom::new(None),
258 bound_buffer_array: MutNullableDom::new(None),
259 bound_renderbuffer: MutNullableDom::new(None),
260 current_program: MutNullableDom::new(None),
261 current_vertex_attribs: DomRefCell::new(
262 vec![VertexAttrib::Float(0f32, 0f32, 0f32, 1f32); max_vertex_attribs].into(),
263 ),
264 current_scissor: Cell::new((0, 0, size.width, size.height)),
265 size: Cell::new(size),
268 current_clear_color: Cell::new((0.0, 0.0, 0.0, 0.0)),
269 extension_manager: WebGLExtensions::new(
270 webgl_version,
271 ctx_data.api_type,
272 ctx_data.glsl_version,
273 ),
274 capabilities: Default::default(),
275 default_vao: Default::default(),
276 current_vao: Default::default(),
277 default_vao_webgl2: Default::default(),
278 current_vao_webgl2: Default::default(),
279 textures: Textures::new(max_combined_texture_image_units),
280 api_type: ctx_data.api_type,
281 }
282 })
283 }
284
285 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
286 pub(crate) fn new(
287 window: &Window,
288 canvas: &HTMLCanvasElementOrOffscreenCanvas,
289 webgl_version: WebGLVersion,
290 size: Size2D<u32>,
291 attrs: GLContextAttributes,
292 can_gc: CanGc,
293 ) -> Option<DomRoot<WebGLRenderingContext>> {
294 match WebGLRenderingContext::new_inherited(window, canvas, webgl_version, size, attrs) {
295 Ok(ctx) => Some(reflect_dom_object(Box::new(ctx), window, can_gc)),
296 Err(msg) => {
297 error!("Couldn't create WebGLRenderingContext: {}", msg);
298 let event = WebGLContextEvent::new(
299 window,
300 atom!("webglcontextcreationerror"),
301 EventBubbles::DoesNotBubble,
302 EventCancelable::Cancelable,
303 DOMString::from(msg),
304 can_gc,
305 );
306 match canvas {
307 HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) => {
308 event.upcast::<Event>().fire(canvas.upcast(), can_gc);
309 },
310 HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(canvas) => {
311 event.upcast::<Event>().fire(canvas.upcast(), can_gc);
312 },
313 }
314 None
315 },
316 }
317 }
318
319 pub(crate) fn webgl_version(&self) -> WebGLVersion {
320 self.webgl_version
321 }
322
323 pub(crate) fn limits(&self) -> &GLLimits {
324 &self.limits
325 }
326
327 pub(crate) fn texture_unpacking_alignment(&self) -> u32 {
328 self.texture_unpacking_alignment.get()
329 }
330
331 pub(crate) fn bound_draw_framebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
332 self.bound_draw_framebuffer.get()
333 }
334
335 pub(crate) fn current_vao(&self) -> DomRoot<WebGLVertexArrayObjectOES> {
336 self.current_vao.or_init(|| {
337 DomRoot::from_ref(
338 self.default_vao
339 .init_once(|| WebGLVertexArrayObjectOES::new(self, None, CanGc::note())),
340 )
341 })
342 }
343
344 pub(crate) fn current_vao_webgl2(&self) -> DomRoot<WebGLVertexArrayObject> {
345 self.current_vao_webgl2.or_init(|| {
346 DomRoot::from_ref(
347 self.default_vao_webgl2
348 .init_once(|| WebGLVertexArrayObject::new(self, None, CanGc::note())),
349 )
350 })
351 }
352
353 pub(crate) fn current_vertex_attribs(&self) -> RefMut<'_, Box<[VertexAttrib]>> {
354 self.current_vertex_attribs.borrow_mut()
355 }
356
357 #[inline]
358 pub(crate) fn send_command(&self, command: WebGLCommand) {
359 self.webgl_sender
360 .send(command, capture_webgl_backtrace(self))
361 .unwrap();
362 }
363
364 pub(crate) fn send_command_ignored(&self, command: WebGLCommand) {
365 let _ = self
366 .webgl_sender
367 .send(command, capture_webgl_backtrace(self));
368 }
369
370 pub(crate) fn webgl_error(&self, err: WebGLError) {
371 warn!(
373 "WebGL error: {:?}, previous error was {:?}",
374 err,
375 self.last_error.get()
376 );
377
378 if self.last_error.get().is_none() {
381 self.last_error.set(Some(err));
382 }
383 }
384
385 pub(crate) fn validate_framebuffer(&self) -> WebGLResult<()> {
404 match self.bound_draw_framebuffer.get() {
405 Some(fb) => match fb.check_status_for_rendering() {
406 CompleteForRendering::Complete => Ok(()),
407 CompleteForRendering::Incomplete => Err(InvalidFramebufferOperation),
408 CompleteForRendering::MissingColorAttachment => Err(InvalidOperation),
409 },
410 None => Ok(()),
411 }
412 }
413
414 pub(crate) fn validate_ownership<T>(&self, object: &T) -> WebGLResult<()>
415 where
416 T: DerivedFrom<WebGLObject>,
417 {
418 if self != object.upcast().context() {
419 return Err(InvalidOperation);
420 }
421 Ok(())
422 }
423
424 pub(crate) fn with_location<F>(&self, location: Option<&WebGLUniformLocation>, f: F)
425 where
426 F: FnOnce(&WebGLUniformLocation) -> WebGLResult<()>,
427 {
428 let location = match location {
429 Some(loc) => loc,
430 None => return,
431 };
432 match self.current_program.get() {
433 Some(ref program)
434 if program.id() == location.program_id() &&
435 program.link_generation() == location.link_generation() => {},
436 _ => return self.webgl_error(InvalidOperation),
437 }
438 handle_potential_webgl_error!(self, f(location));
439 }
440
441 pub(crate) fn textures(&self) -> &Textures {
442 &self.textures
443 }
444
445 fn tex_parameter(&self, target: u32, param: u32, value: TexParameterValue) {
446 let texture_slot = handle_potential_webgl_error!(
447 self,
448 self.textures
449 .active_texture_slot(target, self.webgl_version()),
450 return
451 );
452 let texture =
453 handle_potential_webgl_error!(self, texture_slot.get().ok_or(InvalidOperation), return);
454
455 if !self
456 .extension_manager
457 .is_get_tex_parameter_name_enabled(param)
458 {
459 return self.webgl_error(InvalidEnum);
460 }
461
462 handle_potential_webgl_error!(self, texture.tex_parameter(param, value), return);
463
464 if target != constants::TEXTURE_2D {
466 return;
467 }
468
469 let target = TexImageTarget::Texture2D;
470 if let Some(info) = texture.image_info_for_target(&target, 0) {
471 self.validate_filterable_texture(
472 &texture,
473 target,
474 0,
475 info.internal_format(),
476 Size2D::new(info.width(), info.height()),
477 info.data_type().unwrap_or(TexDataType::UnsignedByte),
478 );
479 }
480 }
481
482 fn vertex_attrib(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) {
483 if indx >= self.limits.max_vertex_attribs {
484 return self.webgl_error(InvalidValue);
485 }
486
487 match self.webgl_version() {
488 WebGLVersion::WebGL1 => self
489 .current_vao()
490 .set_vertex_attrib_type(indx, constants::FLOAT),
491 WebGLVersion::WebGL2 => self
492 .current_vao_webgl2()
493 .set_vertex_attrib_type(indx, constants::FLOAT),
494 };
495 self.current_vertex_attribs.borrow_mut()[indx as usize] = VertexAttrib::Float(x, y, z, w);
496
497 self.send_command(WebGLCommand::VertexAttrib(indx, x, y, z, w));
498 }
499
500 pub(crate) fn get_current_framebuffer_size(&self) -> Option<(i32, i32)> {
501 match self.bound_draw_framebuffer.get() {
502 Some(fb) => fb.size(),
503
504 None => Some((self.DrawingBufferWidth(), self.DrawingBufferHeight())),
506 }
507 }
508
509 pub(crate) fn get_texture_packing_alignment(&self) -> u8 {
510 self.texture_packing_alignment.get()
511 }
512
513 pub(crate) fn get_current_unpack_state(
514 &self,
515 premultiplied: Alpha,
516 ) -> (Option<AlphaTreatment>, YAxisTreatment) {
517 let settings = self.texture_unpacking_settings.get();
518 let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA);
519
520 let alpha_treatment = match (premultiplied, dest_premultiplied) {
521 (Alpha::Premultiplied, false) => Some(AlphaTreatment::Unmultiply),
522 (Alpha::NotPremultiplied, true) => Some(AlphaTreatment::Premultiply),
523 _ => None,
524 };
525
526 let y_axis_treatment = if settings.contains(TextureUnpacking::FLIP_Y_AXIS) {
527 YAxisTreatment::Flipped
528 } else {
529 YAxisTreatment::AsIs
530 };
531
532 (alpha_treatment, y_axis_treatment)
533 }
534
535 fn validate_filterable_texture(
538 &self,
539 texture: &WebGLTexture,
540 target: TexImageTarget,
541 level: u32,
542 internal_format: TexFormat,
543 size: Size2D<u32>,
544 data_type: TexDataType,
545 ) -> bool {
546 if self
547 .extension_manager
548 .is_filterable(data_type.as_gl_constant()) ||
549 !texture.is_using_linear_filtering()
550 {
551 return true;
552 }
553
554 let data_type = TexDataType::UnsignedByte;
557 let expected_byte_length = size.area() * 4;
558 let mut pixels = vec![0u8; expected_byte_length as usize];
559 for rgba8 in pixels.chunks_mut(4) {
560 rgba8[3] = 255u8;
561 }
562
563 self.tex_image_2d(
567 texture,
568 target,
569 data_type,
570 internal_format,
571 internal_format.to_unsized(),
572 level,
573 0,
574 1,
575 size,
576 TexSource::Pixels(TexPixels::new(
577 IpcSharedMemory::from_bytes(&pixels),
578 size,
579 PixelFormat::RGBA8,
580 None,
581 YAxisTreatment::AsIs,
582 )),
583 );
584
585 false
586 }
587
588 fn validate_stencil_actions(&self, action: u32) -> bool {
589 matches!(
590 action,
591 0 | constants::KEEP |
592 constants::REPLACE |
593 constants::INCR |
594 constants::DECR |
595 constants::INVERT |
596 constants::INCR_WRAP |
597 constants::DECR_WRAP
598 )
599 }
600
601 pub(crate) fn get_image_pixels(&self, source: TexImageSource) -> Fallible<Option<TexPixels>> {
602 Ok(Some(match source {
603 TexImageSource::ImageBitmap(bitmap) => {
604 if !bitmap.origin_is_clean() {
605 return Err(Error::Security);
606 }
607
608 let Some(snapshot) = bitmap.bitmap_data().clone() else {
609 return Ok(None);
610 };
611
612 let snapshot = snapshot.as_ipc();
613 let size = snapshot.size().cast();
614 let format = match snapshot.format() {
615 SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
616 SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
617 };
618
619 TexPixels::new(
626 snapshot.to_ipc_shared_memory(),
627 size,
628 format,
629 None,
630 YAxisTreatment::AsIs,
631 )
632 },
633 TexImageSource::ImageData(image_data) => {
634 let (alpha_treatment, y_axis_treatment) =
635 self.get_current_unpack_state(Alpha::NotPremultiplied);
636
637 TexPixels::new(
638 image_data.to_shared_memory(),
639 image_data.get_size(),
640 PixelFormat::RGBA8,
641 alpha_treatment,
642 y_axis_treatment,
643 )
644 },
645 TexImageSource::HTMLImageElement(image) => {
646 let document = match self.canvas {
647 HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(ref canvas) => {
648 canvas.owner_document()
649 },
650 HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(ref _canvas) => {
651 return Ok(None);
653 },
654 };
655 if !image.same_origin(document.origin()) {
656 return Err(Error::Security);
657 }
658
659 let Some(snapshot) = image.get_raster_image_data() else {
663 return Ok(None);
664 };
665
666 let snapshot = snapshot.as_ipc();
667 let size = snapshot.size().cast();
668 let format: PixelFormat = match snapshot.format() {
669 SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
670 SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
671 };
672
673 let (alpha_treatment, y_axis_treatment) =
674 self.get_current_unpack_state(Alpha::NotPremultiplied);
675
676 TexPixels::new(
677 snapshot.to_ipc_shared_memory(),
678 size,
679 format,
680 alpha_treatment,
681 y_axis_treatment,
682 )
683 },
684 TexImageSource::HTMLCanvasElement(canvas) => {
688 if !canvas.origin_is_clean() {
689 return Err(Error::Security);
690 }
691
692 let Some(snapshot) = canvas.get_image_data() else {
693 return Ok(None);
694 };
695
696 let snapshot = snapshot.as_ipc();
697 let size = snapshot.size().cast();
698 let format = match snapshot.format() {
699 SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
700 SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
701 };
702
703 let (alpha_treatment, y_axis_treatment) =
704 self.get_current_unpack_state(snapshot.alpha_mode().alpha());
705
706 TexPixels::new(
707 snapshot.to_ipc_shared_memory(),
708 size,
709 format,
710 alpha_treatment,
711 y_axis_treatment,
712 )
713 },
714 TexImageSource::HTMLVideoElement(video) => {
715 if !video.origin_is_clean() {
716 return Err(Error::Security);
717 }
718
719 let Some(snapshot) = video.get_current_frame_data() else {
720 return Ok(None);
721 };
722
723 let snapshot = snapshot.as_ipc();
724 let size = snapshot.size().cast();
725 let format: PixelFormat = match snapshot.format() {
726 SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
727 SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
728 };
729
730 let (alpha_treatment, y_axis_treatment) =
731 self.get_current_unpack_state(snapshot.alpha_mode().alpha());
732
733 TexPixels::new(
734 snapshot.to_ipc_shared_memory(),
735 size,
736 format,
737 alpha_treatment,
738 y_axis_treatment,
739 )
740 },
741 }))
742 }
743
744 pub(crate) fn validate_tex_image_2d_data(
746 &self,
747 width: u32,
748 height: u32,
749 format: TexFormat,
750 data_type: TexDataType,
751 unpacking_alignment: u32,
752 data: Option<&ArrayBufferView>,
753 ) -> Result<u32, ()> {
754 let element_size = data_type.element_size();
755 let components_per_element = data_type.components_per_element();
756 let components = format.components();
757
758 let data_type_matches = data.as_ref().is_none_or(|buffer| {
766 Some(data_type.sized_data_type()) ==
767 array_buffer_type_to_sized_type(buffer.get_array_type()) &&
768 data_type.required_webgl_version() <= self.webgl_version()
769 });
770
771 if !data_type_matches {
772 self.webgl_error(InvalidOperation);
773 return Err(());
774 }
775
776 if height == 0 {
778 Ok(0)
779 } else {
780 let cpp = element_size * components / components_per_element;
785 let stride = (width * cpp + unpacking_alignment - 1) & !(unpacking_alignment - 1);
786 Ok(stride * (height - 1) + width * cpp)
787 }
788 }
789
790 #[allow(clippy::too_many_arguments)]
791 pub(crate) fn tex_image_2d(
792 &self,
793 texture: &WebGLTexture,
794 target: TexImageTarget,
795 data_type: TexDataType,
796 internal_format: TexFormat,
797 format: TexFormat,
798 level: u32,
799 _border: u32,
800 unpacking_alignment: u32,
801 size: Size2D<u32>,
802 source: TexSource,
803 ) {
804 handle_potential_webgl_error!(
806 self,
807 texture.initialize(
808 target,
809 size.width,
810 size.height,
811 1,
812 format,
813 level,
814 Some(data_type)
815 )
816 );
817
818 let internal_format = self
819 .extension_manager
820 .get_effective_tex_internal_format(internal_format, data_type.as_gl_constant());
821
822 let effective_data_type = self
823 .extension_manager
824 .effective_type(data_type.as_gl_constant());
825
826 match source {
827 TexSource::Pixels(pixels) => {
828 self.send_command(WebGLCommand::TexImage2D {
830 target: target.as_gl_constant(),
831 level,
832 internal_format,
833 size,
834 format,
835 data_type,
836 effective_data_type,
837 unpacking_alignment,
838 alpha_treatment: pixels.alpha_treatment,
839 y_axis_treatment: pixels.y_axis_treatment,
840 pixel_format: pixels.pixel_format,
841 data: pixels.data.into(),
842 });
843 },
844 TexSource::BufferOffset(offset) => {
845 self.send_command(WebGLCommand::TexImage2DPBO {
846 target: target.as_gl_constant(),
847 level,
848 internal_format,
849 size,
850 format,
851 effective_data_type,
852 unpacking_alignment,
853 offset,
854 });
855 },
856 }
857
858 if let Some(fb) = self.bound_draw_framebuffer.get() {
859 fb.invalidate_texture(texture);
860 }
861 }
862
863 #[allow(clippy::too_many_arguments)]
864 fn tex_sub_image_2d(
865 &self,
866 texture: DomRoot<WebGLTexture>,
867 target: TexImageTarget,
868 level: u32,
869 xoffset: i32,
870 yoffset: i32,
871 format: TexFormat,
872 data_type: TexDataType,
873 unpacking_alignment: u32,
874 pixels: TexPixels,
875 ) {
876 let image_info = match texture.image_info_for_target(&target, level) {
878 Some(info) => info,
879 None => return self.webgl_error(InvalidOperation),
880 };
881
882 if xoffset < 0 ||
887 (xoffset as u32 + pixels.size().width) > image_info.width() ||
888 yoffset < 0 ||
889 (yoffset as u32 + pixels.size().height) > image_info.height()
890 {
891 return self.webgl_error(InvalidValue);
892 }
893
894 debug_assert!(!format.is_sized());
896 if format != image_info.internal_format().to_unsized() {
897 return self.webgl_error(InvalidOperation);
898 }
899
900 if self.webgl_version() == WebGLVersion::WebGL1 &&
902 data_type != image_info.data_type().unwrap()
903 {
904 return self.webgl_error(InvalidOperation);
905 }
906
907 let effective_data_type = self
908 .extension_manager
909 .effective_type(data_type.as_gl_constant());
910
911 self.send_command(WebGLCommand::TexSubImage2D {
913 target: target.as_gl_constant(),
914 level,
915 xoffset,
916 yoffset,
917 size: pixels.size(),
918 format,
919 data_type,
920 effective_data_type,
921 unpacking_alignment,
922 alpha_treatment: pixels.alpha_treatment,
923 y_axis_treatment: pixels.y_axis_treatment,
924 pixel_format: pixels.pixel_format,
925 data: pixels.data.into(),
926 });
927 }
928
929 fn get_gl_extensions(&self) -> String {
930 let (sender, receiver) = webgl_channel().unwrap();
931 self.send_command(WebGLCommand::GetExtensions(sender));
932 receiver.recv().unwrap()
933 }
934
935 pub(crate) fn layout_handle(&self) -> Option<ImageKey> {
936 Some(self.webrender_image)
937 }
938
939 pub(crate) fn draw_arrays_instanced(
941 &self,
942 mode: u32,
943 first: i32,
944 count: i32,
945 primcount: i32,
946 ) -> WebGLResult<()> {
947 match mode {
948 constants::POINTS |
949 constants::LINE_STRIP |
950 constants::LINE_LOOP |
951 constants::LINES |
952 constants::TRIANGLE_STRIP |
953 constants::TRIANGLE_FAN |
954 constants::TRIANGLES => {},
955 _ => {
956 return Err(InvalidEnum);
957 },
958 }
959 if first < 0 || count < 0 || primcount < 0 {
960 return Err(InvalidValue);
961 }
962
963 let current_program = self.current_program.get().ok_or(InvalidOperation)?;
964
965 let required_len = if count > 0 {
966 first
967 .checked_add(count)
968 .map(|len| len as u32)
969 .ok_or(InvalidOperation)?
970 } else {
971 0
972 };
973
974 match self.webgl_version() {
975 WebGLVersion::WebGL1 => self.current_vao().validate_for_draw(
976 required_len,
977 primcount as u32,
978 ¤t_program.active_attribs(),
979 )?,
980 WebGLVersion::WebGL2 => self.current_vao_webgl2().validate_for_draw(
981 required_len,
982 primcount as u32,
983 ¤t_program.active_attribs(),
984 )?,
985 };
986
987 self.validate_framebuffer()?;
988
989 if count == 0 || primcount == 0 {
990 return Ok(());
991 }
992
993 self.send_command(if primcount == 1 {
994 WebGLCommand::DrawArrays { mode, first, count }
995 } else {
996 WebGLCommand::DrawArraysInstanced {
997 mode,
998 first,
999 count,
1000 primcount,
1001 }
1002 });
1003 self.mark_as_dirty();
1004 Ok(())
1005 }
1006
1007 pub(crate) fn draw_elements_instanced(
1009 &self,
1010 mode: u32,
1011 count: i32,
1012 type_: u32,
1013 offset: i64,
1014 primcount: i32,
1015 ) -> WebGLResult<()> {
1016 match mode {
1017 constants::POINTS |
1018 constants::LINE_STRIP |
1019 constants::LINE_LOOP |
1020 constants::LINES |
1021 constants::TRIANGLE_STRIP |
1022 constants::TRIANGLE_FAN |
1023 constants::TRIANGLES => {},
1024 _ => {
1025 return Err(InvalidEnum);
1026 },
1027 }
1028 if count < 0 || offset < 0 || primcount < 0 {
1029 return Err(InvalidValue);
1030 }
1031 let type_size = match type_ {
1032 constants::UNSIGNED_BYTE => 1,
1033 constants::UNSIGNED_SHORT => 2,
1034 constants::UNSIGNED_INT => match self.webgl_version() {
1035 WebGLVersion::WebGL1 if self.extension_manager.is_element_index_uint_enabled() => 4,
1036 WebGLVersion::WebGL2 => 4,
1037 _ => return Err(InvalidEnum),
1038 },
1039 _ => return Err(InvalidEnum),
1040 };
1041 if offset % type_size != 0 {
1042 return Err(InvalidOperation);
1043 }
1044
1045 let current_program = self.current_program.get().ok_or(InvalidOperation)?;
1046 let array_buffer = match self.webgl_version() {
1047 WebGLVersion::WebGL1 => self.current_vao().element_array_buffer().get(),
1048 WebGLVersion::WebGL2 => self.current_vao_webgl2().element_array_buffer().get(),
1049 }
1050 .ok_or(InvalidOperation)?;
1051
1052 if count > 0 && primcount > 0 {
1053 let val = offset as u64 + (count as u64 * type_size as u64);
1055 if val > array_buffer.capacity() as u64 {
1056 return Err(InvalidOperation);
1057 }
1058 }
1059
1060 match self.webgl_version() {
1062 WebGLVersion::WebGL1 => self.current_vao().validate_for_draw(
1063 0,
1064 primcount as u32,
1065 ¤t_program.active_attribs(),
1066 )?,
1067 WebGLVersion::WebGL2 => self.current_vao_webgl2().validate_for_draw(
1068 0,
1069 primcount as u32,
1070 ¤t_program.active_attribs(),
1071 )?,
1072 };
1073
1074 self.validate_framebuffer()?;
1075
1076 if count == 0 || primcount == 0 {
1077 return Ok(());
1078 }
1079
1080 let offset = offset as u32;
1081 self.send_command(if primcount == 1 {
1082 WebGLCommand::DrawElements {
1083 mode,
1084 count,
1085 type_,
1086 offset,
1087 }
1088 } else {
1089 WebGLCommand::DrawElementsInstanced {
1090 mode,
1091 count,
1092 type_,
1093 offset,
1094 primcount,
1095 }
1096 });
1097 self.mark_as_dirty();
1098 Ok(())
1099 }
1100
1101 pub(crate) fn vertex_attrib_divisor(&self, index: u32, divisor: u32) {
1102 if index >= self.limits.max_vertex_attribs {
1103 return self.webgl_error(InvalidValue);
1104 }
1105
1106 match self.webgl_version() {
1107 WebGLVersion::WebGL1 => self.current_vao().vertex_attrib_divisor(index, divisor),
1108 WebGLVersion::WebGL2 => self
1109 .current_vao_webgl2()
1110 .vertex_attrib_divisor(index, divisor),
1111 };
1112 self.send_command(WebGLCommand::VertexAttribDivisor { index, divisor });
1113 }
1114
1115 pub(crate) fn array_buffer(&self) -> Option<DomRoot<WebGLBuffer>> {
1116 self.bound_buffer_array.get()
1117 }
1118
1119 pub(crate) fn array_buffer_slot(&self) -> &MutNullableDom<WebGLBuffer> {
1120 &self.bound_buffer_array
1121 }
1122
1123 pub(crate) fn bound_buffer(&self, target: u32) -> WebGLResult<Option<DomRoot<WebGLBuffer>>> {
1124 match target {
1125 constants::ARRAY_BUFFER => Ok(self.bound_buffer_array.get()),
1126 constants::ELEMENT_ARRAY_BUFFER => Ok(self.current_vao().element_array_buffer().get()),
1127 _ => Err(WebGLError::InvalidEnum),
1128 }
1129 }
1130
1131 pub(crate) fn buffer_usage(&self, usage: u32) -> WebGLResult<u32> {
1132 match usage {
1133 constants::STREAM_DRAW | constants::STATIC_DRAW | constants::DYNAMIC_DRAW => Ok(usage),
1134 _ => Err(WebGLError::InvalidEnum),
1135 }
1136 }
1137
1138 pub(crate) fn create_vertex_array(&self) -> Option<DomRoot<WebGLVertexArrayObjectOES>> {
1139 let (sender, receiver) = webgl_channel().unwrap();
1140 self.send_command(WebGLCommand::CreateVertexArray(sender));
1141 receiver
1142 .recv()
1143 .unwrap()
1144 .map(|id| WebGLVertexArrayObjectOES::new(self, Some(id), CanGc::note()))
1145 }
1146
1147 pub(crate) fn create_vertex_array_webgl2(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
1148 let (sender, receiver) = webgl_channel().unwrap();
1149 self.send_command(WebGLCommand::CreateVertexArray(sender));
1150 receiver
1151 .recv()
1152 .unwrap()
1153 .map(|id| WebGLVertexArrayObject::new(self, Some(id), CanGc::note()))
1154 }
1155
1156 pub(crate) fn delete_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
1157 if let Some(vao) = vao {
1158 handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
1159 assert!(vao.id().is_some());
1161 if vao.is_deleted() {
1162 return;
1163 }
1164 if vao == &*self.current_vao() {
1165 self.current_vao.set(None);
1168 self.send_command(WebGLCommand::BindVertexArray(None));
1169 }
1170 vao.delete(Operation::Infallible);
1171 }
1172 }
1173
1174 pub(crate) fn delete_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) {
1175 if let Some(vao) = vao {
1176 handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
1177 assert!(vao.id().is_some());
1179 if vao.is_deleted() {
1180 return;
1181 }
1182 if vao == &*self.current_vao_webgl2() {
1183 self.current_vao_webgl2.set(None);
1186 self.send_command(WebGLCommand::BindVertexArray(None));
1187 }
1188 vao.delete(Operation::Infallible);
1189 }
1190 }
1191
1192 pub(crate) fn is_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) -> bool {
1193 vao.is_some_and(|vao| {
1194 assert!(vao.id().is_some());
1196 self.validate_ownership(vao).is_ok() && vao.ever_bound() && !vao.is_deleted()
1197 })
1198 }
1199
1200 pub(crate) fn is_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) -> bool {
1201 vao.is_some_and(|vao| {
1202 assert!(vao.id().is_some());
1204 self.validate_ownership(vao).is_ok() && vao.ever_bound() && !vao.is_deleted()
1205 })
1206 }
1207
1208 pub(crate) fn bind_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
1209 if let Some(vao) = vao {
1210 assert!(vao.id().is_some());
1212 handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
1213 if vao.is_deleted() {
1214 return self.webgl_error(InvalidOperation);
1215 }
1216 vao.set_ever_bound();
1217 }
1218 self.send_command(WebGLCommand::BindVertexArray(vao.and_then(|vao| vao.id())));
1219 self.current_vao.set(vao);
1222 }
1223
1224 pub(crate) fn bind_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) {
1225 if let Some(vao) = vao {
1226 assert!(vao.id().is_some());
1228 handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
1229 if vao.is_deleted() {
1230 return self.webgl_error(InvalidOperation);
1231 }
1232 vao.set_ever_bound();
1233 }
1234 self.send_command(WebGLCommand::BindVertexArray(vao.and_then(|vao| vao.id())));
1235 self.current_vao_webgl2.set(vao);
1238 }
1239
1240 fn validate_blend_mode(&self, mode: u32) -> WebGLResult<()> {
1241 match mode {
1242 constants::FUNC_ADD | constants::FUNC_SUBTRACT | constants::FUNC_REVERSE_SUBTRACT => {
1243 Ok(())
1244 },
1245 EXTBlendMinmaxConstants::MIN_EXT | EXTBlendMinmaxConstants::MAX_EXT
1246 if self.extension_manager.is_blend_minmax_enabled() =>
1247 {
1248 Ok(())
1249 },
1250 _ => Err(InvalidEnum),
1251 }
1252 }
1253
1254 pub(crate) fn initialize_framebuffer(&self, clear_bits: u32) {
1255 if clear_bits == 0 {
1256 return;
1257 }
1258 self.send_command(WebGLCommand::InitializeFramebuffer {
1259 color: clear_bits & constants::COLOR_BUFFER_BIT != 0,
1260 depth: clear_bits & constants::DEPTH_BUFFER_BIT != 0,
1261 stencil: clear_bits & constants::STENCIL_BUFFER_BIT != 0,
1262 });
1263 }
1264
1265 pub(crate) fn extension_manager(&self) -> &WebGLExtensions {
1266 &self.extension_manager
1267 }
1268
1269 #[allow(unsafe_code)]
1270 pub(crate) fn buffer_data(
1271 &self,
1272 target: u32,
1273 data: Option<ArrayBufferViewOrArrayBuffer>,
1274 usage: u32,
1275 bound_buffer: Option<DomRoot<WebGLBuffer>>,
1276 ) {
1277 let data = handle_potential_webgl_error!(self, data.ok_or(InvalidValue), return);
1278 let bound_buffer =
1279 handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
1280
1281 let data = unsafe {
1282 match data {
1284 ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref data) => data.as_slice(),
1285 ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref data) => data.as_slice(),
1286 }
1287 };
1288 handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, data, usage));
1289 }
1290
1291 pub(crate) fn buffer_data_(
1292 &self,
1293 target: u32,
1294 size: i64,
1295 usage: u32,
1296 bound_buffer: Option<DomRoot<WebGLBuffer>>,
1297 ) {
1298 let bound_buffer =
1299 handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
1300
1301 if size < 0 {
1302 return self.webgl_error(InvalidValue);
1303 }
1304
1305 let data = vec![0u8; size as usize];
1308 handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, &data, usage));
1309 }
1310
1311 #[allow(unsafe_code)]
1312 pub(crate) fn buffer_sub_data(
1313 &self,
1314 target: u32,
1315 offset: i64,
1316 data: ArrayBufferViewOrArrayBuffer,
1317 bound_buffer: Option<DomRoot<WebGLBuffer>>,
1318 ) {
1319 let bound_buffer =
1320 handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
1321
1322 if offset < 0 {
1323 return self.webgl_error(InvalidValue);
1324 }
1325
1326 let data = unsafe {
1327 match data {
1329 ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref data) => data.as_slice(),
1330 ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref data) => data.as_slice(),
1331 }
1332 };
1333 if (offset as u64) + data.len() as u64 > bound_buffer.capacity() as u64 {
1334 return self.webgl_error(InvalidValue);
1335 }
1336 let (sender, receiver) = ipc::bytes_channel().unwrap();
1337 self.send_command(WebGLCommand::BufferSubData(
1338 target,
1339 offset as isize,
1340 receiver,
1341 ));
1342 sender.send(data).unwrap();
1343 }
1344
1345 pub(crate) fn bind_buffer_maybe(
1346 &self,
1347 slot: &MutNullableDom<WebGLBuffer>,
1348 target: u32,
1349 buffer: Option<&WebGLBuffer>,
1350 ) {
1351 if let Some(buffer) = buffer {
1352 handle_potential_webgl_error!(self, self.validate_ownership(buffer), return);
1353
1354 if buffer.is_marked_for_deletion() {
1355 return self.webgl_error(InvalidOperation);
1356 }
1357 handle_potential_webgl_error!(self, buffer.set_target_maybe(target), return);
1358 buffer.increment_attached_counter();
1359 }
1360
1361 self.send_command(WebGLCommand::BindBuffer(target, buffer.map(|b| b.id())));
1362 if let Some(old) = slot.get() {
1363 old.decrement_attached_counter(Operation::Infallible);
1364 }
1365
1366 slot.set(buffer);
1367 }
1368
1369 pub(crate) fn current_program(&self) -> Option<DomRoot<WebGLProgram>> {
1370 self.current_program.get()
1371 }
1372
1373 pub(crate) fn uniform_check_program(
1374 &self,
1375 program: &WebGLProgram,
1376 location: &WebGLUniformLocation,
1377 ) -> WebGLResult<()> {
1378 self.validate_ownership(program)?;
1379
1380 if program.is_deleted() ||
1381 !program.is_linked() ||
1382 self.context_id() != location.context_id() ||
1383 program.id() != location.program_id() ||
1384 program.link_generation() != location.link_generation()
1385 {
1386 return Err(InvalidOperation);
1387 }
1388
1389 Ok(())
1390 }
1391
1392 fn uniform_vec_section_int(
1393 &self,
1394 vec: Int32ArrayOrLongSequence,
1395 offset: u32,
1396 length: u32,
1397 uniform_size: usize,
1398 uniform_location: &WebGLUniformLocation,
1399 ) -> WebGLResult<Vec<i32>> {
1400 let vec = match vec {
1401 Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
1402 Int32ArrayOrLongSequence::LongSequence(v) => v,
1403 };
1404 self.uniform_vec_section::<i32>(vec, offset, length, uniform_size, uniform_location)
1405 }
1406
1407 fn uniform_vec_section_float(
1408 &self,
1409 vec: Float32ArrayOrUnrestrictedFloatSequence,
1410 offset: u32,
1411 length: u32,
1412 uniform_size: usize,
1413 uniform_location: &WebGLUniformLocation,
1414 ) -> WebGLResult<Vec<f32>> {
1415 let vec = match vec {
1416 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
1417 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
1418 };
1419 self.uniform_vec_section::<f32>(vec, offset, length, uniform_size, uniform_location)
1420 }
1421
1422 pub(crate) fn uniform_vec_section<T: Clone>(
1423 &self,
1424 vec: Vec<T>,
1425 offset: u32,
1426 length: u32,
1427 uniform_size: usize,
1428 uniform_location: &WebGLUniformLocation,
1429 ) -> WebGLResult<Vec<T>> {
1430 let offset = offset as usize;
1431 if offset > vec.len() {
1432 return Err(InvalidValue);
1433 }
1434
1435 let length = if length > 0 {
1436 length as usize
1437 } else {
1438 vec.len() - offset
1439 };
1440 if offset + length > vec.len() {
1441 return Err(InvalidValue);
1442 }
1443
1444 let vec = if offset == 0 && length == vec.len() {
1445 vec
1446 } else {
1447 vec[offset..offset + length].to_vec()
1448 };
1449
1450 if vec.len() < uniform_size || vec.len() % uniform_size != 0 {
1451 return Err(InvalidValue);
1452 }
1453 if uniform_location.size().is_none() && vec.len() != uniform_size {
1454 return Err(InvalidOperation);
1455 }
1456
1457 Ok(vec)
1458 }
1459
1460 pub(crate) fn uniform_matrix_section(
1461 &self,
1462 vec: Float32ArrayOrUnrestrictedFloatSequence,
1463 offset: u32,
1464 length: u32,
1465 transpose: bool,
1466 uniform_size: usize,
1467 uniform_location: &WebGLUniformLocation,
1468 ) -> WebGLResult<Vec<f32>> {
1469 let vec = match vec {
1470 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
1471 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
1472 };
1473 if transpose {
1474 return Err(InvalidValue);
1475 }
1476 self.uniform_vec_section::<f32>(vec, offset, length, uniform_size, uniform_location)
1477 }
1478
1479 pub(crate) fn get_draw_framebuffer_slot(&self) -> &MutNullableDom<WebGLFramebuffer> {
1480 &self.bound_draw_framebuffer
1481 }
1482
1483 pub(crate) fn get_read_framebuffer_slot(&self) -> &MutNullableDom<WebGLFramebuffer> {
1484 &self.bound_read_framebuffer
1485 }
1486
1487 pub(crate) fn validate_new_framebuffer_binding(
1488 &self,
1489 framebuffer: Option<&WebGLFramebuffer>,
1490 ) -> WebGLResult<()> {
1491 if let Some(fb) = framebuffer {
1492 self.validate_ownership(fb)?;
1493 if fb.is_deleted() {
1494 return Err(InvalidOperation);
1500 }
1501 }
1502 Ok(())
1503 }
1504
1505 pub(crate) fn bind_framebuffer_to(
1506 &self,
1507 target: u32,
1508 framebuffer: Option<&WebGLFramebuffer>,
1509 slot: &MutNullableDom<WebGLFramebuffer>,
1510 ) {
1511 match framebuffer {
1512 Some(framebuffer) => framebuffer.bind(target),
1513 None => {
1514 let cmd =
1516 WebGLCommand::BindFramebuffer(target, WebGLFramebufferBindingRequest::Default);
1517 self.send_command(cmd);
1518 },
1519 }
1520 slot.set(framebuffer);
1521 }
1522
1523 pub(crate) fn renderbuffer_storage(
1524 &self,
1525 target: u32,
1526 samples: i32,
1527 internal_format: u32,
1528 width: i32,
1529 height: i32,
1530 ) {
1531 if target != constants::RENDERBUFFER {
1532 return self.webgl_error(InvalidEnum);
1533 }
1534
1535 let max = self.limits.max_renderbuffer_size;
1536
1537 if samples < 0 || width < 0 || width as u32 > max || height < 0 || height as u32 > max {
1538 return self.webgl_error(InvalidValue);
1539 }
1540
1541 let rb = handle_potential_webgl_error!(
1542 self,
1543 self.bound_renderbuffer.get().ok_or(InvalidOperation),
1544 return
1545 );
1546 handle_potential_webgl_error!(
1547 self,
1548 rb.storage(self.api_type, samples, internal_format, width, height)
1549 );
1550 if let Some(fb) = self.bound_draw_framebuffer.get() {
1551 fb.invalidate_renderbuffer(&rb);
1552 }
1553
1554 }
1556
1557 pub(crate) fn valid_color_attachment_enum(&self, attachment: u32) -> bool {
1558 let last_slot = constants::COLOR_ATTACHMENT0 + self.limits().max_color_attachments - 1;
1559 constants::COLOR_ATTACHMENT0 <= attachment && attachment <= last_slot
1560 }
1561
1562 #[allow(clippy::too_many_arguments)]
1563 pub(crate) fn compressed_tex_image_2d(
1564 &self,
1565 target: u32,
1566 level: i32,
1567 internal_format: u32,
1568 width: i32,
1569 height: i32,
1570 border: i32,
1571 data: &[u8],
1572 ) {
1573 let validator = CompressedTexImage2DValidator::new(
1574 self,
1575 target,
1576 level,
1577 width,
1578 height,
1579 border,
1580 internal_format,
1581 data.len(),
1582 );
1583 let CommonCompressedTexImage2DValidatorResult {
1584 texture,
1585 target,
1586 level,
1587 width,
1588 height,
1589 compression,
1590 } = match validator.validate() {
1591 Ok(result) => result,
1592 Err(_) => return,
1593 };
1594
1595 if texture.is_immutable() {
1596 return self.webgl_error(InvalidOperation);
1597 }
1598
1599 let size = Size2D::new(width, height);
1600 let data = IpcSharedMemory::from_bytes(data);
1601
1602 handle_potential_webgl_error!(
1603 self,
1604 texture.initialize(
1605 target,
1606 size.width,
1607 size.height,
1608 1,
1609 compression.format,
1610 level,
1611 Some(TexDataType::UnsignedByte)
1612 )
1613 );
1614
1615 self.send_command(WebGLCommand::CompressedTexImage2D {
1616 target: target.as_gl_constant(),
1617 level,
1618 internal_format,
1619 size: Size2D::new(width, height),
1620 data: data.into(),
1621 });
1622
1623 if let Some(fb) = self.bound_draw_framebuffer.get() {
1624 fb.invalidate_texture(&texture);
1625 }
1626 }
1627
1628 #[allow(clippy::too_many_arguments)]
1629 pub(crate) fn compressed_tex_sub_image_2d(
1630 &self,
1631 target: u32,
1632 level: i32,
1633 xoffset: i32,
1634 yoffset: i32,
1635 width: i32,
1636 height: i32,
1637 format: u32,
1638 data: &[u8],
1639 ) {
1640 let validator = CompressedTexSubImage2DValidator::new(
1641 self,
1642 target,
1643 level,
1644 xoffset,
1645 yoffset,
1646 width,
1647 height,
1648 format,
1649 data.len(),
1650 );
1651 let CommonCompressedTexImage2DValidatorResult {
1652 texture: _,
1653 target,
1654 level,
1655 width,
1656 height,
1657 ..
1658 } = match validator.validate() {
1659 Ok(result) => result,
1660 Err(_) => return,
1661 };
1662
1663 let data = IpcSharedMemory::from_bytes(data);
1664
1665 self.send_command(WebGLCommand::CompressedTexSubImage2D {
1666 target: target.as_gl_constant(),
1667 level: level as i32,
1668 xoffset,
1669 yoffset,
1670 size: Size2D::new(width, height),
1671 format,
1672 data: data.into(),
1673 });
1674 }
1675
1676 pub(crate) fn uniform1iv(
1677 &self,
1678 location: Option<&WebGLUniformLocation>,
1679 val: Int32ArrayOrLongSequence,
1680 src_offset: u32,
1681 src_length: u32,
1682 ) {
1683 self.with_location(location, |location| {
1684 match location.type_() {
1685 constants::BOOL |
1686 constants::INT |
1687 constants::SAMPLER_2D |
1688 WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
1689 WebGL2RenderingContextConstants::SAMPLER_3D |
1690 constants::SAMPLER_CUBE => {},
1691 _ => return Err(InvalidOperation),
1692 }
1693
1694 let val = self.uniform_vec_section_int(val, src_offset, src_length, 1, location)?;
1695
1696 match location.type_() {
1697 constants::SAMPLER_2D |
1698 constants::SAMPLER_CUBE |
1699 WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
1700 WebGL2RenderingContextConstants::SAMPLER_3D => {
1701 for &v in val
1702 .iter()
1703 .take(cmp::min(location.size().unwrap_or(1) as usize, val.len()))
1704 {
1705 if v < 0 || v as u32 >= self.limits.max_combined_texture_image_units {
1706 return Err(InvalidValue);
1707 }
1708 }
1709 },
1710 _ => {},
1711 }
1712 self.send_command(WebGLCommand::Uniform1iv(location.id(), val));
1713 Ok(())
1714 });
1715 }
1716
1717 pub(crate) fn uniform1fv(
1718 &self,
1719 location: Option<&WebGLUniformLocation>,
1720 val: Float32ArrayOrUnrestrictedFloatSequence,
1721 src_offset: u32,
1722 src_length: u32,
1723 ) {
1724 self.with_location(location, |location| {
1725 match location.type_() {
1726 constants::BOOL | constants::FLOAT => {},
1727 _ => return Err(InvalidOperation),
1728 }
1729 let val = self.uniform_vec_section_float(val, src_offset, src_length, 1, location)?;
1730 self.send_command(WebGLCommand::Uniform1fv(location.id(), val));
1731 Ok(())
1732 });
1733 }
1734
1735 pub(crate) fn uniform2fv(
1736 &self,
1737 location: Option<&WebGLUniformLocation>,
1738 val: Float32ArrayOrUnrestrictedFloatSequence,
1739 src_offset: u32,
1740 src_length: u32,
1741 ) {
1742 self.with_location(location, |location| {
1743 match location.type_() {
1744 constants::BOOL_VEC2 | constants::FLOAT_VEC2 => {},
1745 _ => return Err(InvalidOperation),
1746 }
1747 let val = self.uniform_vec_section_float(val, src_offset, src_length, 2, location)?;
1748 self.send_command(WebGLCommand::Uniform2fv(location.id(), val));
1749 Ok(())
1750 });
1751 }
1752
1753 pub(crate) fn uniform2iv(
1754 &self,
1755 location: Option<&WebGLUniformLocation>,
1756 val: Int32ArrayOrLongSequence,
1757 src_offset: u32,
1758 src_length: u32,
1759 ) {
1760 self.with_location(location, |location| {
1761 match location.type_() {
1762 constants::BOOL_VEC2 | constants::INT_VEC2 => {},
1763 _ => return Err(InvalidOperation),
1764 }
1765 let val = self.uniform_vec_section_int(val, src_offset, src_length, 2, location)?;
1766 self.send_command(WebGLCommand::Uniform2iv(location.id(), val));
1767 Ok(())
1768 });
1769 }
1770
1771 pub(crate) fn uniform3fv(
1772 &self,
1773 location: Option<&WebGLUniformLocation>,
1774 val: Float32ArrayOrUnrestrictedFloatSequence,
1775 src_offset: u32,
1776 src_length: u32,
1777 ) {
1778 self.with_location(location, |location| {
1779 match location.type_() {
1780 constants::BOOL_VEC3 | constants::FLOAT_VEC3 => {},
1781 _ => return Err(InvalidOperation),
1782 }
1783 let val = self.uniform_vec_section_float(val, src_offset, src_length, 3, location)?;
1784 self.send_command(WebGLCommand::Uniform3fv(location.id(), val));
1785 Ok(())
1786 });
1787 }
1788
1789 pub(crate) fn uniform3iv(
1790 &self,
1791 location: Option<&WebGLUniformLocation>,
1792 val: Int32ArrayOrLongSequence,
1793 src_offset: u32,
1794 src_length: u32,
1795 ) {
1796 self.with_location(location, |location| {
1797 match location.type_() {
1798 constants::BOOL_VEC3 | constants::INT_VEC3 => {},
1799 _ => return Err(InvalidOperation),
1800 }
1801 let val = self.uniform_vec_section_int(val, src_offset, src_length, 3, location)?;
1802 self.send_command(WebGLCommand::Uniform3iv(location.id(), val));
1803 Ok(())
1804 });
1805 }
1806
1807 pub(crate) fn uniform4iv(
1808 &self,
1809 location: Option<&WebGLUniformLocation>,
1810 val: Int32ArrayOrLongSequence,
1811 src_offset: u32,
1812 src_length: u32,
1813 ) {
1814 self.with_location(location, |location| {
1815 match location.type_() {
1816 constants::BOOL_VEC4 | constants::INT_VEC4 => {},
1817 _ => return Err(InvalidOperation),
1818 }
1819 let val = self.uniform_vec_section_int(val, src_offset, src_length, 4, location)?;
1820 self.send_command(WebGLCommand::Uniform4iv(location.id(), val));
1821 Ok(())
1822 });
1823 }
1824
1825 pub(crate) fn uniform4fv(
1826 &self,
1827 location: Option<&WebGLUniformLocation>,
1828 val: Float32ArrayOrUnrestrictedFloatSequence,
1829 src_offset: u32,
1830 src_length: u32,
1831 ) {
1832 self.with_location(location, |location| {
1833 match location.type_() {
1834 constants::BOOL_VEC4 | constants::FLOAT_VEC4 => {},
1835 _ => return Err(InvalidOperation),
1836 }
1837 let val = self.uniform_vec_section_float(val, src_offset, src_length, 4, location)?;
1838 self.send_command(WebGLCommand::Uniform4fv(location.id(), val));
1839 Ok(())
1840 });
1841 }
1842
1843 pub(crate) fn uniform_matrix_2fv(
1844 &self,
1845 location: Option<&WebGLUniformLocation>,
1846 transpose: bool,
1847 val: Float32ArrayOrUnrestrictedFloatSequence,
1848 src_offset: u32,
1849 src_length: u32,
1850 ) {
1851 self.with_location(location, |location| {
1852 match location.type_() {
1853 constants::FLOAT_MAT2 => {},
1854 _ => return Err(InvalidOperation),
1855 }
1856 let val =
1857 self.uniform_matrix_section(val, src_offset, src_length, transpose, 4, location)?;
1858 self.send_command(WebGLCommand::UniformMatrix2fv(location.id(), val));
1859 Ok(())
1860 });
1861 }
1862
1863 pub(crate) fn uniform_matrix_3fv(
1864 &self,
1865 location: Option<&WebGLUniformLocation>,
1866 transpose: bool,
1867 val: Float32ArrayOrUnrestrictedFloatSequence,
1868 src_offset: u32,
1869 src_length: u32,
1870 ) {
1871 self.with_location(location, |location| {
1872 match location.type_() {
1873 constants::FLOAT_MAT3 => {},
1874 _ => return Err(InvalidOperation),
1875 }
1876 let val =
1877 self.uniform_matrix_section(val, src_offset, src_length, transpose, 9, location)?;
1878 self.send_command(WebGLCommand::UniformMatrix3fv(location.id(), val));
1879 Ok(())
1880 });
1881 }
1882
1883 pub(crate) fn uniform_matrix_4fv(
1884 &self,
1885 location: Option<&WebGLUniformLocation>,
1886 transpose: bool,
1887 val: Float32ArrayOrUnrestrictedFloatSequence,
1888 src_offset: u32,
1889 src_length: u32,
1890 ) {
1891 self.with_location(location, |location| {
1892 match location.type_() {
1893 constants::FLOAT_MAT4 => {},
1894 _ => return Err(InvalidOperation),
1895 }
1896 let val =
1897 self.uniform_matrix_section(val, src_offset, src_length, transpose, 16, location)?;
1898 self.send_command(WebGLCommand::UniformMatrix4fv(location.id(), val));
1899 Ok(())
1900 });
1901 }
1902
1903 pub(crate) fn get_buffer_param(
1904 &self,
1905 buffer: Option<DomRoot<WebGLBuffer>>,
1906 parameter: u32,
1907 mut retval: MutableHandleValue,
1908 ) {
1909 let buffer = handle_potential_webgl_error!(
1910 self,
1911 buffer.ok_or(InvalidOperation),
1912 return retval.set(NullValue())
1913 );
1914
1915 retval.set(match parameter {
1916 constants::BUFFER_SIZE => Int32Value(buffer.capacity() as i32),
1917 constants::BUFFER_USAGE => Int32Value(buffer.usage() as i32),
1918 _ => {
1919 self.webgl_error(InvalidEnum);
1920 NullValue()
1921 },
1922 })
1923 }
1924}
1925
1926impl CanvasContext for WebGLRenderingContext {
1927 type ID = WebGLContextId;
1928
1929 fn context_id(&self) -> Self::ID {
1930 self.webgl_sender.context_id()
1931 }
1932
1933 fn canvas(&self) -> Option<HTMLCanvasElementOrOffscreenCanvas> {
1934 Some(self.canvas.clone())
1935 }
1936
1937 fn resize(&self) {
1938 let size = self.size().cast();
1939 let (sender, receiver) = webgl_channel().unwrap();
1940 self.webgl_sender.send_resize(size, sender).unwrap();
1941 self.size.set(size);
1944
1945 if let Err(msg) = receiver.recv().unwrap() {
1946 error!("Error resizing WebGLContext: {}", msg);
1947 return;
1948 };
1949
1950 let color = self.current_clear_color.get();
1953 self.send_command(WebGLCommand::ClearColor(color.0, color.1, color.2, color.3));
1954
1955 let rect = self.current_scissor.get();
1960 self.send_command(WebGLCommand::Scissor(rect.0, rect.1, rect.2, rect.3));
1961
1962 if let Some(texture) = self
1967 .textures
1968 .active_texture_slot(constants::TEXTURE_2D, self.webgl_version())
1969 .unwrap()
1970 .get()
1971 {
1972 self.send_command(WebGLCommand::BindTexture(
1973 constants::TEXTURE_2D,
1974 Some(texture.id()),
1975 ));
1976 }
1977
1978 if let Some(fbo) = self.bound_draw_framebuffer.get() {
1982 let id = WebGLFramebufferBindingRequest::Explicit(fbo.id());
1983 self.send_command(WebGLCommand::BindFramebuffer(constants::FRAMEBUFFER, id));
1984 }
1985 }
1986
1987 fn reset_bitmap(&self) {
1988 warn!("The WebGLRenderingContext 'reset_bitmap' is not implemented yet");
1989 }
1990
1991 fn get_image_data(&self) -> Option<Snapshot> {
1998 handle_potential_webgl_error!(self, self.validate_framebuffer(), return None);
1999 let mut size = self.size().cast();
2000
2001 let (fb_width, fb_height) = handle_potential_webgl_error!(
2002 self,
2003 self.get_current_framebuffer_size().ok_or(InvalidOperation),
2004 return None
2005 );
2006 size.width = cmp::min(size.width, fb_width as u32);
2007 size.height = cmp::min(size.height, fb_height as u32);
2008
2009 let (sender, receiver) = ipc::channel().unwrap();
2010 self.send_command(WebGLCommand::ReadPixels(
2011 Rect::from_size(size),
2012 constants::RGBA,
2013 constants::UNSIGNED_BYTE,
2014 sender,
2015 ));
2016 let (data, alpha_mode) = receiver.recv().unwrap();
2017 Some(Snapshot::from_vec(
2018 size.cast(),
2019 SnapshotPixelFormat::RGBA,
2020 alpha_mode,
2021 data.to_vec(),
2022 ))
2023 }
2024
2025 fn mark_as_dirty(&self) {
2026 if self.bound_draw_framebuffer.get().is_some() {
2028 return;
2029 }
2030
2031 if self.global().as_window().in_immersive_xr_session() {
2034 return;
2035 }
2036
2037 match self.canvas {
2038 HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(ref canvas) => {
2039 canvas.upcast::<Node>().dirty(NodeDamage::Other);
2040 canvas.owner_document().add_dirty_webgl_canvas(self);
2041 },
2042 HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(_) => {},
2043 }
2044 }
2045
2046 fn image_key(&self) -> Option<ImageKey> {
2047 Some(self.webrender_image)
2048 }
2049}
2050
2051#[cfg(not(feature = "webgl_backtrace"))]
2052#[inline]
2053pub(crate) fn capture_webgl_backtrace<T: DomObject>(_: &T) -> WebGLCommandBacktrace {
2054 WebGLCommandBacktrace {}
2055}
2056
2057#[cfg(feature = "webgl_backtrace")]
2058#[cfg_attr(feature = "webgl_backtrace", allow(unsafe_code))]
2059pub(crate) fn capture_webgl_backtrace<T: DomObject>(obj: &T) -> WebGLCommandBacktrace {
2060 let bt = Backtrace::new();
2061 unsafe {
2062 capture_stack!(in(*obj.global().get_cx()) let stack);
2063 WebGLCommandBacktrace {
2064 backtrace: format!("{:?}", bt),
2065 js_backtrace: stack.and_then(|s| s.as_string(None, js::jsapi::StackFormat::Default)),
2066 }
2067 }
2068}
2069
2070impl Drop for WebGLRenderingContext {
2071 fn drop(&mut self) {
2072 let _ = self.webgl_sender.send_remove();
2073 }
2074}
2075
2076impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContext {
2077 fn Canvas(&self) -> HTMLCanvasElementOrOffscreenCanvas {
2079 self.canvas.clone()
2080 }
2081
2082 fn Flush(&self) {
2084 self.send_command(WebGLCommand::Flush);
2085 }
2086
2087 fn Finish(&self) {
2089 let (sender, receiver) = webgl_channel().unwrap();
2090 self.send_command(WebGLCommand::Finish(sender));
2091 receiver.recv().unwrap()
2092 }
2093
2094 fn DrawingBufferWidth(&self) -> i32 {
2096 let (sender, receiver) = webgl_channel().unwrap();
2097 self.send_command(WebGLCommand::DrawingBufferWidth(sender));
2098 receiver.recv().unwrap()
2099 }
2100
2101 fn DrawingBufferHeight(&self) -> i32 {
2103 let (sender, receiver) = webgl_channel().unwrap();
2104 self.send_command(WebGLCommand::DrawingBufferHeight(sender));
2105 receiver.recv().unwrap()
2106 }
2107
2108 fn GetBufferParameter(
2110 &self,
2111 _cx: SafeJSContext,
2112 target: u32,
2113 parameter: u32,
2114 mut retval: MutableHandleValue,
2115 ) {
2116 let buffer = handle_potential_webgl_error!(
2117 self,
2118 self.bound_buffer(target),
2119 return retval.set(NullValue())
2120 );
2121 self.get_buffer_param(buffer, parameter, retval)
2122 }
2123
2124 #[allow(unsafe_code)]
2125 fn GetParameter(&self, cx: SafeJSContext, parameter: u32, mut retval: MutableHandleValue) {
2127 if !self
2128 .extension_manager
2129 .is_get_parameter_name_enabled(parameter)
2130 {
2131 self.webgl_error(WebGLError::InvalidEnum);
2132 return retval.set(NullValue());
2133 }
2134
2135 match parameter {
2136 constants::ARRAY_BUFFER_BINDING => {
2137 self.bound_buffer_array.get().safe_to_jsval(cx, retval);
2138 return;
2139 },
2140 constants::CURRENT_PROGRAM => {
2141 self.current_program.get().safe_to_jsval(cx, retval);
2142 return;
2143 },
2144 constants::ELEMENT_ARRAY_BUFFER_BINDING => {
2145 let buffer = self.current_vao().element_array_buffer().get();
2146 buffer.safe_to_jsval(cx, retval);
2147 return;
2148 },
2149 constants::FRAMEBUFFER_BINDING => {
2150 self.bound_draw_framebuffer.get().safe_to_jsval(cx, retval);
2151 return;
2152 },
2153 constants::RENDERBUFFER_BINDING => {
2154 self.bound_renderbuffer.get().safe_to_jsval(cx, retval);
2155 return;
2156 },
2157 constants::TEXTURE_BINDING_2D => {
2158 let texture = self
2159 .textures
2160 .active_texture_slot(constants::TEXTURE_2D, self.webgl_version())
2161 .unwrap()
2162 .get();
2163 texture.safe_to_jsval(cx, retval);
2164 return;
2165 },
2166 WebGL2RenderingContextConstants::TEXTURE_BINDING_2D_ARRAY => {
2167 let texture = self
2168 .textures
2169 .active_texture_slot(
2170 WebGL2RenderingContextConstants::TEXTURE_2D_ARRAY,
2171 self.webgl_version(),
2172 )
2173 .unwrap()
2174 .get();
2175 texture.safe_to_jsval(cx, retval);
2176 return;
2177 },
2178 WebGL2RenderingContextConstants::TEXTURE_BINDING_3D => {
2179 let texture = self
2180 .textures
2181 .active_texture_slot(
2182 WebGL2RenderingContextConstants::TEXTURE_3D,
2183 self.webgl_version(),
2184 )
2185 .unwrap()
2186 .get();
2187 texture.safe_to_jsval(cx, retval);
2188 return;
2189 },
2190 constants::TEXTURE_BINDING_CUBE_MAP => {
2191 let texture = self
2192 .textures
2193 .active_texture_slot(constants::TEXTURE_CUBE_MAP, self.webgl_version())
2194 .unwrap()
2195 .get();
2196 texture.safe_to_jsval(cx, retval);
2197 return;
2198 },
2199 OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES => {
2200 let vao = self.current_vao.get().filter(|vao| vao.id().is_some());
2201 vao.safe_to_jsval(cx, retval);
2202 return;
2203 },
2204 constants::IMPLEMENTATION_COLOR_READ_FORMAT => {
2210 if self.validate_framebuffer().is_err() {
2211 self.webgl_error(InvalidOperation);
2212 return retval.set(NullValue());
2213 }
2214 return retval.set(Int32Value(constants::RGBA as i32));
2215 },
2216 constants::IMPLEMENTATION_COLOR_READ_TYPE => {
2217 if self.validate_framebuffer().is_err() {
2218 self.webgl_error(InvalidOperation);
2219 return retval.set(NullValue());
2220 }
2221 return retval.set(Int32Value(constants::UNSIGNED_BYTE as i32));
2222 },
2223 constants::COMPRESSED_TEXTURE_FORMATS => unsafe {
2224 let format_ids = self.extension_manager.get_tex_compression_ids();
2225
2226 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
2227 Uint32Array::create(*cx, CreateWith::Slice(&format_ids), rval.handle_mut())
2228 .unwrap();
2229 return retval.set(ObjectValue(rval.get()));
2230 },
2231 constants::VERSION => {
2232 "WebGL 1.0".safe_to_jsval(cx, retval);
2233 return;
2234 },
2235 constants::RENDERER | constants::VENDOR => {
2236 "Mozilla/Servo".safe_to_jsval(cx, retval);
2237 return;
2238 },
2239 constants::SHADING_LANGUAGE_VERSION => {
2240 "WebGL GLSL ES 1.0".safe_to_jsval(cx, retval);
2241 return;
2242 },
2243 constants::UNPACK_FLIP_Y_WEBGL => {
2244 let unpack = self.texture_unpacking_settings.get();
2245 retval.set(BooleanValue(unpack.contains(TextureUnpacking::FLIP_Y_AXIS)));
2246 return;
2247 },
2248 constants::UNPACK_PREMULTIPLY_ALPHA_WEBGL => {
2249 let unpack = self.texture_unpacking_settings.get();
2250 retval.set(BooleanValue(
2251 unpack.contains(TextureUnpacking::PREMULTIPLY_ALPHA),
2252 ));
2253 return;
2254 },
2255 constants::PACK_ALIGNMENT => {
2256 retval.set(UInt32Value(self.texture_packing_alignment.get() as u32));
2257 return;
2258 },
2259 constants::UNPACK_ALIGNMENT => {
2260 retval.set(UInt32Value(self.texture_unpacking_alignment.get()));
2261 return;
2262 },
2263 constants::UNPACK_COLORSPACE_CONVERSION_WEBGL => {
2264 let unpack = self.texture_unpacking_settings.get();
2265 retval.set(UInt32Value(
2266 if unpack.contains(TextureUnpacking::CONVERT_COLORSPACE) {
2267 constants::BROWSER_DEFAULT_WEBGL
2268 } else {
2269 constants::NONE
2270 },
2271 ));
2272 return;
2273 },
2274 _ => {},
2275 }
2276
2277 let limit = match parameter {
2280 constants::MAX_VERTEX_ATTRIBS => Some(self.limits.max_vertex_attribs),
2281 constants::MAX_TEXTURE_SIZE => Some(self.limits.max_tex_size),
2282 constants::MAX_CUBE_MAP_TEXTURE_SIZE => Some(self.limits.max_cube_map_tex_size),
2283 constants::MAX_COMBINED_TEXTURE_IMAGE_UNITS => {
2284 Some(self.limits.max_combined_texture_image_units)
2285 },
2286 constants::MAX_FRAGMENT_UNIFORM_VECTORS => {
2287 Some(self.limits.max_fragment_uniform_vectors)
2288 },
2289 constants::MAX_RENDERBUFFER_SIZE => Some(self.limits.max_renderbuffer_size),
2290 constants::MAX_TEXTURE_IMAGE_UNITS => Some(self.limits.max_texture_image_units),
2291 constants::MAX_VARYING_VECTORS => Some(self.limits.max_varying_vectors),
2292 constants::MAX_VERTEX_TEXTURE_IMAGE_UNITS => {
2293 Some(self.limits.max_vertex_texture_image_units)
2294 },
2295 constants::MAX_VERTEX_UNIFORM_VECTORS => Some(self.limits.max_vertex_uniform_vectors),
2296 _ => None,
2297 };
2298 if let Some(limit) = limit {
2299 retval.set(UInt32Value(limit));
2300 return;
2301 }
2302
2303 if let Ok(value) = self.capabilities.is_enabled(parameter) {
2304 retval.set(BooleanValue(value));
2305 return;
2306 }
2307
2308 match handle_potential_webgl_error!(
2309 self,
2310 Parameter::from_u32(parameter),
2311 return retval.set(NullValue())
2312 ) {
2313 Parameter::Bool(param) => {
2314 let (sender, receiver) = webgl_channel().unwrap();
2315 self.send_command(WebGLCommand::GetParameterBool(param, sender));
2316 retval.set(BooleanValue(receiver.recv().unwrap()))
2317 },
2318 Parameter::Bool4(param) => {
2319 let (sender, receiver) = webgl_channel().unwrap();
2320 self.send_command(WebGLCommand::GetParameterBool4(param, sender));
2321 receiver.recv().unwrap().safe_to_jsval(cx, retval);
2322 },
2323 Parameter::Int(param) => {
2324 let (sender, receiver) = webgl_channel().unwrap();
2325 self.send_command(WebGLCommand::GetParameterInt(param, sender));
2326 retval.set(Int32Value(receiver.recv().unwrap()))
2327 },
2328 Parameter::Int2(param) => unsafe {
2329 let (sender, receiver) = webgl_channel().unwrap();
2330 self.send_command(WebGLCommand::GetParameterInt2(param, sender));
2331 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
2332 Int32Array::create(
2333 *cx,
2334 CreateWith::Slice(&receiver.recv().unwrap()),
2335 rval.handle_mut(),
2336 )
2337 .unwrap();
2338 retval.set(ObjectValue(rval.get()))
2339 },
2340 Parameter::Int4(param) => unsafe {
2341 let (sender, receiver) = webgl_channel().unwrap();
2342 self.send_command(WebGLCommand::GetParameterInt4(param, sender));
2343 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
2344 Int32Array::create(
2345 *cx,
2346 CreateWith::Slice(&receiver.recv().unwrap()),
2347 rval.handle_mut(),
2348 )
2349 .unwrap();
2350 retval.set(ObjectValue(rval.get()))
2351 },
2352 Parameter::Float(param) => {
2353 let (sender, receiver) = webgl_channel().unwrap();
2354 self.send_command(WebGLCommand::GetParameterFloat(param, sender));
2355 retval.set(DoubleValue(receiver.recv().unwrap() as f64))
2356 },
2357 Parameter::Float2(param) => unsafe {
2358 let (sender, receiver) = webgl_channel().unwrap();
2359 self.send_command(WebGLCommand::GetParameterFloat2(param, sender));
2360 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
2361 Float32Array::create(
2362 *cx,
2363 CreateWith::Slice(&receiver.recv().unwrap()),
2364 rval.handle_mut(),
2365 )
2366 .unwrap();
2367 retval.set(ObjectValue(rval.get()))
2368 },
2369 Parameter::Float4(param) => unsafe {
2370 let (sender, receiver) = webgl_channel().unwrap();
2371 self.send_command(WebGLCommand::GetParameterFloat4(param, sender));
2372 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
2373 Float32Array::create(
2374 *cx,
2375 CreateWith::Slice(&receiver.recv().unwrap()),
2376 rval.handle_mut(),
2377 )
2378 .unwrap();
2379 retval.set(ObjectValue(rval.get()))
2380 },
2381 }
2382 }
2383
2384 fn GetTexParameter(
2386 &self,
2387 _cx: SafeJSContext,
2388 target: u32,
2389 pname: u32,
2390 mut retval: MutableHandleValue,
2391 ) {
2392 let texture_slot = handle_potential_webgl_error!(
2393 self,
2394 self.textures
2395 .active_texture_slot(target, self.webgl_version()),
2396 return retval.set(NullValue())
2397 );
2398 let texture = handle_potential_webgl_error!(
2399 self,
2400 texture_slot.get().ok_or(InvalidOperation),
2401 return retval.set(NullValue())
2402 );
2403
2404 if !self
2405 .extension_manager
2406 .is_get_tex_parameter_name_enabled(pname)
2407 {
2408 self.webgl_error(InvalidEnum);
2409 return retval.set(NullValue());
2410 }
2411
2412 match pname {
2413 constants::TEXTURE_MAG_FILTER => return retval.set(UInt32Value(texture.mag_filter())),
2414 constants::TEXTURE_MIN_FILTER => return retval.set(UInt32Value(texture.min_filter())),
2415 _ => {},
2416 }
2417
2418 let texparam = handle_potential_webgl_error!(
2419 self,
2420 TexParameter::from_u32(pname),
2421 return retval.set(NullValue())
2422 );
2423 if self.webgl_version() < texparam.required_webgl_version() {
2424 self.webgl_error(InvalidEnum);
2425 return retval.set(NullValue());
2426 }
2427
2428 if let Some(value) = texture.maybe_get_tex_parameter(texparam) {
2429 match value {
2430 TexParameterValue::Float(v) => retval.set(DoubleValue(v as f64)),
2431 TexParameterValue::Int(v) => retval.set(Int32Value(v)),
2432 TexParameterValue::Bool(v) => retval.set(BooleanValue(v)),
2433 }
2434 return;
2435 }
2436
2437 match texparam {
2438 TexParameter::Float(param) => {
2439 let (sender, receiver) = webgl_channel().unwrap();
2440 self.send_command(WebGLCommand::GetTexParameterFloat(target, param, sender));
2441 retval.set(DoubleValue(receiver.recv().unwrap() as f64))
2442 },
2443 TexParameter::Int(param) => {
2444 let (sender, receiver) = webgl_channel().unwrap();
2445 self.send_command(WebGLCommand::GetTexParameterInt(target, param, sender));
2446 retval.set(Int32Value(receiver.recv().unwrap()))
2447 },
2448 TexParameter::Bool(param) => {
2449 let (sender, receiver) = webgl_channel().unwrap();
2450 self.send_command(WebGLCommand::GetTexParameterBool(target, param, sender));
2451 retval.set(BooleanValue(receiver.recv().unwrap()))
2452 },
2453 }
2454 }
2455
2456 fn GetError(&self) -> u32 {
2458 let error_code = if let Some(error) = self.last_error.get() {
2459 match error {
2460 WebGLError::InvalidEnum => constants::INVALID_ENUM,
2461 WebGLError::InvalidFramebufferOperation => constants::INVALID_FRAMEBUFFER_OPERATION,
2462 WebGLError::InvalidValue => constants::INVALID_VALUE,
2463 WebGLError::InvalidOperation => constants::INVALID_OPERATION,
2464 WebGLError::OutOfMemory => constants::OUT_OF_MEMORY,
2465 WebGLError::ContextLost => constants::CONTEXT_LOST_WEBGL,
2466 }
2467 } else {
2468 constants::NO_ERROR
2469 };
2470 self.last_error.set(None);
2471 error_code
2472 }
2473
2474 fn GetContextAttributes(&self) -> Option<WebGLContextAttributes> {
2476 let (sender, receiver) = webgl_channel().unwrap();
2477
2478 let backtrace = capture_webgl_backtrace(self);
2480 if self
2481 .webgl_sender
2482 .send(WebGLCommand::GetContextAttributes(sender), backtrace)
2483 .is_err()
2484 {
2485 return None;
2486 }
2487
2488 let attrs = receiver.recv().unwrap();
2489
2490 Some(WebGLContextAttributes {
2491 alpha: attrs.alpha,
2492 antialias: attrs.antialias,
2493 depth: attrs.depth,
2494 failIfMajorPerformanceCaveat: false,
2495 preferLowPowerToHighPerformance: false,
2496 premultipliedAlpha: attrs.premultiplied_alpha,
2497 preserveDrawingBuffer: attrs.preserve_drawing_buffer,
2498 stencil: attrs.stencil,
2499 })
2500 }
2501
2502 fn IsContextLost(&self) -> bool {
2504 false
2505 }
2506
2507 fn GetSupportedExtensions(&self) -> Option<Vec<DOMString>> {
2509 self.extension_manager
2510 .init_once(|| self.get_gl_extensions());
2511 let extensions = self.extension_manager.get_supported_extensions();
2512 Some(
2513 extensions
2514 .iter()
2515 .map(|name| DOMString::from(*name))
2516 .collect(),
2517 )
2518 }
2519
2520 fn GetExtension(&self, _cx: SafeJSContext, name: DOMString) -> Option<NonNull<JSObject>> {
2522 self.extension_manager
2523 .init_once(|| self.get_gl_extensions());
2524 self.extension_manager.get_or_init_extension(&name, self)
2525 }
2526
2527 fn ActiveTexture(&self, texture: u32) {
2529 handle_potential_webgl_error!(self, self.textures.set_active_unit_enum(texture), return);
2530 self.send_command(WebGLCommand::ActiveTexture(texture));
2531 }
2532
2533 fn BlendColor(&self, r: f32, g: f32, b: f32, a: f32) {
2535 self.send_command(WebGLCommand::BlendColor(r, g, b, a));
2536 }
2537
2538 fn BlendEquation(&self, mode: u32) {
2540 handle_potential_webgl_error!(self, self.validate_blend_mode(mode), return);
2541 self.send_command(WebGLCommand::BlendEquation(mode))
2542 }
2543
2544 fn BlendEquationSeparate(&self, mode_rgb: u32, mode_alpha: u32) {
2546 handle_potential_webgl_error!(self, self.validate_blend_mode(mode_rgb), return);
2547 handle_potential_webgl_error!(self, self.validate_blend_mode(mode_alpha), return);
2548 self.send_command(WebGLCommand::BlendEquationSeparate(mode_rgb, mode_alpha));
2549 }
2550
2551 fn BlendFunc(&self, src_factor: u32, dest_factor: u32) {
2553 if has_invalid_blend_constants(src_factor, dest_factor) {
2559 return self.webgl_error(InvalidOperation);
2560 }
2561 if has_invalid_blend_constants(dest_factor, src_factor) {
2562 return self.webgl_error(InvalidOperation);
2563 }
2564
2565 self.send_command(WebGLCommand::BlendFunc(src_factor, dest_factor));
2566 }
2567
2568 fn BlendFuncSeparate(&self, src_rgb: u32, dest_rgb: u32, src_alpha: u32, dest_alpha: u32) {
2570 if has_invalid_blend_constants(src_rgb, dest_rgb) {
2576 return self.webgl_error(InvalidOperation);
2577 }
2578 if has_invalid_blend_constants(dest_rgb, src_rgb) {
2579 return self.webgl_error(InvalidOperation);
2580 }
2581
2582 self.send_command(WebGLCommand::BlendFuncSeparate(
2583 src_rgb, dest_rgb, src_alpha, dest_alpha,
2584 ));
2585 }
2586
2587 fn AttachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
2589 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
2590 handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
2591 handle_potential_webgl_error!(self, program.attach_shader(shader));
2592 }
2593
2594 fn DetachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
2596 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
2597 handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
2598 handle_potential_webgl_error!(self, program.detach_shader(shader));
2599 }
2600
2601 fn BindAttribLocation(&self, program: &WebGLProgram, index: u32, name: DOMString) {
2603 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
2604 handle_potential_webgl_error!(self, program.bind_attrib_location(index, name));
2605 }
2606
2607 fn BindBuffer(&self, target: u32, buffer: Option<&WebGLBuffer>) {
2609 let current_vao;
2610 let slot = match target {
2611 constants::ARRAY_BUFFER => &self.bound_buffer_array,
2612 constants::ELEMENT_ARRAY_BUFFER => {
2613 current_vao = self.current_vao();
2614 current_vao.element_array_buffer()
2615 },
2616 _ => return self.webgl_error(InvalidEnum),
2617 };
2618 self.bind_buffer_maybe(slot, target, buffer);
2619 }
2620
2621 fn BindFramebuffer(&self, target: u32, framebuffer: Option<&WebGLFramebuffer>) {
2623 handle_potential_webgl_error!(
2624 self,
2625 self.validate_new_framebuffer_binding(framebuffer),
2626 return
2627 );
2628
2629 if target != constants::FRAMEBUFFER {
2630 return self.webgl_error(InvalidEnum);
2631 }
2632
2633 self.bind_framebuffer_to(target, framebuffer, &self.bound_draw_framebuffer)
2634 }
2635
2636 fn BindRenderbuffer(&self, target: u32, renderbuffer: Option<&WebGLRenderbuffer>) {
2638 if let Some(rb) = renderbuffer {
2639 handle_potential_webgl_error!(self, self.validate_ownership(rb), return);
2640 }
2641
2642 if target != constants::RENDERBUFFER {
2643 return self.webgl_error(InvalidEnum);
2644 }
2645
2646 match renderbuffer {
2647 Some(renderbuffer) if !renderbuffer.is_deleted() => {
2651 self.bound_renderbuffer.set(Some(renderbuffer));
2652 renderbuffer.bind(target);
2653 },
2654 _ => {
2655 if renderbuffer.is_some() {
2656 self.webgl_error(InvalidOperation);
2657 }
2658
2659 self.bound_renderbuffer.set(None);
2660 self.send_command(WebGLCommand::BindRenderbuffer(target, None));
2662 },
2663 }
2664 }
2665
2666 fn BindTexture(&self, target: u32, texture: Option<&WebGLTexture>) {
2668 if let Some(texture) = texture {
2669 handle_potential_webgl_error!(self, self.validate_ownership(texture), return);
2670 }
2671
2672 let texture_slot = handle_potential_webgl_error!(
2673 self,
2674 self.textures
2675 .active_texture_slot(target, self.webgl_version()),
2676 return
2677 );
2678
2679 if let Some(texture) = texture {
2680 handle_potential_webgl_error!(self, texture.bind(target), return);
2681 } else {
2682 self.send_command(WebGLCommand::BindTexture(target, None));
2683 }
2684 texture_slot.set(texture);
2685 }
2686
2687 fn GenerateMipmap(&self, target: u32) {
2689 let texture_slot = handle_potential_webgl_error!(
2690 self,
2691 self.textures
2692 .active_texture_slot(target, self.webgl_version()),
2693 return
2694 );
2695 let texture =
2696 handle_potential_webgl_error!(self, texture_slot.get().ok_or(InvalidOperation), return);
2697 handle_potential_webgl_error!(self, texture.generate_mipmap());
2698 }
2699
2700 fn BufferData_(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
2702 let usage = handle_potential_webgl_error!(self, self.buffer_usage(usage), return);
2703 let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
2704 self.buffer_data(target, data, usage, bound_buffer)
2705 }
2706
2707 fn BufferData(&self, target: u32, size: i64, usage: u32) {
2709 let usage = handle_potential_webgl_error!(self, self.buffer_usage(usage), return);
2710 let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
2711 self.buffer_data_(target, size, usage, bound_buffer)
2712 }
2713
2714 #[allow(unsafe_code)]
2716 fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
2717 let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
2718 self.buffer_sub_data(target, offset, data, bound_buffer)
2719 }
2720
2721 #[allow(unsafe_code)]
2723 fn CompressedTexImage2D(
2724 &self,
2725 target: u32,
2726 level: i32,
2727 internal_format: u32,
2728 width: i32,
2729 height: i32,
2730 border: i32,
2731 data: CustomAutoRooterGuard<ArrayBufferView>,
2732 ) {
2733 let data = unsafe { data.as_slice() };
2734 self.compressed_tex_image_2d(target, level, internal_format, width, height, border, data)
2735 }
2736
2737 #[allow(unsafe_code)]
2739 fn CompressedTexSubImage2D(
2740 &self,
2741 target: u32,
2742 level: i32,
2743 xoffset: i32,
2744 yoffset: i32,
2745 width: i32,
2746 height: i32,
2747 format: u32,
2748 data: CustomAutoRooterGuard<ArrayBufferView>,
2749 ) {
2750 let data = unsafe { data.as_slice() };
2751 self.compressed_tex_sub_image_2d(
2752 target, level, xoffset, yoffset, width, height, format, data,
2753 )
2754 }
2755
2756 fn CopyTexImage2D(
2758 &self,
2759 target: u32,
2760 level: i32,
2761 internal_format: u32,
2762 x: i32,
2763 y: i32,
2764 width: i32,
2765 height: i32,
2766 border: i32,
2767 ) {
2768 handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
2769
2770 let validator = CommonTexImage2DValidator::new(
2771 self,
2772 target,
2773 level,
2774 internal_format,
2775 width,
2776 height,
2777 border,
2778 );
2779 let CommonTexImage2DValidatorResult {
2780 texture,
2781 target,
2782 level,
2783 internal_format,
2784 width,
2785 height,
2786 border,
2787 } = match validator.validate() {
2788 Ok(result) => result,
2789 Err(_) => return,
2790 };
2791
2792 if texture.is_immutable() {
2793 return self.webgl_error(InvalidOperation);
2794 }
2795
2796 let framebuffer_format = match self.bound_draw_framebuffer.get() {
2797 Some(fb) => match fb.attachment(constants::COLOR_ATTACHMENT0) {
2798 Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => {
2799 TexFormat::from_gl_constant(rb.internal_format())
2800 },
2801 Some(WebGLFramebufferAttachmentRoot::Texture(texture)) => texture
2802 .image_info_for_target(&target, 0)
2803 .map(|info| info.internal_format()),
2804 None => None,
2805 },
2806 None => {
2807 let attrs = self.GetContextAttributes().unwrap();
2808 Some(if attrs.alpha {
2809 TexFormat::RGBA
2810 } else {
2811 TexFormat::RGB
2812 })
2813 },
2814 };
2815
2816 let framebuffer_format = match framebuffer_format {
2817 Some(f) => f,
2818 None => {
2819 self.webgl_error(InvalidOperation);
2820 return;
2821 },
2822 };
2823
2824 match (framebuffer_format, internal_format) {
2825 (a, b) if a == b => (),
2826 (TexFormat::RGBA, TexFormat::RGB) => (),
2827 (TexFormat::RGBA, TexFormat::Alpha) => (),
2828 (TexFormat::RGBA, TexFormat::Luminance) => (),
2829 (TexFormat::RGBA, TexFormat::LuminanceAlpha) => (),
2830 (TexFormat::RGB, TexFormat::Luminance) => (),
2831 _ => {
2832 self.webgl_error(InvalidOperation);
2833 return;
2834 },
2835 }
2836
2837 handle_potential_webgl_error!(
2839 self,
2840 texture.initialize(target, width, height, 1, internal_format, level, None)
2841 );
2842
2843 let msg = WebGLCommand::CopyTexImage2D(
2844 target.as_gl_constant(),
2845 level as i32,
2846 internal_format.as_gl_constant(),
2847 x,
2848 y,
2849 width as i32,
2850 height as i32,
2851 border as i32,
2852 );
2853
2854 self.send_command(msg);
2855 }
2856
2857 fn CopyTexSubImage2D(
2859 &self,
2860 target: u32,
2861 level: i32,
2862 xoffset: i32,
2863 yoffset: i32,
2864 x: i32,
2865 y: i32,
2866 width: i32,
2867 height: i32,
2868 ) {
2869 handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
2870
2871 let validator = CommonTexImage2DValidator::new(
2874 self,
2875 target,
2876 level,
2877 TexFormat::RGBA.as_gl_constant(),
2878 width,
2879 height,
2880 0,
2881 );
2882 let CommonTexImage2DValidatorResult {
2883 texture,
2884 target,
2885 level,
2886 width,
2887 height,
2888 ..
2889 } = match validator.validate() {
2890 Ok(result) => result,
2891 Err(_) => return,
2892 };
2893
2894 let image_info = match texture.image_info_for_target(&target, level) {
2895 Some(info) => info,
2896 None => return self.webgl_error(InvalidOperation),
2897 };
2898
2899 if xoffset < 0 ||
2904 (xoffset as u32 + width) > image_info.width() ||
2905 yoffset < 0 ||
2906 (yoffset as u32 + height) > image_info.height()
2907 {
2908 self.webgl_error(InvalidValue);
2909 return;
2910 }
2911
2912 let msg = WebGLCommand::CopyTexSubImage2D(
2913 target.as_gl_constant(),
2914 level as i32,
2915 xoffset,
2916 yoffset,
2917 x,
2918 y,
2919 width as i32,
2920 height as i32,
2921 );
2922
2923 self.send_command(msg);
2924 }
2925
2926 fn Clear(&self, mask: u32) {
2928 handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
2929 if mask &
2930 !(constants::DEPTH_BUFFER_BIT |
2931 constants::STENCIL_BUFFER_BIT |
2932 constants::COLOR_BUFFER_BIT) !=
2933 0
2934 {
2935 return self.webgl_error(InvalidValue);
2936 }
2937
2938 self.send_command(WebGLCommand::Clear(mask));
2939 self.mark_as_dirty();
2940 }
2941
2942 fn ClearColor(&self, red: f32, green: f32, blue: f32, alpha: f32) {
2944 self.current_clear_color.set((red, green, blue, alpha));
2945 self.send_command(WebGLCommand::ClearColor(red, green, blue, alpha));
2946 }
2947
2948 fn ClearDepth(&self, depth: f32) {
2950 self.send_command(WebGLCommand::ClearDepth(depth))
2951 }
2952
2953 fn ClearStencil(&self, stencil: i32) {
2955 self.send_command(WebGLCommand::ClearStencil(stencil))
2956 }
2957
2958 fn ColorMask(&self, r: bool, g: bool, b: bool, a: bool) {
2960 self.send_command(WebGLCommand::ColorMask(r, g, b, a))
2961 }
2962
2963 fn CullFace(&self, mode: u32) {
2965 match mode {
2966 constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => {
2967 self.send_command(WebGLCommand::CullFace(mode))
2968 },
2969 _ => self.webgl_error(InvalidEnum),
2970 }
2971 }
2972
2973 fn FrontFace(&self, mode: u32) {
2975 match mode {
2976 constants::CW | constants::CCW => self.send_command(WebGLCommand::FrontFace(mode)),
2977 _ => self.webgl_error(InvalidEnum),
2978 }
2979 }
2980 fn DepthFunc(&self, func: u32) {
2982 match func {
2983 constants::NEVER |
2984 constants::LESS |
2985 constants::EQUAL |
2986 constants::LEQUAL |
2987 constants::GREATER |
2988 constants::NOTEQUAL |
2989 constants::GEQUAL |
2990 constants::ALWAYS => self.send_command(WebGLCommand::DepthFunc(func)),
2991 _ => self.webgl_error(InvalidEnum),
2992 }
2993 }
2994
2995 fn DepthMask(&self, flag: bool) {
2997 self.send_command(WebGLCommand::DepthMask(flag))
2998 }
2999
3000 fn DepthRange(&self, near: f32, far: f32) {
3002 if near > far {
3004 return self.webgl_error(InvalidOperation);
3005 }
3006 self.send_command(WebGLCommand::DepthRange(near, far))
3007 }
3008
3009 fn Enable(&self, cap: u32) {
3011 if handle_potential_webgl_error!(self, self.capabilities.set(cap, true), return) {
3012 self.send_command(WebGLCommand::Enable(cap));
3013 }
3014 }
3015
3016 fn Disable(&self, cap: u32) {
3018 if handle_potential_webgl_error!(self, self.capabilities.set(cap, false), return) {
3019 self.send_command(WebGLCommand::Disable(cap));
3020 }
3021 }
3022
3023 fn CompileShader(&self, shader: &WebGLShader) {
3025 handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
3026 handle_potential_webgl_error!(
3027 self,
3028 shader.compile(
3029 self.api_type,
3030 self.webgl_version,
3031 self.glsl_version,
3032 &self.limits,
3033 &self.extension_manager,
3034 )
3035 )
3036 }
3037
3038 fn CreateBuffer(&self) -> Option<DomRoot<WebGLBuffer>> {
3040 WebGLBuffer::maybe_new(self, CanGc::note())
3041 }
3042
3043 fn CreateFramebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
3045 WebGLFramebuffer::maybe_new(self, CanGc::note())
3046 }
3047
3048 fn CreateRenderbuffer(&self) -> Option<DomRoot<WebGLRenderbuffer>> {
3050 WebGLRenderbuffer::maybe_new(self)
3051 }
3052
3053 fn CreateTexture(&self) -> Option<DomRoot<WebGLTexture>> {
3055 WebGLTexture::maybe_new(self)
3056 }
3057
3058 fn CreateProgram(&self) -> Option<DomRoot<WebGLProgram>> {
3060 WebGLProgram::maybe_new(self, CanGc::note())
3061 }
3062
3063 fn CreateShader(&self, shader_type: u32) -> Option<DomRoot<WebGLShader>> {
3065 match shader_type {
3066 constants::VERTEX_SHADER | constants::FRAGMENT_SHADER => {},
3067 _ => {
3068 self.webgl_error(InvalidEnum);
3069 return None;
3070 },
3071 }
3072 WebGLShader::maybe_new(self, shader_type)
3073 }
3074
3075 fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) {
3077 let buffer = match buffer {
3078 Some(buffer) => buffer,
3079 None => return,
3080 };
3081 handle_potential_webgl_error!(self, self.validate_ownership(buffer), return);
3082 if buffer.is_marked_for_deletion() {
3083 return;
3084 }
3085 self.current_vao().unbind_buffer(buffer);
3086 if self.bound_buffer_array.get().is_some_and(|b| buffer == &*b) {
3087 self.bound_buffer_array.set(None);
3088 buffer.decrement_attached_counter(Operation::Infallible);
3089 }
3090 buffer.mark_for_deletion(Operation::Infallible);
3091 }
3092
3093 fn DeleteFramebuffer(&self, framebuffer: Option<&WebGLFramebuffer>) {
3095 if let Some(framebuffer) = framebuffer {
3096 handle_potential_webgl_error!(self, framebuffer.validate_transparent(), return);
3100 handle_potential_webgl_error!(self, self.validate_ownership(framebuffer), return);
3101 handle_object_deletion!(
3102 self,
3103 self.bound_draw_framebuffer,
3104 framebuffer,
3105 Some(WebGLCommand::BindFramebuffer(
3106 framebuffer.target().unwrap(),
3107 WebGLFramebufferBindingRequest::Default
3108 ))
3109 );
3110 framebuffer.delete(Operation::Infallible)
3111 }
3112 }
3113
3114 fn DeleteRenderbuffer(&self, renderbuffer: Option<&WebGLRenderbuffer>) {
3116 if let Some(renderbuffer) = renderbuffer {
3117 handle_potential_webgl_error!(self, self.validate_ownership(renderbuffer), return);
3118 handle_object_deletion!(
3119 self,
3120 self.bound_renderbuffer,
3121 renderbuffer,
3122 Some(WebGLCommand::BindRenderbuffer(
3123 constants::RENDERBUFFER,
3124 None
3125 ))
3126 );
3127 renderbuffer.delete(Operation::Infallible)
3128 }
3129 }
3130
3131 fn DeleteTexture(&self, texture: Option<&WebGLTexture>) {
3133 if let Some(texture) = texture {
3134 handle_potential_webgl_error!(self, self.validate_ownership(texture), return);
3135
3136 let mut active_unit_enum = self.textures.active_unit_enum();
3145 for (unit_enum, slot) in self.textures.iter() {
3146 if let Some(target) = slot.unbind(texture) {
3147 if unit_enum != active_unit_enum {
3148 self.send_command(WebGLCommand::ActiveTexture(unit_enum));
3149 active_unit_enum = unit_enum;
3150 }
3151 self.send_command(WebGLCommand::BindTexture(target, None));
3152 }
3153 }
3154
3155 if active_unit_enum != self.textures.active_unit_enum() {
3157 self.send_command(WebGLCommand::ActiveTexture(
3158 self.textures.active_unit_enum(),
3159 ));
3160 }
3161
3162 texture.delete(Operation::Infallible)
3163 }
3164 }
3165
3166 fn DeleteProgram(&self, program: Option<&WebGLProgram>) {
3168 if let Some(program) = program {
3169 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
3170 program.mark_for_deletion(Operation::Infallible)
3171 }
3172 }
3173
3174 fn DeleteShader(&self, shader: Option<&WebGLShader>) {
3176 if let Some(shader) = shader {
3177 handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
3178 shader.mark_for_deletion(Operation::Infallible)
3179 }
3180 }
3181
3182 fn DrawArrays(&self, mode: u32, first: i32, count: i32) {
3184 handle_potential_webgl_error!(self, self.draw_arrays_instanced(mode, first, count, 1));
3185 }
3186
3187 fn DrawElements(&self, mode: u32, count: i32, type_: u32, offset: i64) {
3189 handle_potential_webgl_error!(
3190 self,
3191 self.draw_elements_instanced(mode, count, type_, offset, 1)
3192 );
3193 }
3194
3195 fn EnableVertexAttribArray(&self, attrib_id: u32) {
3197 if attrib_id >= self.limits.max_vertex_attribs {
3198 return self.webgl_error(InvalidValue);
3199 }
3200 match self.webgl_version() {
3201 WebGLVersion::WebGL1 => self
3202 .current_vao()
3203 .enabled_vertex_attrib_array(attrib_id, true),
3204 WebGLVersion::WebGL2 => self
3205 .current_vao_webgl2()
3206 .enabled_vertex_attrib_array(attrib_id, true),
3207 };
3208 self.send_command(WebGLCommand::EnableVertexAttribArray(attrib_id));
3209 }
3210
3211 fn DisableVertexAttribArray(&self, attrib_id: u32) {
3213 if attrib_id >= self.limits.max_vertex_attribs {
3214 return self.webgl_error(InvalidValue);
3215 }
3216 match self.webgl_version() {
3217 WebGLVersion::WebGL1 => self
3218 .current_vao()
3219 .enabled_vertex_attrib_array(attrib_id, false),
3220 WebGLVersion::WebGL2 => self
3221 .current_vao_webgl2()
3222 .enabled_vertex_attrib_array(attrib_id, false),
3223 };
3224 self.send_command(WebGLCommand::DisableVertexAttribArray(attrib_id));
3225 }
3226
3227 fn GetActiveUniform(
3229 &self,
3230 program: &WebGLProgram,
3231 index: u32,
3232 ) -> Option<DomRoot<WebGLActiveInfo>> {
3233 handle_potential_webgl_error!(self, self.validate_ownership(program), return None);
3234 match program.get_active_uniform(index, CanGc::note()) {
3235 Ok(ret) => Some(ret),
3236 Err(e) => {
3237 self.webgl_error(e);
3238 None
3239 },
3240 }
3241 }
3242
3243 fn GetActiveAttrib(
3245 &self,
3246 program: &WebGLProgram,
3247 index: u32,
3248 ) -> Option<DomRoot<WebGLActiveInfo>> {
3249 handle_potential_webgl_error!(self, self.validate_ownership(program), return None);
3250 handle_potential_webgl_error!(
3251 self,
3252 program.get_active_attrib(index, CanGc::note()).map(Some),
3253 None
3254 )
3255 }
3256
3257 fn GetAttribLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
3259 handle_potential_webgl_error!(self, self.validate_ownership(program), return -1);
3260 handle_potential_webgl_error!(self, program.get_attrib_location(name), -1)
3261 }
3262
3263 fn GetFramebufferAttachmentParameter(
3265 &self,
3266 cx: SafeJSContext,
3267 target: u32,
3268 attachment: u32,
3269 pname: u32,
3270 mut retval: MutableHandleValue,
3271 ) {
3272 if let Some(fb) = self.bound_draw_framebuffer.get() {
3274 handle_potential_webgl_error!(
3277 self,
3278 fb.validate_transparent(),
3279 return retval.set(NullValue())
3280 );
3281 } else {
3282 self.webgl_error(InvalidOperation);
3283 return retval.set(NullValue());
3284 }
3285
3286 let target_matches = match target {
3288 constants::FRAMEBUFFER => true,
3291 _ => false,
3292 };
3293 let attachment_matches = match attachment {
3294 constants::COLOR_ATTACHMENT0 |
3297 constants::DEPTH_STENCIL_ATTACHMENT |
3298 constants::DEPTH_ATTACHMENT |
3299 constants::STENCIL_ATTACHMENT => true,
3300 _ => false,
3301 };
3302 let pname_matches = match pname {
3303 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME |
3313 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE |
3314 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE |
3315 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL => true,
3316 _ => false,
3317 };
3318
3319 let bound_attachment_matches = match self
3320 .bound_draw_framebuffer
3321 .get()
3322 .unwrap()
3323 .attachment(attachment)
3324 {
3325 Some(attachment_root) => match attachment_root {
3326 WebGLFramebufferAttachmentRoot::Renderbuffer(_) => matches!(
3327 pname,
3328 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE |
3329 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME
3330 ),
3331 WebGLFramebufferAttachmentRoot::Texture(_) => matches!(
3332 pname,
3333 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE |
3334 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME |
3335 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL |
3336 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE
3337 ),
3338 },
3339 _ => matches!(pname, constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE),
3340 };
3341
3342 if !target_matches || !attachment_matches || !pname_matches || !bound_attachment_matches {
3343 self.webgl_error(InvalidEnum);
3344 return retval.set(NullValue());
3345 }
3346
3347 if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME {
3354 let fb = self.bound_draw_framebuffer.get().unwrap();
3357 if let Some(webgl_attachment) = fb.attachment(attachment) {
3358 match webgl_attachment {
3359 WebGLFramebufferAttachmentRoot::Renderbuffer(rb) => {
3360 rb.safe_to_jsval(cx, retval);
3361 return;
3362 },
3363 WebGLFramebufferAttachmentRoot::Texture(texture) => {
3364 texture.safe_to_jsval(cx, retval);
3365 return;
3366 },
3367 }
3368 }
3369 self.webgl_error(InvalidEnum);
3370 return retval.set(NullValue());
3371 }
3372
3373 let (sender, receiver) = webgl_channel().unwrap();
3374 self.send_command(WebGLCommand::GetFramebufferAttachmentParameter(
3375 target, attachment, pname, sender,
3376 ));
3377
3378 retval.set(Int32Value(receiver.recv().unwrap()))
3379 }
3380
3381 fn GetRenderbufferParameter(
3383 &self,
3384 _cx: SafeJSContext,
3385 target: u32,
3386 pname: u32,
3387 mut retval: MutableHandleValue,
3388 ) {
3389 let target_matches = target == constants::RENDERBUFFER;
3392
3393 let pname_matches = matches!(
3394 pname,
3395 constants::RENDERBUFFER_WIDTH |
3396 constants::RENDERBUFFER_HEIGHT |
3397 constants::RENDERBUFFER_INTERNAL_FORMAT |
3398 constants::RENDERBUFFER_RED_SIZE |
3399 constants::RENDERBUFFER_GREEN_SIZE |
3400 constants::RENDERBUFFER_BLUE_SIZE |
3401 constants::RENDERBUFFER_ALPHA_SIZE |
3402 constants::RENDERBUFFER_DEPTH_SIZE |
3403 constants::RENDERBUFFER_STENCIL_SIZE
3404 );
3405
3406 if !target_matches || !pname_matches {
3407 self.webgl_error(InvalidEnum);
3408 return retval.set(NullValue());
3409 }
3410
3411 if self.bound_renderbuffer.get().is_none() {
3412 self.webgl_error(InvalidOperation);
3413 return retval.set(NullValue());
3414 }
3415
3416 let result = if pname == constants::RENDERBUFFER_INTERNAL_FORMAT {
3417 let rb = self.bound_renderbuffer.get().unwrap();
3418 rb.internal_format() as i32
3419 } else {
3420 let (sender, receiver) = webgl_channel().unwrap();
3421 self.send_command(WebGLCommand::GetRenderbufferParameter(
3422 target, pname, sender,
3423 ));
3424 receiver.recv().unwrap()
3425 };
3426
3427 retval.set(Int32Value(result))
3428 }
3429
3430 fn GetProgramInfoLog(&self, program: &WebGLProgram) -> Option<DOMString> {
3432 handle_potential_webgl_error!(self, self.validate_ownership(program), return None);
3433 match program.get_info_log() {
3434 Ok(value) => Some(DOMString::from(value)),
3435 Err(e) => {
3436 self.webgl_error(e);
3437 None
3438 },
3439 }
3440 }
3441
3442 fn GetProgramParameter(
3444 &self,
3445 _: SafeJSContext,
3446 program: &WebGLProgram,
3447 param: u32,
3448 mut retval: MutableHandleValue,
3449 ) {
3450 handle_potential_webgl_error!(
3451 self,
3452 self.validate_ownership(program),
3453 return retval.set(NullValue())
3454 );
3455 if program.is_deleted() {
3456 self.webgl_error(InvalidOperation);
3457 return retval.set(NullValue());
3458 }
3459 retval.set(match param {
3460 constants::DELETE_STATUS => BooleanValue(program.is_marked_for_deletion()),
3461 constants::LINK_STATUS => BooleanValue(program.is_linked()),
3462 constants::VALIDATE_STATUS => {
3463 let (sender, receiver) = webgl_channel().unwrap();
3466 self.send_command(WebGLCommand::GetProgramValidateStatus(program.id(), sender));
3467 BooleanValue(receiver.recv().unwrap())
3468 },
3469 constants::ATTACHED_SHADERS => {
3470 Int32Value(
3472 program
3473 .attached_shaders()
3474 .map(|shaders| shaders.len() as i32)
3475 .unwrap_or(0),
3476 )
3477 },
3478 constants::ACTIVE_ATTRIBUTES => Int32Value(program.active_attribs().len() as i32),
3479 constants::ACTIVE_UNIFORMS => Int32Value(program.active_uniforms().len() as i32),
3480 _ => {
3481 self.webgl_error(InvalidEnum);
3482 NullValue()
3483 },
3484 })
3485 }
3486
3487 fn GetShaderInfoLog(&self, shader: &WebGLShader) -> Option<DOMString> {
3489 handle_potential_webgl_error!(self, self.validate_ownership(shader), return None);
3490 Some(shader.info_log())
3491 }
3492
3493 fn GetShaderParameter(
3495 &self,
3496 _: SafeJSContext,
3497 shader: &WebGLShader,
3498 param: u32,
3499 mut retval: MutableHandleValue,
3500 ) {
3501 handle_potential_webgl_error!(
3502 self,
3503 self.validate_ownership(shader),
3504 return retval.set(NullValue())
3505 );
3506 if shader.is_deleted() {
3507 self.webgl_error(InvalidValue);
3508 return retval.set(NullValue());
3509 }
3510 retval.set(match param {
3511 constants::DELETE_STATUS => BooleanValue(shader.is_marked_for_deletion()),
3512 constants::COMPILE_STATUS => BooleanValue(shader.successfully_compiled()),
3513 constants::SHADER_TYPE => UInt32Value(shader.gl_type()),
3514 _ => {
3515 self.webgl_error(InvalidEnum);
3516 NullValue()
3517 },
3518 })
3519 }
3520
3521 fn GetShaderPrecisionFormat(
3523 &self,
3524 shader_type: u32,
3525 precision_type: u32,
3526 ) -> Option<DomRoot<WebGLShaderPrecisionFormat>> {
3527 match shader_type {
3528 constants::FRAGMENT_SHADER | constants::VERTEX_SHADER => (),
3529 _ => {
3530 self.webgl_error(InvalidEnum);
3531 return None;
3532 },
3533 }
3534
3535 match precision_type {
3536 constants::LOW_FLOAT |
3537 constants::MEDIUM_FLOAT |
3538 constants::HIGH_FLOAT |
3539 constants::LOW_INT |
3540 constants::MEDIUM_INT |
3541 constants::HIGH_INT => (),
3542 _ => {
3543 self.webgl_error(InvalidEnum);
3544 return None;
3545 },
3546 }
3547
3548 let (sender, receiver) = webgl_channel().unwrap();
3549 self.send_command(WebGLCommand::GetShaderPrecisionFormat(
3550 shader_type,
3551 precision_type,
3552 sender,
3553 ));
3554
3555 let (range_min, range_max, precision) = receiver.recv().unwrap();
3556 Some(WebGLShaderPrecisionFormat::new(
3557 self.global().as_window(),
3558 range_min,
3559 range_max,
3560 precision,
3561 CanGc::note(),
3562 ))
3563 }
3564
3565 fn GetUniformLocation(
3567 &self,
3568 program: &WebGLProgram,
3569 name: DOMString,
3570 ) -> Option<DomRoot<WebGLUniformLocation>> {
3571 handle_potential_webgl_error!(self, self.validate_ownership(program), return None);
3572 handle_potential_webgl_error!(
3573 self,
3574 program.get_uniform_location(name, CanGc::note()),
3575 None
3576 )
3577 }
3578
3579 #[allow(unsafe_code)]
3580 fn GetVertexAttrib(
3582 &self,
3583 cx: SafeJSContext,
3584 index: u32,
3585 param: u32,
3586 mut retval: MutableHandleValue,
3587 ) {
3588 let mut get_attrib = |data: Ref<'_, VertexAttribData>| {
3589 if param == constants::CURRENT_VERTEX_ATTRIB {
3590 let attrib = self.current_vertex_attribs.borrow()[index as usize];
3591 match attrib {
3592 VertexAttrib::Float(x, y, z, w) => {
3593 let value = [x, y, z, w];
3594 unsafe {
3595 rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
3596 Float32Array::create(
3597 *cx,
3598 CreateWith::Slice(&value),
3599 result.handle_mut(),
3600 )
3601 .unwrap();
3602 return retval.set(ObjectValue(result.get()));
3603 }
3604 },
3605 VertexAttrib::Int(x, y, z, w) => {
3606 let value = [x, y, z, w];
3607 unsafe {
3608 rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
3609 Int32Array::create(*cx, CreateWith::Slice(&value), result.handle_mut())
3610 .unwrap();
3611 return retval.set(ObjectValue(result.get()));
3612 }
3613 },
3614 VertexAttrib::Uint(x, y, z, w) => {
3615 let value = [x, y, z, w];
3616 unsafe {
3617 rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
3618 Uint32Array::create(
3619 *cx,
3620 CreateWith::Slice(&value),
3621 result.handle_mut(),
3622 )
3623 .unwrap();
3624 return retval.set(ObjectValue(result.get()));
3625 }
3626 },
3627 };
3628 }
3629 if !self
3630 .extension_manager
3631 .is_get_vertex_attrib_name_enabled(param)
3632 {
3633 self.webgl_error(WebGLError::InvalidEnum);
3634 return retval.set(NullValue());
3635 }
3636
3637 match param {
3638 constants::VERTEX_ATTRIB_ARRAY_ENABLED => {
3639 retval.set(BooleanValue(data.enabled_as_array))
3640 },
3641 constants::VERTEX_ATTRIB_ARRAY_SIZE => retval.set(Int32Value(data.size as i32)),
3642 constants::VERTEX_ATTRIB_ARRAY_TYPE => retval.set(Int32Value(data.type_ as i32)),
3643 constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => {
3644 retval.set(BooleanValue(data.normalized))
3645 },
3646 constants::VERTEX_ATTRIB_ARRAY_STRIDE => retval.set(Int32Value(data.stride as i32)),
3647 constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => {
3648 if let Some(buffer) = data.buffer() {
3649 buffer.safe_to_jsval(cx, retval.reborrow());
3650 } else {
3651 retval.set(NullValue());
3652 }
3653 },
3654 ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE => {
3655 retval.set(UInt32Value(data.divisor))
3656 },
3657 _ => {
3658 self.webgl_error(InvalidEnum);
3659 retval.set(NullValue())
3660 },
3661 }
3662 };
3663
3664 match self.webgl_version() {
3665 WebGLVersion::WebGL1 => {
3666 let current_vao = self.current_vao();
3667 let data = handle_potential_webgl_error!(
3668 self,
3669 current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
3670 return retval.set(NullValue())
3671 );
3672 get_attrib(data)
3673 },
3674 WebGLVersion::WebGL2 => {
3675 let current_vao = self.current_vao_webgl2();
3676 let data = handle_potential_webgl_error!(
3677 self,
3678 current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
3679 return retval.set(NullValue())
3680 );
3681 get_attrib(data)
3682 },
3683 }
3684 }
3685
3686 fn GetVertexAttribOffset(&self, index: u32, pname: u32) -> i64 {
3688 if pname != constants::VERTEX_ATTRIB_ARRAY_POINTER {
3689 self.webgl_error(InvalidEnum);
3690 return 0;
3691 }
3692 match self.webgl_version() {
3693 WebGLVersion::WebGL1 => {
3694 let current_vao = self.current_vao();
3695 let data = handle_potential_webgl_error!(
3696 self,
3697 current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
3698 return 0
3699 );
3700 data.offset as i64
3701 },
3702 WebGLVersion::WebGL2 => {
3703 let current_vao = self.current_vao_webgl2();
3704 let data = handle_potential_webgl_error!(
3705 self,
3706 current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
3707 return 0
3708 );
3709 data.offset as i64
3710 },
3711 }
3712 }
3713
3714 fn Hint(&self, target: u32, mode: u32) {
3716 if target != constants::GENERATE_MIPMAP_HINT &&
3717 !self.extension_manager.is_hint_target_enabled(target)
3718 {
3719 return self.webgl_error(InvalidEnum);
3720 }
3721
3722 match mode {
3723 constants::FASTEST | constants::NICEST | constants::DONT_CARE => (),
3724
3725 _ => return self.webgl_error(InvalidEnum),
3726 }
3727
3728 self.send_command(WebGLCommand::Hint(target, mode));
3729 }
3730
3731 fn IsBuffer(&self, buffer: Option<&WebGLBuffer>) -> bool {
3733 buffer.is_some_and(|buf| {
3734 self.validate_ownership(buf).is_ok() && buf.target().is_some() && !buf.is_deleted()
3735 })
3736 }
3737
3738 fn IsEnabled(&self, cap: u32) -> bool {
3740 handle_potential_webgl_error!(self, self.capabilities.is_enabled(cap), false)
3741 }
3742
3743 fn IsFramebuffer(&self, frame_buffer: Option<&WebGLFramebuffer>) -> bool {
3745 frame_buffer.is_some_and(|buf| {
3746 self.validate_ownership(buf).is_ok() && buf.target().is_some() && !buf.is_deleted()
3747 })
3748 }
3749
3750 fn IsProgram(&self, program: Option<&WebGLProgram>) -> bool {
3752 program.is_some_and(|p| self.validate_ownership(p).is_ok() && !p.is_deleted())
3753 }
3754
3755 fn IsRenderbuffer(&self, render_buffer: Option<&WebGLRenderbuffer>) -> bool {
3757 render_buffer.is_some_and(|buf| {
3758 self.validate_ownership(buf).is_ok() && buf.ever_bound() && !buf.is_deleted()
3759 })
3760 }
3761
3762 fn IsShader(&self, shader: Option<&WebGLShader>) -> bool {
3764 shader.is_some_and(|s| self.validate_ownership(s).is_ok() && !s.is_deleted())
3765 }
3766
3767 fn IsTexture(&self, texture: Option<&WebGLTexture>) -> bool {
3769 texture.is_some_and(|tex| {
3770 self.validate_ownership(tex).is_ok() && tex.target().is_some() && !tex.is_invalid()
3771 })
3772 }
3773
3774 fn LineWidth(&self, width: f32) {
3776 if width.is_nan() || width <= 0f32 {
3777 return self.webgl_error(InvalidValue);
3778 }
3779
3780 self.send_command(WebGLCommand::LineWidth(width))
3781 }
3782
3783 fn PixelStorei(&self, param_name: u32, param_value: i32) {
3787 let mut texture_settings = self.texture_unpacking_settings.get();
3788 match param_name {
3789 constants::UNPACK_FLIP_Y_WEBGL => {
3790 texture_settings.set(TextureUnpacking::FLIP_Y_AXIS, param_value != 0);
3791 },
3792 constants::UNPACK_PREMULTIPLY_ALPHA_WEBGL => {
3793 texture_settings.set(TextureUnpacking::PREMULTIPLY_ALPHA, param_value != 0);
3794 },
3795 constants::UNPACK_COLORSPACE_CONVERSION_WEBGL => {
3796 let convert = match param_value as u32 {
3797 constants::BROWSER_DEFAULT_WEBGL => true,
3798 constants::NONE => false,
3799 _ => return self.webgl_error(InvalidEnum),
3800 };
3801 texture_settings.set(TextureUnpacking::CONVERT_COLORSPACE, convert);
3802 },
3803 constants::UNPACK_ALIGNMENT => {
3804 match param_value {
3805 1 | 2 | 4 | 8 => (),
3806 _ => return self.webgl_error(InvalidValue),
3807 }
3808 self.texture_unpacking_alignment.set(param_value as u32);
3809 return;
3810 },
3811 constants::PACK_ALIGNMENT => {
3812 match param_value {
3813 1 | 2 | 4 | 8 => (),
3814 _ => return self.webgl_error(InvalidValue),
3815 }
3816 self.texture_packing_alignment.set(param_value as u8);
3820 return;
3821 },
3822 _ => return self.webgl_error(InvalidEnum),
3823 }
3824 self.texture_unpacking_settings.set(texture_settings);
3825 }
3826
3827 fn PolygonOffset(&self, factor: f32, units: f32) {
3829 self.send_command(WebGLCommand::PolygonOffset(factor, units))
3830 }
3831
3832 #[allow(unsafe_code)]
3834 fn ReadPixels(
3835 &self,
3836 x: i32,
3837 y: i32,
3838 width: i32,
3839 height: i32,
3840 format: u32,
3841 pixel_type: u32,
3842 mut pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3843 ) {
3844 handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
3845
3846 let pixels =
3847 handle_potential_webgl_error!(self, pixels.as_mut().ok_or(InvalidValue), return);
3848
3849 if width < 0 || height < 0 {
3850 return self.webgl_error(InvalidValue);
3851 }
3852
3853 if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
3854 return self.webgl_error(InvalidOperation);
3855 }
3856
3857 if pixels.get_array_type() != Type::Uint8 {
3858 return self.webgl_error(InvalidOperation);
3859 }
3860
3861 let (fb_width, fb_height) = handle_potential_webgl_error!(
3862 self,
3863 self.get_current_framebuffer_size().ok_or(InvalidOperation),
3864 return
3865 );
3866
3867 if width == 0 || height == 0 {
3868 return;
3869 }
3870
3871 let bytes_per_pixel = 4;
3872
3873 let row_len = handle_potential_webgl_error!(
3874 self,
3875 width.checked_mul(bytes_per_pixel).ok_or(InvalidOperation),
3876 return
3877 );
3878
3879 let pack_alignment = self.texture_packing_alignment.get() as i32;
3880 let dest_padding = match row_len % pack_alignment {
3881 0 => 0,
3882 remainder => pack_alignment - remainder,
3883 };
3884 let dest_stride = row_len + dest_padding;
3885
3886 let full_rows_len = handle_potential_webgl_error!(
3887 self,
3888 dest_stride.checked_mul(height - 1).ok_or(InvalidOperation),
3889 return
3890 );
3891 let required_dest_len = handle_potential_webgl_error!(
3892 self,
3893 full_rows_len.checked_add(row_len).ok_or(InvalidOperation),
3894 return
3895 );
3896
3897 let dest = unsafe { pixels.as_mut_slice() };
3898 if dest.len() < required_dest_len as usize {
3899 return self.webgl_error(InvalidOperation);
3900 }
3901
3902 let src_origin = Point2D::new(x, y);
3903 let src_size = Size2D::new(width as u32, height as u32);
3904 let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
3905 let src_rect = match pixels::clip(src_origin, src_size.to_u32(), fb_size.to_u32()) {
3906 Some(rect) => rect,
3907 None => return,
3908 };
3909
3910 let src_rect = src_rect.to_u32();
3914
3915 let mut dest_offset = 0;
3916 if x < 0 {
3917 dest_offset += -x * bytes_per_pixel;
3918 }
3919 if y < 0 {
3920 dest_offset += -y * row_len;
3921 }
3922
3923 let (sender, receiver) = ipc::channel().unwrap();
3924 self.send_command(WebGLCommand::ReadPixels(
3925 src_rect, format, pixel_type, sender,
3926 ));
3927 let (src, _) = receiver.recv().unwrap();
3928
3929 let src_row_len = src_rect.size.width as usize * bytes_per_pixel as usize;
3930 for i in 0..src_rect.size.height {
3931 let dest_start = dest_offset as usize + i as usize * dest_stride as usize;
3932 let dest_end = dest_start + src_row_len;
3933 let src_start = i as usize * src_row_len;
3934 let src_end = src_start + src_row_len;
3935 dest[dest_start..dest_end].copy_from_slice(&src[src_start..src_end]);
3936 }
3937 }
3938
3939 fn SampleCoverage(&self, value: f32, invert: bool) {
3941 self.send_command(WebGLCommand::SampleCoverage(value, invert));
3942 }
3943
3944 fn Scissor(&self, x: i32, y: i32, width: i32, height: i32) {
3946 if width < 0 || height < 0 {
3947 return self.webgl_error(InvalidValue);
3948 }
3949
3950 let width = width as u32;
3951 let height = height as u32;
3952
3953 self.current_scissor.set((x, y, width, height));
3954 self.send_command(WebGLCommand::Scissor(x, y, width, height));
3955 }
3956
3957 fn StencilFunc(&self, func: u32, ref_: i32, mask: u32) {
3959 match func {
3960 constants::NEVER |
3961 constants::LESS |
3962 constants::EQUAL |
3963 constants::LEQUAL |
3964 constants::GREATER |
3965 constants::NOTEQUAL |
3966 constants::GEQUAL |
3967 constants::ALWAYS => self.send_command(WebGLCommand::StencilFunc(func, ref_, mask)),
3968 _ => self.webgl_error(InvalidEnum),
3969 }
3970 }
3971
3972 fn StencilFuncSeparate(&self, face: u32, func: u32, ref_: i32, mask: u32) {
3974 match face {
3975 constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => (),
3976 _ => return self.webgl_error(InvalidEnum),
3977 }
3978
3979 match func {
3980 constants::NEVER |
3981 constants::LESS |
3982 constants::EQUAL |
3983 constants::LEQUAL |
3984 constants::GREATER |
3985 constants::NOTEQUAL |
3986 constants::GEQUAL |
3987 constants::ALWAYS => {
3988 self.send_command(WebGLCommand::StencilFuncSeparate(face, func, ref_, mask))
3989 },
3990 _ => self.webgl_error(InvalidEnum),
3991 }
3992 }
3993
3994 fn StencilMask(&self, mask: u32) {
3996 self.send_command(WebGLCommand::StencilMask(mask))
3997 }
3998
3999 fn StencilMaskSeparate(&self, face: u32, mask: u32) {
4001 match face {
4002 constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => {
4003 self.send_command(WebGLCommand::StencilMaskSeparate(face, mask))
4004 },
4005 _ => self.webgl_error(InvalidEnum),
4006 };
4007 }
4008
4009 fn StencilOp(&self, fail: u32, zfail: u32, zpass: u32) {
4011 if self.validate_stencil_actions(fail) &&
4012 self.validate_stencil_actions(zfail) &&
4013 self.validate_stencil_actions(zpass)
4014 {
4015 self.send_command(WebGLCommand::StencilOp(fail, zfail, zpass));
4016 } else {
4017 self.webgl_error(InvalidEnum)
4018 }
4019 }
4020
4021 fn StencilOpSeparate(&self, face: u32, fail: u32, zfail: u32, zpass: u32) {
4023 match face {
4024 constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => (),
4025 _ => return self.webgl_error(InvalidEnum),
4026 }
4027
4028 if self.validate_stencil_actions(fail) &&
4029 self.validate_stencil_actions(zfail) &&
4030 self.validate_stencil_actions(zpass)
4031 {
4032 self.send_command(WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass))
4033 } else {
4034 self.webgl_error(InvalidEnum)
4035 }
4036 }
4037
4038 fn LinkProgram(&self, program: &WebGLProgram) {
4040 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
4041 if program.is_deleted() {
4042 return self.webgl_error(InvalidValue);
4043 }
4044 handle_potential_webgl_error!(self, program.link());
4045 }
4046
4047 fn ShaderSource(&self, shader: &WebGLShader, source: DOMString) {
4049 handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
4050 shader.set_source(source)
4051 }
4052
4053 fn GetShaderSource(&self, shader: &WebGLShader) -> Option<DOMString> {
4055 handle_potential_webgl_error!(self, self.validate_ownership(shader), return None);
4056 Some(shader.source())
4057 }
4058
4059 fn Uniform1f(&self, location: Option<&WebGLUniformLocation>, val: f32) {
4061 self.with_location(location, |location| {
4062 match location.type_() {
4063 constants::BOOL | constants::FLOAT => {},
4064 _ => return Err(InvalidOperation),
4065 }
4066 self.send_command(WebGLCommand::Uniform1f(location.id(), val));
4067 Ok(())
4068 });
4069 }
4070
4071 fn Uniform1i(&self, location: Option<&WebGLUniformLocation>, val: i32) {
4073 self.with_location(location, |location| {
4074 match location.type_() {
4075 constants::BOOL | constants::INT => {},
4076 constants::SAMPLER_2D |
4077 WebGL2RenderingContextConstants::SAMPLER_3D |
4078 WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
4079 constants::SAMPLER_CUBE => {
4080 if val < 0 || val as u32 >= self.limits.max_combined_texture_image_units {
4081 return Err(InvalidValue);
4082 }
4083 },
4084 _ => return Err(InvalidOperation),
4085 }
4086 self.send_command(WebGLCommand::Uniform1i(location.id(), val));
4087 Ok(())
4088 });
4089 }
4090
4091 fn Uniform1iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
4093 self.uniform1iv(location, val, 0, 0)
4094 }
4095
4096 fn Uniform1fv(
4098 &self,
4099 location: Option<&WebGLUniformLocation>,
4100 val: Float32ArrayOrUnrestrictedFloatSequence,
4101 ) {
4102 self.uniform1fv(location, val, 0, 0)
4103 }
4104
4105 fn Uniform2f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32) {
4107 self.with_location(location, |location| {
4108 match location.type_() {
4109 constants::BOOL_VEC2 | constants::FLOAT_VEC2 => {},
4110 _ => return Err(InvalidOperation),
4111 }
4112 self.send_command(WebGLCommand::Uniform2f(location.id(), x, y));
4113 Ok(())
4114 });
4115 }
4116
4117 fn Uniform2fv(
4119 &self,
4120 location: Option<&WebGLUniformLocation>,
4121 val: Float32ArrayOrUnrestrictedFloatSequence,
4122 ) {
4123 self.uniform2fv(location, val, 0, 0)
4124 }
4125
4126 fn Uniform2i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32) {
4128 self.with_location(location, |location| {
4129 match location.type_() {
4130 constants::BOOL_VEC2 | constants::INT_VEC2 => {},
4131 _ => return Err(InvalidOperation),
4132 }
4133 self.send_command(WebGLCommand::Uniform2i(location.id(), x, y));
4134 Ok(())
4135 });
4136 }
4137
4138 fn Uniform2iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
4140 self.uniform2iv(location, val, 0, 0)
4141 }
4142
4143 fn Uniform3f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32) {
4145 self.with_location(location, |location| {
4146 match location.type_() {
4147 constants::BOOL_VEC3 | constants::FLOAT_VEC3 => {},
4148 _ => return Err(InvalidOperation),
4149 }
4150 self.send_command(WebGLCommand::Uniform3f(location.id(), x, y, z));
4151 Ok(())
4152 });
4153 }
4154
4155 fn Uniform3fv(
4157 &self,
4158 location: Option<&WebGLUniformLocation>,
4159 val: Float32ArrayOrUnrestrictedFloatSequence,
4160 ) {
4161 self.uniform3fv(location, val, 0, 0)
4162 }
4163
4164 fn Uniform3i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32) {
4166 self.with_location(location, |location| {
4167 match location.type_() {
4168 constants::BOOL_VEC3 | constants::INT_VEC3 => {},
4169 _ => return Err(InvalidOperation),
4170 }
4171 self.send_command(WebGLCommand::Uniform3i(location.id(), x, y, z));
4172 Ok(())
4173 });
4174 }
4175
4176 fn Uniform3iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
4178 self.uniform3iv(location, val, 0, 0)
4179 }
4180
4181 fn Uniform4i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32, w: i32) {
4183 self.with_location(location, |location| {
4184 match location.type_() {
4185 constants::BOOL_VEC4 | constants::INT_VEC4 => {},
4186 _ => return Err(InvalidOperation),
4187 }
4188 self.send_command(WebGLCommand::Uniform4i(location.id(), x, y, z, w));
4189 Ok(())
4190 });
4191 }
4192
4193 fn Uniform4iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
4195 self.uniform4iv(location, val, 0, 0)
4196 }
4197
4198 fn Uniform4f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32, w: f32) {
4200 self.with_location(location, |location| {
4201 match location.type_() {
4202 constants::BOOL_VEC4 | constants::FLOAT_VEC4 => {},
4203 _ => return Err(InvalidOperation),
4204 }
4205 self.send_command(WebGLCommand::Uniform4f(location.id(), x, y, z, w));
4206 Ok(())
4207 });
4208 }
4209
4210 fn Uniform4fv(
4212 &self,
4213 location: Option<&WebGLUniformLocation>,
4214 val: Float32ArrayOrUnrestrictedFloatSequence,
4215 ) {
4216 self.uniform4fv(location, val, 0, 0)
4217 }
4218
4219 fn UniformMatrix2fv(
4221 &self,
4222 location: Option<&WebGLUniformLocation>,
4223 transpose: bool,
4224 val: Float32ArrayOrUnrestrictedFloatSequence,
4225 ) {
4226 self.uniform_matrix_2fv(location, transpose, val, 0, 0)
4227 }
4228
4229 fn UniformMatrix3fv(
4231 &self,
4232 location: Option<&WebGLUniformLocation>,
4233 transpose: bool,
4234 val: Float32ArrayOrUnrestrictedFloatSequence,
4235 ) {
4236 self.uniform_matrix_3fv(location, transpose, val, 0, 0)
4237 }
4238
4239 fn UniformMatrix4fv(
4241 &self,
4242 location: Option<&WebGLUniformLocation>,
4243 transpose: bool,
4244 val: Float32ArrayOrUnrestrictedFloatSequence,
4245 ) {
4246 self.uniform_matrix_4fv(location, transpose, val, 0, 0)
4247 }
4248
4249 #[allow(unsafe_code)]
4251 fn GetUniform(
4252 &self,
4253 cx: SafeJSContext,
4254 program: &WebGLProgram,
4255 location: &WebGLUniformLocation,
4256 mut rval: MutableHandleValue,
4257 ) {
4258 handle_potential_webgl_error!(
4259 self,
4260 self.uniform_check_program(program, location),
4261 return rval.set(NullValue())
4262 );
4263
4264 let triple = (self, program.id(), location.id());
4265
4266 match location.type_() {
4267 constants::BOOL => rval.set(BooleanValue(uniform_get(
4268 triple,
4269 WebGLCommand::GetUniformBool,
4270 ))),
4271 constants::BOOL_VEC2 => {
4272 uniform_get(triple, WebGLCommand::GetUniformBool2).safe_to_jsval(cx, rval)
4273 },
4274 constants::BOOL_VEC3 => {
4275 uniform_get(triple, WebGLCommand::GetUniformBool3).safe_to_jsval(cx, rval)
4276 },
4277 constants::BOOL_VEC4 => {
4278 uniform_get(triple, WebGLCommand::GetUniformBool4).safe_to_jsval(cx, rval)
4279 },
4280 constants::INT |
4281 constants::SAMPLER_2D |
4282 constants::SAMPLER_CUBE |
4283 WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
4284 WebGL2RenderingContextConstants::SAMPLER_3D => {
4285 rval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)))
4286 },
4287 constants::INT_VEC2 => unsafe {
4288 uniform_typed::<Int32>(
4289 *cx,
4290 &uniform_get(triple, WebGLCommand::GetUniformInt2),
4291 rval,
4292 )
4293 },
4294 constants::INT_VEC3 => unsafe {
4295 uniform_typed::<Int32>(
4296 *cx,
4297 &uniform_get(triple, WebGLCommand::GetUniformInt3),
4298 rval,
4299 )
4300 },
4301 constants::INT_VEC4 => unsafe {
4302 uniform_typed::<Int32>(
4303 *cx,
4304 &uniform_get(triple, WebGLCommand::GetUniformInt4),
4305 rval,
4306 )
4307 },
4308 constants::FLOAT => rval
4309 .set(DoubleValue(
4310 uniform_get(triple, WebGLCommand::GetUniformFloat) as f64,
4311 )),
4312 constants::FLOAT_VEC2 => unsafe {
4313 uniform_typed::<Float32>(
4314 *cx,
4315 &uniform_get(triple, WebGLCommand::GetUniformFloat2),
4316 rval,
4317 )
4318 },
4319 constants::FLOAT_VEC3 => unsafe {
4320 uniform_typed::<Float32>(
4321 *cx,
4322 &uniform_get(triple, WebGLCommand::GetUniformFloat3),
4323 rval,
4324 )
4325 },
4326 constants::FLOAT_VEC4 | constants::FLOAT_MAT2 => unsafe {
4327 uniform_typed::<Float32>(
4328 *cx,
4329 &uniform_get(triple, WebGLCommand::GetUniformFloat4),
4330 rval,
4331 )
4332 },
4333 constants::FLOAT_MAT3 => unsafe {
4334 uniform_typed::<Float32>(
4335 *cx,
4336 &uniform_get(triple, WebGLCommand::GetUniformFloat9),
4337 rval,
4338 )
4339 },
4340 constants::FLOAT_MAT4 => unsafe {
4341 uniform_typed::<Float32>(
4342 *cx,
4343 &uniform_get(triple, WebGLCommand::GetUniformFloat16),
4344 rval,
4345 )
4346 },
4347 _ => panic!("wrong uniform type"),
4348 }
4349 }
4350
4351 fn UseProgram(&self, program: Option<&WebGLProgram>) {
4353 if let Some(program) = program {
4354 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
4355 if program.is_deleted() || !program.is_linked() {
4356 return self.webgl_error(InvalidOperation);
4357 }
4358 if program.is_in_use() {
4359 return;
4360 }
4361 program.in_use(true);
4362 }
4363 match self.current_program.get() {
4364 Some(ref current) if program != Some(&**current) => current.in_use(false),
4365 _ => {},
4366 }
4367 self.send_command(WebGLCommand::UseProgram(program.map(|p| p.id())));
4368 self.current_program.set(program);
4369 }
4370
4371 fn ValidateProgram(&self, program: &WebGLProgram) {
4373 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
4374 if let Err(e) = program.validate() {
4375 self.webgl_error(e);
4376 }
4377 }
4378
4379 fn VertexAttrib1f(&self, indx: u32, x: f32) {
4381 self.vertex_attrib(indx, x, 0f32, 0f32, 1f32)
4382 }
4383
4384 fn VertexAttrib1fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
4386 let values = match v {
4387 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4388 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4389 };
4390 if values.is_empty() {
4391 return self.webgl_error(InvalidValue);
4393 }
4394 self.vertex_attrib(indx, values[0], 0f32, 0f32, 1f32);
4395 }
4396
4397 fn VertexAttrib2f(&self, indx: u32, x: f32, y: f32) {
4399 self.vertex_attrib(indx, x, y, 0f32, 1f32)
4400 }
4401
4402 fn VertexAttrib2fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
4404 let values = match v {
4405 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4406 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4407 };
4408 if values.len() < 2 {
4409 return self.webgl_error(InvalidValue);
4411 }
4412 self.vertex_attrib(indx, values[0], values[1], 0f32, 1f32);
4413 }
4414
4415 fn VertexAttrib3f(&self, indx: u32, x: f32, y: f32, z: f32) {
4417 self.vertex_attrib(indx, x, y, z, 1f32)
4418 }
4419
4420 fn VertexAttrib3fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
4422 let values = match v {
4423 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4424 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4425 };
4426 if values.len() < 3 {
4427 return self.webgl_error(InvalidValue);
4429 }
4430 self.vertex_attrib(indx, values[0], values[1], values[2], 1f32);
4431 }
4432
4433 fn VertexAttrib4f(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) {
4435 self.vertex_attrib(indx, x, y, z, w)
4436 }
4437
4438 fn VertexAttrib4fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
4440 let values = match v {
4441 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4442 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4443 };
4444 if values.len() < 4 {
4445 return self.webgl_error(InvalidValue);
4447 }
4448 self.vertex_attrib(indx, values[0], values[1], values[2], values[3]);
4449 }
4450
4451 fn VertexAttribPointer(
4453 &self,
4454 index: u32,
4455 size: i32,
4456 type_: u32,
4457 normalized: bool,
4458 stride: i32,
4459 offset: i64,
4460 ) {
4461 let res = match self.webgl_version() {
4462 WebGLVersion::WebGL1 => self
4463 .current_vao()
4464 .vertex_attrib_pointer(index, size, type_, normalized, stride, offset),
4465 WebGLVersion::WebGL2 => self
4466 .current_vao_webgl2()
4467 .vertex_attrib_pointer(index, size, type_, normalized, stride, offset),
4468 };
4469 handle_potential_webgl_error!(self, res);
4470 }
4471
4472 fn Viewport(&self, x: i32, y: i32, width: i32, height: i32) {
4474 if width < 0 || height < 0 {
4475 return self.webgl_error(InvalidValue);
4476 }
4477
4478 self.send_command(WebGLCommand::SetViewport(x, y, width, height))
4479 }
4480
4481 #[allow(unsafe_code)]
4483 fn TexImage2D(
4484 &self,
4485 target: u32,
4486 level: i32,
4487 internal_format: i32,
4488 width: i32,
4489 height: i32,
4490 border: i32,
4491 format: u32,
4492 data_type: u32,
4493 pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
4494 ) -> ErrorResult {
4495 if !self.extension_manager.is_tex_type_enabled(data_type) {
4496 self.webgl_error(InvalidEnum);
4497 return Ok(());
4498 }
4499
4500 let validator = TexImage2DValidator::new(
4501 self,
4502 target,
4503 level,
4504 internal_format as u32,
4505 width,
4506 height,
4507 border,
4508 format,
4509 data_type,
4510 );
4511
4512 let TexImage2DValidatorResult {
4513 texture,
4514 target,
4515 width,
4516 height,
4517 level,
4518 border,
4519 internal_format,
4520 format,
4521 data_type,
4522 } = match validator.validate() {
4523 Ok(result) => result,
4524 Err(_) => return Ok(()), };
4526
4527 if !internal_format.compatible_data_types().contains(&data_type) {
4528 return {
4529 self.webgl_error(InvalidOperation);
4530 Ok(())
4531 };
4532 }
4533 if texture.is_immutable() {
4534 return {
4535 self.webgl_error(InvalidOperation);
4536 Ok(())
4537 };
4538 }
4539
4540 let unpacking_alignment = self.texture_unpacking_alignment.get();
4541
4542 let expected_byte_length = match self.validate_tex_image_2d_data(
4543 width,
4544 height,
4545 format,
4546 data_type,
4547 unpacking_alignment,
4548 pixels.as_ref(),
4549 ) {
4550 Ok(byte_length) => byte_length,
4551 Err(()) => return Ok(()),
4552 };
4553
4554 let buff = match *pixels {
4557 None => IpcSharedMemory::from_bytes(&vec![0u8; expected_byte_length as usize]),
4558 Some(ref data) => IpcSharedMemory::from_bytes(unsafe { data.as_slice() }),
4559 };
4560
4561 if buff.len() < expected_byte_length as usize {
4568 return {
4569 self.webgl_error(InvalidOperation);
4570 Ok(())
4571 };
4572 }
4573
4574 let size = Size2D::new(width, height);
4575
4576 if !self.validate_filterable_texture(
4577 &texture,
4578 target,
4579 level,
4580 internal_format,
4581 size,
4582 data_type,
4583 ) {
4584 return Ok(());
4587 }
4588
4589 let size = Size2D::new(width, height);
4590
4591 let (alpha_treatment, y_axis_treatment) =
4592 self.get_current_unpack_state(Alpha::NotPremultiplied);
4593
4594 self.tex_image_2d(
4595 &texture,
4596 target,
4597 data_type,
4598 internal_format,
4599 format,
4600 level,
4601 border,
4602 unpacking_alignment,
4603 size,
4604 TexSource::Pixels(TexPixels::from_array(
4605 buff,
4606 size,
4607 alpha_treatment,
4608 y_axis_treatment,
4609 )),
4610 );
4611
4612 Ok(())
4613 }
4614
4615 fn TexImage2D_(
4617 &self,
4618 target: u32,
4619 level: i32,
4620 internal_format: i32,
4621 format: u32,
4622 data_type: u32,
4623 source: TexImageSource,
4624 ) -> ErrorResult {
4625 if !self.extension_manager.is_tex_type_enabled(data_type) {
4626 self.webgl_error(InvalidEnum);
4627 return Ok(());
4628 }
4629
4630 let pixels = match self.get_image_pixels(source)? {
4631 Some(pixels) => pixels,
4632 None => return Ok(()),
4633 };
4634
4635 let validator = TexImage2DValidator::new(
4636 self,
4637 target,
4638 level,
4639 internal_format as u32,
4640 pixels.size().width as i32,
4641 pixels.size().height as i32,
4642 0,
4643 format,
4644 data_type,
4645 );
4646
4647 let TexImage2DValidatorResult {
4648 texture,
4649 target,
4650 level,
4651 border,
4652 internal_format,
4653 format,
4654 data_type,
4655 ..
4656 } = match validator.validate() {
4657 Ok(result) => result,
4658 Err(_) => return Ok(()), };
4660
4661 if !internal_format.compatible_data_types().contains(&data_type) {
4662 return {
4663 self.webgl_error(InvalidOperation);
4664 Ok(())
4665 };
4666 }
4667 if texture.is_immutable() {
4668 return {
4669 self.webgl_error(InvalidOperation);
4670 Ok(())
4671 };
4672 }
4673
4674 if !self.validate_filterable_texture(
4675 &texture,
4676 target,
4677 level,
4678 internal_format,
4679 pixels.size(),
4680 data_type,
4681 ) {
4682 return Ok(());
4685 }
4686
4687 self.tex_image_2d(
4688 &texture,
4689 target,
4690 data_type,
4691 internal_format,
4692 format,
4693 level,
4694 border,
4695 1,
4696 pixels.size(),
4697 TexSource::Pixels(pixels),
4698 );
4699 Ok(())
4700 }
4701
4702 #[allow(unsafe_code)]
4704 fn TexSubImage2D(
4705 &self,
4706 target: u32,
4707 level: i32,
4708 xoffset: i32,
4709 yoffset: i32,
4710 width: i32,
4711 height: i32,
4712 format: u32,
4713 data_type: u32,
4714 pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
4715 ) -> ErrorResult {
4716 let validator = TexImage2DValidator::new(
4717 self, target, level, format, width, height, 0, format, data_type,
4718 );
4719 let TexImage2DValidatorResult {
4720 texture,
4721 target,
4722 width,
4723 height,
4724 level,
4725 format,
4726 data_type,
4727 ..
4728 } = match validator.validate() {
4729 Ok(result) => result,
4730 Err(_) => return Ok(()), };
4732
4733 let unpacking_alignment = self.texture_unpacking_alignment.get();
4734
4735 let expected_byte_length = match self.validate_tex_image_2d_data(
4736 width,
4737 height,
4738 format,
4739 data_type,
4740 unpacking_alignment,
4741 pixels.as_ref(),
4742 ) {
4743 Ok(byte_length) => byte_length,
4744 Err(()) => return Ok(()),
4745 };
4746
4747 let buff = handle_potential_webgl_error!(
4748 self,
4749 pixels
4750 .as_ref()
4751 .map(|p| IpcSharedMemory::from_bytes(unsafe { p.as_slice() }))
4752 .ok_or(InvalidValue),
4753 return Ok(())
4754 );
4755
4756 if buff.len() < expected_byte_length as usize {
4763 return {
4764 self.webgl_error(InvalidOperation);
4765 Ok(())
4766 };
4767 }
4768
4769 let (alpha_treatment, y_axis_treatment) =
4770 self.get_current_unpack_state(Alpha::NotPremultiplied);
4771
4772 self.tex_sub_image_2d(
4773 texture,
4774 target,
4775 level,
4776 xoffset,
4777 yoffset,
4778 format,
4779 data_type,
4780 unpacking_alignment,
4781 TexPixels::from_array(
4782 buff,
4783 Size2D::new(width, height),
4784 alpha_treatment,
4785 y_axis_treatment,
4786 ),
4787 );
4788 Ok(())
4789 }
4790
4791 fn TexSubImage2D_(
4793 &self,
4794 target: u32,
4795 level: i32,
4796 xoffset: i32,
4797 yoffset: i32,
4798 format: u32,
4799 data_type: u32,
4800 source: TexImageSource,
4801 ) -> ErrorResult {
4802 let pixels = match self.get_image_pixels(source)? {
4803 Some(pixels) => pixels,
4804 None => return Ok(()),
4805 };
4806
4807 let validator = TexImage2DValidator::new(
4808 self,
4809 target,
4810 level,
4811 format,
4812 pixels.size().width as i32,
4813 pixels.size().height as i32,
4814 0,
4815 format,
4816 data_type,
4817 );
4818 let TexImage2DValidatorResult {
4819 texture,
4820 target,
4821 level,
4822 format,
4823 data_type,
4824 ..
4825 } = match validator.validate() {
4826 Ok(result) => result,
4827 Err(_) => return Ok(()), };
4829
4830 self.tex_sub_image_2d(
4831 texture, target, level, xoffset, yoffset, format, data_type, 1, pixels,
4832 );
4833 Ok(())
4834 }
4835
4836 fn TexParameterf(&self, target: u32, name: u32, value: f32) {
4838 self.tex_parameter(target, name, TexParameterValue::Float(value))
4839 }
4840
4841 fn TexParameteri(&self, target: u32, name: u32, value: i32) {
4843 self.tex_parameter(target, name, TexParameterValue::Int(value))
4844 }
4845
4846 fn CheckFramebufferStatus(&self, target: u32) -> u32 {
4848 if target != constants::FRAMEBUFFER {
4854 self.webgl_error(InvalidEnum);
4855 return 0;
4856 }
4857
4858 match self.bound_draw_framebuffer.get() {
4859 Some(fb) => fb.check_status(),
4860 None => constants::FRAMEBUFFER_COMPLETE,
4861 }
4862 }
4863
4864 fn RenderbufferStorage(&self, target: u32, internal_format: u32, width: i32, height: i32) {
4866 self.renderbuffer_storage(target, 0, internal_format, width, height)
4867 }
4868
4869 fn FramebufferRenderbuffer(
4871 &self,
4872 target: u32,
4873 attachment: u32,
4874 renderbuffertarget: u32,
4875 rb: Option<&WebGLRenderbuffer>,
4876 ) {
4877 if let Some(rb) = rb {
4878 handle_potential_webgl_error!(self, self.validate_ownership(rb), return);
4879 }
4880
4881 if target != constants::FRAMEBUFFER || renderbuffertarget != constants::RENDERBUFFER {
4882 return self.webgl_error(InvalidEnum);
4883 }
4884
4885 match self.bound_draw_framebuffer.get() {
4886 Some(fb) => handle_potential_webgl_error!(self, fb.renderbuffer(attachment, rb)),
4887 None => self.webgl_error(InvalidOperation),
4888 };
4889 }
4890
4891 fn FramebufferTexture2D(
4893 &self,
4894 target: u32,
4895 attachment: u32,
4896 textarget: u32,
4897 texture: Option<&WebGLTexture>,
4898 level: i32,
4899 ) {
4900 if let Some(texture) = texture {
4901 handle_potential_webgl_error!(self, self.validate_ownership(texture), return);
4902 }
4903
4904 if target != constants::FRAMEBUFFER {
4905 return self.webgl_error(InvalidEnum);
4906 }
4907
4908 if level != 0 {
4914 return self.webgl_error(InvalidValue);
4915 }
4916
4917 match self.bound_draw_framebuffer.get() {
4918 Some(fb) => handle_potential_webgl_error!(
4919 self,
4920 fb.texture2d(attachment, textarget, texture, level)
4921 ),
4922 None => self.webgl_error(InvalidOperation),
4923 };
4924 }
4925
4926 fn GetAttachedShaders(&self, program: &WebGLProgram) -> Option<Vec<DomRoot<WebGLShader>>> {
4928 handle_potential_webgl_error!(self, self.validate_ownership(program), return None);
4929 handle_potential_webgl_error!(self, program.attached_shaders().map(Some), None)
4930 }
4931
4932 #[cfg(feature = "webxr")]
4934 fn MakeXRCompatible(&self, can_gc: CanGc) -> Rc<Promise> {
4935 let p = Promise::new(&self.global(), can_gc);
4937 p.resolve_native(&(), can_gc);
4938 p
4939 }
4940}
4941
4942impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGLRenderingContext> {
4943 fn canvas_data_source(self) -> Option<ImageKey> {
4944 (*self.unsafe_get()).layout_handle()
4945 }
4946}
4947
4948#[derive(Default, JSTraceable, MallocSizeOf)]
4949struct Capabilities {
4950 value: Cell<CapFlags>,
4951}
4952
4953impl Capabilities {
4954 fn set(&self, cap: u32, set: bool) -> WebGLResult<bool> {
4955 let cap = CapFlags::from_enum(cap)?;
4956 let mut value = self.value.get();
4957 if value.contains(cap) == set {
4958 return Ok(false);
4959 }
4960 value.set(cap, set);
4961 self.value.set(value);
4962 Ok(true)
4963 }
4964
4965 fn is_enabled(&self, cap: u32) -> WebGLResult<bool> {
4966 Ok(self.value.get().contains(CapFlags::from_enum(cap)?))
4967 }
4968}
4969
4970impl Default for CapFlags {
4971 fn default() -> Self {
4972 CapFlags::DITHER
4973 }
4974}
4975
4976macro_rules! capabilities {
4977 ($name:ident, $next:ident, $($rest:ident,)*) => {
4978 capabilities!($name, $next, $($rest,)* [$name = 1;]);
4979 };
4980 ($prev:ident, $name:ident, $($rest:ident,)* [$($tt:tt)*]) => {
4981 capabilities!($name, $($rest,)* [$($tt)* $name = Self::$prev.bits() << 1;]);
4982 };
4983 ($prev:ident, [$($name:ident = $value:expr;)*]) => {
4984 #[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
4985 pub(crate) struct CapFlags(u16);
4986
4987 bitflags! {
4988 impl CapFlags: u16 {
4989 $(const $name = $value;)*
4990 }
4991 }
4992
4993 impl CapFlags {
4994 fn from_enum(cap: u32) -> WebGLResult<Self> {
4995 match cap {
4996 $(constants::$name => Ok(Self::$name),)*
4997 _ => Err(InvalidEnum),
4998 }
4999 }
5000 }
5001 };
5002}
5003
5004capabilities! {
5005 BLEND,
5006 CULL_FACE,
5007 DEPTH_TEST,
5008 DITHER,
5009 POLYGON_OFFSET_FILL,
5010 SAMPLE_ALPHA_TO_COVERAGE,
5011 SAMPLE_COVERAGE,
5012 SCISSOR_TEST,
5013 STENCIL_TEST,
5014}
5015
5016#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
5017#[derive(JSTraceable, MallocSizeOf)]
5018pub(crate) struct Textures {
5019 active_unit: Cell<u32>,
5020 units: Box<[TextureUnit]>,
5021}
5022
5023impl Textures {
5024 fn new(max_combined_textures: u32) -> Self {
5025 Self {
5026 active_unit: Default::default(),
5027 units: (0..max_combined_textures)
5028 .map(|_| Default::default())
5029 .collect::<Vec<_>>()
5030 .into(),
5031 }
5032 }
5033
5034 pub(crate) fn active_unit_enum(&self) -> u32 {
5035 self.active_unit.get() + constants::TEXTURE0
5036 }
5037
5038 fn set_active_unit_enum(&self, index: u32) -> WebGLResult<()> {
5039 if index < constants::TEXTURE0 || (index - constants::TEXTURE0) as usize > self.units.len()
5040 {
5041 return Err(InvalidEnum);
5042 }
5043 self.active_unit.set(index - constants::TEXTURE0);
5044 Ok(())
5045 }
5046
5047 pub(crate) fn active_texture_slot(
5048 &self,
5049 target: u32,
5050 webgl_version: WebGLVersion,
5051 ) -> WebGLResult<&MutNullableDom<WebGLTexture>> {
5052 let active_unit = self.active_unit();
5053 let is_webgl2 = webgl_version == WebGLVersion::WebGL2;
5054 match target {
5055 constants::TEXTURE_2D => Ok(&active_unit.tex_2d),
5056 constants::TEXTURE_CUBE_MAP => Ok(&active_unit.tex_cube_map),
5057 WebGL2RenderingContextConstants::TEXTURE_2D_ARRAY if is_webgl2 => {
5058 Ok(&active_unit.tex_2d_array)
5059 },
5060 WebGL2RenderingContextConstants::TEXTURE_3D if is_webgl2 => Ok(&active_unit.tex_3d),
5061 _ => Err(InvalidEnum),
5062 }
5063 }
5064
5065 pub(crate) fn active_texture_for_image_target(
5066 &self,
5067 target: TexImageTarget,
5068 ) -> Option<DomRoot<WebGLTexture>> {
5069 let active_unit = self.active_unit();
5070 match target {
5071 TexImageTarget::Texture2D => active_unit.tex_2d.get(),
5072 TexImageTarget::Texture2DArray => active_unit.tex_2d_array.get(),
5073 TexImageTarget::Texture3D => active_unit.tex_3d.get(),
5074 TexImageTarget::CubeMap |
5075 TexImageTarget::CubeMapPositiveX |
5076 TexImageTarget::CubeMapNegativeX |
5077 TexImageTarget::CubeMapPositiveY |
5078 TexImageTarget::CubeMapNegativeY |
5079 TexImageTarget::CubeMapPositiveZ |
5080 TexImageTarget::CubeMapNegativeZ => active_unit.tex_cube_map.get(),
5081 }
5082 }
5083
5084 fn active_unit(&self) -> &TextureUnit {
5085 &self.units[self.active_unit.get() as usize]
5086 }
5087
5088 fn iter(&self) -> impl Iterator<Item = (u32, &TextureUnit)> {
5089 self.units
5090 .iter()
5091 .enumerate()
5092 .map(|(index, unit)| (index as u32 + constants::TEXTURE0, unit))
5093 }
5094}
5095
5096#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
5097#[derive(Default, JSTraceable, MallocSizeOf)]
5098struct TextureUnit {
5099 tex_2d: MutNullableDom<WebGLTexture>,
5100 tex_cube_map: MutNullableDom<WebGLTexture>,
5101 tex_2d_array: MutNullableDom<WebGLTexture>,
5102 tex_3d: MutNullableDom<WebGLTexture>,
5103}
5104
5105impl TextureUnit {
5106 fn unbind(&self, texture: &WebGLTexture) -> Option<u32> {
5107 let fields = [
5108 (&self.tex_2d, constants::TEXTURE_2D),
5109 (&self.tex_cube_map, constants::TEXTURE_CUBE_MAP),
5110 (
5111 &self.tex_2d_array,
5112 WebGL2RenderingContextConstants::TEXTURE_2D_ARRAY,
5113 ),
5114 (&self.tex_3d, WebGL2RenderingContextConstants::TEXTURE_3D),
5115 ];
5116 for &(slot, target) in &fields {
5117 if slot.get().is_some_and(|t| texture == &*t) {
5118 slot.set(None);
5119 return Some(target);
5120 }
5121 }
5122 None
5123 }
5124}
5125
5126pub(crate) struct TexPixels {
5127 data: IpcSharedMemory,
5128 size: Size2D<u32>,
5129 pixel_format: Option<PixelFormat>,
5130 alpha_treatment: Option<AlphaTreatment>,
5131 y_axis_treatment: YAxisTreatment,
5132}
5133
5134impl TexPixels {
5135 fn new(
5136 data: IpcSharedMemory,
5137 size: Size2D<u32>,
5138 pixel_format: PixelFormat,
5139 alpha_treatment: Option<AlphaTreatment>,
5140 y_axis_treatment: YAxisTreatment,
5141 ) -> Self {
5142 Self {
5143 data,
5144 size,
5145 pixel_format: Some(pixel_format),
5146 alpha_treatment,
5147 y_axis_treatment,
5148 }
5149 }
5150
5151 pub(crate) fn from_array(
5152 data: IpcSharedMemory,
5153 size: Size2D<u32>,
5154 alpha_treatment: Option<AlphaTreatment>,
5155 y_axis_treatment: YAxisTreatment,
5156 ) -> Self {
5157 Self {
5158 data,
5159 size,
5160 pixel_format: None,
5161 alpha_treatment,
5162 y_axis_treatment,
5163 }
5164 }
5165
5166 pub(crate) fn size(&self) -> Size2D<u32> {
5167 self.size
5168 }
5169
5170 pub(crate) fn pixel_format(&self) -> Option<PixelFormat> {
5171 self.pixel_format
5172 }
5173
5174 pub(crate) fn alpha_treatment(&self) -> Option<AlphaTreatment> {
5175 self.alpha_treatment
5176 }
5177
5178 pub(crate) fn y_axis_treatment(&self) -> YAxisTreatment {
5179 self.y_axis_treatment
5180 }
5181
5182 pub(crate) fn into_shared_memory(self) -> IpcSharedMemory {
5183 self.data
5184 }
5185}
5186
5187pub(crate) enum TexSource {
5188 Pixels(TexPixels),
5189 BufferOffset(i64),
5190}
5191
5192#[derive(JSTraceable)]
5193pub(crate) struct WebGLCommandSender {
5194 #[no_trace]
5195 sender: WebGLChan,
5196}
5197
5198impl WebGLCommandSender {
5199 pub(crate) fn new(sender: WebGLChan) -> WebGLCommandSender {
5200 WebGLCommandSender { sender }
5201 }
5202
5203 pub(crate) fn send(&self, msg: WebGLMsg) -> WebGLSendResult {
5204 self.sender.send(msg)
5205 }
5206}
5207
5208#[derive(JSTraceable, MallocSizeOf)]
5209pub(crate) struct WebGLMessageSender {
5210 #[no_trace]
5211 sender: WebGLMsgSender,
5212}
5213
5214impl Clone for WebGLMessageSender {
5215 fn clone(&self) -> WebGLMessageSender {
5216 WebGLMessageSender {
5217 sender: self.sender.clone(),
5218 }
5219 }
5220}
5221
5222impl WebGLMessageSender {
5223 pub(crate) fn new(sender: WebGLMsgSender) -> WebGLMessageSender {
5224 WebGLMessageSender { sender }
5225 }
5226
5227 pub(crate) fn context_id(&self) -> WebGLContextId {
5228 self.sender.context_id()
5229 }
5230
5231 pub(crate) fn send(
5232 &self,
5233 msg: WebGLCommand,
5234 backtrace: WebGLCommandBacktrace,
5235 ) -> WebGLSendResult {
5236 self.sender.send(msg, backtrace)
5237 }
5238
5239 pub(crate) fn send_resize(
5240 &self,
5241 size: Size2D<u32>,
5242 sender: WebGLSender<Result<(), String>>,
5243 ) -> WebGLSendResult {
5244 self.sender.send_resize(size, sender)
5245 }
5246
5247 pub(crate) fn send_remove(&self) -> WebGLSendResult {
5248 self.sender.send_remove()
5249 }
5250}
5251
5252fn array_buffer_type_to_sized_type(type_: Type) -> Option<SizedDataType> {
5253 match type_ {
5254 Type::Uint8 | Type::Uint8Clamped => Some(SizedDataType::Uint8),
5255 Type::Uint16 => Some(SizedDataType::Uint16),
5256 Type::Uint32 => Some(SizedDataType::Uint32),
5257 Type::Int8 => Some(SizedDataType::Int8),
5258 Type::Int16 => Some(SizedDataType::Int16),
5259 Type::Int32 => Some(SizedDataType::Int32),
5260 Type::Float32 => Some(SizedDataType::Float32),
5261 Type::Float16 |
5262 Type::Float64 |
5263 Type::BigInt64 |
5264 Type::BigUint64 |
5265 Type::MaxTypedArrayViewType |
5266 Type::Int64 |
5267 Type::Simd128 => None,
5268 }
5269}