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