Merge pull request #460 from Smithay/feature/egl_userdata
This commit is contained in:
commit
d554c7d2b9
|
@ -168,7 +168,14 @@ pub fn run_winit(log: Logger) {
|
|||
.and_then(|_| {
|
||||
backend
|
||||
.renderer()
|
||||
.render(size, Transform::Flipped180, |renderer, frame| {
|
||||
.render(
|
||||
output_geometry
|
||||
.size
|
||||
.to_f64()
|
||||
.to_physical(output_scale as f64)
|
||||
.to_i32_round(),
|
||||
Transform::Flipped180,
|
||||
|renderer, frame| {
|
||||
render_layers_and_windows(
|
||||
renderer,
|
||||
frame,
|
||||
|
@ -238,7 +245,8 @@ pub fn run_winit(log: Logger) {
|
|||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
},
|
||||
)
|
||||
.map_err(Into::<SwapBuffersError>::into)
|
||||
.and_then(|x| x)
|
||||
})
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
//! EGL context related structs
|
||||
use std::collections::HashSet;
|
||||
use std::os::raw::c_int;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
os::raw::c_int,
|
||||
sync::{atomic::Ordering, Arc},
|
||||
};
|
||||
|
||||
use super::{ffi, wrap_egl_call, Error, MakeCurrentError};
|
||||
use crate::backend::allocator::Format as DrmFormat;
|
||||
use crate::backend::egl::display::{EGLDisplay, PixelFormat};
|
||||
use crate::backend::egl::EGLSurface;
|
||||
use crate::{
|
||||
backend::{
|
||||
allocator::Format as DrmFormat,
|
||||
egl::{
|
||||
display::{EGLDisplay, PixelFormat},
|
||||
EGLSurface,
|
||||
},
|
||||
},
|
||||
utils::user_data::UserDataMap,
|
||||
};
|
||||
|
||||
use slog::{info, o, trace};
|
||||
|
||||
|
@ -17,6 +26,7 @@ pub struct EGLContext {
|
|||
pub(crate) display: EGLDisplay,
|
||||
config_id: ffi::egl::types::EGLConfig,
|
||||
pixel_format: Option<PixelFormat>,
|
||||
user_data: Arc<UserDataMap>,
|
||||
}
|
||||
// EGLContexts can be moved between threads safely
|
||||
unsafe impl Send for EGLContext {}
|
||||
|
@ -162,6 +172,11 @@ impl EGLContext {
|
|||
display: display.clone(),
|
||||
config_id,
|
||||
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> {
|
||||
&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 {
|
||||
|
|
|
@ -173,7 +173,9 @@ impl 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,6 +172,16 @@ impl EGLSurface {
|
|||
pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
|
||||
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 {
|
||||
|
|
|
@ -178,6 +178,8 @@ pub struct Gles2Renderer {
|
|||
// This field is only accessed if the image or wayland_frontend features are active
|
||||
#[allow(dead_code)]
|
||||
destruction_callback_sender: Sender<CleanupResource>,
|
||||
min_filter: TextureFilter,
|
||||
max_filter: TextureFilter,
|
||||
logger_ptr: Option<*mut ::slog::Logger>,
|
||||
logger: ::slog::Logger,
|
||||
_not_send: *mut (),
|
||||
|
@ -186,11 +188,14 @@ pub struct Gles2Renderer {
|
|||
/// Handle to the currently rendered frame during [`Gles2Renderer::render`](Renderer::render)
|
||||
pub struct Gles2Frame {
|
||||
current_projection: Matrix3<f32>,
|
||||
transform: Transform,
|
||||
gl: ffi::Gles2,
|
||||
tex_programs: [Gles2TexProgram; shaders::FRAGMENT_COUNT],
|
||||
solid_program: Gles2SolidProgram,
|
||||
vbos: [ffi::types::GLuint; 2],
|
||||
size: Size<i32, Physical>,
|
||||
min_filter: TextureFilter,
|
||||
max_filter: TextureFilter,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Gles2Frame {
|
||||
|
@ -200,6 +205,8 @@ impl fmt::Debug for Gles2Frame {
|
|||
.field("tex_programs", &self.tex_programs)
|
||||
.field("solid_program", &self.solid_program)
|
||||
.field("size", &self.size)
|
||||
.field("min_filter", &self.min_filter)
|
||||
.field("max_filter", &self.max_filter)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
@ -215,6 +222,8 @@ impl fmt::Debug for Gles2Renderer {
|
|||
.field("solid_program", &self.solid_program)
|
||||
// ffi::Gles2 does not implement Debug
|
||||
.field("egl", &self.egl)
|
||||
.field("min_filter", &self.min_filter)
|
||||
.field("max_filter", &self.max_filter)
|
||||
.field("logger", &self.logger)
|
||||
.finish()
|
||||
}
|
||||
|
@ -521,7 +530,7 @@ impl Gles2Renderer {
|
|||
gl.BindBuffer(ffi::ARRAY_BUFFER, 0);
|
||||
|
||||
let (tx, rx) = channel();
|
||||
let mut renderer = Gles2Renderer {
|
||||
let renderer = Gles2Renderer {
|
||||
gl,
|
||||
egl: context,
|
||||
#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
|
||||
|
@ -537,12 +546,12 @@ impl Gles2Renderer {
|
|||
destruction_callback: rx,
|
||||
destruction_callback_sender: tx,
|
||||
vbos,
|
||||
min_filter: TextureFilter::Nearest,
|
||||
max_filter: TextureFilter::Linear,
|
||||
logger_ptr,
|
||||
logger: log,
|
||||
_not_send: std::ptr::null_mut(),
|
||||
};
|
||||
renderer.downscale_filter(TextureFilter::Nearest)?;
|
||||
renderer.upscale_filter(TextureFilter::Linear)?;
|
||||
renderer.egl.unbind()?;
|
||||
Ok(renderer)
|
||||
}
|
||||
|
@ -635,7 +644,6 @@ impl ImportShm for Gles2Renderer {
|
|||
|
||||
unsafe {
|
||||
self.gl.BindTexture(ffi::TEXTURE_2D, texture.0.texture);
|
||||
|
||||
self.gl
|
||||
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
|
||||
self.gl
|
||||
|
@ -1017,12 +1025,25 @@ impl Drop for 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.
|
||||
///
|
||||
/// *Note*: Any changes to the GL state should be restored at the end of this function.
|
||||
/// Otherwise this can lead to rendering errors while using functions of this renderer.
|
||||
/// Relying on any state set by the renderer may break on any smithay update as the
|
||||
/// details about how this renderer works are considered an implementation detail.
|
||||
/// The OpenGL state of the renderer is considered an implementation detail
|
||||
/// and no guarantee is made about what can or cannot be changed,
|
||||
/// as such you should reset everything you change back to its previous value
|
||||
/// 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>
|
||||
where
|
||||
F: FnOnce(&mut Self, &ffi::Gles2) -> R,
|
||||
|
@ -1039,31 +1060,11 @@ impl Renderer for Gles2Renderer {
|
|||
type Frame = Gles2Frame;
|
||||
|
||||
fn downscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error> {
|
||||
self.make_current()?;
|
||||
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,
|
||||
},
|
||||
);
|
||||
}
|
||||
self.min_filter = filter;
|
||||
Ok(())
|
||||
}
|
||||
fn upscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error> {
|
||||
self.make_current()?;
|
||||
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,
|
||||
},
|
||||
);
|
||||
}
|
||||
self.max_filter = filter;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1116,8 +1117,11 @@ impl Renderer for Gles2Renderer {
|
|||
solid_program: self.solid_program.clone(),
|
||||
// output transformation passed in by the user
|
||||
current_projection: flip180 * transform.matrix() * renderer,
|
||||
transform,
|
||||
vbos: self.vbos,
|
||||
size,
|
||||
min_filter: self.min_filter,
|
||||
max_filter: self.max_filter,
|
||||
};
|
||||
|
||||
let result = rendering(self, &mut frame);
|
||||
|
@ -1305,6 +1309,10 @@ impl Frame for Gles2Frame {
|
|||
|
||||
self.render_texture(texture, mat, Some(&damage), tex_verts, alpha)
|
||||
}
|
||||
|
||||
fn transformation(&self) -> Transform {
|
||||
self.transform
|
||||
}
|
||||
}
|
||||
|
||||
impl Gles2Frame {
|
||||
|
@ -1331,8 +1339,22 @@ impl Gles2Frame {
|
|||
unsafe {
|
||||
self.gl.ActiveTexture(ffi::TEXTURE0);
|
||||
self.gl.BindTexture(target, tex.0.texture);
|
||||
self.gl
|
||||
.TexParameteri(target, ffi::TEXTURE_MIN_FILTER, ffi::LINEAR as i32);
|
||||
self.gl.TexParameteri(
|
||||
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
|
||||
|
@ -1415,4 +1437,9 @@ impl Gles2Frame {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Projection matrix for this frame
|
||||
pub fn projection(&self) -> &[f32; 9] {
|
||||
self.current_projection.as_ref()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,6 +108,36 @@ impl Transform {
|
|||
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")]
|
||||
|
@ -219,6 +249,9 @@ pub trait Frame {
|
|||
src_transform: Transform,
|
||||
alpha: f32,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
/// Output transformation that is applied to this frame
|
||||
fn transformation(&self) -> Transform;
|
||||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
|
||||
#[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> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transformation(&self) -> Transform {
|
||||
Transform::Normal
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DummyTexture {
|
||||
|
|
Loading…
Reference in New Issue