diff options
author | Cristian Brinza <cristianb@gmail.com> | 2024-08-03 23:04:26 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-03 20:04:26 +0000 |
commit | 7c2c383bb1fb15dfeea1e0f33af2e42b407af4e1 (patch) | |
tree | ae26b2a6512b5cd142f7bfd12f92c3dbac3d60fa /components/compositing/gl.rs | |
parent | bb176514c64b50011ee0be5cfb10f0cbce48cd93 (diff) | |
download | servo-7c2c383bb1fb15dfeea1e0f33af2e42b407af4e1.tar.gz servo-7c2c383bb1fb15dfeea1e0f33af2e42b407af4e1.zip |
Fix save to image on Windows (#32914)
* Read pixels in same format (gl::RGBA) as the texture
Signed-off-by: crbrz <cristianb@gmail.com>
* Add read pixels test
Signed-off-by: crbrz <cristianb@gmail.com>
* Use patched surfman
Signed-off-by: crbrz <cristianb@gmail.com>
* Update surfman to 0.9.5
Signed-off-by: crbrz <cristianb@gmail.com>
---------
Signed-off-by: crbrz <cristianb@gmail.com>
Diffstat (limited to 'components/compositing/gl.rs')
-rw-r--r-- | components/compositing/gl.rs | 70 |
1 files changed, 64 insertions, 6 deletions
diff --git a/components/compositing/gl.rs b/components/compositing/gl.rs index e5bd588b298..8587c61d7a0 100644 --- a/components/compositing/gl.rs +++ b/components/compositing/gl.rs @@ -5,8 +5,8 @@ use std::rc::Rc; use gleam::gl::{self, Gl}; -use image::RgbImage; -use log::trace; +use image::RgbaImage; +use log::{trace, warn}; use servo_geometry::FramebufferUintLength; pub struct RenderTargetInfo { @@ -105,7 +105,7 @@ impl RenderTargetInfo { y: i32, width: FramebufferUintLength, height: FramebufferUintLength, - ) -> RgbImage { + ) -> RgbaImage { let width = width.get() as usize; let height = height.get() as usize; // For some reason, OSMesa fails to render on the 3rd @@ -121,13 +121,17 @@ impl RenderTargetInfo { y, width as gl::GLsizei, height as gl::GLsizei, - gl::RGB, + gl::RGBA, gl::UNSIGNED_BYTE, ); + let gl_error = self.gl.get_error(); + if gl_error != gl::NO_ERROR { + warn!("GL error code 0x{gl_error:x} set after read_pixels"); + } // flip image vertically (texture is upside down) let orig_pixels = pixels.clone(); - let stride = width * 3; + let stride = width * 4; for y in 0..height { let dst_start = y * stride; let src_start = (height - y - 1) * stride; @@ -135,7 +139,7 @@ impl RenderTargetInfo { pixels[dst_start..dst_start + stride].clone_from_slice(&src_slice[..stride]); } - RgbImage::from_raw(width as u32, height as u32, pixels).expect("Flipping image failed!") + RgbaImage::from_raw(width as u32, height as u32, pixels).expect("Flipping image failed!") } } @@ -148,3 +152,57 @@ impl Drop for RenderTargetInfo { self.gl.delete_framebuffers(&self.framebuffer_ids); } } + +#[cfg(test)] +mod test { + use gleam::gl; + use image::Rgba; + use servo_geometry::FramebufferUintLength; + use surfman::{Connection, ContextAttributeFlags, ContextAttributes, Error, GLApi, GLVersion}; + + use super::RenderTargetInfo; + + #[test] + #[allow(unsafe_code)] + fn test_read_pixels() -> Result<(), Error> { + let connection = Connection::new()?; + let adapter = connection.create_software_adapter()?; + let mut device = connection.create_device(&adapter)?; + let context_descriptor = device.create_context_descriptor(&ContextAttributes { + version: GLVersion::new(3, 0), + flags: ContextAttributeFlags::empty(), + })?; + let mut context = device.create_context(&context_descriptor, None)?; + + let gl = match connection.gl_api() { + GLApi::GL => unsafe { gl::GlFns::load_with(|s| device.get_proc_address(&context, s)) }, + GLApi::GLES => unsafe { + gl::GlesFns::load_with(|s| device.get_proc_address(&context, s)) + }, + }; + + device.make_context_current(&context)?; + + { + const WIDTH: FramebufferUintLength = FramebufferUintLength::new(16); + const HEIGHT: FramebufferUintLength = FramebufferUintLength::new(16); + let render_target = RenderTargetInfo::new(gl, WIDTH, HEIGHT); + render_target.bind(); + render_target + .gl + .clear_color(12.0 / 255.0, 34.0 / 255.0, 56.0 / 255.0, 78.0 / 255.0); + render_target.gl.clear(gl::COLOR_BUFFER_BIT); + + let img = render_target.read_back_from_gpu(0, 0, WIDTH, HEIGHT); + assert_eq!(img.width(), WIDTH.get()); + assert_eq!(img.height(), HEIGHT.get()); + + let expected_pixel: Rgba<u8> = Rgba([12, 34, 56, 78]); + assert!(img.pixels().all(|&p| p == expected_pixel)); + } + + device.destroy_context(&mut context)?; + + Ok(()) + } +} |