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