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