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