Merge pull request #460 from Smithay/feature/egl_userdata
This commit is contained in:
commit
d554c7d2b9
|
@ -168,24 +168,57 @@ pub fn run_winit(log: Logger) {
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
backend
|
backend
|
||||||
.renderer()
|
.renderer()
|
||||||
.render(size, Transform::Flipped180, |renderer, frame| {
|
.render(
|
||||||
render_layers_and_windows(
|
output_geometry
|
||||||
renderer,
|
.size
|
||||||
frame,
|
.to_f64()
|
||||||
&*state.window_map.borrow(),
|
.to_physical(output_scale as f64)
|
||||||
output_geometry,
|
.to_i32_round(),
|
||||||
output_scale,
|
Transform::Flipped180,
|
||||||
&log,
|
|renderer, frame| {
|
||||||
)?;
|
render_layers_and_windows(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
&*state.window_map.borrow(),
|
||||||
|
output_geometry,
|
||||||
|
output_scale,
|
||||||
|
&log,
|
||||||
|
)?;
|
||||||
|
|
||||||
let (x, y) = state.pointer_location.into();
|
let (x, y) = state.pointer_location.into();
|
||||||
|
|
||||||
// draw the dnd icon if any
|
// draw the dnd icon if any
|
||||||
{
|
{
|
||||||
let guard = state.dnd_icon.lock().unwrap();
|
let guard = state.dnd_icon.lock().unwrap();
|
||||||
if let Some(ref surface) = *guard {
|
if let Some(ref surface) = *guard {
|
||||||
if surface.as_ref().is_alive() {
|
if surface.as_ref().is_alive() {
|
||||||
draw_dnd_icon(
|
draw_dnd_icon(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
surface,
|
||||||
|
(x as i32, y as i32).into(),
|
||||||
|
output_scale,
|
||||||
|
&log,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// draw the cursor as relevant
|
||||||
|
{
|
||||||
|
let mut guard = state.cursor_status.lock().unwrap();
|
||||||
|
// reset the cursor if the surface is no longer alive
|
||||||
|
let mut reset = false;
|
||||||
|
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||||
|
reset = !surface.as_ref().is_alive();
|
||||||
|
}
|
||||||
|
if reset {
|
||||||
|
*guard = CursorImageStatus::Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw as relevant
|
||||||
|
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||||
|
cursor_visible = false;
|
||||||
|
draw_cursor(
|
||||||
renderer,
|
renderer,
|
||||||
frame,
|
frame,
|
||||||
surface,
|
surface,
|
||||||
|
@ -193,52 +226,27 @@ pub fn run_winit(log: Logger) {
|
||||||
output_scale,
|
output_scale,
|
||||||
&log,
|
&log,
|
||||||
)?;
|
)?;
|
||||||
|
} else {
|
||||||
|
cursor_visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// draw the cursor as relevant
|
|
||||||
{
|
|
||||||
let mut guard = state.cursor_status.lock().unwrap();
|
|
||||||
// reset the cursor if the surface is no longer alive
|
|
||||||
let mut reset = false;
|
|
||||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
|
||||||
reset = !surface.as_ref().is_alive();
|
|
||||||
}
|
|
||||||
if reset {
|
|
||||||
*guard = CursorImageStatus::Default;
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw as relevant
|
#[cfg(feature = "debug")]
|
||||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
{
|
||||||
cursor_visible = false;
|
let fps = state.backend_data.fps.avg().round() as u32;
|
||||||
draw_cursor(
|
|
||||||
|
draw_fps(
|
||||||
renderer,
|
renderer,
|
||||||
frame,
|
frame,
|
||||||
surface,
|
&state.backend_data.fps_texture,
|
||||||
(x as i32, y as i32).into(),
|
output_scale as f64,
|
||||||
output_scale,
|
fps,
|
||||||
&log,
|
|
||||||
)?;
|
)?;
|
||||||
} else {
|
|
||||||
cursor_visible = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "debug")]
|
Ok(())
|
||||||
{
|
},
|
||||||
let fps = state.backend_data.fps.avg().round() as u32;
|
)
|
||||||
|
|
||||||
draw_fps(
|
|
||||||
renderer,
|
|
||||||
frame,
|
|
||||||
&state.backend_data.fps_texture,
|
|
||||||
output_scale as f64,
|
|
||||||
fps,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.map_err(Into::<SwapBuffersError>::into)
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
.and_then(|x| x)
|
.and_then(|x| x)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
//! EGL context related structs
|
//! EGL context related structs
|
||||||
use std::collections::HashSet;
|
use std::{
|
||||||
use std::os::raw::c_int;
|
collections::HashSet,
|
||||||
use std::sync::atomic::Ordering;
|
os::raw::c_int,
|
||||||
|
sync::{atomic::Ordering, Arc},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{ffi, wrap_egl_call, Error, MakeCurrentError};
|
use super::{ffi, wrap_egl_call, Error, MakeCurrentError};
|
||||||
use crate::backend::allocator::Format as DrmFormat;
|
use crate::{
|
||||||
use crate::backend::egl::display::{EGLDisplay, PixelFormat};
|
backend::{
|
||||||
use crate::backend::egl::EGLSurface;
|
allocator::Format as DrmFormat,
|
||||||
|
egl::{
|
||||||
|
display::{EGLDisplay, PixelFormat},
|
||||||
|
EGLSurface,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
utils::user_data::UserDataMap,
|
||||||
|
};
|
||||||
|
|
||||||
use slog::{info, o, trace};
|
use slog::{info, o, trace};
|
||||||
|
|
||||||
|
@ -17,6 +26,7 @@ pub struct EGLContext {
|
||||||
pub(crate) display: EGLDisplay,
|
pub(crate) display: EGLDisplay,
|
||||||
config_id: ffi::egl::types::EGLConfig,
|
config_id: ffi::egl::types::EGLConfig,
|
||||||
pixel_format: Option<PixelFormat>,
|
pixel_format: Option<PixelFormat>,
|
||||||
|
user_data: Arc<UserDataMap>,
|
||||||
}
|
}
|
||||||
// EGLContexts can be moved between threads safely
|
// EGLContexts can be moved between threads safely
|
||||||
unsafe impl Send for EGLContext {}
|
unsafe impl Send for EGLContext {}
|
||||||
|
@ -162,6 +172,11 @@ impl EGLContext {
|
||||||
display: display.clone(),
|
display: display.clone(),
|
||||||
config_id,
|
config_id,
|
||||||
pixel_format,
|
pixel_format,
|
||||||
|
user_data: if let Some(shared) = shared {
|
||||||
|
shared.user_data.clone()
|
||||||
|
} else {
|
||||||
|
Arc::new(UserDataMap::default())
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +256,21 @@ impl EGLContext {
|
||||||
pub fn dmabuf_texture_formats(&self) -> &HashSet<DrmFormat> {
|
pub fn dmabuf_texture_formats(&self) -> &HashSet<DrmFormat> {
|
||||||
&self.display.dmabuf_import_formats
|
&self.display.dmabuf_import_formats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve user_data associated with this context
|
||||||
|
///
|
||||||
|
/// *Note:* UserData is shared between shared context, if constructed with
|
||||||
|
/// [`new_shared`](EGLContext::new_shared) or [`new_shared_with_config`](EGLContext::new_shared_with_config).
|
||||||
|
pub fn user_data(&self) -> &UserDataMap {
|
||||||
|
&*self.user_data
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a raw handle to the underlying context.
|
||||||
|
///
|
||||||
|
/// The pointer will become invalid, when this struct is destroyed.
|
||||||
|
pub fn get_context_handle(&self) -> ffi::egl::types::EGLContext {
|
||||||
|
self.context
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for EGLContext {
|
impl Drop for EGLContext {
|
||||||
|
|
|
@ -173,7 +173,9 @@ impl EGLDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the pointer to the raw [`EGLDevice`].
|
/// Returns the pointer to the raw [`EGLDevice`].
|
||||||
pub fn inner(&self) -> *const c_void {
|
///
|
||||||
|
/// The pointer will become invalid, when this struct is destroyed.
|
||||||
|
pub fn get_device_handle(&self) -> *const c_void {
|
||||||
self.inner
|
self.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,16 @@ impl EGLSurface {
|
||||||
pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
|
pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
|
||||||
self.native.resize(width, height, dx, dy)
|
self.native.resize(width, height, dx, dy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a raw handle to the underlying surface
|
||||||
|
///
|
||||||
|
/// *Note*: The surface might get dynamically recreated during swap-buffers
|
||||||
|
/// causing the pointer to become invalid.
|
||||||
|
///
|
||||||
|
/// The pointer will become invalid, when this struct is destroyed.
|
||||||
|
pub fn get_surface_handle(&self) -> ffi::egl::types::EGLSurface {
|
||||||
|
self.surface.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for EGLSurface {
|
impl Drop for EGLSurface {
|
||||||
|
|
|
@ -178,6 +178,8 @@ pub struct Gles2Renderer {
|
||||||
// This field is only accessed if the image or wayland_frontend features are active
|
// This field is only accessed if the image or wayland_frontend features are active
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
destruction_callback_sender: Sender<CleanupResource>,
|
destruction_callback_sender: Sender<CleanupResource>,
|
||||||
|
min_filter: TextureFilter,
|
||||||
|
max_filter: TextureFilter,
|
||||||
logger_ptr: Option<*mut ::slog::Logger>,
|
logger_ptr: Option<*mut ::slog::Logger>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
_not_send: *mut (),
|
_not_send: *mut (),
|
||||||
|
@ -186,11 +188,14 @@ pub struct Gles2Renderer {
|
||||||
/// Handle to the currently rendered frame during [`Gles2Renderer::render`](Renderer::render)
|
/// Handle to the currently rendered frame during [`Gles2Renderer::render`](Renderer::render)
|
||||||
pub struct Gles2Frame {
|
pub struct Gles2Frame {
|
||||||
current_projection: Matrix3<f32>,
|
current_projection: Matrix3<f32>,
|
||||||
|
transform: Transform,
|
||||||
gl: ffi::Gles2,
|
gl: ffi::Gles2,
|
||||||
tex_programs: [Gles2TexProgram; shaders::FRAGMENT_COUNT],
|
tex_programs: [Gles2TexProgram; shaders::FRAGMENT_COUNT],
|
||||||
solid_program: Gles2SolidProgram,
|
solid_program: Gles2SolidProgram,
|
||||||
vbos: [ffi::types::GLuint; 2],
|
vbos: [ffi::types::GLuint; 2],
|
||||||
size: Size<i32, Physical>,
|
size: Size<i32, Physical>,
|
||||||
|
min_filter: TextureFilter,
|
||||||
|
max_filter: TextureFilter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Gles2Frame {
|
impl fmt::Debug for Gles2Frame {
|
||||||
|
@ -200,6 +205,8 @@ impl fmt::Debug for Gles2Frame {
|
||||||
.field("tex_programs", &self.tex_programs)
|
.field("tex_programs", &self.tex_programs)
|
||||||
.field("solid_program", &self.solid_program)
|
.field("solid_program", &self.solid_program)
|
||||||
.field("size", &self.size)
|
.field("size", &self.size)
|
||||||
|
.field("min_filter", &self.min_filter)
|
||||||
|
.field("max_filter", &self.max_filter)
|
||||||
.finish_non_exhaustive()
|
.finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,6 +222,8 @@ impl fmt::Debug for Gles2Renderer {
|
||||||
.field("solid_program", &self.solid_program)
|
.field("solid_program", &self.solid_program)
|
||||||
// ffi::Gles2 does not implement Debug
|
// ffi::Gles2 does not implement Debug
|
||||||
.field("egl", &self.egl)
|
.field("egl", &self.egl)
|
||||||
|
.field("min_filter", &self.min_filter)
|
||||||
|
.field("max_filter", &self.max_filter)
|
||||||
.field("logger", &self.logger)
|
.field("logger", &self.logger)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
@ -521,7 +530,7 @@ impl Gles2Renderer {
|
||||||
gl.BindBuffer(ffi::ARRAY_BUFFER, 0);
|
gl.BindBuffer(ffi::ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let mut renderer = Gles2Renderer {
|
let renderer = Gles2Renderer {
|
||||||
gl,
|
gl,
|
||||||
egl: context,
|
egl: context,
|
||||||
#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
|
#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
|
||||||
|
@ -537,12 +546,12 @@ impl Gles2Renderer {
|
||||||
destruction_callback: rx,
|
destruction_callback: rx,
|
||||||
destruction_callback_sender: tx,
|
destruction_callback_sender: tx,
|
||||||
vbos,
|
vbos,
|
||||||
|
min_filter: TextureFilter::Nearest,
|
||||||
|
max_filter: TextureFilter::Linear,
|
||||||
logger_ptr,
|
logger_ptr,
|
||||||
logger: log,
|
logger: log,
|
||||||
_not_send: std::ptr::null_mut(),
|
_not_send: std::ptr::null_mut(),
|
||||||
};
|
};
|
||||||
renderer.downscale_filter(TextureFilter::Nearest)?;
|
|
||||||
renderer.upscale_filter(TextureFilter::Linear)?;
|
|
||||||
renderer.egl.unbind()?;
|
renderer.egl.unbind()?;
|
||||||
Ok(renderer)
|
Ok(renderer)
|
||||||
}
|
}
|
||||||
|
@ -635,7 +644,6 @@ impl ImportShm for Gles2Renderer {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.BindTexture(ffi::TEXTURE_2D, texture.0.texture);
|
self.gl.BindTexture(ffi::TEXTURE_2D, texture.0.texture);
|
||||||
|
|
||||||
self.gl
|
self.gl
|
||||||
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
|
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
|
||||||
self.gl
|
self.gl
|
||||||
|
@ -1017,12 +1025,25 @@ impl Drop for Gles2Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gles2Renderer {
|
impl Gles2Renderer {
|
||||||
|
/// Get access to the underlying [`EGLContext`].
|
||||||
|
///
|
||||||
|
/// *Note*: Modifying the context state, might result in rendering issues.
|
||||||
|
/// The context state is considerd an implementation detail
|
||||||
|
/// and no guarantee is made about what can or cannot be changed.
|
||||||
|
/// To make sure a certain modification does not interfere with
|
||||||
|
/// the renderer's behaviour, check the source.
|
||||||
|
pub fn egl_context(&self) -> &EGLContext {
|
||||||
|
&self.egl
|
||||||
|
}
|
||||||
|
|
||||||
/// Run custom code in the GL context owned by this renderer.
|
/// Run custom code in the GL context owned by this renderer.
|
||||||
///
|
///
|
||||||
/// *Note*: Any changes to the GL state should be restored at the end of this function.
|
/// The OpenGL state of the renderer is considered an implementation detail
|
||||||
/// Otherwise this can lead to rendering errors while using functions of this renderer.
|
/// and no guarantee is made about what can or cannot be changed,
|
||||||
/// Relying on any state set by the renderer may break on any smithay update as the
|
/// as such you should reset everything you change back to its previous value
|
||||||
/// details about how this renderer works are considered an implementation detail.
|
/// or check the source code of the version of Smithay you are using to ensure
|
||||||
|
/// your changes don't interfere with the renderer's behavior.
|
||||||
|
/// Doing otherwise can lead to rendering errors while using other functions of this renderer.
|
||||||
pub fn with_context<F, R>(&mut self, func: F) -> Result<R, Gles2Error>
|
pub fn with_context<F, R>(&mut self, func: F) -> Result<R, Gles2Error>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self, &ffi::Gles2) -> R,
|
F: FnOnce(&mut Self, &ffi::Gles2) -> R,
|
||||||
|
@ -1039,31 +1060,11 @@ impl Renderer for Gles2Renderer {
|
||||||
type Frame = Gles2Frame;
|
type Frame = Gles2Frame;
|
||||||
|
|
||||||
fn downscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error> {
|
fn downscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error> {
|
||||||
self.make_current()?;
|
self.min_filter = filter;
|
||||||
unsafe {
|
|
||||||
self.gl.TexParameteri(
|
|
||||||
ffi::TEXTURE_2D,
|
|
||||||
ffi::TEXTURE_MIN_FILTER,
|
|
||||||
match filter {
|
|
||||||
TextureFilter::Nearest => ffi::NEAREST as i32,
|
|
||||||
TextureFilter::Linear => ffi::LINEAR as i32,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn upscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error> {
|
fn upscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error> {
|
||||||
self.make_current()?;
|
self.max_filter = filter;
|
||||||
unsafe {
|
|
||||||
self.gl.TexParameteri(
|
|
||||||
ffi::TEXTURE_2D,
|
|
||||||
ffi::TEXTURE_MAG_FILTER,
|
|
||||||
match filter {
|
|
||||||
TextureFilter::Nearest => ffi::NEAREST as i32,
|
|
||||||
TextureFilter::Linear => ffi::LINEAR as i32,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1116,8 +1117,11 @@ impl Renderer for Gles2Renderer {
|
||||||
solid_program: self.solid_program.clone(),
|
solid_program: self.solid_program.clone(),
|
||||||
// output transformation passed in by the user
|
// output transformation passed in by the user
|
||||||
current_projection: flip180 * transform.matrix() * renderer,
|
current_projection: flip180 * transform.matrix() * renderer,
|
||||||
|
transform,
|
||||||
vbos: self.vbos,
|
vbos: self.vbos,
|
||||||
size,
|
size,
|
||||||
|
min_filter: self.min_filter,
|
||||||
|
max_filter: self.max_filter,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = rendering(self, &mut frame);
|
let result = rendering(self, &mut frame);
|
||||||
|
@ -1305,6 +1309,10 @@ impl Frame for Gles2Frame {
|
||||||
|
|
||||||
self.render_texture(texture, mat, Some(&damage), tex_verts, alpha)
|
self.render_texture(texture, mat, Some(&damage), tex_verts, alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transformation(&self) -> Transform {
|
||||||
|
self.transform
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gles2Frame {
|
impl Gles2Frame {
|
||||||
|
@ -1331,8 +1339,22 @@ impl Gles2Frame {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.ActiveTexture(ffi::TEXTURE0);
|
self.gl.ActiveTexture(ffi::TEXTURE0);
|
||||||
self.gl.BindTexture(target, tex.0.texture);
|
self.gl.BindTexture(target, tex.0.texture);
|
||||||
self.gl
|
self.gl.TexParameteri(
|
||||||
.TexParameteri(target, ffi::TEXTURE_MIN_FILTER, ffi::LINEAR as i32);
|
ffi::TEXTURE_2D,
|
||||||
|
ffi::TEXTURE_MIN_FILTER,
|
||||||
|
match self.min_filter {
|
||||||
|
TextureFilter::Nearest => ffi::NEAREST as i32,
|
||||||
|
TextureFilter::Linear => ffi::LINEAR as i32,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.gl.TexParameteri(
|
||||||
|
ffi::TEXTURE_2D,
|
||||||
|
ffi::TEXTURE_MAG_FILTER,
|
||||||
|
match self.max_filter {
|
||||||
|
TextureFilter::Nearest => ffi::NEAREST as i32,
|
||||||
|
TextureFilter::Linear => ffi::LINEAR as i32,
|
||||||
|
},
|
||||||
|
);
|
||||||
self.gl.UseProgram(self.tex_programs[tex.0.texture_kind].program);
|
self.gl.UseProgram(self.tex_programs[tex.0.texture_kind].program);
|
||||||
|
|
||||||
self.gl
|
self.gl
|
||||||
|
@ -1415,4 +1437,9 @@ impl Gles2Frame {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Projection matrix for this frame
|
||||||
|
pub fn projection(&self) -> &[f32; 9] {
|
||||||
|
self.current_projection.as_ref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,36 @@ impl Transform {
|
||||||
size
|
size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transforms a rectangle inside an area of a given size by applying this transformation
|
||||||
|
pub fn transform_rect_in<N: Coordinate, Kind>(
|
||||||
|
&self,
|
||||||
|
rect: Rectangle<N, Kind>,
|
||||||
|
area: &Size<N, Kind>,
|
||||||
|
) -> Rectangle<N, Kind> {
|
||||||
|
let size = self.transform_size(rect.size);
|
||||||
|
|
||||||
|
let loc = match *self {
|
||||||
|
Transform::Normal => rect.loc,
|
||||||
|
Transform::_90 => (area.h - rect.loc.y - rect.size.h, rect.loc.x).into(),
|
||||||
|
Transform::_180 => (
|
||||||
|
area.w - rect.loc.x - rect.size.w,
|
||||||
|
area.h - rect.loc.y - rect.size.h,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
Transform::_270 => (rect.loc.y, area.w - rect.loc.x - rect.size.w).into(),
|
||||||
|
Transform::Flipped => (area.w - rect.loc.x - rect.size.w, rect.loc.y).into(),
|
||||||
|
Transform::Flipped90 => (rect.loc.y, rect.loc.x).into(),
|
||||||
|
Transform::Flipped180 => (rect.loc.x, area.h - rect.loc.y - rect.size.h).into(),
|
||||||
|
Transform::Flipped270 => (
|
||||||
|
area.h - rect.loc.y - rect.size.h,
|
||||||
|
area.w - rect.loc.x - rect.size.w,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Rectangle::from_loc_and_size(loc, size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
|
@ -219,6 +249,9 @@ pub trait Frame {
|
||||||
src_transform: Transform,
|
src_transform: Transform,
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
) -> Result<(), Self::Error>;
|
) -> Result<(), Self::Error>;
|
||||||
|
|
||||||
|
/// Output transformation that is applied to this frame
|
||||||
|
fn transformation(&self) -> Transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Abstraction of commonly used rendering operations for compositors.
|
/// Abstraction of commonly used rendering operations for compositors.
|
||||||
|
@ -527,3 +560,102 @@ pub fn buffer_dimensions(buffer: &wl_buffer::WlBuffer) -> Option<Size<i32, Physi
|
||||||
|
|
||||||
crate::wayland::shm::with_buffer_contents(buffer, |_, data| (data.width, data.height).into()).ok()
|
crate::wayland::shm::with_buffer_contents(buffer, |_, data| (data.width, data.height).into()).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::Transform;
|
||||||
|
use crate::utils::{Logical, Rectangle, Size};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transform_rect_ident() {
|
||||||
|
let rect = Rectangle::<i32, Logical>::from_loc_and_size((10, 20), (30, 40));
|
||||||
|
let size = Size::from((70, 90));
|
||||||
|
let transform = Transform::Normal;
|
||||||
|
|
||||||
|
assert_eq!(rect, transform.transform_rect_in(rect, &size))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transform_rect_90() {
|
||||||
|
let rect = Rectangle::<i32, Logical>::from_loc_and_size((10, 20), (30, 40));
|
||||||
|
let size = Size::from((70, 90));
|
||||||
|
let transform = Transform::_90;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Rectangle::from_loc_and_size((30, 10), (40, 30)),
|
||||||
|
transform.transform_rect_in(rect, &size)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transform_rect_180() {
|
||||||
|
let rect = Rectangle::<i32, Logical>::from_loc_and_size((10, 20), (30, 40));
|
||||||
|
let size = Size::from((70, 90));
|
||||||
|
let transform = Transform::_180;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Rectangle::from_loc_and_size((30, 30), (30, 40)),
|
||||||
|
transform.transform_rect_in(rect, &size)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transform_rect_270() {
|
||||||
|
let rect = Rectangle::<i32, Logical>::from_loc_and_size((10, 20), (30, 40));
|
||||||
|
let size = Size::from((70, 90));
|
||||||
|
let transform = Transform::_270;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Rectangle::from_loc_and_size((20, 30), (40, 30)),
|
||||||
|
transform.transform_rect_in(rect, &size)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transform_rect_f() {
|
||||||
|
let rect = Rectangle::<i32, Logical>::from_loc_and_size((10, 20), (30, 40));
|
||||||
|
let size = Size::from((70, 90));
|
||||||
|
let transform = Transform::Flipped;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Rectangle::from_loc_and_size((30, 20), (30, 40)),
|
||||||
|
transform.transform_rect_in(rect, &size)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transform_rect_f90() {
|
||||||
|
let rect = Rectangle::<i32, Logical>::from_loc_and_size((10, 20), (30, 40));
|
||||||
|
let size = Size::from((70, 80));
|
||||||
|
let transform = Transform::Flipped90;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Rectangle::from_loc_and_size((20, 10), (40, 30)),
|
||||||
|
transform.transform_rect_in(rect, &size)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transform_rect_f180() {
|
||||||
|
let rect = Rectangle::<i32, Logical>::from_loc_and_size((10, 20), (30, 40));
|
||||||
|
let size = Size::from((70, 90));
|
||||||
|
let transform = Transform::Flipped180;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Rectangle::from_loc_and_size((10, 30), (30, 40)),
|
||||||
|
transform.transform_rect_in(rect, &size)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transform_rect_f270() {
|
||||||
|
let rect = Rectangle::<i32, Logical>::from_loc_and_size((10, 20), (30, 40));
|
||||||
|
let size = Size::from((70, 90));
|
||||||
|
let transform = Transform::Flipped270;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Rectangle::from_loc_and_size((30, 30), (40, 30)),
|
||||||
|
transform.transform_rect_in(rect, &size)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -112,6 +112,10 @@ impl Frame for DummyFrame {
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transformation(&self) -> Transform {
|
||||||
|
Transform::Normal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DummyTexture {
|
pub struct DummyTexture {
|
||||||
|
|
Loading…
Reference in New Issue