renderer: Support cropping and scaling

This commit is contained in:
Victor Brekenfeld 2021-07-10 23:50:01 +02:00
parent b67688e1c8
commit 8bd17d71d2
4 changed files with 79 additions and 45 deletions

View File

@ -155,7 +155,7 @@ where
let mut location = *location; let mut location = *location;
if let Some(ref data) = states.data_map.get::<RefCell<SurfaceData>>() { if let Some(ref data) = states.data_map.get::<RefCell<SurfaceData>>() {
let mut data = data.borrow_mut(); let mut data = data.borrow_mut();
let buffer_scale = data.buffer_scale as f32; let buffer_scale = data.buffer_scale;
if let Some(texture) = data if let Some(texture) = data
.texture .texture
.as_mut() .as_mut()
@ -167,12 +167,12 @@ where
let current = states.cached_state.current::<SubsurfaceCachedState>(); let current = states.cached_state.current::<SubsurfaceCachedState>();
location += current.location; location += current.location;
} }
let render_scale = output_scale as f32 / buffer_scale;
if let Err(err) = frame.render_texture_at( if let Err(err) = frame.render_texture_at(
&texture.texture, &texture.texture,
location.to_f64().to_physical(output_scale as f64).to_i32_round(), location.to_f64().to_physical(output_scale as f64).to_i32_round(),
buffer_scale,
output_scale as f64,
Transform::Normal, /* TODO */ Transform::Normal, /* TODO */
render_scale,
1.0, 1.0,
) { ) {
result = Err(err.into()); result = Err(err.into());

View File

@ -755,8 +755,9 @@ fn render_surface(
.to_f64() .to_f64()
.to_physical(output_scale as f64) .to_physical(output_scale as f64)
.to_i32_round(), .to_i32_round(),
1,
output_scale as f64,
Transform::Normal, Transform::Normal,
output_scale,
1.0, 1.0,
)?; )?;
} }

View File

@ -11,7 +11,7 @@ use std::sync::{
}; };
use std::{collections::HashSet, os::raw::c_char}; use std::{collections::HashSet, os::raw::c_char};
use cgmath::{prelude::*, Matrix3}; use cgmath::{prelude::*, Matrix3, Vector2};
mod shaders; mod shaders;
mod version; mod version;
@ -76,7 +76,9 @@ impl Gles2Texture {
/// ///
/// Ownership over the texture is taken by the renderer, you should not free the texture yourself. /// Ownership over the texture is taken by the renderer, you should not free the texture yourself.
/// ///
/// *Safety*: The renderer cannot make sure `tex` is a valid texture id. /// # Safety
///
/// The renderer cannot make sure `tex` is a valid texture id.
pub unsafe fn from_raw( pub unsafe fn from_raw(
renderer: &Gles2Renderer, renderer: &Gles2Renderer,
tex: ffi::types::GLuint, tex: ffi::types::GLuint,
@ -979,20 +981,6 @@ impl Drop for Gles2Renderer {
} }
} }
static VERTS: [ffi::types::GLfloat; 8] = [
1.0, 0.0, // top right
0.0, 0.0, // top left
1.0, 1.0, // bottom right
0.0, 1.0, // bottom left
];
static TEX_COORDS: [ffi::types::GLfloat; 8] = [
1.0, 0.0, // top right
0.0, 0.0, // top left
1.0, 1.0, // bottom right
0.0, 1.0, // bottom left
];
impl Gles2Renderer { impl Gles2Renderer {
/// Run custom code in the GL context owned by this renderer. /// Run custom code in the GL context owned by this renderer.
/// ///
@ -1085,6 +1073,13 @@ impl Renderer for Gles2Renderer {
} }
} }
static VERTS: [ffi::types::GLfloat; 8] = [
1.0, 0.0, // top right
0.0, 0.0, // top left
1.0, 1.0, // bottom right
0.0, 1.0, // bottom left
];
impl Frame for Gles2Frame { impl Frame for Gles2Frame {
type Error = Gles2Error; type Error = Gles2Error;
type TextureId = Gles2Texture; type TextureId = Gles2Texture;
@ -1102,6 +1097,7 @@ impl Frame for Gles2Frame {
&mut self, &mut self,
tex: &Self::TextureId, tex: &Self::TextureId,
mut matrix: Matrix3<f32>, mut matrix: Matrix3<f32>,
tex_coords: [Vector2<f32>; 4],
alpha: f32, alpha: f32,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
//apply output transformation //apply output transformation
@ -1150,7 +1146,7 @@ impl Frame for Gles2Frame {
ffi::FLOAT, ffi::FLOAT,
ffi::FALSE, ffi::FALSE,
0, 0,
TEX_COORDS.as_ptr() as *const _, tex_coords.as_ptr() as *const _, // cgmath::Vector2 is marked as repr(C), this cast should be safe
); );
self.gl self.gl

View File

@ -10,16 +10,18 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::error::Error; use std::error::Error;
use crate::utils::{Physical, Point, Size}; use crate::utils::{Buffer, Physical, Point, Rectangle, Size};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use crate::{utils::Rectangle, wayland::compositor::SurfaceData}; use crate::wayland::compositor::SurfaceData;
use cgmath::{prelude::*, Matrix3, Vector2}; use cgmath::{prelude::*, Matrix3, Vector2, Vector3};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_buffer, wl_shm}; use wayland_server::protocol::{wl_buffer, wl_shm};
#[cfg(feature = "renderer_gl")] #[cfg(feature = "renderer_gl")]
pub mod gles2; pub mod gles2;
#[cfg(feature = "wayland_frontend")]
use crate::backend::allocator::{dmabuf::Dmabuf, Format};
#[cfg(all( #[cfg(all(
feature = "wayland_frontend", feature = "wayland_frontend",
feature = "backend_egl", feature = "backend_egl",
@ -29,11 +31,6 @@ use crate::backend::egl::{
display::{EGLBufferReader, BUFFER_READER}, display::{EGLBufferReader, BUFFER_READER},
Error as EglError, Error as EglError,
}; };
#[cfg(feature = "wayland_frontend")]
use crate::{
backend::allocator::{dmabuf::Dmabuf, Format},
utils::Buffer,
};
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
/// Possible transformations to two-dimensional planes /// Possible transformations to two-dimensional planes
@ -142,9 +139,9 @@ pub trait Unbind: Renderer {
/// A two dimensional texture /// A two dimensional texture
pub trait Texture { pub trait Texture {
/// Size of the texture plane (w x h) /// Size of the texture plane
fn size(&self) -> (u32, u32) { fn size(&self) -> Size<i32, Buffer> {
(self.width(), self.height()) Size::from((self.width() as i32, self.height() as i32))
} }
/// Width of the texture plane /// Width of the texture plane
@ -166,34 +163,57 @@ pub trait Frame {
/// If called outside this operation may error-out, do nothing or modify future rendering results in any way. /// If called outside this operation may error-out, do nothing or modify future rendering results in any way.
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>; fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>;
/// Render a texture to the current target using given projection matrix and alpha. /// Render a texture to the current target using given projection matrix and alpha.
/// /// The given verticies are used to source the texture. This is mostly useful for cropping the texture.
/// This operation is only valid in between a `begin` and `finish`-call.
/// If called outside this operation may error-out, do nothing or modify future rendering results in any way.
fn render_texture( fn render_texture(
&mut self, &mut self,
texture: &Self::TextureId, texture: &Self::TextureId,
matrix: Matrix3<f32>, matrix: Matrix3<f32>,
tex_coords: [Vector2<f32>; 4],
alpha: f32, alpha: f32,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
/// Render a texture to the current target as a flat 2d-plane at a given /// Render a texture to the current target as a flat 2d-plane at a given
/// position, applying the given transformation with the given alpha value. /// position and applying the given transformation with the given alpha value.
///
/// This operation is only valid in between a `begin` and `finish`-call.
/// If called outside this operation may error-out, do nothing or modify future rendering results in any way.
fn render_texture_at( fn render_texture_at(
&mut self, &mut self,
texture: &Self::TextureId, texture: &Self::TextureId,
pos: Point<i32, Physical>, pos: Point<f64, Physical>,
texture_scale: i32,
output_scale: f64,
transform: Transform,
alpha: f32,
) -> Result<(), Self::Error> {
self.render_texture_from_to(
texture,
Rectangle::from_loc_and_size(Point::<i32, Buffer>::from((0, 0)), texture.size()),
Rectangle::from_loc_and_size(
pos,
texture
.size()
.to_logical(texture_scale)
.to_f64()
.to_physical(output_scale),
),
transform,
alpha,
)
}
/// Render part of a texture as given by src to the current target into the rectangle described by dest
/// as a flat 2d-plane after applying the given transformations.
fn render_texture_from_to(
&mut self,
texture: &Self::TextureId,
src: Rectangle<i32, Buffer>,
dest: Rectangle<f64, Physical>,
transform: Transform, transform: Transform,
scale: f32,
alpha: f32, alpha: f32,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
let mut mat = Matrix3::<f32>::identity(); let mut mat = Matrix3::<f32>::identity();
// position and scale // position and scale
let size = texture.size(); mat = mat * Matrix3::from_translation(Vector2::new(dest.loc.x as f32, dest.loc.y as f32));
mat = mat * Matrix3::from_translation(Vector2::new(pos.x as f32, pos.y as f32)); mat = mat * Matrix3::from_nonuniform_scale(dest.size.w as f32, dest.size.h as f32);
mat = mat * Matrix3::from_nonuniform_scale(size.0 as f32 * scale, size.1 as f32 * scale);
//apply surface transformation //apply surface transformation
mat = mat * Matrix3::from_translation(Vector2::new(0.5, 0.5)); mat = mat * Matrix3::from_translation(Vector2::new(0.5, 0.5));
@ -204,7 +224,24 @@ pub trait Frame {
mat = mat * transform.invert().matrix(); mat = mat * transform.invert().matrix();
mat = mat * Matrix3::from_translation(Vector2::new(-0.5, -0.5)); mat = mat * Matrix3::from_translation(Vector2::new(-0.5, -0.5));
self.render_texture(texture, mat, alpha) // this matrix should be regular, we can expect invert to succeed
let tex_size = texture.size();
let texture_mat = Matrix3::from_nonuniform_scale(tex_size.w as f32, tex_size.h as f32)
.invert()
.unwrap();
let verts = [
(texture_mat * Vector3::new((src.loc.x + src.size.w) as f32, src.loc.y as f32, 0.0)).truncate(), // top-right
(texture_mat * Vector3::new(src.loc.x as f32, src.loc.y as f32, 0.0)).truncate(), // top-left
(texture_mat
* Vector3::new(
(src.loc.x + src.size.w) as f32,
(src.loc.y + src.size.h) as f32,
0.0,
))
.truncate(), // bottom-right
(texture_mat * Vector3::new(src.loc.x as f32, (src.loc.y + src.size.h) as f32, 0.0)).truncate(), // bottom-left
];
self.render_texture(texture, mat, verts, alpha)
} }
} }