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