1#![expect(unsafe_code)]
5use std::borrow::Cow;
6use std::collections::HashMap;
7use std::collections::hash_map::Entry;
8use std::num::NonZeroU32;
9use std::rc::Rc;
10use std::sync::Arc;
11use std::thread::JoinHandle;
12use std::{slice, thread};
13
14use bitflags::bitflags;
15use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
16use euclid::default::Size2D;
17use glow::{
18 self as gl, ActiveTransformFeedback, Context as Gl, HasContext, NativeTransformFeedback,
19 NativeUniformLocation, NativeVertexArray, PixelUnpackData, ShaderPrecisionFormat,
20 bytes_per_type, components_per_format,
21};
22use half::f16;
23use itertools::Itertools;
24use log::{debug, error, trace, warn};
25use paint_api::{
26 CrossProcessPaintApi, PainterSurfmanDetailsMap, SerializableImageData,
27 WebRenderExternalImageIdManager, WebRenderImageHandlerType,
28};
29use parking_lot::RwLock;
30use pixels::{self, PixelFormat, SnapshotAlphaMode, unmultiply_inplace};
31use rustc_hash::FxHashMap;
32use servo_base::Epoch;
33use servo_base::generic_channel::{
34 GenericReceiver, GenericSender, GenericSharedMemory, RoutedReceiver,
35};
36use servo_base::id::PainterId;
37use servo_canvas_traits::webgl;
38#[cfg(feature = "webxr")]
39use servo_canvas_traits::webgl::WebXRCommand;
40use servo_canvas_traits::webgl::{
41 ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, AlphaTreatment,
42 GLContextAttributes, GLLimits, GlType, InternalFormatIntVec, ProgramLinkInfo, TexDataType,
43 TexFormat, WebGLBufferId, WebGLChan, WebGLCommand, WebGLCommandBacktrace, WebGLContextId,
44 WebGLCreateContextResult, WebGLFramebufferBindingRequest, WebGLFramebufferId, WebGLMsg,
45 WebGLMsgSender, WebGLProgramId, WebGLQueryId, WebGLRenderbufferId, WebGLSLVersion,
46 WebGLSamplerId, WebGLShaderId, WebGLSyncId, WebGLTextureId, WebGLVersion, WebGLVertexArrayId,
47 YAxisTreatment,
48};
49use surfman::chains::{PreserveBuffer, SwapChains, SwapChainsAPI};
50use surfman::{
51 self, Context, ContextAttributeFlags, ContextAttributes, Device, GLVersion, SurfaceAccess,
52 SurfaceInfo, SurfaceType,
53};
54use webrender_api::units::DeviceIntSize;
55use webrender_api::{
56 ExternalImageData, ExternalImageId, ExternalImageType, ImageBufferKind, ImageDescriptor,
57 ImageDescriptorFlags, ImageFormat, ImageKey,
58};
59
60use crate::webgl_limits::GLLimitsDetect;
61#[cfg(feature = "webxr")]
62use crate::webxr::{WebXRBridge, WebXRBridgeInit};
63
64type GLint = i32;
65
66fn native_uniform_location(location: i32) -> Option<NativeUniformLocation> {
67 location.try_into().ok().map(NativeUniformLocation)
68}
69
70pub type WebGLContextBusyMap = Arc<RwLock<HashMap<WebGLContextId, usize>>>;
75
76pub(crate) struct GLContextData {
77 pub(crate) ctx: Context,
78 pub(crate) gl: Rc<glow::Context>,
79 device: Rc<Device>,
80 state: GLState,
81 attributes: GLContextAttributes,
82 marked_for_deletion: bool,
85}
86
87#[derive(Debug)]
88pub struct GLState {
89 _webgl_version: WebGLVersion,
90 _gl_version: GLVersion,
91 requested_flags: ContextAttributeFlags,
92 color_write_mask: [bool; 4],
97 clear_color: (f32, f32, f32, f32),
98 scissor_test_enabled: bool,
99 stencil_write_mask: (u32, u32),
101 stencil_value_mask: (u32, u32),
103 stencil_test_enabled: bool,
104 stencil_clear_value: i32,
105 depth_write_mask: bool,
107 depth_test_enabled: bool,
108 depth_clear_value: f64,
109 drawing_to_default_framebuffer: bool,
111 default_vao: Option<NativeVertexArray>,
112}
113
114impl GLState {
115 fn fake_no_alpha(&self) -> bool {
117 self.drawing_to_default_framebuffer &
118 !self.requested_flags.contains(ContextAttributeFlags::ALPHA)
119 }
120
121 fn fake_no_depth(&self) -> bool {
122 self.drawing_to_default_framebuffer &
123 !self.requested_flags.contains(ContextAttributeFlags::DEPTH)
124 }
125
126 fn fake_no_stencil(&self) -> bool {
127 self.drawing_to_default_framebuffer &
128 !self
129 .requested_flags
130 .contains(ContextAttributeFlags::STENCIL)
131 }
132
133 fn restore_invariant(&self, gl: &Gl) {
135 self.restore_clear_invariant(gl);
136 self.restore_scissor_invariant(gl);
137 self.restore_alpha_invariant(gl);
138 self.restore_depth_invariant(gl);
139 self.restore_stencil_invariant(gl);
140 }
141
142 fn restore_clear_invariant(&self, gl: &Gl) {
143 let (r, g, b, a) = self.clear_color;
144 unsafe {
145 gl.clear_color(r, g, b, a);
146 gl.clear_depth(self.depth_clear_value);
147 gl.clear_stencil(self.stencil_clear_value);
148 }
149 }
150
151 fn restore_scissor_invariant(&self, gl: &Gl) {
152 if self.scissor_test_enabled {
153 unsafe { gl.enable(gl::SCISSOR_TEST) };
154 } else {
155 unsafe { gl.disable(gl::SCISSOR_TEST) };
156 }
157 }
158
159 fn restore_alpha_invariant(&self, gl: &Gl) {
160 let [r, g, b, a] = self.color_write_mask;
161 if self.fake_no_alpha() {
162 unsafe { gl.color_mask(r, g, b, false) };
163 } else {
164 unsafe { gl.color_mask(r, g, b, a) };
165 }
166 }
167
168 fn restore_depth_invariant(&self, gl: &Gl) {
169 unsafe {
170 if self.fake_no_depth() {
171 gl.depth_mask(false);
172 gl.disable(gl::DEPTH_TEST);
173 } else {
174 gl.depth_mask(self.depth_write_mask);
175 if self.depth_test_enabled {
176 gl.enable(gl::DEPTH_TEST);
177 } else {
178 gl.disable(gl::DEPTH_TEST);
179 }
180 }
181 }
182 }
183
184 fn restore_stencil_invariant(&self, gl: &Gl) {
185 unsafe {
186 if self.fake_no_stencil() {
187 gl.stencil_mask(0);
188 gl.disable(gl::STENCIL_TEST);
189 } else {
190 let (f, b) = self.stencil_write_mask;
191 gl.stencil_mask_separate(gl::FRONT, f);
192 gl.stencil_mask_separate(gl::BACK, b);
193 if self.stencil_test_enabled {
194 gl.enable(gl::STENCIL_TEST);
195 } else {
196 gl.disable(gl::STENCIL_TEST);
197 }
198 }
199 }
200 }
201}
202
203impl Default for GLState {
204 fn default() -> GLState {
205 GLState {
206 _gl_version: GLVersion { major: 1, minor: 0 },
207 _webgl_version: WebGLVersion::WebGL1,
208 requested_flags: ContextAttributeFlags::empty(),
209 color_write_mask: [true, true, true, true],
210 clear_color: (0., 0., 0., 0.),
211 scissor_test_enabled: false,
212 stencil_write_mask: (u32::MAX, u32::MAX),
214 stencil_value_mask: (u32::MAX, u32::MAX),
215 stencil_test_enabled: false,
216 stencil_clear_value: 0,
217 depth_write_mask: true,
218 depth_test_enabled: false,
219 depth_clear_value: 1.,
220 default_vao: None,
221 drawing_to_default_framebuffer: true,
222 }
223 }
224}
225
226pub(crate) struct WebGLThread {
229 device_map: HashMap<PainterId, Rc<Device>>,
231 paint_api: CrossProcessPaintApi,
233 contexts: FxHashMap<WebGLContextId, GLContextData>,
235 cached_context_info: FxHashMap<WebGLContextId, WebGLContextInfo>,
237 bound_context_id: Option<WebGLContextId>,
239 external_image_id_manager: WebRenderExternalImageIdManager,
242 receiver: RoutedReceiver<WebGLMsg>,
244 sender: GenericSender<WebGLMsg>,
246 webrender_swap_chains: SwapChains<WebGLContextId, Device>,
248 painter_surfman_details_map: PainterSurfmanDetailsMap,
250 busy_webgl_context_map: WebGLContextBusyMap,
253
254 #[cfg(feature = "webxr")]
255 pub webxr_bridge: Option<WebXRBridge>,
257}
258
259pub(crate) struct WebGLThreadInit {
261 pub paint_api: CrossProcessPaintApi,
262 pub external_image_id_manager: WebRenderExternalImageIdManager,
263 pub sender: GenericSender<WebGLMsg>,
264 pub receiver: GenericReceiver<WebGLMsg>,
265 pub webrender_swap_chains: SwapChains<WebGLContextId, Device>,
266 pub painter_surfman_details_map: PainterSurfmanDetailsMap,
267 pub busy_webgl_context_map: WebGLContextBusyMap,
268 #[cfg(feature = "webxr")]
269 pub webxr_init: WebXRBridgeInit,
270}
271
272const SAFE_VIEWPORT_DIMS: [u32; 2] = [1024, 1024];
274
275impl WebGLThread {
276 pub(crate) fn new(
278 WebGLThreadInit {
279 paint_api,
280 external_image_id_manager: external_images,
281 sender,
282 receiver,
283 webrender_swap_chains,
284 painter_surfman_details_map,
285 busy_webgl_context_map,
286 #[cfg(feature = "webxr")]
287 webxr_init,
288 }: WebGLThreadInit,
289 ) -> Self {
290 WebGLThread {
291 device_map: Default::default(),
292 paint_api,
293 contexts: Default::default(),
294 cached_context_info: Default::default(),
295 bound_context_id: None,
296 external_image_id_manager: external_images,
297 sender,
298 receiver: receiver.route_preserving_errors(),
299 webrender_swap_chains,
300 painter_surfman_details_map,
301 busy_webgl_context_map,
302 #[cfg(feature = "webxr")]
303 webxr_bridge: Some(WebXRBridge::new(webxr_init)),
304 }
305 }
306
307 pub(crate) fn run_on_own_thread(init: WebGLThreadInit) -> JoinHandle<()> {
310 thread::Builder::new()
311 .name("WebGL".to_owned())
312 .spawn(move || {
313 let mut data = WebGLThread::new(init);
314 data.process();
315 })
316 .expect("Thread spawning failed")
317 }
318
319 fn process(&mut self) {
320 let webgl_chan = WebGLChan(self.sender.clone());
321 while let Ok(Ok(msg)) = self.receiver.recv() {
322 let exit = self.handle_msg(msg, &webgl_chan);
323 if exit {
324 break;
325 }
326 }
327 }
328
329 fn ensure_point_sprite_and_program_point_size_enabled(gl_context_data: &GLContextData) {
334 if gl_context_data.gl.version().is_embedded {
337 return;
338 }
339
340 const GL_POINT_SPRITE: u32 = 0x8861;
343 unsafe { gl_context_data.gl.enable(GL_POINT_SPRITE) };
344 let error = unsafe { gl_context_data.gl.get_error() };
345 if error != 0 {
346 warn!("Error enabling GL point sprites: {error}");
347 }
348
349 unsafe { gl_context_data.gl.enable(gl::PROGRAM_POINT_SIZE) };
350 let error = unsafe { gl_context_data.gl.get_error() };
351 if error != 0 {
352 warn!("Error enabling GL program point size: {error}");
353 }
354 }
355
356 fn handle_msg(&mut self, msg: WebGLMsg, webgl_chan: &WebGLChan) -> bool {
358 trace!("processing {:?}", msg);
359 match msg {
360 WebGLMsg::CreateContext(painter_id, version, size, attributes, result_sender) => {
361 let result = self.create_webgl_context(painter_id, version, size, attributes);
362
363 result_sender
364 .send(result.map(|(id, limits)| {
365 let data = self
366 .make_current_if_needed(id)
367 .expect("WebGLContext not found");
368
369 Self::ensure_point_sprite_and_program_point_size_enabled(data);
370
371 let glsl_version = Self::get_glsl_version(&data.gl);
372 let api_type = if data.gl.version().is_embedded {
373 GlType::Gles
374 } else {
375 GlType::Gl
376 };
377
378 WebGLCreateContextResult {
379 sender: WebGLMsgSender::new(id, webgl_chan.clone()),
380 limits,
381 glsl_version,
382 api_type,
383 }
384 }))
385 .unwrap();
386 },
387 WebGLMsg::SetImageKey(ctx_id, image_key) => {
388 self.handle_set_image_key(ctx_id, image_key);
389 },
390 WebGLMsg::ResizeContext(ctx_id, size, sender) => {
391 let _ = sender.send(self.resize_webgl_context(ctx_id, size));
392 },
393 WebGLMsg::RemoveContext(ctx_id) => {
394 self.remove_webgl_context(ctx_id);
395 },
396 WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => {
397 self.handle_webgl_command(ctx_id, command, backtrace);
398 },
399 WebGLMsg::WebXRCommand(_command) => {
400 #[cfg(feature = "webxr")]
401 self.handle_webxr_command(_command);
402 },
403 WebGLMsg::SwapBuffers(swap_ids, canvas_epoch, sent_time) => {
404 self.handle_swap_buffers(canvas_epoch, swap_ids, sent_time);
405 },
406 WebGLMsg::FinishedRenderingToContext(context_id) => {
407 self.handle_finished_rendering_to_context(context_id);
408 },
409 WebGLMsg::ClearPainterResources(painter_id, sender) => {
410 self.device_map.remove(&painter_id);
411 if let Err(error) = sender.send(()) {
412 warn!("Failed to send response to WebGLMsg::ClearPainterResources ({error})");
413 }
414 },
415 WebGLMsg::Exit => {
416 let context_ids: Vec<WebGLContextId> = self.contexts.keys().copied().collect();
418 for id in context_ids {
419 self.remove_webgl_context(id);
420 }
421 return true;
422 },
423 }
424
425 false
426 }
427
428 fn get_or_create_device_for_painter(
429 &mut self,
430 painter_id: PainterId,
431 ) -> Result<Rc<Device>, String> {
432 let entry = self.device_map.entry(painter_id);
433 if let Entry::Occupied(entry) = entry {
434 return Ok(entry.get().clone());
435 }
436
437 let Some(surfman_details) = self.painter_surfman_details_map.get(painter_id) else {
440 return Err(format!("No PainterSurfmanDetails found for {painter_id:?}"));
441 };
442
443 let Ok(device) = surfman_details
445 .connection
446 .create_device(&surfman_details.adapter)
447 else {
448 return Err("Could not open WebGL device".into());
449 };
450
451 Ok(entry.or_insert(Rc::new(device)).clone())
452 }
453
454 #[cfg(feature = "webxr")]
455 fn handle_webxr_command(&mut self, command: WebXRCommand) {
457 trace!("processing {:?}", command);
458 let Some(mut webxr_bridge) = self.webxr_bridge.take() else {
460 return;
461 };
462 match command {
463 WebXRCommand::CreateLayerManager(sender) => {
464 let result = webxr_bridge.create_layer_manager(self);
465 let _ = sender.send(result);
466 },
467 WebXRCommand::DestroyLayerManager(manager_id) => {
468 webxr_bridge.destroy_layer_manager(manager_id);
469 },
470 WebXRCommand::CreateLayer(manager_id, context_id, layer_init, sender) => {
471 let result = webxr_bridge.create_layer(manager_id, self, context_id, layer_init);
472 let _ = sender.send(result);
473 },
474 WebXRCommand::DestroyLayer(manager_id, context_id, layer_id) => {
475 webxr_bridge.destroy_layer(manager_id, self, context_id, layer_id);
476 },
477 WebXRCommand::BeginFrame(manager_id, layers, sender) => {
478 let result = webxr_bridge.begin_frame(manager_id, self, &layers[..]);
479 let _ = sender.send(result);
480 },
481 WebXRCommand::EndFrame(manager_id, layers, sender) => {
482 let result = webxr_bridge.end_frame(manager_id, self, &layers[..]);
483 let _ = sender.send(result);
484 },
485 }
486
487 self.webxr_bridge.replace(webxr_bridge);
488 }
489
490 fn device_for_context(&self, context_id: WebGLContextId) -> Rc<Device> {
491 self.maybe_device_for_context(context_id)
492 .expect("Should be called with a valid WebGLContextId")
493 }
494
495 pub(crate) fn maybe_device_for_context(
499 &self,
500 context_id: WebGLContextId,
501 ) -> Option<Rc<Device>> {
502 self.contexts
503 .get(&context_id)
504 .map(|context| context.device.clone())
505 }
506
507 fn handle_webgl_command(
509 &mut self,
510 context_id: WebGLContextId,
511 command: WebGLCommand,
512 backtrace: WebGLCommandBacktrace,
513 ) {
514 if self.cached_context_info.get_mut(&context_id).is_none() {
515 return;
516 }
517 let data = self.make_current_if_needed_mut(context_id);
518 if let Some(data) = data {
519 WebGLImpl::apply(
520 &data.device,
521 &data.ctx,
522 &data.gl,
523 &mut data.state,
524 &data.attributes,
525 command,
526 backtrace,
527 );
528 }
529 }
530
531 fn create_webgl_context(
533 &mut self,
534 painter_id: PainterId,
535 webgl_version: WebGLVersion,
536 requested_size: Size2D<u32>,
537 attributes: GLContextAttributes,
538 ) -> Result<(WebGLContextId, webgl::GLLimits), String> {
539 debug!(
540 "WebGLThread::create_webgl_context({:?}, {:?}, {:?})",
541 webgl_version, requested_size, attributes
542 );
543
544 self.bound_context_id = None;
547
548 let Some(painter_surfman_details) = self.painter_surfman_details_map.get(painter_id) else {
551 return Err(format!(
552 "PainterSurfmanDetails not found for {painter_id:?}"
553 ));
554 };
555
556 let api_type = match painter_surfman_details.connection.gl_api() {
557 surfman::GLApi::GL => GlType::Gl,
558 surfman::GLApi::GLES => GlType::Gles,
559 };
560
561 let requested_flags =
562 attributes.to_surfman_context_attribute_flags(webgl_version, api_type);
563 let flags = requested_flags |
569 ContextAttributeFlags::ALPHA |
570 ContextAttributeFlags::DEPTH |
571 ContextAttributeFlags::STENCIL;
572 let context_attributes = &ContextAttributes {
573 version: webgl_version.to_surfman_version(api_type),
574 flags,
575 };
576
577 let device = self.get_or_create_device_for_painter(painter_id)?;
578 let context_descriptor = device
579 .create_context_descriptor(context_attributes)
580 .map_err(|err| format!("Failed to create context descriptor: {:?}", err))?;
581
582 let safe_size = Size2D::new(
583 requested_size.width.min(SAFE_VIEWPORT_DIMS[0]).max(1),
584 requested_size.height.min(SAFE_VIEWPORT_DIMS[1]).max(1),
585 );
586 let surface_type = SurfaceType::Generic {
587 size: safe_size.to_i32(),
588 };
589 let surface_access = self.surface_access();
590
591 let mut ctx = device
592 .create_context(&context_descriptor, None)
593 .map_err(|err| format!("Failed to create the GL context: {:?}", err))?;
594 let surface = device
595 .create_surface(&ctx, surface_access, surface_type)
596 .map_err(|err| format!("Failed to create the initial surface: {:?}", err))?;
597 device
598 .bind_surface_to_context(&mut ctx, surface)
599 .map_err(|err| format!("Failed to bind initial surface: {:?}", err))?;
600 device
602 .make_context_current(&ctx)
603 .map_err(|err| format!("Failed to make new context current: {:?}", err))?;
604
605 let context_id = WebGLContextId(
606 self.external_image_id_manager
607 .next_id(WebRenderImageHandlerType::WebGl)
608 .0,
609 );
610
611 self.webrender_swap_chains
612 .create_attached_swap_chain(context_id, &*device, &mut ctx, surface_access)
613 .map_err(|err| format!("Failed to create swap chain: {:?}", err))?;
614
615 let Some(swap_chain) = self.webrender_swap_chains.get(context_id) else {
616 return Err("Failed to get the swap chain".into());
617 };
618
619 debug!(
620 "Created webgl context {:?}/{:?}",
621 context_id,
622 device.context_id(&ctx),
623 );
624
625 let gl = unsafe {
626 Rc::new(match api_type {
627 GlType::Gl => glow::Context::from_loader_function(|symbol_name| {
628 device.get_proc_address(&ctx, symbol_name)
629 }),
630 GlType::Gles => glow::Context::from_loader_function(|symbol_name| {
631 device.get_proc_address(&ctx, symbol_name)
632 }),
633 })
634 };
635
636 let limits = GLLimits::detect(&gl, webgl_version);
637
638 let size = clamp_viewport(&gl, requested_size);
639 debug_assert_eq!(unsafe { gl.get_error() }, gl::NO_ERROR);
640
641 if safe_size != size {
642 debug!("Resizing swap chain from {:?} to {:?}", safe_size, size);
643 swap_chain
644 .resize(&device, &mut ctx, size.to_i32())
645 .map_err(|err| format!("Failed to resize swap chain: {:?}", err))?;
646 }
647
648 let descriptor = device.context_descriptor(&ctx);
649 let descriptor_attributes = device.context_descriptor_attributes(&descriptor);
650 let gl_version = descriptor_attributes.version;
651 let has_alpha = requested_flags.contains(ContextAttributeFlags::ALPHA);
652
653 device.make_context_current(&ctx).unwrap();
654 let framebuffer = device
655 .context_surface_info(&ctx)
656 .map_err(|err| format!("Failed to get context surface info: {:?}", err))?
657 .ok_or_else(|| "Failed to get context surface info".to_string())?
658 .framebuffer_object;
659
660 unsafe {
661 gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer);
662 gl.viewport(0, 0, size.width as i32, size.height as i32);
663 gl.scissor(0, 0, size.width as i32, size.height as i32);
664 gl.clear_color(0., 0., 0., !has_alpha as u32 as f32);
665 gl.clear_depth(1.);
666 gl.clear_stencil(0);
667 gl.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
668 gl.clear_color(0., 0., 0., 0.);
669 debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
670 }
671
672 let default_vao = if let Some(vao) = WebGLImpl::create_vertex_array(&gl) {
673 unsafe { gl.bind_vertex_array(Some(vao.glow())) }
674 Some(vao.glow())
675 } else {
676 None
677 };
678 debug_assert_eq!(unsafe { gl.get_error() }, gl::NO_ERROR);
679
680 let state = GLState {
681 _gl_version: gl_version,
682 _webgl_version: webgl_version,
683 requested_flags,
684 default_vao,
685 ..Default::default()
686 };
687 debug!("Created state {:?}", state);
688
689 state.restore_invariant(&gl);
690 debug_assert_eq!(unsafe { gl.get_error() }, gl::NO_ERROR);
691
692 self.contexts.insert(
693 context_id,
694 GLContextData {
695 ctx,
696 device,
697 gl,
698 state,
699 attributes,
700 marked_for_deletion: false,
701 },
702 );
703
704 self.cached_context_info.insert(
705 context_id,
706 WebGLContextInfo {
707 image_key: None,
708 size: size.to_i32(),
709 alpha: has_alpha,
710 },
711 );
712
713 Ok((context_id, limits))
714 }
715
716 fn resize_webgl_context(
718 &mut self,
719 context_id: WebGLContextId,
720 requested_size: Size2D<u32>,
721 ) -> Result<(), String> {
722 self.make_current_if_needed(context_id);
723
724 let Some(data) = self.contexts.get_mut(&context_id) else {
725 return Err("Missing WebGL context!".into());
726 };
727
728 let size = clamp_viewport(&data.gl, requested_size);
729 debug_assert_eq!(unsafe { data.gl.get_error() }, gl::NO_ERROR);
730
731 let framebuffer_rebinding_info =
734 FramebufferRebindingInfo::detect(&data.device, &data.ctx, &data.gl);
735
736 if let Some(swap_chain) = self.webrender_swap_chains.get(context_id) {
738 let alpha = data
739 .state
740 .requested_flags
741 .contains(ContextAttributeFlags::ALPHA);
742 let clear_color = [0.0, 0.0, 0.0, !alpha as i32 as f32];
743 swap_chain
744 .resize(&data.device, &mut data.ctx, size.to_i32())
745 .map_err(|err| format!("Failed to resize swap chain: {:?}", err))?;
746 swap_chain
747 .clear_surface(&data.device, &mut data.ctx, &data.gl, clear_color)
748 .map_err(|err| format!("Failed to clear resized swap chain: {:?}", err))?;
749 } else {
750 error!("Failed to find swap chain");
751 }
752
753 framebuffer_rebinding_info.apply(&data.device, &data.ctx, &data.gl);
755 debug_assert_eq!(unsafe { data.gl.get_error() }, gl::NO_ERROR);
756
757 let has_alpha = data
758 .state
759 .requested_flags
760 .contains(ContextAttributeFlags::ALPHA);
761 self.update_webrender_image_for_context(context_id, size.to_i32(), has_alpha, None);
762
763 Ok(())
764 }
765
766 fn handle_finished_rendering_to_context(&mut self, context_id: WebGLContextId) {
769 let marked_for_deletion = self
770 .contexts
771 .get(&context_id)
772 .is_some_and(|context_data| context_data.marked_for_deletion);
773 if marked_for_deletion {
774 self.remove_webgl_context(context_id);
775 }
776 }
777
778 fn remove_webgl_context(&mut self, context_id: WebGLContextId) {
780 {
781 let mut busy_webgl_context_map = self.busy_webgl_context_map.write();
782 let entry = busy_webgl_context_map.entry(context_id);
783 match entry {
784 Entry::Vacant(..) => {},
785 Entry::Occupied(occupied_entry) if *occupied_entry.get() > 0 => {
786 if let Some(context_data) = self.contexts.get_mut(&context_id) {
789 context_data.marked_for_deletion = true;
790 }
791 return;
792 },
793 Entry::Occupied(occupied_entry) => {
794 occupied_entry.remove();
795 },
796 }
797 }
798
799 if let Some(image_key) = self
801 .cached_context_info
802 .remove(&context_id)
803 .and_then(|info| info.image_key)
804 {
805 self.paint_api.delete_image(image_key);
806 }
807
808 if !self.contexts.contains_key(&context_id) {
809 return;
810 };
811
812 self.make_current_if_needed(context_id);
814
815 #[cfg(feature = "webxr")]
817 {
818 let mut webxr_bridge = self.webxr_bridge.take();
821 if let Some(webxr_bridge) = &mut webxr_bridge {
822 webxr_bridge.destroy_all_layers(self, context_id.into());
823 }
824 self.webxr_bridge = webxr_bridge;
825 }
826
827 let Some(mut data) = self.contexts.remove(&context_id) else {
829 return;
830 };
831
832 self.webrender_swap_chains
834 .destroy(context_id, &data.device, &mut data.ctx)
835 .unwrap();
836
837 data.device.destroy_context(&mut data.ctx).unwrap();
839
840 self.bound_context_id = None;
842 }
843
844 fn handle_swap_buffers(
845 &mut self,
846 canvas_epoch: Option<Epoch>,
847 context_ids: Vec<WebGLContextId>,
848 _sent_time: u64,
849 ) {
850 debug!("handle_swap_buffers()");
851 for context_id in context_ids {
852 self.make_current_if_needed(context_id)
853 .expect("Where's the GL data?");
854
855 let data = self
856 .contexts
857 .get_mut(&context_id)
858 .expect("Missing WebGL context");
859
860 debug_assert_eq!(unsafe { data.gl.get_error() }, gl::NO_ERROR);
862
863 let framebuffer_rebinding_info =
866 FramebufferRebindingInfo::detect(&data.device, &data.ctx, &data.gl);
867 debug_assert_eq!(unsafe { data.gl.get_error() }, gl::NO_ERROR);
868
869 debug!("Getting swap chain for {:?}", context_id);
870 let swap_chain = self
871 .webrender_swap_chains
872 .get(context_id)
873 .expect("Where's the swap chain?");
874
875 debug!("Swapping {:?}", context_id);
876 swap_chain
877 .swap_buffers(
878 &data.device,
879 &mut data.ctx,
880 if data.attributes.preserve_drawing_buffer {
881 PreserveBuffer::Yes(&data.gl)
882 } else {
883 PreserveBuffer::No
884 },
885 )
886 .unwrap();
887 debug_assert_eq!(unsafe { data.gl.get_error() }, gl::NO_ERROR);
888
889 if !data.attributes.preserve_drawing_buffer {
890 debug!("Clearing {:?}", context_id);
891 let alpha = data
892 .state
893 .requested_flags
894 .contains(ContextAttributeFlags::ALPHA);
895 let clear_color = [0.0, 0.0, 0.0, !alpha as i32 as f32];
896 swap_chain
897 .clear_surface(&data.device, &mut data.ctx, &data.gl, clear_color)
898 .unwrap();
899 debug_assert_eq!(unsafe { data.gl.get_error() }, gl::NO_ERROR);
900 }
901
902 debug!("Rebinding {:?}", context_id);
904 framebuffer_rebinding_info.apply(&data.device, &data.ctx, &data.gl);
905 debug_assert_eq!(unsafe { data.gl.get_error() }, gl::NO_ERROR);
906
907 let SurfaceInfo {
908 size,
909 framebuffer_object,
910 id,
911 ..
912 } = data
913 .device
914 .context_surface_info(&data.ctx)
915 .unwrap()
916 .unwrap();
917 debug!(
918 "... rebound framebuffer {:?}, new back buffer surface is {:?}",
919 framebuffer_object, id
920 );
921
922 let has_alpha = data
923 .state
924 .requested_flags
925 .contains(ContextAttributeFlags::ALPHA);
926 self.update_webrender_image_for_context(context_id, size, has_alpha, canvas_epoch);
927 }
928 }
929
930 fn surface_access(&self) -> SurfaceAccess {
932 SurfaceAccess::GPUOnly
933 }
934
935 pub(crate) fn make_current_if_needed(
937 &mut self,
938 context_id: WebGLContextId,
939 ) -> Option<&GLContextData> {
940 let data = self.contexts.get(&context_id);
941
942 if let Some(data) = data &&
943 Some(context_id) != self.bound_context_id
944 {
945 data.device.make_context_current(&data.ctx).unwrap();
946 self.bound_context_id = Some(context_id);
947 }
948
949 data
950 }
951
952 pub(crate) fn make_current_if_needed_mut(
954 &mut self,
955 context_id: WebGLContextId,
956 ) -> Option<&mut GLContextData> {
957 let data = self.contexts.get_mut(&context_id);
958 if let Some(ref data) = data &&
959 Some(context_id) != self.bound_context_id
960 {
961 data.device.make_context_current(&data.ctx).unwrap();
962 self.bound_context_id = Some(context_id);
963 }
964
965 data
966 }
967
968 fn update_webrender_image_for_context(
971 &mut self,
972 context_id: WebGLContextId,
973 size: Size2D<i32>,
974 has_alpha: bool,
975 canvas_epoch: Option<Epoch>,
976 ) {
977 let image_data = self.external_image_data(context_id);
978 let info = self.cached_context_info.get_mut(&context_id).unwrap();
979 info.size = size;
980 info.alpha = has_alpha;
981
982 if let Some(image_key) = info.image_key {
983 self.paint_api.update_image(
984 image_key,
985 info.image_descriptor(),
986 image_data,
987 canvas_epoch,
988 );
989 }
990 }
991
992 fn external_image_data(&self, context_id: WebGLContextId) -> SerializableImageData {
994 let device = self.device_for_context(context_id);
996 let image_buffer_kind = match device.surface_gl_texture_target() {
997 gl::TEXTURE_RECTANGLE => ImageBufferKind::TextureRect,
998 _ => ImageBufferKind::Texture2D,
999 };
1000
1001 let data = ExternalImageData {
1002 id: ExternalImageId(context_id.0),
1003 channel_index: 0,
1004 image_type: ExternalImageType::TextureHandle(image_buffer_kind),
1005 normalized_uvs: false,
1006 };
1007 SerializableImageData::External(data)
1008 }
1009
1010 fn get_glsl_version(gl: &Gl) -> WebGLSLVersion {
1012 let version = unsafe { gl.get_parameter_string(gl::SHADING_LANGUAGE_VERSION) };
1013 let mut values = version.split(&['.', ' '][..]);
1015 let major = values
1016 .next()
1017 .and_then(|v| v.parse::<u32>().ok())
1018 .unwrap_or(1);
1019 let minor = values
1020 .next()
1021 .and_then(|v| v.parse::<u32>().ok())
1022 .unwrap_or(20);
1023
1024 WebGLSLVersion { major, minor }
1025 }
1026
1027 fn handle_set_image_key(&mut self, context_id: WebGLContextId, image_key: ImageKey) {
1028 let external_image_data = self.external_image_data(context_id);
1029 let Some(info) = self.cached_context_info.get_mut(&context_id) else {
1030 self.paint_api.delete_image(image_key);
1031 return;
1032 };
1033
1034 if let Some(old_image_key) = info.image_key.replace(image_key) {
1035 self.paint_api.delete_image(old_image_key);
1036 return;
1037 }
1038
1039 self.paint_api.add_image(
1040 image_key,
1041 info.image_descriptor(),
1042 external_image_data,
1043 false,
1044 );
1045 }
1046}
1047
1048struct WebGLContextInfo {
1050 image_key: Option<ImageKey>,
1051 size: Size2D<i32>,
1052 alpha: bool,
1053}
1054
1055impl WebGLContextInfo {
1056 fn image_descriptor(&self) -> ImageDescriptor {
1058 let mut flags = ImageDescriptorFlags::empty();
1059 flags.set(ImageDescriptorFlags::IS_OPAQUE, !self.alpha);
1060 ImageDescriptor {
1061 size: DeviceIntSize::new(self.size.width, self.size.height),
1062 stride: None,
1063 format: ImageFormat::BGRA8,
1064 offset: 0,
1065 flags,
1066 }
1067 }
1068}
1069
1070pub struct WebGLImpl;
1072
1073impl WebGLImpl {
1074 pub fn apply(
1075 device: &Device,
1076 ctx: &Context,
1077 gl: &Gl,
1078 state: &mut GLState,
1079 attributes: &GLContextAttributes,
1080 command: WebGLCommand,
1081 _backtrace: WebGLCommandBacktrace,
1082 ) {
1083 debug_assert_eq!(unsafe { gl.get_error() }, gl::NO_ERROR);
1085
1086 match command {
1087 WebGLCommand::GetContextAttributes(ref sender) => sender.send(*attributes).unwrap(),
1088 WebGLCommand::ActiveTexture(target) => unsafe { gl.active_texture(target) },
1089 WebGLCommand::AttachShader(program_id, shader_id) => unsafe {
1090 gl.attach_shader(program_id.glow(), shader_id.glow())
1091 },
1092 WebGLCommand::DetachShader(program_id, shader_id) => unsafe {
1093 gl.detach_shader(program_id.glow(), shader_id.glow())
1094 },
1095 WebGLCommand::BindAttribLocation(program_id, index, ref name) => unsafe {
1096 gl.bind_attrib_location(program_id.glow(), index, &to_name_in_compiled_shader(name))
1097 },
1098 WebGLCommand::BlendColor(r, g, b, a) => unsafe { gl.blend_color(r, g, b, a) },
1099 WebGLCommand::BlendEquation(mode) => unsafe { gl.blend_equation(mode) },
1100 WebGLCommand::BlendEquationSeparate(mode_rgb, mode_alpha) => unsafe {
1101 gl.blend_equation_separate(mode_rgb, mode_alpha)
1102 },
1103 WebGLCommand::BlendFunc(src, dest) => unsafe { gl.blend_func(src, dest) },
1104 WebGLCommand::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha) => unsafe {
1105 gl.blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha)
1106 },
1107 WebGLCommand::BufferData(buffer_type, ref receiver, usage) => unsafe {
1108 gl.buffer_data_u8_slice(buffer_type, &receiver.recv().unwrap(), usage)
1109 },
1110 WebGLCommand::BufferSubData(buffer_type, offset, ref receiver) => unsafe {
1111 gl.buffer_sub_data_u8_slice(buffer_type, offset as i32, &receiver.recv().unwrap())
1112 },
1113 WebGLCommand::CopyBufferSubData(src, dst, src_offset, dst_offset, size) => {
1114 unsafe {
1115 gl.copy_buffer_sub_data(
1116 src,
1117 dst,
1118 src_offset as i32,
1119 dst_offset as i32,
1120 size as i32,
1121 )
1122 };
1123 },
1124 WebGLCommand::GetBufferSubData(buffer_type, offset, length, ref sender) => unsafe {
1125 let ptr = gl.map_buffer_range(
1126 buffer_type,
1127 offset as i32,
1128 length as i32,
1129 gl::MAP_READ_BIT,
1130 );
1131 let data: &[u8] = slice::from_raw_parts(ptr as _, length);
1132 let buffer = GenericSharedMemory::from_bytes(data);
1133 sender.send(buffer).unwrap();
1134 gl.unmap_buffer(buffer_type);
1135 },
1136 WebGLCommand::Clear(mask) => {
1137 unsafe { gl.clear(mask) };
1138 },
1139 WebGLCommand::ClearColor(r, g, b, a) => {
1140 state.clear_color = (r, g, b, a);
1141 unsafe { gl.clear_color(r, g, b, a) };
1142 },
1143 WebGLCommand::ClearDepth(depth) => {
1144 let value = depth.clamp(0., 1.) as f64;
1145 state.depth_clear_value = value;
1146 unsafe { gl.clear_depth(value) }
1147 },
1148 WebGLCommand::ClearStencil(stencil) => {
1149 state.stencil_clear_value = stencil;
1150 unsafe { gl.clear_stencil(stencil) };
1151 },
1152 WebGLCommand::ColorMask(r, g, b, a) => {
1153 state.color_write_mask = [r, g, b, a];
1154 state.restore_alpha_invariant(gl);
1155 },
1156 WebGLCommand::CopyTexImage2D(
1157 target,
1158 level,
1159 internal_format,
1160 x,
1161 y,
1162 width,
1163 height,
1164 border,
1165 ) => unsafe {
1166 gl.copy_tex_image_2d(target, level, internal_format, x, y, width, height, border)
1167 },
1168 WebGLCommand::CopyTexSubImage2D(
1169 target,
1170 level,
1171 xoffset,
1172 yoffset,
1173 x,
1174 y,
1175 width,
1176 height,
1177 ) => unsafe {
1178 gl.copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height)
1179 },
1180 WebGLCommand::CullFace(mode) => unsafe { gl.cull_face(mode) },
1181 WebGLCommand::DepthFunc(func) => unsafe { gl.depth_func(func) },
1182 WebGLCommand::DepthMask(flag) => {
1183 state.depth_write_mask = flag;
1184 state.restore_depth_invariant(gl);
1185 },
1186 WebGLCommand::DepthRange(near, far) => unsafe {
1187 gl.depth_range(near.clamp(0., 1.) as f64, far.clamp(0., 1.) as f64)
1188 },
1189 WebGLCommand::Disable(cap) => match cap {
1190 gl::SCISSOR_TEST => {
1191 state.scissor_test_enabled = false;
1192 state.restore_scissor_invariant(gl);
1193 },
1194 gl::DEPTH_TEST => {
1195 state.depth_test_enabled = false;
1196 state.restore_depth_invariant(gl);
1197 },
1198 gl::STENCIL_TEST => {
1199 state.stencil_test_enabled = false;
1200 state.restore_stencil_invariant(gl);
1201 },
1202 _ => unsafe { gl.disable(cap) },
1203 },
1204 WebGLCommand::Enable(cap) => match cap {
1205 gl::SCISSOR_TEST => {
1206 state.scissor_test_enabled = true;
1207 state.restore_scissor_invariant(gl);
1208 },
1209 gl::DEPTH_TEST => {
1210 state.depth_test_enabled = true;
1211 state.restore_depth_invariant(gl);
1212 },
1213 gl::STENCIL_TEST => {
1214 state.stencil_test_enabled = true;
1215 state.restore_stencil_invariant(gl);
1216 },
1217 _ => unsafe { gl.enable(cap) },
1218 },
1219 WebGLCommand::FramebufferRenderbuffer(target, attachment, renderbuffertarget, rb) => {
1220 let attach = |attachment| unsafe {
1221 gl.framebuffer_renderbuffer(
1222 target,
1223 attachment,
1224 renderbuffertarget,
1225 rb.map(WebGLRenderbufferId::glow),
1226 )
1227 };
1228 if attachment == gl::DEPTH_STENCIL_ATTACHMENT {
1229 attach(gl::DEPTH_ATTACHMENT);
1230 attach(gl::STENCIL_ATTACHMENT);
1231 } else {
1232 attach(attachment);
1233 }
1234 },
1235 WebGLCommand::FramebufferTexture2D(target, attachment, textarget, texture, level) => {
1236 let attach = |attachment| unsafe {
1237 gl.framebuffer_texture_2d(
1238 target,
1239 attachment,
1240 textarget,
1241 texture.map(WebGLTextureId::glow),
1242 level,
1243 )
1244 };
1245 if attachment == gl::DEPTH_STENCIL_ATTACHMENT {
1246 attach(gl::DEPTH_ATTACHMENT);
1247 attach(gl::STENCIL_ATTACHMENT);
1248 } else {
1249 attach(attachment)
1250 }
1251 },
1252 WebGLCommand::FrontFace(mode) => unsafe { gl.front_face(mode) },
1253 WebGLCommand::DisableVertexAttribArray(attrib_id) => unsafe {
1254 gl.disable_vertex_attrib_array(attrib_id)
1255 },
1256 WebGLCommand::EnableVertexAttribArray(attrib_id) => unsafe {
1257 gl.enable_vertex_attrib_array(attrib_id)
1258 },
1259 WebGLCommand::Hint(name, val) => unsafe { gl.hint(name, val) },
1260 WebGLCommand::LineWidth(width) => {
1261 unsafe { gl.line_width(width) };
1262 if width != 1.0 {
1264 let _ = unsafe { gl.get_error() };
1265 }
1266 },
1267 WebGLCommand::PixelStorei(name, val) => unsafe { gl.pixel_store_i32(name, val) },
1268 WebGLCommand::PolygonOffset(factor, units) => unsafe {
1269 gl.polygon_offset(factor, units)
1270 },
1271 WebGLCommand::ReadPixels(rect, format, pixel_type, ref sender) => {
1272 let len = bytes_per_type(pixel_type) *
1273 components_per_format(format) *
1274 rect.size.area() as usize;
1275 let mut pixels = vec![0; len];
1276 unsafe {
1277 gl.pixel_store_i32(glow::PACK_ALIGNMENT, 1);
1279 gl.read_pixels(
1280 rect.origin.x as i32,
1281 rect.origin.y as i32,
1282 rect.size.width as i32,
1283 rect.size.height as i32,
1284 format,
1285 pixel_type,
1286 glow::PixelPackData::Slice(Some(&mut pixels)),
1287 )
1288 };
1289 let alpha_mode = match (attributes.alpha, attributes.premultiplied_alpha) {
1290 (true, premultiplied) => SnapshotAlphaMode::Transparent { premultiplied },
1291 (false, _) => SnapshotAlphaMode::Opaque,
1292 };
1293 sender
1294 .send((GenericSharedMemory::from_vec(pixels), alpha_mode))
1295 .unwrap();
1296 },
1297 WebGLCommand::ReadPixelsPP(rect, format, pixel_type, offset) => unsafe {
1298 gl.read_pixels(
1299 rect.origin.x,
1300 rect.origin.y,
1301 rect.size.width,
1302 rect.size.height,
1303 format,
1304 pixel_type,
1305 glow::PixelPackData::BufferOffset(offset as u32),
1306 );
1307 },
1308 WebGLCommand::RenderbufferStorage(target, format, width, height) => unsafe {
1309 gl.renderbuffer_storage(target, format, width, height)
1310 },
1311 WebGLCommand::RenderbufferStorageMultisample(
1312 target,
1313 samples,
1314 format,
1315 width,
1316 height,
1317 ) => unsafe {
1318 gl.renderbuffer_storage_multisample(target, samples, format, width, height)
1319 },
1320 WebGLCommand::SampleCoverage(value, invert) => unsafe {
1321 gl.sample_coverage(value, invert)
1322 },
1323 WebGLCommand::Scissor(x, y, width, height) => {
1324 unsafe { gl.scissor(x, y, width as i32, height as i32) };
1328 },
1329 WebGLCommand::StencilFunc(func, ref_, mask) => {
1330 state.stencil_value_mask = (mask, mask);
1331 unsafe { gl.stencil_func(func, ref_, mask) }
1332 },
1333 WebGLCommand::StencilFuncSeparate(face, func, ref_, mask) => {
1334 if face != gl::BACK {
1335 state.stencil_value_mask.0 = mask;
1336 }
1337 if face != gl::FRONT {
1338 state.stencil_value_mask.1 = mask;
1339 }
1340 unsafe { gl.stencil_func_separate(face, func, ref_, mask) }
1341 },
1342 WebGLCommand::StencilMask(mask) => {
1343 state.stencil_write_mask = (mask, mask);
1344 state.restore_stencil_invariant(gl);
1345 },
1346 WebGLCommand::StencilMaskSeparate(face, mask) => {
1347 match face {
1348 gl::FRONT => state.stencil_write_mask.0 = mask,
1349 gl::BACK => state.stencil_write_mask.1 = mask,
1350 gl::FRONT_AND_BACK => state.stencil_write_mask = (mask, mask),
1351 _ => debug_assert!(
1352 false,
1353 "stencilMaskSeparate face {face:#x} should have been rejected by the DOM"
1354 ),
1355 }
1356 state.restore_stencil_invariant(gl);
1357 },
1358 WebGLCommand::StencilOp(fail, zfail, zpass) => unsafe {
1359 gl.stencil_op(fail, zfail, zpass)
1360 },
1361 WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass) => unsafe {
1362 gl.stencil_op_separate(face, fail, zfail, zpass)
1363 },
1364 WebGLCommand::GetRenderbufferParameter(target, pname, ref chan) => {
1365 Self::get_renderbuffer_parameter(gl, target, pname, chan)
1366 },
1367 WebGLCommand::CreateTransformFeedback(ref sender) => {
1368 let value = unsafe { gl.create_transform_feedback() }.ok();
1369 sender
1370 .send(value.map(|ntf| ntf.0.get()).unwrap_or_default())
1371 .unwrap()
1372 },
1373 WebGLCommand::DeleteTransformFeedback(id) => {
1374 if let Some(tf) = NonZeroU32::new(id) {
1375 unsafe { gl.delete_transform_feedback(NativeTransformFeedback(tf)) };
1376 }
1377 },
1378 WebGLCommand::IsTransformFeedback(id, ref sender) => {
1379 let value = NonZeroU32::new(id)
1380 .map(|id| unsafe { gl.is_transform_feedback(NativeTransformFeedback(id)) })
1381 .unwrap_or_default();
1382 sender.send(value).unwrap()
1383 },
1384 WebGLCommand::BindTransformFeedback(target, id) => {
1385 unsafe {
1386 gl.bind_transform_feedback(
1387 target,
1388 NonZeroU32::new(id).map(NativeTransformFeedback),
1389 )
1390 };
1391 },
1392 WebGLCommand::BeginTransformFeedback(mode) => {
1393 unsafe { gl.begin_transform_feedback(mode) };
1394 },
1395 WebGLCommand::EndTransformFeedback() => {
1396 unsafe { gl.end_transform_feedback() };
1397 },
1398 WebGLCommand::PauseTransformFeedback() => {
1399 unsafe { gl.pause_transform_feedback() };
1400 },
1401 WebGLCommand::ResumeTransformFeedback() => {
1402 unsafe { gl.resume_transform_feedback() };
1403 },
1404 WebGLCommand::GetTransformFeedbackVarying(program, index, ref sender) => {
1405 let ActiveTransformFeedback { size, tftype, name } =
1406 unsafe { gl.get_transform_feedback_varying(program.glow(), index) }.unwrap();
1407 let name = from_name_in_compiled_shader(&name);
1409 sender.send((size, tftype, name)).unwrap();
1410 },
1411 WebGLCommand::TransformFeedbackVaryings(program, ref varyings, buffer_mode) => {
1412 let varyings: Vec<String> = varyings
1413 .iter()
1414 .map(|varying| to_name_in_compiled_shader(varying))
1415 .collect();
1416 let varyings_refs: Vec<&str> = varyings.iter().map(String::as_ref).collect();
1417 unsafe {
1418 gl.transform_feedback_varyings(
1419 program.glow(),
1420 varyings_refs.as_slice(),
1421 buffer_mode,
1422 )
1423 };
1424 },
1425 WebGLCommand::GetFramebufferAttachmentParameter(
1426 target,
1427 attachment,
1428 pname,
1429 ref chan,
1430 ) => Self::get_framebuffer_attachment_parameter(gl, target, attachment, pname, chan),
1431 WebGLCommand::GetShaderPrecisionFormat(shader_type, precision_type, ref chan) => {
1432 Self::shader_precision_format(gl, shader_type, precision_type, chan)
1433 },
1434 WebGLCommand::GetExtensions(ref chan) => Self::get_extensions(gl, chan),
1435 WebGLCommand::GetFragDataLocation(program_id, ref name, ref sender) => {
1436 let location = unsafe {
1437 gl.get_frag_data_location(program_id.glow(), &to_name_in_compiled_shader(name))
1438 };
1439 sender.send(location).unwrap();
1440 },
1441 WebGLCommand::GetUniformLocation(program_id, ref name, ref chan) => {
1442 Self::uniform_location(gl, program_id, name, chan)
1443 },
1444 WebGLCommand::GetShaderInfoLog(shader_id, ref chan) => {
1445 Self::shader_info_log(gl, shader_id, chan)
1446 },
1447 WebGLCommand::GetProgramInfoLog(program_id, ref chan) => {
1448 Self::program_info_log(gl, program_id, chan)
1449 },
1450 WebGLCommand::CompileShader(shader_id, ref source) => {
1451 Self::compile_shader(gl, shader_id, source)
1452 },
1453 WebGLCommand::CreateBuffer(ref chan) => Self::create_buffer(gl, chan),
1454 WebGLCommand::CreateFramebuffer(ref chan) => Self::create_framebuffer(gl, chan),
1455 WebGLCommand::CreateRenderbuffer(ref chan) => Self::create_renderbuffer(gl, chan),
1456 WebGLCommand::CreateTexture(ref chan) => Self::create_texture(gl, chan),
1457 WebGLCommand::CreateProgram(ref chan) => Self::create_program(gl, chan),
1458 WebGLCommand::CreateShader(shader_type, ref chan) => {
1459 Self::create_shader(gl, shader_type, chan)
1460 },
1461 WebGLCommand::DeleteBuffer(id) => unsafe { gl.delete_buffer(id.glow()) },
1462 WebGLCommand::DeleteFramebuffer(id) => unsafe { gl.delete_framebuffer(id.glow()) },
1463 WebGLCommand::DeleteRenderbuffer(id) => unsafe { gl.delete_renderbuffer(id.glow()) },
1464 WebGLCommand::DeleteTexture(id) => unsafe { gl.delete_texture(id.glow()) },
1465 WebGLCommand::DeleteProgram(id) => unsafe { gl.delete_program(id.glow()) },
1466 WebGLCommand::DeleteShader(id) => unsafe { gl.delete_shader(id.glow()) },
1467 WebGLCommand::BindBuffer(target, id) => unsafe {
1468 gl.bind_buffer(target, id.map(WebGLBufferId::glow))
1469 },
1470 WebGLCommand::BindFramebuffer(target, request) => {
1471 Self::bind_framebuffer(gl, target, request, ctx, device, state)
1472 },
1473 WebGLCommand::BindRenderbuffer(target, id) => unsafe {
1474 gl.bind_renderbuffer(target, id.map(WebGLRenderbufferId::glow))
1475 },
1476 WebGLCommand::BindTexture(target, id) => unsafe {
1477 gl.bind_texture(target, id.map(WebGLTextureId::glow))
1478 },
1479 WebGLCommand::BlitFrameBuffer(
1480 src_x0,
1481 src_y0,
1482 src_x1,
1483 src_y1,
1484 dst_x0,
1485 dst_y0,
1486 dst_x1,
1487 dst_y1,
1488 mask,
1489 filter,
1490 ) => unsafe {
1491 gl.blit_framebuffer(
1492 src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter,
1493 );
1494 },
1495 WebGLCommand::Uniform1f(uniform_id, v) => unsafe {
1496 gl.uniform_1_f32(native_uniform_location(uniform_id).as_ref(), v)
1497 },
1498 WebGLCommand::Uniform1fv(uniform_id, ref v) => unsafe {
1499 gl.uniform_1_f32_slice(native_uniform_location(uniform_id).as_ref(), v)
1500 },
1501 WebGLCommand::Uniform1i(uniform_id, v) => unsafe {
1502 gl.uniform_1_i32(native_uniform_location(uniform_id).as_ref(), v)
1503 },
1504 WebGLCommand::Uniform1iv(uniform_id, ref v) => unsafe {
1505 gl.uniform_1_i32_slice(native_uniform_location(uniform_id).as_ref(), v)
1506 },
1507 WebGLCommand::Uniform1ui(uniform_id, v) => unsafe {
1508 gl.uniform_1_u32(native_uniform_location(uniform_id).as_ref(), v)
1509 },
1510 WebGLCommand::Uniform1uiv(uniform_id, ref v) => unsafe {
1511 gl.uniform_1_u32_slice(native_uniform_location(uniform_id).as_ref(), v)
1512 },
1513 WebGLCommand::Uniform2f(uniform_id, x, y) => unsafe {
1514 gl.uniform_2_f32(native_uniform_location(uniform_id).as_ref(), x, y)
1515 },
1516 WebGLCommand::Uniform2fv(uniform_id, ref v) => unsafe {
1517 gl.uniform_2_f32_slice(native_uniform_location(uniform_id).as_ref(), v)
1518 },
1519 WebGLCommand::Uniform2i(uniform_id, x, y) => unsafe {
1520 gl.uniform_2_i32(native_uniform_location(uniform_id).as_ref(), x, y)
1521 },
1522 WebGLCommand::Uniform2iv(uniform_id, ref v) => unsafe {
1523 gl.uniform_2_i32_slice(native_uniform_location(uniform_id).as_ref(), v)
1524 },
1525 WebGLCommand::Uniform2ui(uniform_id, x, y) => unsafe {
1526 gl.uniform_2_u32(native_uniform_location(uniform_id).as_ref(), x, y)
1527 },
1528 WebGLCommand::Uniform2uiv(uniform_id, ref v) => unsafe {
1529 gl.uniform_2_u32_slice(native_uniform_location(uniform_id).as_ref(), v)
1530 },
1531 WebGLCommand::Uniform3f(uniform_id, x, y, z) => unsafe {
1532 gl.uniform_3_f32(native_uniform_location(uniform_id).as_ref(), x, y, z)
1533 },
1534 WebGLCommand::Uniform3fv(uniform_id, ref v) => unsafe {
1535 gl.uniform_3_f32_slice(native_uniform_location(uniform_id).as_ref(), v)
1536 },
1537 WebGLCommand::Uniform3i(uniform_id, x, y, z) => unsafe {
1538 gl.uniform_3_i32(native_uniform_location(uniform_id).as_ref(), x, y, z)
1539 },
1540 WebGLCommand::Uniform3iv(uniform_id, ref v) => unsafe {
1541 gl.uniform_3_i32_slice(native_uniform_location(uniform_id).as_ref(), v)
1542 },
1543 WebGLCommand::Uniform3ui(uniform_id, x, y, z) => unsafe {
1544 gl.uniform_3_u32(native_uniform_location(uniform_id).as_ref(), x, y, z)
1545 },
1546 WebGLCommand::Uniform3uiv(uniform_id, ref v) => unsafe {
1547 gl.uniform_3_u32_slice(native_uniform_location(uniform_id).as_ref(), v)
1548 },
1549 WebGLCommand::Uniform4f(uniform_id, x, y, z, w) => unsafe {
1550 gl.uniform_4_f32(native_uniform_location(uniform_id).as_ref(), x, y, z, w)
1551 },
1552 WebGLCommand::Uniform4fv(uniform_id, ref v) => unsafe {
1553 gl.uniform_4_f32_slice(native_uniform_location(uniform_id).as_ref(), v)
1554 },
1555 WebGLCommand::Uniform4i(uniform_id, x, y, z, w) => unsafe {
1556 gl.uniform_4_i32(native_uniform_location(uniform_id).as_ref(), x, y, z, w)
1557 },
1558 WebGLCommand::Uniform4iv(uniform_id, ref v) => unsafe {
1559 gl.uniform_4_i32_slice(native_uniform_location(uniform_id).as_ref(), v)
1560 },
1561 WebGLCommand::Uniform4ui(uniform_id, x, y, z, w) => unsafe {
1562 gl.uniform_4_u32(native_uniform_location(uniform_id).as_ref(), x, y, z, w)
1563 },
1564 WebGLCommand::Uniform4uiv(uniform_id, ref v) => unsafe {
1565 gl.uniform_4_u32_slice(native_uniform_location(uniform_id).as_ref(), v)
1566 },
1567 WebGLCommand::UniformMatrix2fv(uniform_id, ref v) => unsafe {
1568 gl.uniform_matrix_2_f32_slice(
1569 native_uniform_location(uniform_id).as_ref(),
1570 false,
1571 v,
1572 )
1573 },
1574 WebGLCommand::UniformMatrix3fv(uniform_id, ref v) => unsafe {
1575 gl.uniform_matrix_3_f32_slice(
1576 native_uniform_location(uniform_id).as_ref(),
1577 false,
1578 v,
1579 )
1580 },
1581 WebGLCommand::UniformMatrix4fv(uniform_id, ref v) => unsafe {
1582 gl.uniform_matrix_4_f32_slice(
1583 native_uniform_location(uniform_id).as_ref(),
1584 false,
1585 v,
1586 )
1587 },
1588 WebGLCommand::UniformMatrix3x2fv(uniform_id, ref v) => unsafe {
1589 gl.uniform_matrix_3x2_f32_slice(
1590 native_uniform_location(uniform_id).as_ref(),
1591 false,
1592 v,
1593 )
1594 },
1595 WebGLCommand::UniformMatrix4x2fv(uniform_id, ref v) => unsafe {
1596 gl.uniform_matrix_4x2_f32_slice(
1597 native_uniform_location(uniform_id).as_ref(),
1598 false,
1599 v,
1600 )
1601 },
1602 WebGLCommand::UniformMatrix2x3fv(uniform_id, ref v) => unsafe {
1603 gl.uniform_matrix_2x3_f32_slice(
1604 native_uniform_location(uniform_id).as_ref(),
1605 false,
1606 v,
1607 )
1608 },
1609 WebGLCommand::UniformMatrix4x3fv(uniform_id, ref v) => unsafe {
1610 gl.uniform_matrix_4x3_f32_slice(
1611 native_uniform_location(uniform_id).as_ref(),
1612 false,
1613 v,
1614 )
1615 },
1616 WebGLCommand::UniformMatrix2x4fv(uniform_id, ref v) => unsafe {
1617 gl.uniform_matrix_2x4_f32_slice(
1618 native_uniform_location(uniform_id).as_ref(),
1619 false,
1620 v,
1621 )
1622 },
1623 WebGLCommand::UniformMatrix3x4fv(uniform_id, ref v) => unsafe {
1624 gl.uniform_matrix_3x4_f32_slice(
1625 native_uniform_location(uniform_id).as_ref(),
1626 false,
1627 v,
1628 )
1629 },
1630 WebGLCommand::ValidateProgram(program_id) => unsafe {
1631 gl.validate_program(program_id.glow())
1632 },
1633 WebGLCommand::VertexAttrib(attrib_id, x, y, z, w) => unsafe {
1634 gl.vertex_attrib_4_f32(attrib_id, x, y, z, w)
1635 },
1636 WebGLCommand::VertexAttribI(attrib_id, x, y, z, w) => unsafe {
1637 gl.vertex_attrib_4_i32(attrib_id, x, y, z, w)
1638 },
1639 WebGLCommand::VertexAttribU(attrib_id, x, y, z, w) => unsafe {
1640 gl.vertex_attrib_4_u32(attrib_id, x, y, z, w)
1641 },
1642 WebGLCommand::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset) => unsafe {
1643 gl.vertex_attrib_pointer_f32(
1644 attrib_id,
1645 size,
1646 gl::FLOAT,
1647 normalized,
1648 stride,
1649 offset as _,
1650 )
1651 },
1652 WebGLCommand::VertexAttribPointer(
1653 attrib_id,
1654 size,
1655 data_type,
1656 normalized,
1657 stride,
1658 offset,
1659 ) => unsafe {
1660 gl.vertex_attrib_pointer_f32(
1661 attrib_id,
1662 size,
1663 data_type,
1664 normalized,
1665 stride,
1666 offset as _,
1667 )
1668 },
1669 WebGLCommand::SetViewport(x, y, width, height) => unsafe {
1670 gl.viewport(x, y, width, height)
1671 },
1672 WebGLCommand::TexImage3D {
1673 target,
1674 level,
1675 internal_format,
1676 size,
1677 depth,
1678 format,
1679 data_type,
1680 effective_data_type,
1681 unpacking_alignment,
1682 alpha_treatment,
1683 y_axis_treatment,
1684 pixel_format,
1685 ref data,
1686 } => {
1687 let pixels = prepare_pixels(
1688 internal_format,
1689 data_type,
1690 size,
1691 unpacking_alignment,
1692 alpha_treatment,
1693 y_axis_treatment,
1694 pixel_format,
1695 Cow::Borrowed(data),
1696 );
1697
1698 unsafe {
1699 gl.pixel_store_i32(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32);
1700 gl.tex_image_3d(
1701 target,
1702 level as i32,
1703 internal_format.as_gl_constant() as i32,
1704 size.width as i32,
1705 size.height as i32,
1706 depth as i32,
1707 0,
1708 format.as_gl_constant(),
1709 effective_data_type,
1710 PixelUnpackData::Slice(Some(&pixels)),
1711 );
1712 }
1713 },
1714 WebGLCommand::TexImage2D {
1715 target,
1716 level,
1717 internal_format,
1718 size,
1719 format,
1720 data_type,
1721 effective_data_type,
1722 unpacking_alignment,
1723 alpha_treatment,
1724 y_axis_treatment,
1725 pixel_format,
1726 ref data,
1727 } => {
1728 let pixels = prepare_pixels(
1729 internal_format,
1730 data_type,
1731 size,
1732 unpacking_alignment,
1733 alpha_treatment,
1734 y_axis_treatment,
1735 pixel_format,
1736 Cow::Borrowed(data),
1737 );
1738
1739 unsafe {
1740 gl.pixel_store_i32(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32);
1741 gl.tex_image_2d(
1742 target,
1743 level as i32,
1744 internal_format.as_gl_constant() as i32,
1745 size.width as i32,
1746 size.height as i32,
1747 0,
1748 format.as_gl_constant(),
1749 effective_data_type,
1750 PixelUnpackData::Slice(Some(&pixels)),
1751 );
1752 }
1753 },
1754 WebGLCommand::TexImage2DPBO {
1755 target,
1756 level,
1757 internal_format,
1758 size,
1759 format,
1760 effective_data_type,
1761 unpacking_alignment,
1762 offset,
1763 } => unsafe {
1764 gl.pixel_store_i32(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32);
1765
1766 gl.tex_image_2d(
1767 target,
1768 level as i32,
1769 internal_format.as_gl_constant() as i32,
1770 size.width as i32,
1771 size.height as i32,
1772 0,
1773 format.as_gl_constant(),
1774 effective_data_type,
1775 PixelUnpackData::BufferOffset(offset as u32),
1776 );
1777 },
1778 WebGLCommand::TexSubImage2D {
1779 target,
1780 level,
1781 xoffset,
1782 yoffset,
1783 size,
1784 format,
1785 data_type,
1786 effective_data_type,
1787 unpacking_alignment,
1788 alpha_treatment,
1789 y_axis_treatment,
1790 pixel_format,
1791 ref data,
1792 } => {
1793 let pixels = prepare_pixels(
1794 format,
1795 data_type,
1796 size,
1797 unpacking_alignment,
1798 alpha_treatment,
1799 y_axis_treatment,
1800 pixel_format,
1801 Cow::Borrowed(data),
1802 );
1803
1804 unsafe {
1805 gl.pixel_store_i32(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32);
1806 gl.tex_sub_image_2d(
1807 target,
1808 level as i32,
1809 xoffset,
1810 yoffset,
1811 size.width as i32,
1812 size.height as i32,
1813 format.as_gl_constant(),
1814 effective_data_type,
1815 glow::PixelUnpackData::Slice(Some(&pixels)),
1816 );
1817 }
1818 },
1819 WebGLCommand::CompressedTexImage2D {
1820 target,
1821 level,
1822 internal_format,
1823 size,
1824 ref data,
1825 } => unsafe {
1826 gl.compressed_tex_image_2d(
1827 target,
1828 level as i32,
1829 internal_format as i32,
1830 size.width as i32,
1831 size.height as i32,
1832 0,
1833 data.len() as i32,
1834 data,
1835 )
1836 },
1837 WebGLCommand::CompressedTexSubImage2D {
1838 target,
1839 level,
1840 xoffset,
1841 yoffset,
1842 size,
1843 format,
1844 ref data,
1845 } => {
1846 unsafe {
1847 gl.compressed_tex_sub_image_2d(
1848 target,
1849 level,
1850 xoffset,
1851 yoffset,
1852 size.width as i32,
1853 size.height as i32,
1854 format,
1855 glow::CompressedPixelUnpackData::Slice(data),
1856 )
1857 };
1858 },
1859 WebGLCommand::TexStorage2D(target, levels, internal_format, width, height) => unsafe {
1860 gl.tex_storage_2d(
1861 target,
1862 levels as i32,
1863 internal_format.as_gl_constant(),
1864 width as i32,
1865 height as i32,
1866 )
1867 },
1868 WebGLCommand::TexStorage3D(target, levels, internal_format, width, height, depth) => unsafe {
1869 gl.tex_storage_3d(
1870 target,
1871 levels as i32,
1872 internal_format.as_gl_constant(),
1873 width as i32,
1874 height as i32,
1875 depth as i32,
1876 )
1877 },
1878 WebGLCommand::DrawingBufferWidth(ref sender) => {
1879 let size = device
1880 .context_surface_info(ctx)
1881 .unwrap()
1882 .expect("Where's the front buffer?")
1883 .size;
1884 sender.send(size.width).unwrap()
1885 },
1886 WebGLCommand::DrawingBufferHeight(ref sender) => {
1887 let size = device
1888 .context_surface_info(ctx)
1889 .unwrap()
1890 .expect("Where's the front buffer?")
1891 .size;
1892 sender.send(size.height).unwrap()
1893 },
1894 WebGLCommand::Finish(ref sender) => Self::finish(gl, sender),
1895 WebGLCommand::Flush => unsafe { gl.flush() },
1896 WebGLCommand::GenerateMipmap(target) => unsafe { gl.generate_mipmap(target) },
1897 WebGLCommand::CreateVertexArray(ref chan) => {
1898 let id = Self::create_vertex_array(gl);
1899 let _ = chan.send(id);
1900 },
1901 WebGLCommand::DeleteVertexArray(id) => {
1902 unsafe { gl.delete_vertex_array(id.glow()) };
1903 },
1904 WebGLCommand::BindVertexArray(id) => {
1905 let id = id.map(WebGLVertexArrayId::glow).or(state.default_vao);
1906 unsafe { gl.bind_vertex_array(id) }
1907 },
1908 WebGLCommand::GetParameterBool(param, ref sender) => {
1909 let value = match param {
1910 webgl::ParameterBool::DepthWritemask => state.depth_write_mask,
1911 _ => unsafe { gl.get_parameter_bool(param as u32) },
1912 };
1913 sender.send(value).unwrap()
1914 },
1915 WebGLCommand::FenceSync(ref sender) => {
1916 let value = unsafe { gl.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0).unwrap() };
1917 sender.send(WebGLSyncId::from_glow(value)).unwrap();
1918 },
1919 WebGLCommand::IsSync(sync_id, ref sender) => {
1920 let value = unsafe { gl.is_sync(sync_id.glow()) };
1921 sender.send(value).unwrap();
1922 },
1923 WebGLCommand::ClientWaitSync(sync_id, flags, timeout, ref sender) => {
1924 let value = unsafe { gl.client_wait_sync(sync_id.glow(), flags, timeout as _) };
1925 sender.send(value).unwrap();
1926 },
1927 WebGLCommand::WaitSync(sync_id, flags, timeout) => {
1928 unsafe { gl.wait_sync(sync_id.glow(), flags, timeout as u64) };
1929 },
1930 WebGLCommand::GetSyncParameter(sync_id, param, ref sender) => {
1931 let value = unsafe { gl.get_sync_parameter_i32(sync_id.glow(), param) };
1932 sender.send(value as u32).unwrap();
1933 },
1934 WebGLCommand::DeleteSync(sync_id) => {
1935 unsafe { gl.delete_sync(sync_id.glow()) };
1936 },
1937 WebGLCommand::GetParameterBool4(param, ref sender) => {
1938 let value = match param {
1939 webgl::ParameterBool4::ColorWritemask => state.color_write_mask,
1940 };
1941 sender.send(value).unwrap()
1942 },
1943 WebGLCommand::GetParameterInt(param, ref sender) => {
1944 let value = match param {
1945 webgl::ParameterInt::AlphaBits if state.fake_no_alpha() => 0,
1946 webgl::ParameterInt::DepthBits if state.fake_no_depth() => 0,
1947 webgl::ParameterInt::StencilBits if state.fake_no_stencil() => 0,
1948 _ => unsafe { gl.get_parameter_i32(param as u32) },
1949 };
1950 sender.send(value).unwrap()
1951 },
1952 WebGLCommand::GetParameterUInt(param, ref sender) => {
1953 let value = match param {
1954 webgl::ParameterUInt::StencilWritemask => state.stencil_write_mask.0,
1955 webgl::ParameterUInt::StencilBackWritemask => state.stencil_write_mask.1,
1956 webgl::ParameterUInt::StencilValueMask => state.stencil_value_mask.0,
1957 webgl::ParameterUInt::StencilBackValueMask => state.stencil_value_mask.1,
1958 };
1959 sender.send(value).unwrap()
1960 },
1961 WebGLCommand::GetParameterInt2(param, ref sender) => {
1962 let mut value = [0; 2];
1963 unsafe {
1964 gl.get_parameter_i32_slice(param as u32, &mut value);
1965 }
1966 sender.send(value).unwrap()
1967 },
1968 WebGLCommand::GetParameterInt4(param, ref sender) => {
1969 let mut value = [0; 4];
1970 unsafe {
1971 gl.get_parameter_i32_slice(param as u32, &mut value);
1972 }
1973 sender.send(value).unwrap()
1974 },
1975 WebGLCommand::GetParameterFloat(param, ref sender) => {
1976 let mut value = [0.];
1977 unsafe {
1978 gl.get_parameter_f32_slice(param as u32, &mut value);
1979 }
1980 sender.send(value[0]).unwrap()
1981 },
1982 WebGLCommand::GetParameterFloat2(param, ref sender) => {
1983 let mut value = [0.; 2];
1984 unsafe {
1985 gl.get_parameter_f32_slice(param as u32, &mut value);
1986 }
1987 sender.send(value).unwrap()
1988 },
1989 WebGLCommand::GetParameterFloat4(param, ref sender) => {
1990 let mut value = [0.; 4];
1991 unsafe {
1992 gl.get_parameter_f32_slice(param as u32, &mut value);
1993 }
1994 sender.send(value).unwrap()
1995 },
1996 WebGLCommand::GetProgramValidateStatus(program, ref sender) => sender
1997 .send(unsafe { gl.get_program_validate_status(program.glow()) })
1998 .unwrap(),
1999 WebGLCommand::GetProgramActiveUniforms(program, ref sender) => sender
2000 .send(unsafe { gl.get_program_parameter_i32(program.glow(), gl::ACTIVE_UNIFORMS) })
2001 .unwrap(),
2002 WebGLCommand::GetCurrentVertexAttrib(index, ref sender) => {
2003 let mut value = [0.; 4];
2004 unsafe {
2005 gl.get_vertex_attrib_parameter_f32_slice(
2006 index,
2007 gl::CURRENT_VERTEX_ATTRIB,
2008 &mut value,
2009 );
2010 }
2011 sender.send(value).unwrap();
2012 },
2013 WebGLCommand::GetTexParameterFloat(target, param, ref sender) => {
2014 sender
2015 .send(unsafe { gl.get_tex_parameter_f32(target, param as u32) })
2016 .unwrap();
2017 },
2018 WebGLCommand::GetTexParameterInt(target, param, ref sender) => {
2019 sender
2020 .send(unsafe { gl.get_tex_parameter_i32(target, param as u32) })
2021 .unwrap();
2022 },
2023 WebGLCommand::GetTexParameterBool(target, param, ref sender) => {
2024 sender
2025 .send(unsafe { gl.get_tex_parameter_i32(target, param as u32) } != 0)
2026 .unwrap();
2027 },
2028 WebGLCommand::GetInternalFormatIntVec(target, internal_format, param, ref sender) => {
2029 match param {
2030 InternalFormatIntVec::Samples => {
2031 let mut count = [0; 1];
2032 unsafe {
2033 gl.get_internal_format_i32_slice(
2034 target,
2035 internal_format,
2036 gl::NUM_SAMPLE_COUNTS,
2037 &mut count,
2038 )
2039 };
2040 assert!(count[0] >= 0);
2041
2042 let mut values = vec![0; count[0] as usize];
2043 unsafe {
2044 gl.get_internal_format_i32_slice(
2045 target,
2046 internal_format,
2047 param as u32,
2048 &mut values,
2049 )
2050 };
2051 sender.send(values).unwrap()
2052 },
2053 }
2054 },
2055 WebGLCommand::TexParameteri(target, param, value) => unsafe {
2056 gl.tex_parameter_i32(target, param, value)
2057 },
2058 WebGLCommand::TexParameterf(target, param, value) => unsafe {
2059 gl.tex_parameter_f32(target, param, value)
2060 },
2061 WebGLCommand::LinkProgram(program_id, ref sender) => {
2062 sender.send(Self::link_program(gl, program_id)).unwrap()
2063 },
2064 WebGLCommand::UseProgram(program_id) => unsafe {
2065 gl.use_program(program_id.map(|p| p.glow()))
2066 },
2067 WebGLCommand::DrawArrays { mode, first, count } => unsafe {
2068 gl.draw_arrays(mode, first, count)
2069 },
2070 WebGLCommand::DrawArraysInstanced {
2071 mode,
2072 first,
2073 count,
2074 primcount,
2075 } => unsafe { gl.draw_arrays_instanced(mode, first, count, primcount) },
2076 WebGLCommand::DrawElements {
2077 mode,
2078 count,
2079 type_,
2080 offset,
2081 } => unsafe { gl.draw_elements(mode, count, type_, offset as _) },
2082 WebGLCommand::DrawElementsInstanced {
2083 mode,
2084 count,
2085 type_,
2086 offset,
2087 primcount,
2088 } => unsafe {
2089 gl.draw_elements_instanced(mode, count, type_, offset as i32, primcount)
2090 },
2091 WebGLCommand::VertexAttribDivisor { index, divisor } => unsafe {
2092 gl.vertex_attrib_divisor(index, divisor)
2093 },
2094 WebGLCommand::GetUniformBool(program_id, loc, ref sender) => {
2095 let mut value = [0];
2096 unsafe {
2097 gl.get_uniform_i32(
2098 program_id.glow(),
2099 &NativeUniformLocation(loc as u32),
2100 &mut value,
2101 );
2102 }
2103 sender.send(value[0] != 0).unwrap();
2104 },
2105 WebGLCommand::GetUniformBool2(program_id, loc, ref sender) => {
2106 let mut value = [0; 2];
2107 unsafe {
2108 gl.get_uniform_i32(
2109 program_id.glow(),
2110 &NativeUniformLocation(loc as u32),
2111 &mut value,
2112 );
2113 }
2114 let value = [value[0] != 0, value[1] != 0];
2115 sender.send(value).unwrap();
2116 },
2117 WebGLCommand::GetUniformBool3(program_id, loc, ref sender) => {
2118 let mut value = [0; 3];
2119 unsafe {
2120 gl.get_uniform_i32(
2121 program_id.glow(),
2122 &NativeUniformLocation(loc as u32),
2123 &mut value,
2124 );
2125 }
2126 let value = [value[0] != 0, value[1] != 0, value[2] != 0];
2127 sender.send(value).unwrap();
2128 },
2129 WebGLCommand::GetUniformBool4(program_id, loc, ref sender) => {
2130 let mut value = [0; 4];
2131 unsafe {
2132 gl.get_uniform_i32(
2133 program_id.glow(),
2134 &NativeUniformLocation(loc as u32),
2135 &mut value,
2136 );
2137 }
2138 let value = [value[0] != 0, value[1] != 0, value[2] != 0, value[3] != 0];
2139 sender.send(value).unwrap();
2140 },
2141 WebGLCommand::GetUniformInt(program_id, loc, ref sender) => {
2142 let mut value = [0];
2143 unsafe {
2144 gl.get_uniform_i32(
2145 program_id.glow(),
2146 &NativeUniformLocation(loc as u32),
2147 &mut value,
2148 );
2149 }
2150 sender.send(value[0]).unwrap();
2151 },
2152 WebGLCommand::GetUniformInt2(program_id, loc, ref sender) => {
2153 let mut value = [0; 2];
2154 unsafe {
2155 gl.get_uniform_i32(
2156 program_id.glow(),
2157 &NativeUniformLocation(loc as u32),
2158 &mut value,
2159 );
2160 }
2161 sender.send(value).unwrap();
2162 },
2163 WebGLCommand::GetUniformInt3(program_id, loc, ref sender) => {
2164 let mut value = [0; 3];
2165 unsafe {
2166 gl.get_uniform_i32(
2167 program_id.glow(),
2168 &NativeUniformLocation(loc as u32),
2169 &mut value,
2170 );
2171 }
2172 sender.send(value).unwrap();
2173 },
2174 WebGLCommand::GetUniformInt4(program_id, loc, ref sender) => {
2175 let mut value = [0; 4];
2176 unsafe {
2177 gl.get_uniform_i32(
2178 program_id.glow(),
2179 &NativeUniformLocation(loc as u32),
2180 &mut value,
2181 );
2182 }
2183 sender.send(value).unwrap();
2184 },
2185 WebGLCommand::GetUniformUint(program_id, loc, ref sender) => {
2186 let mut value = [0];
2187 unsafe {
2188 gl.get_uniform_u32(
2189 program_id.glow(),
2190 &NativeUniformLocation(loc as u32),
2191 &mut value,
2192 );
2193 }
2194 sender.send(value[0]).unwrap();
2195 },
2196 WebGLCommand::GetUniformUint2(program_id, loc, ref sender) => {
2197 let mut value = [0; 2];
2198 unsafe {
2199 gl.get_uniform_u32(
2200 program_id.glow(),
2201 &NativeUniformLocation(loc as u32),
2202 &mut value,
2203 );
2204 }
2205 sender.send(value).unwrap();
2206 },
2207 WebGLCommand::GetUniformUint3(program_id, loc, ref sender) => {
2208 let mut value = [0; 3];
2209 unsafe {
2210 gl.get_uniform_u32(
2211 program_id.glow(),
2212 &NativeUniformLocation(loc as u32),
2213 &mut value,
2214 );
2215 }
2216 sender.send(value).unwrap();
2217 },
2218 WebGLCommand::GetUniformUint4(program_id, loc, ref sender) => {
2219 let mut value = [0; 4];
2220 unsafe {
2221 gl.get_uniform_u32(
2222 program_id.glow(),
2223 &NativeUniformLocation(loc as u32),
2224 &mut value,
2225 );
2226 }
2227 sender.send(value).unwrap();
2228 },
2229 WebGLCommand::GetUniformFloat(program_id, loc, ref sender) => {
2230 let mut value = [0.];
2231 unsafe {
2232 gl.get_uniform_f32(
2233 program_id.glow(),
2234 &NativeUniformLocation(loc as u32),
2235 &mut value,
2236 );
2237 }
2238 sender.send(value[0]).unwrap();
2239 },
2240 WebGLCommand::GetUniformFloat2(program_id, loc, ref sender) => {
2241 let mut value = [0.; 2];
2242 unsafe {
2243 gl.get_uniform_f32(
2244 program_id.glow(),
2245 &NativeUniformLocation(loc as u32),
2246 &mut value,
2247 );
2248 }
2249 sender.send(value).unwrap();
2250 },
2251 WebGLCommand::GetUniformFloat3(program_id, loc, ref sender) => {
2252 let mut value = [0.; 3];
2253 unsafe {
2254 gl.get_uniform_f32(
2255 program_id.glow(),
2256 &NativeUniformLocation(loc as u32),
2257 &mut value,
2258 );
2259 }
2260 sender.send(value).unwrap();
2261 },
2262 WebGLCommand::GetUniformFloat4(program_id, loc, ref sender) => {
2263 let mut value = [0.; 4];
2264 unsafe {
2265 gl.get_uniform_f32(
2266 program_id.glow(),
2267 &NativeUniformLocation(loc as u32),
2268 &mut value,
2269 );
2270 }
2271 sender.send(value).unwrap();
2272 },
2273 WebGLCommand::GetUniformFloat9(program_id, loc, ref sender) => {
2274 let mut value = [0.; 9];
2275 unsafe {
2276 gl.get_uniform_f32(
2277 program_id.glow(),
2278 &NativeUniformLocation(loc as u32),
2279 &mut value,
2280 );
2281 }
2282 sender.send(value).unwrap();
2283 },
2284 WebGLCommand::GetUniformFloat16(program_id, loc, ref sender) => {
2285 let mut value = [0.; 16];
2286 unsafe {
2287 gl.get_uniform_f32(
2288 program_id.glow(),
2289 &NativeUniformLocation(loc as u32),
2290 &mut value,
2291 );
2292 }
2293 sender.send(value).unwrap();
2294 },
2295 WebGLCommand::GetUniformFloat2x3(program_id, loc, ref sender) => {
2296 let mut value = [0.; 2 * 3];
2297 unsafe {
2298 gl.get_uniform_f32(
2299 program_id.glow(),
2300 &NativeUniformLocation(loc as u32),
2301 &mut value,
2302 );
2303 }
2304 sender.send(value).unwrap()
2305 },
2306 WebGLCommand::GetUniformFloat2x4(program_id, loc, ref sender) => {
2307 let mut value = [0.; 2 * 4];
2308 unsafe {
2309 gl.get_uniform_f32(
2310 program_id.glow(),
2311 &NativeUniformLocation(loc as u32),
2312 &mut value,
2313 );
2314 }
2315 sender.send(value).unwrap()
2316 },
2317 WebGLCommand::GetUniformFloat3x2(program_id, loc, ref sender) => {
2318 let mut value = [0.; 3 * 2];
2319 unsafe {
2320 gl.get_uniform_f32(
2321 program_id.glow(),
2322 &NativeUniformLocation(loc as u32),
2323 &mut value,
2324 );
2325 }
2326 sender.send(value).unwrap()
2327 },
2328 WebGLCommand::GetUniformFloat3x4(program_id, loc, ref sender) => {
2329 let mut value = [0.; 3 * 4];
2330 unsafe {
2331 gl.get_uniform_f32(
2332 program_id.glow(),
2333 &NativeUniformLocation(loc as u32),
2334 &mut value,
2335 );
2336 }
2337 sender.send(value).unwrap()
2338 },
2339 WebGLCommand::GetUniformFloat4x2(program_id, loc, ref sender) => {
2340 let mut value = [0.; 4 * 2];
2341 unsafe {
2342 gl.get_uniform_f32(
2343 program_id.glow(),
2344 &NativeUniformLocation(loc as u32),
2345 &mut value,
2346 );
2347 }
2348 sender.send(value).unwrap()
2349 },
2350 WebGLCommand::GetUniformFloat4x3(program_id, loc, ref sender) => {
2351 let mut value = [0.; 4 * 3];
2352 unsafe {
2353 gl.get_uniform_f32(
2354 program_id.glow(),
2355 &NativeUniformLocation(loc as u32),
2356 &mut value,
2357 );
2358 }
2359 sender.send(value).unwrap()
2360 },
2361 WebGLCommand::GetUniformBlockIndex(program_id, ref name, ref sender) => {
2362 let name = to_name_in_compiled_shader(name);
2363 let index = unsafe { gl.get_uniform_block_index(program_id.glow(), &name) };
2364 sender.send(index.unwrap_or(gl::INVALID_INDEX)).unwrap();
2366 },
2367 WebGLCommand::GetUniformIndices(program_id, ref names, ref sender) => {
2368 let names = names
2369 .iter()
2370 .map(|name| to_name_in_compiled_shader(name))
2371 .collect::<Vec<_>>();
2372 let name_strs = names.iter().map(|name| name.as_str()).collect::<Vec<_>>();
2373 let indices = unsafe {
2374 gl.get_uniform_indices(program_id.glow(), &name_strs)
2375 .iter()
2376 .map(|index| index.unwrap_or(gl::INVALID_INDEX))
2377 .collect()
2378 };
2379 sender.send(indices).unwrap();
2380 },
2381 WebGLCommand::GetActiveUniforms(program_id, ref indices, pname, ref sender) => {
2382 let results =
2383 unsafe { gl.get_active_uniforms_parameter(program_id.glow(), indices, pname) };
2384 sender.send(results).unwrap();
2385 },
2386 WebGLCommand::GetActiveUniformBlockName(program_id, block_idx, ref sender) => {
2387 let name =
2388 unsafe { gl.get_active_uniform_block_name(program_id.glow(), block_idx) };
2389 sender.send(name).unwrap();
2390 },
2391 WebGLCommand::GetActiveUniformBlockParameter(
2392 program_id,
2393 block_idx,
2394 pname,
2395 ref sender,
2396 ) => {
2397 let size = match pname {
2398 gl::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES => unsafe {
2399 gl.get_active_uniform_block_parameter_i32(
2400 program_id.glow(),
2401 block_idx,
2402 gl::UNIFORM_BLOCK_ACTIVE_UNIFORMS,
2403 ) as usize
2404 },
2405 _ => 1,
2406 };
2407 let mut result = vec![0; size];
2408 unsafe {
2409 gl.get_active_uniform_block_parameter_i32_slice(
2410 program_id.glow(),
2411 block_idx,
2412 pname,
2413 &mut result,
2414 )
2415 };
2416 sender.send(result).unwrap();
2417 },
2418 WebGLCommand::UniformBlockBinding(program_id, block_idx, block_binding) => unsafe {
2419 gl.uniform_block_binding(program_id.glow(), block_idx, block_binding)
2420 },
2421 WebGLCommand::InitializeFramebuffer {
2422 color,
2423 depth,
2424 stencil,
2425 } => Self::initialize_framebuffer(gl, state, color, depth, stencil),
2426 WebGLCommand::BeginQuery(target, query_id) => {
2427 unsafe { gl.begin_query(target, query_id.glow()) };
2428 },
2429 WebGLCommand::EndQuery(target) => {
2430 unsafe { gl.end_query(target) };
2431 },
2432 WebGLCommand::DeleteQuery(query_id) => {
2433 unsafe { gl.delete_query(query_id.glow()) };
2434 },
2435 WebGLCommand::GenerateQuery(ref sender) => {
2436 let id = unsafe { gl.create_query().unwrap() };
2438 sender.send(WebGLQueryId::from_glow(id)).unwrap()
2439 },
2440 WebGLCommand::GetQueryState(ref sender, query_id, pname) => {
2441 let value = unsafe { gl.get_query_parameter_u32(query_id.glow(), pname) };
2442 sender.send(value).unwrap()
2443 },
2444 WebGLCommand::GenerateSampler(ref sender) => {
2445 let id = unsafe { gl.create_sampler().unwrap() };
2446 sender.send(WebGLSamplerId::from_glow(id)).unwrap()
2447 },
2448 WebGLCommand::DeleteSampler(sampler_id) => {
2449 unsafe { gl.delete_sampler(sampler_id.glow()) };
2450 },
2451 WebGLCommand::BindSampler(unit, sampler_id) => {
2452 unsafe { gl.bind_sampler(unit, Some(sampler_id.glow())) };
2453 },
2454 WebGLCommand::SetSamplerParameterInt(sampler_id, pname, value) => {
2455 unsafe { gl.sampler_parameter_i32(sampler_id.glow(), pname, value) };
2456 },
2457 WebGLCommand::SetSamplerParameterFloat(sampler_id, pname, value) => {
2458 unsafe { gl.sampler_parameter_f32(sampler_id.glow(), pname, value) };
2459 },
2460 WebGLCommand::GetSamplerParameterInt(sampler_id, pname, ref sender) => {
2461 let value = unsafe { gl.get_sampler_parameter_i32(sampler_id.glow(), pname) };
2462 sender.send(value).unwrap();
2463 },
2464 WebGLCommand::GetSamplerParameterFloat(sampler_id, pname, ref sender) => {
2465 let value = unsafe { gl.get_sampler_parameter_f32(sampler_id.glow(), pname) };
2466 sender.send(value).unwrap();
2467 },
2468 WebGLCommand::BindBufferBase(target, index, id) => {
2469 let id = id.map(WebGLBufferId::glow);
2474 unsafe {
2475 gl.bind_buffer(target, id);
2476 gl.bind_buffer(target, None);
2477 gl.bind_buffer_base(target, index, id);
2478 }
2479 },
2480 WebGLCommand::BindBufferRange(target, index, id, offset, size) => {
2481 let id = id.map(WebGLBufferId::glow);
2486 unsafe {
2487 gl.bind_buffer(target, id);
2488 gl.bind_buffer(target, None);
2489 gl.bind_buffer_range(target, index, id, offset as i32, size as i32);
2490 }
2491 },
2492 WebGLCommand::ClearBufferfv(buffer, draw_buffer, ref value) => unsafe {
2493 gl.clear_buffer_f32_slice(buffer, draw_buffer as u32, value)
2494 },
2495 WebGLCommand::ClearBufferiv(buffer, draw_buffer, ref value) => unsafe {
2496 gl.clear_buffer_i32_slice(buffer, draw_buffer as u32, value)
2497 },
2498 WebGLCommand::ClearBufferuiv(buffer, draw_buffer, ref value) => unsafe {
2499 gl.clear_buffer_u32_slice(buffer, draw_buffer as u32, value)
2500 },
2501 WebGLCommand::ClearBufferfi(buffer, draw_buffer, depth, stencil) => unsafe {
2502 gl.clear_buffer_depth_stencil(buffer, draw_buffer as u32, depth, stencil)
2503 },
2504 WebGLCommand::InvalidateFramebuffer(target, ref attachments) => unsafe {
2505 gl.invalidate_framebuffer(target, attachments)
2506 },
2507 WebGLCommand::InvalidateSubFramebuffer(target, ref attachments, x, y, w, h) => unsafe {
2508 gl.invalidate_sub_framebuffer(target, attachments, x, y, w, h)
2509 },
2510 WebGLCommand::FramebufferTextureLayer(target, attachment, tex_id, level, layer) => {
2511 let tex_id = tex_id.map(WebGLTextureId::glow);
2512 let attach = |attachment| unsafe {
2513 gl.framebuffer_texture_layer(target, attachment, tex_id, level, layer)
2514 };
2515
2516 if attachment == gl::DEPTH_STENCIL_ATTACHMENT {
2517 attach(gl::DEPTH_ATTACHMENT);
2518 attach(gl::STENCIL_ATTACHMENT);
2519 } else {
2520 attach(attachment)
2521 }
2522 },
2523 WebGLCommand::ReadBuffer(buffer) => unsafe { gl.read_buffer(buffer) },
2524 WebGLCommand::DrawBuffers(ref buffers) => unsafe { gl.draw_buffers(buffers) },
2525 }
2526
2527 #[cfg(debug_assertions)]
2529 {
2530 let error = unsafe { gl.get_error() };
2531 if error != gl::NO_ERROR {
2532 error!("Last GL operation failed: {:?}", command);
2533 if error == gl::INVALID_FRAMEBUFFER_OPERATION {
2534 let framebuffer_bindings =
2535 unsafe { gl.get_parameter_framebuffer(gl::DRAW_FRAMEBUFFER_BINDING) };
2536 debug!(
2537 "(thread {:?}) Current draw framebuffer binding: {:?}",
2538 ::std::thread::current().id(),
2539 framebuffer_bindings
2540 );
2541 }
2542 #[cfg(feature = "webgl_backtrace")]
2543 {
2544 error!("Backtrace from failed WebGL API:\n{}", _backtrace.backtrace);
2545 if let Some(backtrace) = _backtrace.js_backtrace {
2546 error!("JS backtrace from failed WebGL API:\n{}", backtrace);
2547 }
2548 }
2549 log::warn!(
2551 "debug assertion failed! Unexpected WebGL error: 0x{:x} ({}) [{:?}]",
2552 error,
2553 error,
2554 command
2555 );
2556 }
2557 }
2558 }
2559
2560 fn initialize_framebuffer(gl: &Gl, state: &GLState, color: bool, depth: bool, stencil: bool) {
2561 let bits = [
2562 (color, gl::COLOR_BUFFER_BIT),
2563 (depth, gl::DEPTH_BUFFER_BIT),
2564 (stencil, gl::STENCIL_BUFFER_BIT),
2565 ]
2566 .iter()
2567 .fold(0, |bits, &(enabled, bit)| {
2568 bits | if enabled { bit } else { 0 }
2569 });
2570
2571 unsafe {
2572 gl.disable(gl::SCISSOR_TEST);
2573 gl.color_mask(true, true, true, true);
2574 gl.clear_color(0., 0., 0., 0.);
2575 gl.depth_mask(true);
2576 gl.clear_depth(1.);
2577 gl.stencil_mask_separate(gl::FRONT, 0xFFFFFFFF);
2578 gl.stencil_mask_separate(gl::BACK, 0xFFFFFFFF);
2579 gl.clear_stencil(0);
2580 gl.clear(bits);
2581 }
2582
2583 state.restore_invariant(gl);
2584 }
2585
2586 fn link_program(gl: &Gl, program: WebGLProgramId) -> ProgramLinkInfo {
2587 unsafe { gl.link_program(program.glow()) };
2588 let linked = unsafe { gl.get_program_link_status(program.glow()) };
2589 if !linked {
2590 return ProgramLinkInfo {
2591 linked: false,
2592 active_attribs: vec![].into(),
2593 active_uniforms: vec![].into(),
2594 active_uniform_blocks: vec![].into(),
2595 transform_feedback_length: Default::default(),
2596 transform_feedback_mode: Default::default(),
2597 };
2598 }
2599 let num_active_attribs =
2600 unsafe { gl.get_program_parameter_i32(program.glow(), gl::ACTIVE_ATTRIBUTES) };
2601 let active_attribs = (0..num_active_attribs as u32)
2602 .map(|i| {
2603 let active_attribute =
2604 unsafe { gl.get_active_attribute(program.glow(), i) }.unwrap();
2605 let name = &active_attribute.name;
2606 let location = if name.starts_with("gl_") {
2607 None
2608 } else {
2609 unsafe { gl.get_attrib_location(program.glow(), name) }
2610 };
2611 ActiveAttribInfo {
2612 name: from_name_in_compiled_shader(name),
2613 size: active_attribute.size,
2614 type_: active_attribute.atype,
2615 location,
2616 }
2617 })
2618 .collect::<Vec<_>>()
2619 .into();
2620
2621 let num_active_uniforms =
2622 unsafe { gl.get_program_parameter_i32(program.glow(), gl::ACTIVE_UNIFORMS) };
2623 let active_uniforms = (0..num_active_uniforms as u32)
2624 .map(|i| {
2625 let active_uniform = unsafe { gl.get_active_uniform(program.glow(), i) }.unwrap();
2626 let is_array = active_uniform.name.ends_with("[0]");
2627 let active_uniform_name = active_uniform
2628 .name
2629 .strip_suffix("[0]")
2630 .unwrap_or_else(|| &active_uniform.name);
2631 ActiveUniformInfo {
2632 base_name: from_name_in_compiled_shader(active_uniform_name).into(),
2633 size: if is_array {
2634 Some(active_uniform.size)
2635 } else {
2636 None
2637 },
2638 type_: active_uniform.utype,
2639 bind_index: None,
2640 }
2641 })
2642 .collect::<Vec<_>>()
2643 .into();
2644
2645 let num_active_uniform_blocks =
2646 unsafe { gl.get_program_parameter_i32(program.glow(), gl::ACTIVE_UNIFORM_BLOCKS) };
2647 let active_uniform_blocks = (0..num_active_uniform_blocks as u32)
2648 .map(|i| {
2649 let name = unsafe { gl.get_active_uniform_block_name(program.glow(), i) };
2650 let size = unsafe {
2651 gl.get_active_uniform_block_parameter_i32(
2652 program.glow(),
2653 i,
2654 gl::UNIFORM_BLOCK_DATA_SIZE,
2655 )
2656 };
2657 ActiveUniformBlockInfo { name, size }
2658 })
2659 .collect::<Vec<_>>()
2660 .into();
2661
2662 let transform_feedback_length = unsafe {
2663 gl.get_program_parameter_i32(program.glow(), gl::TRANSFORM_FEEDBACK_VARYINGS)
2664 };
2665 let transform_feedback_mode = unsafe {
2666 gl.get_program_parameter_i32(program.glow(), gl::TRANSFORM_FEEDBACK_BUFFER_MODE)
2667 };
2668
2669 ProgramLinkInfo {
2670 linked: true,
2671 active_attribs,
2672 active_uniforms,
2673 active_uniform_blocks,
2674 transform_feedback_length,
2675 transform_feedback_mode,
2676 }
2677 }
2678
2679 fn finish(gl: &Gl, chan: &GenericSender<()>) {
2680 unsafe { gl.finish() };
2681 chan.send(()).unwrap();
2682 }
2683
2684 fn shader_precision_format(
2685 gl: &Gl,
2686 shader_type: u32,
2687 precision_type: u32,
2688 chan: &GenericSender<(i32, i32, i32)>,
2689 ) {
2690 let ShaderPrecisionFormat {
2691 range_min,
2692 range_max,
2693 precision,
2694 } = unsafe {
2695 gl.get_shader_precision_format(shader_type, precision_type)
2696 .unwrap_or_else(|| {
2697 ShaderPrecisionFormat::common_desktop_hardware(
2698 precision_type,
2699 gl.version().is_embedded,
2700 )
2701 })
2702 };
2703 chan.send((range_min, range_max, precision)).unwrap();
2704 }
2705
2706 fn get_extensions(gl: &Gl, result_sender: &GenericSender<String>) {
2709 let _ = result_sender.send(gl.supported_extensions().iter().join(" "));
2710 }
2711
2712 fn get_framebuffer_attachment_parameter(
2714 gl: &Gl,
2715 target: u32,
2716 attachment: u32,
2717 pname: u32,
2718 chan: &GenericSender<i32>,
2719 ) {
2720 let parameter =
2721 unsafe { gl.get_framebuffer_attachment_parameter_i32(target, attachment, pname) };
2722 chan.send(parameter).unwrap();
2723 }
2724
2725 fn get_renderbuffer_parameter(gl: &Gl, target: u32, pname: u32, chan: &GenericSender<i32>) {
2727 let parameter = unsafe { gl.get_renderbuffer_parameter_i32(target, pname) };
2728 chan.send(parameter).unwrap();
2729 }
2730
2731 fn uniform_location(
2732 gl: &Gl,
2733 program_id: WebGLProgramId,
2734 name: &str,
2735 chan: &GenericSender<i32>,
2736 ) {
2737 let location = unsafe {
2738 gl.get_uniform_location(program_id.glow(), &to_name_in_compiled_shader(name))
2739 };
2740 chan.send(location.map(|l| l.0).unwrap_or_default() as i32)
2742 .unwrap();
2743 }
2744
2745 fn shader_info_log(gl: &Gl, shader_id: WebGLShaderId, chan: &GenericSender<String>) {
2746 let log = unsafe { gl.get_shader_info_log(shader_id.glow()) };
2747 chan.send(log).unwrap();
2748 }
2749
2750 fn program_info_log(gl: &Gl, program_id: WebGLProgramId, chan: &GenericSender<String>) {
2751 let log = unsafe { gl.get_program_info_log(program_id.glow()) };
2752 chan.send(log).unwrap();
2753 }
2754
2755 fn create_buffer(gl: &Gl, chan: &GenericSender<Option<WebGLBufferId>>) {
2756 let buffer = unsafe { gl.create_buffer() }
2757 .ok()
2758 .map(WebGLBufferId::from_glow);
2759 chan.send(buffer).unwrap();
2760 }
2761
2762 fn create_framebuffer(gl: &Gl, chan: &GenericSender<Option<WebGLFramebufferId>>) {
2763 let framebuffer = unsafe { gl.create_framebuffer() }
2764 .ok()
2765 .map(WebGLFramebufferId::from_glow);
2766 chan.send(framebuffer).unwrap();
2767 }
2768
2769 fn create_renderbuffer(gl: &Gl, chan: &GenericSender<Option<WebGLRenderbufferId>>) {
2770 let renderbuffer = unsafe { gl.create_renderbuffer() }
2771 .ok()
2772 .map(WebGLRenderbufferId::from_glow);
2773 chan.send(renderbuffer).unwrap();
2774 }
2775
2776 fn create_texture(gl: &Gl, chan: &GenericSender<Option<WebGLTextureId>>) {
2777 let texture = unsafe { gl.create_texture() }
2778 .ok()
2779 .map(WebGLTextureId::from_glow);
2780 chan.send(texture).unwrap();
2781 }
2782
2783 fn create_program(gl: &Gl, chan: &GenericSender<Option<WebGLProgramId>>) {
2784 let program = unsafe { gl.create_program() }
2785 .ok()
2786 .map(WebGLProgramId::from_glow);
2787 chan.send(program).unwrap();
2788 }
2789
2790 fn create_shader(gl: &Gl, shader_type: u32, chan: &GenericSender<Option<WebGLShaderId>>) {
2791 let shader = unsafe { gl.create_shader(shader_type) }
2792 .ok()
2793 .map(WebGLShaderId::from_glow);
2794 chan.send(shader).unwrap();
2795 }
2796
2797 fn create_vertex_array(gl: &Gl) -> Option<WebGLVertexArrayId> {
2798 let vao = unsafe { gl.create_vertex_array() }
2799 .ok()
2800 .map(WebGLVertexArrayId::from_glow);
2801 if vao.is_none() {
2802 let code = unsafe { gl.get_error() };
2803 warn!("Failed to create vertex array with error code {:x}", code);
2804 }
2805 vao
2806 }
2807
2808 #[inline]
2809 fn bind_framebuffer(
2810 gl: &Gl,
2811 target: u32,
2812 request: WebGLFramebufferBindingRequest,
2813 ctx: &Context,
2814 device: &Device,
2815 state: &mut GLState,
2816 ) {
2817 let id = match request {
2818 WebGLFramebufferBindingRequest::Explicit(id) => Some(id.glow()),
2819 WebGLFramebufferBindingRequest::Default => {
2820 device
2821 .context_surface_info(ctx)
2822 .unwrap()
2823 .expect("No surface attached!")
2824 .framebuffer_object
2825 },
2826 };
2827
2828 debug!("WebGLImpl::bind_framebuffer: {:?}", id);
2829 unsafe { gl.bind_framebuffer(target, id) };
2830
2831 if (target == gl::FRAMEBUFFER) || (target == gl::DRAW_FRAMEBUFFER) {
2832 state.drawing_to_default_framebuffer =
2833 request == WebGLFramebufferBindingRequest::Default;
2834 state.restore_invariant(gl);
2835 }
2836 }
2837
2838 #[inline]
2839 fn compile_shader(gl: &Gl, shader_id: WebGLShaderId, source: &str) {
2840 unsafe {
2841 gl.shader_source(shader_id.glow(), source);
2842 gl.compile_shader(shader_id.glow());
2843 }
2844 }
2845}
2846
2847const ANGLE_NAME_PREFIX: &str = "_u";
2854
2855fn to_name_in_compiled_shader(s: &str) -> String {
2857 map_dot_separated(s, |s, mapped| {
2858 mapped.push_str(ANGLE_NAME_PREFIX);
2859 mapped.push_str(s);
2860 })
2861}
2862
2863fn from_name_in_compiled_shader(s: &str) -> String {
2865 map_dot_separated(s, |s, mapped| {
2866 mapped.push_str(if let Some(stripped) = s.strip_prefix(ANGLE_NAME_PREFIX) {
2867 stripped
2868 } else {
2869 s
2870 })
2871 })
2872}
2873
2874fn map_dot_separated<F: Fn(&str, &mut String)>(s: &str, f: F) -> String {
2875 let mut iter = s.split('.');
2876 let mut mapped = String::new();
2877 f(iter.next().unwrap(), &mut mapped);
2878 for s in iter {
2879 mapped.push('.');
2880 f(s, &mut mapped);
2881 }
2882 mapped
2883}
2884
2885#[expect(clippy::too_many_arguments)]
2886fn prepare_pixels(
2887 internal_format: TexFormat,
2888 data_type: TexDataType,
2889 size: Size2D<u32>,
2890 unpacking_alignment: u32,
2891 alpha_treatment: Option<AlphaTreatment>,
2892 y_axis_treatment: YAxisTreatment,
2893 pixel_format: Option<PixelFormat>,
2894 mut pixels: Cow<[u8]>,
2895) -> Cow<[u8]> {
2896 match alpha_treatment {
2897 Some(AlphaTreatment::Premultiply) => {
2898 if let Some(pixel_format) = pixel_format {
2899 match pixel_format {
2900 PixelFormat::BGRA8 | PixelFormat::RGBA8 => {},
2901 _ => unimplemented!("unsupported pixel format ({:?})", pixel_format),
2902 }
2903 premultiply_inplace(TexFormat::RGBA, TexDataType::UnsignedByte, pixels.to_mut());
2904 } else {
2905 premultiply_inplace(internal_format, data_type, pixels.to_mut());
2906 }
2907 },
2908 Some(AlphaTreatment::Unmultiply) => {
2909 assert!(pixel_format.is_some());
2910 unmultiply_inplace::<false>(pixels.to_mut());
2911 },
2912 None => {},
2913 }
2914
2915 if let Some(pixel_format) = pixel_format {
2916 pixels = image_to_tex_image_data(
2917 pixel_format,
2918 internal_format,
2919 data_type,
2920 pixels.into_owned(),
2921 )
2922 .into();
2923 }
2924
2925 if y_axis_treatment == YAxisTreatment::Flipped {
2926 pixels = flip_pixels_y(
2928 internal_format,
2929 data_type,
2930 size.width as usize,
2931 size.height as usize,
2932 unpacking_alignment as usize,
2933 pixels.into_owned(),
2934 )
2935 .into();
2936 }
2937
2938 pixels
2939}
2940
2941fn image_to_tex_image_data(
2944 pixel_format: PixelFormat,
2945 format: TexFormat,
2946 data_type: TexDataType,
2947 mut pixels: Vec<u8>,
2948) -> Vec<u8> {
2949 let pixel_count = pixels.len() / 4;
2951
2952 match pixel_format {
2953 PixelFormat::BGRA8 => pixels::rgba8_byte_swap_colors_inplace(&mut pixels),
2954 PixelFormat::RGBA8 => {},
2955 _ => unimplemented!("unsupported pixel format ({:?})", pixel_format),
2956 }
2957
2958 match (format, data_type) {
2959 (TexFormat::RGBA, TexDataType::UnsignedByte) |
2960 (TexFormat::RGBA8, TexDataType::UnsignedByte) => pixels,
2961 (TexFormat::RGB, TexDataType::UnsignedByte) |
2962 (TexFormat::RGB8, TexDataType::UnsignedByte) => {
2963 for i in 0..pixel_count {
2964 let rgb = {
2965 let rgb = &pixels[i * 4..i * 4 + 3];
2966 [rgb[0], rgb[1], rgb[2]]
2967 };
2968 pixels[i * 3..i * 3 + 3].copy_from_slice(&rgb);
2969 }
2970 pixels.truncate(pixel_count * 3);
2971 pixels
2972 },
2973 (TexFormat::Alpha, TexDataType::UnsignedByte) => {
2974 for i in 0..pixel_count {
2975 let p = pixels[i * 4 + 3];
2976 pixels[i] = p;
2977 }
2978 pixels.truncate(pixel_count);
2979 pixels
2980 },
2981 (TexFormat::Luminance, TexDataType::UnsignedByte) => {
2982 for i in 0..pixel_count {
2983 let p = pixels[i * 4];
2984 pixels[i] = p;
2985 }
2986 pixels.truncate(pixel_count);
2987 pixels
2988 },
2989 (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => {
2990 for i in 0..pixel_count {
2991 let (lum, a) = {
2992 let rgba = &pixels[i * 4..i * 4 + 4];
2993 (rgba[0], rgba[3])
2994 };
2995 pixels[i * 2] = lum;
2996 pixels[i * 2 + 1] = a;
2997 }
2998 pixels.truncate(pixel_count * 2);
2999 pixels
3000 },
3001 (TexFormat::RGBA, TexDataType::UnsignedShort4444) => {
3002 for i in 0..pixel_count {
3003 let p = {
3004 let rgba = &pixels[i * 4..i * 4 + 4];
3005 ((rgba[0] as u16 & 0xf0) << 8) |
3006 ((rgba[1] as u16 & 0xf0) << 4) |
3007 (rgba[2] as u16 & 0xf0) |
3008 ((rgba[3] as u16 & 0xf0) >> 4)
3009 };
3010 NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p);
3011 }
3012 pixels.truncate(pixel_count * 2);
3013 pixels
3014 },
3015 (TexFormat::RGBA, TexDataType::UnsignedShort5551) => {
3016 for i in 0..pixel_count {
3017 let p = {
3018 let rgba = &pixels[i * 4..i * 4 + 4];
3019 ((rgba[0] as u16 & 0xf8) << 8) |
3020 ((rgba[1] as u16 & 0xf8) << 3) |
3021 ((rgba[2] as u16 & 0xf8) >> 2) |
3022 ((rgba[3] as u16) >> 7)
3023 };
3024 NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p);
3025 }
3026 pixels.truncate(pixel_count * 2);
3027 pixels
3028 },
3029 (TexFormat::RGB, TexDataType::UnsignedShort565) => {
3030 for i in 0..pixel_count {
3031 let p = {
3032 let rgb = &pixels[i * 4..i * 4 + 3];
3033 ((rgb[0] as u16 & 0xf8) << 8) |
3034 ((rgb[1] as u16 & 0xfc) << 3) |
3035 ((rgb[2] as u16 & 0xf8) >> 3)
3036 };
3037 NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p);
3038 }
3039 pixels.truncate(pixel_count * 2);
3040 pixels
3041 },
3042 (TexFormat::RGBA, TexDataType::Float) | (TexFormat::RGBA32f, TexDataType::Float) => {
3043 let mut rgbaf32 = Vec::<u8>::with_capacity(pixel_count * 16);
3044 for rgba8 in pixels.chunks(4) {
3045 rgbaf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
3046 rgbaf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap();
3047 rgbaf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap();
3048 rgbaf32.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap();
3049 }
3050 rgbaf32
3051 },
3052
3053 (TexFormat::RGB, TexDataType::Float) | (TexFormat::RGB32f, TexDataType::Float) => {
3054 let mut rgbf32 = Vec::<u8>::with_capacity(pixel_count * 12);
3055 for rgba8 in pixels.chunks(4) {
3056 rgbf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
3057 rgbf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap();
3058 rgbf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap();
3059 }
3060 rgbf32
3061 },
3062
3063 (TexFormat::Alpha, TexDataType::Float) | (TexFormat::Alpha32f, TexDataType::Float) => {
3064 for rgba8 in pixels.chunks_mut(4) {
3065 let p = rgba8[3] as f32;
3066 NativeEndian::write_f32(rgba8, p);
3067 }
3068 pixels
3069 },
3070
3071 (TexFormat::Luminance, TexDataType::Float) |
3072 (TexFormat::Luminance32f, TexDataType::Float) => {
3073 for rgba8 in pixels.chunks_mut(4) {
3074 let p = rgba8[0] as f32;
3075 NativeEndian::write_f32(rgba8, p);
3076 }
3077 pixels
3078 },
3079
3080 (TexFormat::LuminanceAlpha, TexDataType::Float) |
3081 (TexFormat::LuminanceAlpha32f, TexDataType::Float) => {
3082 let mut data = Vec::<u8>::with_capacity(pixel_count * 8);
3083 for rgba8 in pixels.chunks(4) {
3084 data.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
3085 data.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap();
3086 }
3087 data
3088 },
3089
3090 (TexFormat::RGBA, TexDataType::HalfFloat) |
3091 (TexFormat::RGBA16f, TexDataType::HalfFloat) => {
3092 let mut rgbaf16 = Vec::<u8>::with_capacity(pixel_count * 8);
3093 for rgba8 in pixels.chunks(4) {
3094 rgbaf16
3095 .write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).to_bits())
3096 .unwrap();
3097 rgbaf16
3098 .write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).to_bits())
3099 .unwrap();
3100 rgbaf16
3101 .write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).to_bits())
3102 .unwrap();
3103 rgbaf16
3104 .write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).to_bits())
3105 .unwrap();
3106 }
3107 rgbaf16
3108 },
3109
3110 (TexFormat::RGB, TexDataType::HalfFloat) | (TexFormat::RGB16f, TexDataType::HalfFloat) => {
3111 let mut rgbf16 = Vec::<u8>::with_capacity(pixel_count * 6);
3112 for rgba8 in pixels.chunks(4) {
3113 rgbf16
3114 .write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).to_bits())
3115 .unwrap();
3116 rgbf16
3117 .write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).to_bits())
3118 .unwrap();
3119 rgbf16
3120 .write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).to_bits())
3121 .unwrap();
3122 }
3123 rgbf16
3124 },
3125 (TexFormat::Alpha, TexDataType::HalfFloat) |
3126 (TexFormat::Alpha16f, TexDataType::HalfFloat) => {
3127 for i in 0..pixel_count {
3128 let p = f16::from_f32(pixels[i * 4 + 3] as f32).to_bits();
3129 NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p);
3130 }
3131 pixels.truncate(pixel_count * 2);
3132 pixels
3133 },
3134 (TexFormat::Luminance, TexDataType::HalfFloat) |
3135 (TexFormat::Luminance16f, TexDataType::HalfFloat) => {
3136 for i in 0..pixel_count {
3137 let p = f16::from_f32(pixels[i * 4] as f32).to_bits();
3138 NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p);
3139 }
3140 pixels.truncate(pixel_count * 2);
3141 pixels
3142 },
3143 (TexFormat::LuminanceAlpha, TexDataType::HalfFloat) |
3144 (TexFormat::LuminanceAlpha16f, TexDataType::HalfFloat) => {
3145 for rgba8 in pixels.chunks_mut(4) {
3146 let lum = f16::from_f32(rgba8[0] as f32).to_bits();
3147 let a = f16::from_f32(rgba8[3] as f32).to_bits();
3148 NativeEndian::write_u16(&mut rgba8[0..2], lum);
3149 NativeEndian::write_u16(&mut rgba8[2..4], a);
3150 }
3151 pixels
3152 },
3153
3154 _ => unreachable!("Unsupported formats {:?} {:?}", format, data_type),
3158 }
3159}
3160
3161fn premultiply_inplace(format: TexFormat, data_type: TexDataType, pixels: &mut [u8]) {
3162 match (format, data_type) {
3163 (TexFormat::RGBA, TexDataType::UnsignedByte) => {
3164 pixels::rgba8_premultiply_inplace(pixels);
3165 },
3166 (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => {
3167 for la in pixels.chunks_mut(2) {
3168 la[0] = pixels::multiply_u8_color(la[0], la[1]);
3169 }
3170 },
3171 (TexFormat::RGBA, TexDataType::UnsignedShort5551) => {
3172 for rgba in pixels.chunks_mut(2) {
3173 if NativeEndian::read_u16(rgba) & 1 == 0 {
3174 NativeEndian::write_u16(rgba, 0);
3175 }
3176 }
3177 },
3178 (TexFormat::RGBA, TexDataType::UnsignedShort4444) => {
3179 for rgba in pixels.chunks_mut(2) {
3180 let pix = NativeEndian::read_u16(rgba);
3181 let extend_to_8_bits = |val| (val | (val << 4)) as u8;
3182 let r = extend_to_8_bits((pix >> 12) & 0x0f);
3183 let g = extend_to_8_bits((pix >> 8) & 0x0f);
3184 let b = extend_to_8_bits((pix >> 4) & 0x0f);
3185 let a = extend_to_8_bits(pix & 0x0f);
3186 NativeEndian::write_u16(
3187 rgba,
3188 (((pixels::multiply_u8_color(r, a) & 0xf0) as u16) << 8) |
3189 (((pixels::multiply_u8_color(g, a) & 0xf0) as u16) << 4) |
3190 ((pixels::multiply_u8_color(b, a) & 0xf0) as u16) |
3191 ((a & 0x0f) as u16),
3192 );
3193 }
3194 },
3195 _ => {},
3197 }
3198}
3199
3200fn flip_pixels_y(
3202 internal_format: TexFormat,
3203 data_type: TexDataType,
3204 width: usize,
3205 height: usize,
3206 unpacking_alignment: usize,
3207 pixels: Vec<u8>,
3208) -> Vec<u8> {
3209 let cpp = (data_type.element_size() * internal_format.components() /
3210 data_type.components_per_element()) as usize;
3211
3212 let stride = (width * cpp + unpacking_alignment - 1) & !(unpacking_alignment - 1);
3213
3214 let mut flipped = Vec::<u8>::with_capacity(pixels.len());
3215
3216 for y in 0..height {
3217 let flipped_y = height - 1 - y;
3218 let start = flipped_y * stride;
3219
3220 flipped.extend_from_slice(&pixels[start..(start + width * cpp)]);
3221 flipped.extend(vec![0u8; stride - width * cpp]);
3222 }
3223
3224 flipped
3225}
3226
3227fn clamp_viewport(gl: &Gl, size: Size2D<u32>) -> Size2D<u32> {
3229 let mut max_viewport = [i32::MAX, i32::MAX];
3230 let mut max_renderbuffer = [i32::MAX];
3231
3232 unsafe {
3233 gl.get_parameter_i32_slice(gl::MAX_VIEWPORT_DIMS, &mut max_viewport);
3234 gl.get_parameter_i32_slice(gl::MAX_RENDERBUFFER_SIZE, &mut max_renderbuffer);
3235 }
3236 Size2D::new(
3237 size.width
3238 .min(max_viewport[0] as u32)
3239 .min(max_renderbuffer[0] as u32)
3240 .max(1),
3241 size.height
3242 .min(max_viewport[1] as u32)
3243 .min(max_renderbuffer[0] as u32)
3244 .max(1),
3245 )
3246}
3247
3248trait ToSurfmanVersion {
3249 fn to_surfman_version(self, api_type: GlType) -> GLVersion;
3250}
3251
3252impl ToSurfmanVersion for WebGLVersion {
3253 fn to_surfman_version(self, api_type: GlType) -> GLVersion {
3254 if api_type == GlType::Gles {
3255 return GLVersion::new(3, 0);
3256 }
3257 match self {
3258 WebGLVersion::WebGL1 => GLVersion::new(2, 1),
3261 WebGLVersion::WebGL2 => GLVersion::new(3, 2),
3263 }
3264 }
3265}
3266
3267trait SurfmanContextAttributeFlagsConvert {
3268 fn to_surfman_context_attribute_flags(
3269 &self,
3270 webgl_version: WebGLVersion,
3271 api_type: GlType,
3272 ) -> ContextAttributeFlags;
3273}
3274
3275impl SurfmanContextAttributeFlagsConvert for GLContextAttributes {
3276 fn to_surfman_context_attribute_flags(
3277 &self,
3278 webgl_version: WebGLVersion,
3279 api_type: GlType,
3280 ) -> ContextAttributeFlags {
3281 let mut flags = ContextAttributeFlags::empty();
3282 flags.set(ContextAttributeFlags::ALPHA, self.alpha);
3283 flags.set(ContextAttributeFlags::DEPTH, self.depth);
3284 flags.set(ContextAttributeFlags::STENCIL, self.stencil);
3285 if (webgl_version == WebGLVersion::WebGL1) && (api_type == GlType::Gl) {
3286 flags.set(ContextAttributeFlags::COMPATIBILITY_PROFILE, true);
3287 }
3288 flags
3289 }
3290}
3291
3292bitflags! {
3293 struct FramebufferRebindingFlags: u8 {
3294 const REBIND_READ_FRAMEBUFFER = 0x1;
3295 const REBIND_DRAW_FRAMEBUFFER = 0x2;
3296 }
3297}
3298
3299struct FramebufferRebindingInfo {
3300 flags: FramebufferRebindingFlags,
3301 viewport: [GLint; 4],
3302}
3303
3304impl FramebufferRebindingInfo {
3305 fn detect(device: &Device, context: &Context, gl: &Gl) -> FramebufferRebindingInfo {
3306 unsafe {
3307 let read_framebuffer = gl.get_parameter_framebuffer(gl::READ_FRAMEBUFFER_BINDING);
3308 let draw_framebuffer = gl.get_parameter_framebuffer(gl::DRAW_FRAMEBUFFER_BINDING);
3309
3310 let context_surface_framebuffer = device
3311 .context_surface_info(context)
3312 .unwrap()
3313 .unwrap()
3314 .framebuffer_object;
3315
3316 let mut flags = FramebufferRebindingFlags::empty();
3317 if context_surface_framebuffer == read_framebuffer {
3318 flags.insert(FramebufferRebindingFlags::REBIND_READ_FRAMEBUFFER);
3319 }
3320 if context_surface_framebuffer == draw_framebuffer {
3321 flags.insert(FramebufferRebindingFlags::REBIND_DRAW_FRAMEBUFFER);
3322 }
3323
3324 let mut viewport = [0; 4];
3325 gl.get_parameter_i32_slice(gl::VIEWPORT, &mut viewport);
3326
3327 FramebufferRebindingInfo { flags, viewport }
3328 }
3329 }
3330
3331 fn apply(self, device: &Device, context: &Context, gl: &Gl) {
3332 if self.flags.is_empty() {
3333 return;
3334 }
3335
3336 let context_surface_framebuffer = device
3337 .context_surface_info(context)
3338 .unwrap()
3339 .unwrap()
3340 .framebuffer_object;
3341 if self
3342 .flags
3343 .contains(FramebufferRebindingFlags::REBIND_READ_FRAMEBUFFER)
3344 {
3345 unsafe { gl.bind_framebuffer(gl::READ_FRAMEBUFFER, context_surface_framebuffer) };
3346 }
3347 if self
3348 .flags
3349 .contains(FramebufferRebindingFlags::REBIND_DRAW_FRAMEBUFFER)
3350 {
3351 unsafe { gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, context_surface_framebuffer) };
3352 }
3353
3354 unsafe {
3355 gl.viewport(
3356 self.viewport[0],
3357 self.viewport[1],
3358 self.viewport[2],
3359 self.viewport[3],
3360 )
3361 };
3362 }
3363}