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