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