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