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