Merge pull request #334 from Smithay/features/renderer
gles2: add and use cropping to the renderer
This commit is contained in:
commit
af2aa017bf
|
@ -22,7 +22,6 @@ drm = { version = "0.4.0", optional = true }
|
||||||
drm-ffi = { version = "0.1.0", optional = true }
|
drm-ffi = { version = "0.1.0", optional = true }
|
||||||
gbm = { version = "0.6.0", optional = true, default-features = false, features = ["drm-support"] }
|
gbm = { version = "0.6.0", optional = true, default-features = false, features = ["drm-support"] }
|
||||||
input = { version = "0.6", default-features = false, features=["libinput_1_14"], optional = true }
|
input = { version = "0.6", default-features = false, features=["libinput_1_14"], optional = true }
|
||||||
image = { version = "0.23.14", default-features = false, optional = true }
|
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
libc = "0.2.70"
|
libc = "0.2.70"
|
||||||
libseat= { version = "0.1.1", optional = true }
|
libseat= { version = "0.1.1", optional = true }
|
||||||
|
@ -50,7 +49,7 @@ gl_generator = { version = "0.14", optional = true }
|
||||||
pkg-config = { version = "0.3.17", optional = true }
|
pkg-config = { version = "0.3.17", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["backend_drm", "backend_gbm", "backend_libinput", "backend_udev", "backend_session_logind", "backend_winit", "image", "renderer_gl", "xwayland", "wayland_frontend", "slog-stdlog"]
|
default = ["backend_drm", "backend_gbm", "backend_libinput", "backend_udev", "backend_session_logind", "backend_winit", "renderer_gl", "xwayland", "wayland_frontend", "slog-stdlog"]
|
||||||
backend_winit = ["winit", "wayland-server/dlopen", "backend_egl", "wayland-egl", "renderer_gl"]
|
backend_winit = ["winit", "wayland-server/dlopen", "backend_egl", "wayland-egl", "renderer_gl"]
|
||||||
backend_drm = ["drm", "drm-ffi"]
|
backend_drm = ["drm", "drm-ffi"]
|
||||||
backend_gbm = ["gbm"]
|
backend_gbm = ["gbm"]
|
||||||
|
|
|
@ -9,7 +9,10 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "1.2.1"
|
bitflags = "1.2.1"
|
||||||
input = { version = "0.5.0", features = ["udev"], optional = true }
|
input = { version = "0.5.0", features = ["udev"], optional = true }
|
||||||
image = { version = "0.23.0", optional = true, default-features = false }
|
thiserror = "1"
|
||||||
|
xcursor = { version = "0.3.3", optional = true }
|
||||||
|
image = { version = "0.23.14", default-features = false, optional = true }
|
||||||
|
fps_ticker = { version = "1.0.0", optional = true }
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
slog = { version = "2.1.1" }
|
slog = { version = "2.1.1" }
|
||||||
slog-term = "2.8"
|
slog-term = "2.8"
|
||||||
|
@ -36,9 +39,10 @@ gl_generator = "0.14"
|
||||||
default = [ "winit", "udev", "logind", "egl", "xwayland" ]
|
default = [ "winit", "udev", "logind", "egl", "xwayland" ]
|
||||||
egl = [ "smithay/use_system_lib", "smithay/backend_egl" ]
|
egl = [ "smithay/use_system_lib", "smithay/backend_egl" ]
|
||||||
winit = [ "smithay/backend_winit" ]
|
winit = [ "smithay/backend_winit" ]
|
||||||
udev = [ "smithay/backend_libinput", "smithay/backend_udev", "smithay/backend_drm", "smithay/backend_gbm", "smithay/backend_egl", "smithay/backend_session", "input", "image", "smithay/image"]
|
udev = [ "smithay/backend_libinput", "smithay/backend_udev", "smithay/backend_drm", "smithay/backend_gbm", "smithay/backend_egl", "smithay/backend_session", "input", "image", "xcursor" ]
|
||||||
logind = [ "smithay/backend_session_logind" ]
|
logind = [ "smithay/backend_session_logind" ]
|
||||||
elogind = ["logind", "smithay/backend_session_elogind" ]
|
elogind = ["logind", "smithay/backend_session_elogind" ]
|
||||||
libseat = ["smithay/backend_session_libseat" ]
|
libseat = ["smithay/backend_session_libseat" ]
|
||||||
xwayland = [ "smithay/xwayland", "x11rb" ]
|
xwayland = [ "smithay/xwayland", "x11rb" ]
|
||||||
test_all_features = ["default"]
|
debug = [ "fps_ticker", "image/png" ]
|
||||||
|
test_all_features = ["default", "debug"]
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,92 @@
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
use xcursor::{
|
||||||
|
parser::{parse_xcursor, Image},
|
||||||
|
CursorTheme,
|
||||||
|
};
|
||||||
|
|
||||||
|
static FALLBACK_CURSOR_DATA: &[u8] = include_bytes!("../resources/cursor.rgba");
|
||||||
|
|
||||||
|
pub struct Cursor {
|
||||||
|
icons: Vec<Image>,
|
||||||
|
size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cursor {
|
||||||
|
pub fn load(log: &::slog::Logger) -> Cursor {
|
||||||
|
let name = std::env::var("XCURSOR_THEME")
|
||||||
|
.ok()
|
||||||
|
.unwrap_or_else(|| "default".into());
|
||||||
|
let size = std::env::var("XCURSOR_SIZE")
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s.parse().ok())
|
||||||
|
.unwrap_or(24);
|
||||||
|
|
||||||
|
let theme = CursorTheme::load(&name);
|
||||||
|
let icons = load_icon(&theme)
|
||||||
|
.map_err(|err| slog::warn!(log, "Unable to load xcursor: {}, using fallback cursor", err))
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
vec![Image {
|
||||||
|
size: 32,
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
xhot: 1,
|
||||||
|
yhot: 1,
|
||||||
|
delay: 1,
|
||||||
|
pixels_rgba: Vec::from(FALLBACK_CURSOR_DATA),
|
||||||
|
pixels_argb: vec![], //unused
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
Cursor { icons, size }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_image(&self, scale: u32, millis: u32) -> Image {
|
||||||
|
let size = self.size * scale;
|
||||||
|
frame(millis, size, &self.icons)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nearest_images(size: u32, images: &[Image]) -> impl Iterator<Item = &Image> {
|
||||||
|
// Follow the nominal size of the cursor to choose the nearest
|
||||||
|
let nearest_image = images
|
||||||
|
.iter()
|
||||||
|
.min_by_key(|image| (size as i32 - image.size as i32).abs())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
images
|
||||||
|
.iter()
|
||||||
|
.filter(move |image| image.width == nearest_image.width && image.height == nearest_image.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(mut millis: u32, size: u32, images: &[Image]) -> Image {
|
||||||
|
let total = nearest_images(size, images).fold(0, |acc, image| acc + image.delay);
|
||||||
|
millis %= total;
|
||||||
|
|
||||||
|
for img in nearest_images(size, images) {
|
||||||
|
if millis < img.delay {
|
||||||
|
return img.clone();
|
||||||
|
}
|
||||||
|
millis -= img.delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
enum Error {
|
||||||
|
#[error("Theme has no default cursor")]
|
||||||
|
NoDefaultCursor,
|
||||||
|
#[error("Error opening xcursor file: {0}")]
|
||||||
|
File(#[from] std::io::Error),
|
||||||
|
#[error("Failed to parse XCursor file")]
|
||||||
|
Parse,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_icon(theme: &CursorTheme) -> Result<Vec<Image>, Error> {
|
||||||
|
let icon_path = theme.load_icon("default").ok_or(Error::NoDefaultCursor)?;
|
||||||
|
let mut cursor_file = std::fs::File::open(&icon_path)?;
|
||||||
|
let mut cursor_data = Vec::new();
|
||||||
|
cursor_file.read_to_end(&mut cursor_data)?;
|
||||||
|
parse_xcursor(&cursor_data).ok_or(Error::Parse)
|
||||||
|
}
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
use std::{cell::RefCell, sync::Mutex};
|
use std::{cell::RefCell, sync::Mutex};
|
||||||
|
|
||||||
|
#[cfg(feature = "image")]
|
||||||
|
use image::{ImageBuffer, Rgba};
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
#[cfg(feature = "image")]
|
||||||
|
use smithay::backend::renderer::gles2::{Gles2Error, Gles2Renderer, Gles2Texture};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
renderer::{buffer_type, BufferType, Frame, ImportAll, Renderer, Texture, Transform},
|
renderer::{buffer_type, BufferType, Frame, ImportAll, Renderer, Texture, Transform},
|
||||||
|
@ -155,7 +159,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 +171,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());
|
||||||
|
@ -260,3 +264,84 @@ where
|
||||||
}
|
}
|
||||||
draw_surface_tree(renderer, frame, surface, location, output_scale, log)
|
draw_surface_tree(renderer, frame, surface, location, output_scale, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub static FPS_NUMBERS_PNG: &[u8] = include_bytes!("../resources/numbers.png");
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub fn draw_fps<R, E, F, T>(
|
||||||
|
_renderer: &mut R,
|
||||||
|
frame: &mut F,
|
||||||
|
texture: &T,
|
||||||
|
output_scale: f64,
|
||||||
|
value: u32,
|
||||||
|
) -> Result<(), SwapBuffersError>
|
||||||
|
where
|
||||||
|
R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
|
||||||
|
F: Frame<Error = E, TextureId = T>,
|
||||||
|
E: std::error::Error + Into<SwapBuffersError>,
|
||||||
|
T: Texture + 'static,
|
||||||
|
{
|
||||||
|
let value_str = value.to_string();
|
||||||
|
let mut offset_x = 0f64;
|
||||||
|
for digit in value_str.chars().map(|d| d.to_digit(10).unwrap()) {
|
||||||
|
frame
|
||||||
|
.render_texture_from_to(
|
||||||
|
texture,
|
||||||
|
match digit {
|
||||||
|
9 => Rectangle::from_loc_and_size((0, 0), (22, 35)),
|
||||||
|
6 => Rectangle::from_loc_and_size((22, 0), (22, 35)),
|
||||||
|
3 => Rectangle::from_loc_and_size((44, 0), (22, 35)),
|
||||||
|
1 => Rectangle::from_loc_and_size((66, 0), (22, 35)),
|
||||||
|
8 => Rectangle::from_loc_and_size((0, 35), (22, 35)),
|
||||||
|
0 => Rectangle::from_loc_and_size((22, 35), (22, 35)),
|
||||||
|
2 => Rectangle::from_loc_and_size((44, 35), (22, 35)),
|
||||||
|
7 => Rectangle::from_loc_and_size((0, 70), (22, 35)),
|
||||||
|
4 => Rectangle::from_loc_and_size((22, 70), (22, 35)),
|
||||||
|
5 => Rectangle::from_loc_and_size((44, 70), (22, 35)),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
Rectangle::from_loc_and_size((offset_x, 0.0), (22.0 * output_scale, 35.0 * output_scale)),
|
||||||
|
Transform::Normal,
|
||||||
|
1.0,
|
||||||
|
)
|
||||||
|
.map_err(Into::into)?;
|
||||||
|
offset_x += 24.0 * output_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "image")]
|
||||||
|
pub fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
|
||||||
|
renderer: &mut Gles2Renderer,
|
||||||
|
image: &ImageBuffer<Rgba<u8>, C>,
|
||||||
|
) -> Result<Gles2Texture, Gles2Error> {
|
||||||
|
use smithay::backend::renderer::gles2::ffi;
|
||||||
|
|
||||||
|
renderer.with_context(|renderer, gl| unsafe {
|
||||||
|
let mut tex = 0;
|
||||||
|
gl.GenTextures(1, &mut tex);
|
||||||
|
gl.BindTexture(ffi::TEXTURE_2D, tex);
|
||||||
|
gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
|
||||||
|
gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
||||||
|
gl.TexImage2D(
|
||||||
|
ffi::TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
ffi::RGBA as i32,
|
||||||
|
image.width() as i32,
|
||||||
|
image.height() as i32,
|
||||||
|
0,
|
||||||
|
ffi::RGBA,
|
||||||
|
ffi::UNSIGNED_BYTE as u32,
|
||||||
|
image.as_ptr() as *const _,
|
||||||
|
);
|
||||||
|
gl.BindTexture(ffi::TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
Gles2Texture::from_raw(
|
||||||
|
renderer,
|
||||||
|
tex,
|
||||||
|
(image.width() as i32, image.height() as i32).into(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ use std::{cell::RefCell, rc::Rc};
|
||||||
use slog::Drain;
|
use slog::Drain;
|
||||||
use smithay::reexports::{calloop::EventLoop, wayland_server::Display};
|
use smithay::reexports::{calloop::EventLoop, wayland_server::Display};
|
||||||
|
|
||||||
|
#[cfg(feature = "udev")]
|
||||||
|
mod cursor;
|
||||||
mod drawing;
|
mod drawing;
|
||||||
mod input_handler;
|
mod input_handler;
|
||||||
mod shell;
|
mod shell;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use image::{ImageBuffer, Rgba};
|
use image::ImageBuffer;
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
@ -90,7 +90,7 @@ pub struct UdevData {
|
||||||
primary_gpu: Option<PathBuf>,
|
primary_gpu: Option<PathBuf>,
|
||||||
backends: HashMap<dev_t, BackendData>,
|
backends: HashMap<dev_t, BackendData>,
|
||||||
signaler: Signaler<SessionSignal>,
|
signaler: Signaler<SessionSignal>,
|
||||||
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
|
pointer_image: crate::cursor::Cursor,
|
||||||
render_timer: TimerHandle<(u64, crtc::Handle)>,
|
render_timer: TimerHandle<(u64, crtc::Handle)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,6 @@ pub fn run_udev(
|
||||||
/*
|
/*
|
||||||
* Initialize the compositor
|
* Initialize the compositor
|
||||||
*/
|
*/
|
||||||
let pointer_bytes = include_bytes!("../resources/cursor2.rgba");
|
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
let primary_gpu = primary_gpu(&session.seat()).unwrap_or_default();
|
let primary_gpu = primary_gpu(&session.seat()).unwrap_or_default();
|
||||||
|
|
||||||
|
@ -135,7 +134,7 @@ pub fn run_udev(
|
||||||
primary_gpu,
|
primary_gpu,
|
||||||
backends: HashMap::new(),
|
backends: HashMap::new(),
|
||||||
signaler: session_signal.clone(),
|
signaler: session_signal.clone(),
|
||||||
pointer_image: ImageBuffer::from_raw(64, 64, pointer_bytes.to_vec()).unwrap(),
|
pointer_image: crate::cursor::Cursor::load(&log),
|
||||||
render_timer: timer.handle(),
|
render_timer: timer.handle(),
|
||||||
};
|
};
|
||||||
let mut state = AnvilState::init(display.clone(), event_loop.handle(), data, log.clone());
|
let mut state = AnvilState::init(display.clone(), event_loop.handle(), data, log.clone());
|
||||||
|
@ -255,10 +254,18 @@ pub fn run_udev(
|
||||||
|
|
||||||
pub type RenderSurface = GbmBufferedSurface<SessionFd>;
|
pub type RenderSurface = GbmBufferedSurface<SessionFd>;
|
||||||
|
|
||||||
|
struct SurfaceData {
|
||||||
|
surface: RenderSurface,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
fps: fps_ticker::Fps,
|
||||||
|
}
|
||||||
|
|
||||||
struct BackendData {
|
struct BackendData {
|
||||||
_restart_token: SignalToken,
|
_restart_token: SignalToken,
|
||||||
surfaces: Rc<RefCell<HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>>>>,
|
surfaces: Rc<RefCell<HashMap<crtc::Handle, Rc<RefCell<SurfaceData>>>>>,
|
||||||
pointer_image: Gles2Texture,
|
pointer_images: Vec<(xcursor::parser::Image, Gles2Texture)>,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
fps_texture: Gles2Texture,
|
||||||
renderer: Rc<RefCell<Gles2Renderer>>,
|
renderer: Rc<RefCell<Gles2Renderer>>,
|
||||||
gbm: GbmDevice<SessionFd>,
|
gbm: GbmDevice<SessionFd>,
|
||||||
registration_token: RegistrationToken,
|
registration_token: RegistrationToken,
|
||||||
|
@ -273,7 +280,7 @@ fn scan_connectors(
|
||||||
output_map: &mut crate::output_map::OutputMap,
|
output_map: &mut crate::output_map::OutputMap,
|
||||||
signaler: &Signaler<SessionSignal>,
|
signaler: &Signaler<SessionSignal>,
|
||||||
logger: &::slog::Logger,
|
logger: &::slog::Logger,
|
||||||
) -> HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>> {
|
) -> HashMap<crtc::Handle, Rc<RefCell<SurfaceData>>> {
|
||||||
// Get a set of all modesetting resource handles (excluding planes):
|
// Get a set of all modesetting resource handles (excluding planes):
|
||||||
let res_handles = device.resource_handles().unwrap();
|
let res_handles = device.resource_handles().unwrap();
|
||||||
|
|
||||||
|
@ -322,7 +329,7 @@ fn scan_connectors(
|
||||||
let renderer_formats =
|
let renderer_formats =
|
||||||
Bind::<Dmabuf>::supported_formats(renderer).expect("Dmabuf renderer without formats");
|
Bind::<Dmabuf>::supported_formats(renderer).expect("Dmabuf renderer without formats");
|
||||||
|
|
||||||
let renderer =
|
let gbm_surface =
|
||||||
match GbmBufferedSurface::new(surface, gbm.clone(), renderer_formats, logger.clone())
|
match GbmBufferedSurface::new(surface, gbm.clone(), renderer_formats, logger.clone())
|
||||||
{
|
{
|
||||||
Ok(renderer) => renderer,
|
Ok(renderer) => renderer,
|
||||||
|
@ -374,7 +381,11 @@ fn scan_connectors(
|
||||||
device_id: device.device_id(),
|
device_id: device.device_id(),
|
||||||
});
|
});
|
||||||
|
|
||||||
entry.insert(Rc::new(RefCell::new(renderer)));
|
entry.insert(Rc::new(RefCell::new(SurfaceData {
|
||||||
|
surface: gbm_surface,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
fps: fps_ticker::Fps::default(),
|
||||||
|
})));
|
||||||
break 'outer;
|
break 'outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,11 +480,6 @@ impl AnvilState<UdevData> {
|
||||||
&self.log,
|
&self.log,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let pointer_image = renderer
|
|
||||||
.borrow_mut()
|
|
||||||
.import_bitmap(&self.backend_data.pointer_image)
|
|
||||||
.expect("Failed to load pointer");
|
|
||||||
|
|
||||||
let dev_id = device.device_id();
|
let dev_id = device.device_id();
|
||||||
let handle = self.handle.clone();
|
let handle = self.handle.clone();
|
||||||
let restart_token = self.backend_data.signaler.register(move |signal| match signal {
|
let restart_token = self.backend_data.signaler.register(move |signal| match signal {
|
||||||
|
@ -502,6 +508,19 @@ impl AnvilState<UdevData> {
|
||||||
schedule_initial_render(backend.clone(), renderer.clone(), &self.handle, self.log.clone());
|
schedule_initial_render(backend.clone(), renderer.clone(), &self.handle, self.log.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
let fps_texture = import_bitmap(
|
||||||
|
&mut renderer.borrow_mut(),
|
||||||
|
&image::io::Reader::with_format(
|
||||||
|
std::io::Cursor::new(FPS_NUMBERS_PNG),
|
||||||
|
image::ImageFormat::Png,
|
||||||
|
)
|
||||||
|
.decode()
|
||||||
|
.unwrap()
|
||||||
|
.to_rgba8(),
|
||||||
|
)
|
||||||
|
.expect("Unable to upload FPS texture");
|
||||||
|
|
||||||
self.backend_data.backends.insert(
|
self.backend_data.backends.insert(
|
||||||
dev_id,
|
dev_id,
|
||||||
BackendData {
|
BackendData {
|
||||||
|
@ -511,7 +530,9 @@ impl AnvilState<UdevData> {
|
||||||
surfaces: backends,
|
surfaces: backends,
|
||||||
renderer,
|
renderer,
|
||||||
gbm,
|
gbm,
|
||||||
pointer_image,
|
pointer_images: Vec::new(),
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
fps_texture,
|
||||||
dev_id,
|
dev_id,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -602,7 +623,7 @@ impl AnvilState<UdevData> {
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|crtc| surfaces.get(&crtc).map(|surface| (crtc, surface)));
|
.flat_map(|crtc| surfaces.get(&crtc).map(|surface| (crtc, surface)));
|
||||||
|
|
||||||
let to_render_iter: &mut dyn Iterator<Item = (&crtc::Handle, &Rc<RefCell<RenderSurface>>)> =
|
let to_render_iter: &mut dyn Iterator<Item = (&crtc::Handle, &Rc<RefCell<SurfaceData>>)> =
|
||||||
if crtc.is_some() {
|
if crtc.is_some() {
|
||||||
&mut option_iter
|
&mut option_iter
|
||||||
} else {
|
} else {
|
||||||
|
@ -610,15 +631,36 @@ impl AnvilState<UdevData> {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (&crtc, surface) in to_render_iter {
|
for (&crtc, surface) in to_render_iter {
|
||||||
|
// TODO get scale from the rendersurface when supporting HiDPI
|
||||||
|
let frame = self
|
||||||
|
.backend_data
|
||||||
|
.pointer_image
|
||||||
|
.get_image(1 /*scale*/, self.start_time.elapsed().as_millis() as u32);
|
||||||
|
let renderer = &mut *device_backend.renderer.borrow_mut();
|
||||||
|
let pointer_images = &mut device_backend.pointer_images;
|
||||||
|
let pointer_image = pointer_images
|
||||||
|
.iter()
|
||||||
|
.find_map(|(image, texture)| if image == &frame { Some(texture) } else { None })
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let image =
|
||||||
|
ImageBuffer::from_raw(frame.width, frame.height, &*frame.pixels_rgba).unwrap();
|
||||||
|
let texture = import_bitmap(renderer, &image).expect("Failed to import cursor bitmap");
|
||||||
|
pointer_images.push((frame, texture.clone()));
|
||||||
|
texture
|
||||||
|
});
|
||||||
|
|
||||||
let result = render_surface(
|
let result = render_surface(
|
||||||
&mut *surface.borrow_mut(),
|
&mut *surface.borrow_mut(),
|
||||||
&mut *device_backend.renderer.borrow_mut(),
|
renderer,
|
||||||
device_backend.dev_id,
|
device_backend.dev_id,
|
||||||
crtc,
|
crtc,
|
||||||
&mut *self.window_map.borrow_mut(),
|
&mut *self.window_map.borrow_mut(),
|
||||||
&*self.output_map.borrow(),
|
&*self.output_map.borrow(),
|
||||||
self.pointer_location,
|
self.pointer_location,
|
||||||
&device_backend.pointer_image,
|
&pointer_image,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
&device_backend.fps_texture,
|
||||||
&*self.dnd_icon.lock().unwrap(),
|
&*self.dnd_icon.lock().unwrap(),
|
||||||
&mut *self.cursor_status.lock().unwrap(),
|
&mut *self.cursor_status.lock().unwrap(),
|
||||||
&self.log,
|
&self.log,
|
||||||
|
@ -658,7 +700,7 @@ impl AnvilState<UdevData> {
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn render_surface(
|
fn render_surface(
|
||||||
surface: &mut RenderSurface,
|
surface: &mut SurfaceData,
|
||||||
renderer: &mut Gles2Renderer,
|
renderer: &mut Gles2Renderer,
|
||||||
device_id: dev_t,
|
device_id: dev_t,
|
||||||
crtc: crtc::Handle,
|
crtc: crtc::Handle,
|
||||||
|
@ -666,11 +708,12 @@ fn render_surface(
|
||||||
output_map: &crate::output_map::OutputMap,
|
output_map: &crate::output_map::OutputMap,
|
||||||
pointer_location: Point<f64, Logical>,
|
pointer_location: Point<f64, Logical>,
|
||||||
pointer_image: &Gles2Texture,
|
pointer_image: &Gles2Texture,
|
||||||
|
#[cfg(feature = "debug")] fps_texture: &Gles2Texture,
|
||||||
dnd_icon: &Option<wl_surface::WlSurface>,
|
dnd_icon: &Option<wl_surface::WlSurface>,
|
||||||
cursor_status: &mut CursorImageStatus,
|
cursor_status: &mut CursorImageStatus,
|
||||||
logger: &slog::Logger,
|
logger: &slog::Logger,
|
||||||
) -> Result<(), SwapBuffersError> {
|
) -> Result<(), SwapBuffersError> {
|
||||||
surface.frame_submitted()?;
|
surface.surface.frame_submitted()?;
|
||||||
|
|
||||||
let output = output_map
|
let output = output_map
|
||||||
.find(|o| o.userdata().get::<UdevOutputId>() == Some(&UdevOutputId { device_id, crtc }))
|
.find(|o| o.userdata().get::<UdevOutputId>() == Some(&UdevOutputId { device_id, crtc }))
|
||||||
|
@ -683,7 +726,7 @@ fn render_surface(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let dmabuf = surface.next_buffer()?;
|
let dmabuf = surface.surface.next_buffer()?;
|
||||||
renderer.bind(dmabuf)?;
|
renderer.bind(dmabuf)?;
|
||||||
// and draw to our buffer
|
// and draw to our buffer
|
||||||
match renderer
|
match renderer
|
||||||
|
@ -742,13 +785,26 @@ 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,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
{
|
||||||
|
draw_fps(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
fps_texture,
|
||||||
|
output_scale as f64,
|
||||||
|
surface.fps.avg().round() as u32,
|
||||||
|
)?;
|
||||||
|
surface.fps.tick();
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -756,13 +812,16 @@ fn render_surface(
|
||||||
.and_then(|x| x)
|
.and_then(|x| x)
|
||||||
.map_err(Into::<SwapBuffersError>::into)
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
{
|
{
|
||||||
Ok(()) => surface.queue_buffer().map_err(Into::<SwapBuffersError>::into),
|
Ok(()) => surface
|
||||||
|
.surface
|
||||||
|
.queue_buffer()
|
||||||
|
.map_err(Into::<SwapBuffersError>::into),
|
||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schedule_initial_render<Data: 'static>(
|
fn schedule_initial_render<Data: 'static>(
|
||||||
surface: Rc<RefCell<RenderSurface>>,
|
surface: Rc<RefCell<SurfaceData>>,
|
||||||
renderer: Rc<RefCell<Gles2Renderer>>,
|
renderer: Rc<RefCell<Gles2Renderer>>,
|
||||||
evt_handle: &LoopHandle<'static, Data>,
|
evt_handle: &LoopHandle<'static, Data>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
|
@ -770,7 +829,7 @@ fn schedule_initial_render<Data: 'static>(
|
||||||
let result = {
|
let result = {
|
||||||
let mut surface = surface.borrow_mut();
|
let mut surface = surface.borrow_mut();
|
||||||
let mut renderer = renderer.borrow_mut();
|
let mut renderer = renderer.borrow_mut();
|
||||||
initial_render(&mut *surface, &mut *renderer)
|
initial_render(&mut surface.surface, &mut *renderer)
|
||||||
};
|
};
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
match err {
|
match err {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::{cell::RefCell, rc::Rc, sync::atomic::Ordering, time::Duration};
|
use std::{cell::RefCell, rc::Rc, sync::atomic::Ordering, time::Duration};
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
use smithay::backend::renderer::gles2::Gles2Texture;
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{ImportDma, ImportEgl},
|
backend::renderer::{ImportDma, ImportEgl},
|
||||||
|
@ -24,7 +26,12 @@ use crate::state::{AnvilState, Backend};
|
||||||
|
|
||||||
pub const OUTPUT_NAME: &str = "winit";
|
pub const OUTPUT_NAME: &str = "winit";
|
||||||
|
|
||||||
pub struct WinitData;
|
pub struct WinitData {
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
fps_texture: Gles2Texture,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub fps: fps_ticker::Fps,
|
||||||
|
}
|
||||||
|
|
||||||
impl Backend for WinitData {
|
impl Backend for WinitData {
|
||||||
fn seat_name(&self) -> String {
|
fn seat_name(&self) -> String {
|
||||||
|
@ -71,7 +78,20 @@ pub fn run_winit(
|
||||||
* Initialize the globals
|
* Initialize the globals
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let mut state = AnvilState::init(display.clone(), event_loop.handle(), WinitData, log.clone());
|
let data = WinitData {
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
fps_texture: import_bitmap(
|
||||||
|
&mut renderer.borrow_mut().renderer(),
|
||||||
|
&image::io::Reader::with_format(std::io::Cursor::new(FPS_NUMBERS_PNG), image::ImageFormat::Png)
|
||||||
|
.decode()
|
||||||
|
.unwrap()
|
||||||
|
.to_rgba8(),
|
||||||
|
)
|
||||||
|
.expect("Unable to upload FPS texture"),
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
fps: fps_ticker::Fps::default(),
|
||||||
|
};
|
||||||
|
let mut state = AnvilState::init(display.clone(), event_loop.handle(), data, log.clone());
|
||||||
|
|
||||||
let mode = Mode {
|
let mode = Mode {
|
||||||
size,
|
size,
|
||||||
|
@ -176,6 +196,18 @@ pub fn run_winit(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
{
|
||||||
|
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(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.map_err(Into::<SwapBuffersError>::into)
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
|
@ -206,6 +238,9 @@ pub fn run_winit(
|
||||||
state.window_map.borrow_mut().refresh();
|
state.window_map.borrow_mut().refresh();
|
||||||
state.output_map.borrow_mut().refresh();
|
state.output_map.borrow_mut().refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
state.backend_data.fps.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup stuff
|
// Cleanup stuff
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
//! the lifetime of the buffer. E.g. when you are only caching associated resources for a dmabuf.
|
//! the lifetime of the buffer. E.g. when you are only caching associated resources for a dmabuf.
|
||||||
|
|
||||||
use super::{Buffer, Format, Fourcc, Modifier};
|
use super::{Buffer, Format, Fourcc, Modifier};
|
||||||
|
use crate::utils::{Buffer as BufferCoords, Size};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::os::unix::io::{IntoRawFd, RawFd};
|
use std::os::unix::io::{IntoRawFd, RawFd};
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
@ -22,10 +23,8 @@ pub const MAX_PLANES: usize = 4;
|
||||||
pub(crate) struct DmabufInternal {
|
pub(crate) struct DmabufInternal {
|
||||||
/// The submitted planes
|
/// The submitted planes
|
||||||
pub planes: Vec<Plane>,
|
pub planes: Vec<Plane>,
|
||||||
/// The width of this buffer
|
/// The size of this buffer
|
||||||
pub width: i32,
|
pub size: Size<i32, BufferCoords>,
|
||||||
/// The height of this buffer
|
|
||||||
pub height: i32,
|
|
||||||
/// The format in use
|
/// The format in use
|
||||||
pub format: Fourcc,
|
pub format: Fourcc,
|
||||||
/// The flags applied to it
|
/// The flags applied to it
|
||||||
|
@ -107,12 +106,8 @@ impl Hash for WeakDmabuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer for Dmabuf {
|
impl Buffer for Dmabuf {
|
||||||
fn width(&self) -> u32 {
|
fn size(&self) -> Size<i32, BufferCoords> {
|
||||||
self.0.width as u32
|
self.0.size
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self) -> u32 {
|
|
||||||
self.0.height as u32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format(&self) -> Format {
|
fn format(&self) -> Format {
|
||||||
|
@ -172,8 +167,7 @@ impl Dmabuf {
|
||||||
DmabufBuilder {
|
DmabufBuilder {
|
||||||
internal: DmabufInternal {
|
internal: DmabufInternal {
|
||||||
planes: Vec::with_capacity(MAX_PLANES),
|
planes: Vec::with_capacity(MAX_PLANES),
|
||||||
width: src.width() as i32,
|
size: src.size(),
|
||||||
height: src.height() as i32,
|
|
||||||
format: src.format().code,
|
format: src.format().code,
|
||||||
flags,
|
flags,
|
||||||
},
|
},
|
||||||
|
@ -181,12 +175,15 @@ impl Dmabuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Dmabuf builder
|
/// Create a new Dmabuf builder
|
||||||
pub fn builder(width: u32, height: u32, format: Fourcc, flags: DmabufFlags) -> DmabufBuilder {
|
pub fn builder(
|
||||||
|
size: impl Into<Size<i32, BufferCoords>>,
|
||||||
|
format: Fourcc,
|
||||||
|
flags: DmabufFlags,
|
||||||
|
) -> DmabufBuilder {
|
||||||
DmabufBuilder {
|
DmabufBuilder {
|
||||||
internal: DmabufInternal {
|
internal: DmabufInternal {
|
||||||
planes: Vec::with_capacity(MAX_PLANES),
|
planes: Vec::with_capacity(MAX_PLANES),
|
||||||
width: width as i32,
|
size: size.into(),
|
||||||
height: height as i32,
|
|
||||||
format,
|
format,
|
||||||
flags,
|
flags,
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,6 +9,7 @@ use drm::control::{dumbbuffer::DumbBuffer as Handle, Device as ControlDevice};
|
||||||
|
|
||||||
use super::{Allocator, Buffer, Format, Fourcc, Modifier};
|
use super::{Allocator, Buffer, Format, Fourcc, Modifier};
|
||||||
use crate::backend::drm::device::{DrmDevice, DrmDeviceInternal, FdWrapper};
|
use crate::backend::drm::device::{DrmDevice, DrmDeviceInternal, FdWrapper};
|
||||||
|
use crate::utils::{Buffer as BufferCoords, Size};
|
||||||
|
|
||||||
/// Wrapper around raw DumbBuffer handles.
|
/// Wrapper around raw DumbBuffer handles.
|
||||||
pub struct DumbBuffer<A: AsRawFd + 'static> {
|
pub struct DumbBuffer<A: AsRawFd + 'static> {
|
||||||
|
@ -61,12 +62,9 @@ impl<A: AsRawFd + 'static> Allocator<DumbBuffer<A>> for DrmDevice<A> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> Buffer for DumbBuffer<A> {
|
impl<A: AsRawFd + 'static> Buffer for DumbBuffer<A> {
|
||||||
fn width(&self) -> u32 {
|
fn size(&self) -> Size<i32, BufferCoords> {
|
||||||
self.handle.size().0
|
let (w, h) = self.handle.size();
|
||||||
}
|
(w as i32, h as i32).into()
|
||||||
|
|
||||||
fn height(&self) -> u32 {
|
|
||||||
self.handle.size().1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format(&self) -> Format {
|
fn format(&self) -> Format {
|
||||||
|
|
|
@ -8,6 +8,7 @@ use super::{
|
||||||
dmabuf::{AsDmabuf, Dmabuf, DmabufFlags, MAX_PLANES},
|
dmabuf::{AsDmabuf, Dmabuf, DmabufFlags, MAX_PLANES},
|
||||||
Allocator, Buffer, Format, Fourcc, Modifier,
|
Allocator, Buffer, Format, Fourcc, Modifier,
|
||||||
};
|
};
|
||||||
|
use crate::utils::{Buffer as BufferCoords, Size};
|
||||||
pub use gbm::{BufferObject as GbmBuffer, BufferObjectFlags as GbmBufferFlags, Device as GbmDevice};
|
pub use gbm::{BufferObject as GbmBuffer, BufferObjectFlags as GbmBufferFlags, Device as GbmDevice};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
|
@ -39,12 +40,12 @@ impl<A: AsRawFd + 'static, T> Allocator<GbmBuffer<T>> for GbmDevice<A> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Buffer for GbmBuffer<T> {
|
impl<T> Buffer for GbmBuffer<T> {
|
||||||
fn width(&self) -> u32 {
|
fn size(&self) -> Size<i32, BufferCoords> {
|
||||||
self.width().unwrap_or(0)
|
(
|
||||||
}
|
self.width().unwrap_or(0) as i32,
|
||||||
|
self.height().unwrap_or(0) as i32,
|
||||||
fn height(&self) -> u32 {
|
)
|
||||||
self.height().unwrap_or(0)
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format(&self) -> Format {
|
fn format(&self) -> Format {
|
||||||
|
|
|
@ -22,6 +22,7 @@ pub mod dumb;
|
||||||
pub mod gbm;
|
pub mod gbm;
|
||||||
|
|
||||||
mod swapchain;
|
mod swapchain;
|
||||||
|
use crate::utils::{Buffer as BufferCoords, Size};
|
||||||
pub use swapchain::{Slot, Swapchain};
|
pub use swapchain::{Slot, Swapchain};
|
||||||
|
|
||||||
pub use drm_fourcc::{
|
pub use drm_fourcc::{
|
||||||
|
@ -32,13 +33,15 @@ pub use drm_fourcc::{
|
||||||
/// Common trait describing common properties of most types of buffers.
|
/// Common trait describing common properties of most types of buffers.
|
||||||
pub trait Buffer {
|
pub trait Buffer {
|
||||||
/// Width of the two-dimensional buffer
|
/// Width of the two-dimensional buffer
|
||||||
fn width(&self) -> u32;
|
fn width(&self) -> u32 {
|
||||||
/// Height of the two-dimensional buffer
|
self.size().w as u32
|
||||||
fn height(&self) -> u32;
|
|
||||||
/// Size (w x h) of the two-dimensional buffer
|
|
||||||
fn size(&self) -> (u32, u32) {
|
|
||||||
(self.width(), self.height())
|
|
||||||
}
|
}
|
||||||
|
/// Height of the two-dimensional buffer
|
||||||
|
fn height(&self) -> u32 {
|
||||||
|
self.size().h as u32
|
||||||
|
}
|
||||||
|
/// Size of the two-dimensional buffer
|
||||||
|
fn size(&self) -> Size<i32, BufferCoords>;
|
||||||
/// Pixel format of the buffer
|
/// Pixel format of the buffer
|
||||||
fn format(&self) -> Format;
|
fn format(&self) -> Format;
|
||||||
}
|
}
|
||||||
|
|
|
@ -808,8 +808,7 @@ impl EGLBufferReader {
|
||||||
|
|
||||||
Ok(EGLBuffer {
|
Ok(EGLBuffer {
|
||||||
display: self.display.clone(),
|
display: self.display.clone(),
|
||||||
width: width as u32,
|
size: (width, height).into(),
|
||||||
height: height as u32,
|
|
||||||
// y_inverted is negated here because the gles2 renderer
|
// y_inverted is negated here because the gles2 renderer
|
||||||
// already inverts the buffer during rendering.
|
// already inverts the buffer during rendering.
|
||||||
y_inverted: !y_inverted,
|
y_inverted: !y_inverted,
|
||||||
|
|
|
@ -32,6 +32,8 @@ pub use self::context::EGLContext;
|
||||||
mod error;
|
mod error;
|
||||||
pub use self::error::*;
|
pub use self::error::*;
|
||||||
use crate::backend::SwapBuffersError as GraphicsSwapBuffersError;
|
use crate::backend::SwapBuffersError as GraphicsSwapBuffersError;
|
||||||
|
#[cfg(feature = "wayland_frontend")]
|
||||||
|
use crate::utils::{Buffer, Size};
|
||||||
|
|
||||||
use nix::libc::c_void;
|
use nix::libc::c_void;
|
||||||
|
|
||||||
|
@ -248,10 +250,8 @@ impl Format {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EGLBuffer {
|
pub struct EGLBuffer {
|
||||||
display: Arc<EGLDisplayHandle>,
|
display: Arc<EGLDisplayHandle>,
|
||||||
/// Width in pixels
|
/// Size of the buffer
|
||||||
pub width: u32,
|
pub size: Size<i32, Buffer>,
|
||||||
/// Height in pixels
|
|
||||||
pub height: u32,
|
|
||||||
/// If the y-axis is inverted or not
|
/// If the y-axis is inverted or not
|
||||||
pub y_inverted: bool,
|
pub y_inverted: bool,
|
||||||
/// Format of these images
|
/// Format of these images
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -34,7 +34,6 @@ use super::ImportEgl;
|
||||||
use super::{ImportDma, ImportShm};
|
use super::{ImportDma, ImportShm};
|
||||||
#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
|
#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
|
||||||
use crate::backend::egl::{display::EGLBufferReader, Format as EGLFormat};
|
use crate::backend::egl::{display::EGLBufferReader, Format as EGLFormat};
|
||||||
#[cfg(feature = "wayland_frontend")]
|
|
||||||
use crate::utils::{Buffer, Rectangle};
|
use crate::utils::{Buffer, Rectangle};
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use wayland_server::protocol::{wl_buffer, wl_shm};
|
use wayland_server::protocol::{wl_buffer, wl_shm};
|
||||||
|
@ -67,14 +66,42 @@ struct Gles2Program {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Gles2Texture(Rc<Gles2TextureInternal>);
|
pub struct Gles2Texture(Rc<Gles2TextureInternal>);
|
||||||
|
|
||||||
|
impl Gles2Texture {
|
||||||
|
/// Create a Gles2Texture from a raw gl texture id.
|
||||||
|
///
|
||||||
|
/// This expects the texture to be in RGBA format to be rendered
|
||||||
|
/// correctly by the `render_texture*`-functions of [`Frame`](super::Frame).
|
||||||
|
/// It is also expected to not be external or y_inverted.
|
||||||
|
///
|
||||||
|
/// 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.
|
||||||
|
pub unsafe fn from_raw(
|
||||||
|
renderer: &Gles2Renderer,
|
||||||
|
tex: ffi::types::GLuint,
|
||||||
|
size: Size<i32, Buffer>,
|
||||||
|
) -> Gles2Texture {
|
||||||
|
Gles2Texture(Rc::new(Gles2TextureInternal {
|
||||||
|
texture: tex,
|
||||||
|
texture_kind: 0,
|
||||||
|
is_external: false,
|
||||||
|
y_inverted: false,
|
||||||
|
size,
|
||||||
|
egl_images: None,
|
||||||
|
destruction_callback_sender: renderer.destruction_callback_sender.clone(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Gles2TextureInternal {
|
struct Gles2TextureInternal {
|
||||||
texture: ffi::types::GLuint,
|
texture: ffi::types::GLuint,
|
||||||
texture_kind: usize,
|
texture_kind: usize,
|
||||||
is_external: bool,
|
is_external: bool,
|
||||||
y_inverted: bool,
|
y_inverted: bool,
|
||||||
width: u32,
|
size: Size<i32, Buffer>,
|
||||||
height: u32,
|
|
||||||
egl_images: Option<Vec<EGLImage>>,
|
egl_images: Option<Vec<EGLImage>>,
|
||||||
destruction_callback_sender: Sender<CleanupResource>,
|
destruction_callback_sender: Sender<CleanupResource>,
|
||||||
}
|
}
|
||||||
|
@ -101,10 +128,13 @@ enum CleanupResource {
|
||||||
|
|
||||||
impl Texture for Gles2Texture {
|
impl Texture for Gles2Texture {
|
||||||
fn width(&self) -> u32 {
|
fn width(&self) -> u32 {
|
||||||
self.0.width
|
self.0.size.w as u32
|
||||||
}
|
}
|
||||||
fn height(&self) -> u32 {
|
fn height(&self) -> u32 {
|
||||||
self.0.height
|
self.0.size.h as u32
|
||||||
|
}
|
||||||
|
fn size(&self) -> Size<i32, Buffer> {
|
||||||
|
self.0.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,8 +589,7 @@ impl ImportShm for Gles2Renderer {
|
||||||
texture_kind: shader_idx,
|
texture_kind: shader_idx,
|
||||||
is_external: false,
|
is_external: false,
|
||||||
y_inverted: false,
|
y_inverted: false,
|
||||||
width: width as u32,
|
size: (width, height).into(),
|
||||||
height: height as u32,
|
|
||||||
egl_images: None,
|
egl_images: None,
|
||||||
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
||||||
})
|
})
|
||||||
|
@ -689,8 +718,7 @@ impl ImportEgl for Gles2Renderer {
|
||||||
},
|
},
|
||||||
is_external: egl.format == EGLFormat::External,
|
is_external: egl.format == EGLFormat::External,
|
||||||
y_inverted: egl.y_inverted,
|
y_inverted: egl.y_inverted,
|
||||||
width: egl.width,
|
size: egl.size,
|
||||||
height: egl.height,
|
|
||||||
egl_images: Some(egl.into_images()),
|
egl_images: Some(egl.into_images()),
|
||||||
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
||||||
}));
|
}));
|
||||||
|
@ -723,8 +751,7 @@ impl ImportDma for Gles2Renderer {
|
||||||
texture_kind: if is_external { 2 } else { 0 },
|
texture_kind: if is_external { 2 } else { 0 },
|
||||||
is_external,
|
is_external,
|
||||||
y_inverted: buffer.y_inverted(),
|
y_inverted: buffer.y_inverted(),
|
||||||
width: buffer.width(),
|
size: buffer.size(),
|
||||||
height: buffer.height(),
|
|
||||||
egl_images: Some(vec![image]),
|
egl_images: Some(vec![image]),
|
||||||
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
||||||
}));
|
}));
|
||||||
|
@ -950,69 +977,28 @@ impl Drop for Gles2Renderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static VERTS: [ffi::types::GLfloat; 8] = [
|
impl Gles2Renderer {
|
||||||
1.0, 0.0, // top right
|
/// Run custom code in the GL context owned by this renderer.
|
||||||
0.0, 0.0, // top left
|
///
|
||||||
1.0, 1.0, // bottom right
|
/// *Note*: Any changes to the GL state should be restored at the end of this function.
|
||||||
0.0, 1.0, // bottom left
|
/// 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.
|
||||||
static TEX_COORDS: [ffi::types::GLfloat; 8] = [
|
pub fn with_context<F, R>(&mut self, func: F) -> Result<R, Gles2Error>
|
||||||
1.0, 0.0, // top right
|
where
|
||||||
0.0, 0.0, // top left
|
F: FnOnce(&mut Self, &ffi::Gles2) -> R,
|
||||||
1.0, 1.0, // bottom right
|
{
|
||||||
0.0, 1.0, // bottom left
|
self.make_current()?;
|
||||||
];
|
let gl = self.gl.clone();
|
||||||
|
Ok(func(self, &gl))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Renderer for Gles2Renderer {
|
impl Renderer for Gles2Renderer {
|
||||||
type Error = Gles2Error;
|
type Error = Gles2Error;
|
||||||
type TextureId = Gles2Texture;
|
type TextureId = Gles2Texture;
|
||||||
type Frame = Gles2Frame;
|
type Frame = Gles2Frame;
|
||||||
|
|
||||||
#[cfg(feature = "image")]
|
|
||||||
fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
|
|
||||||
&mut self,
|
|
||||||
image: &image::ImageBuffer<image::Rgba<u8>, C>,
|
|
||||||
) -> Result<Self::TextureId, Self::Error> {
|
|
||||||
self.make_current()?;
|
|
||||||
|
|
||||||
let mut tex = 0;
|
|
||||||
unsafe {
|
|
||||||
self.gl.GenTextures(1, &mut tex);
|
|
||||||
self.gl.BindTexture(ffi::TEXTURE_2D, tex);
|
|
||||||
self.gl
|
|
||||||
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
|
|
||||||
self.gl
|
|
||||||
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
|
||||||
self.gl.TexImage2D(
|
|
||||||
ffi::TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
ffi::RGBA as i32,
|
|
||||||
image.width() as i32,
|
|
||||||
image.height() as i32,
|
|
||||||
0,
|
|
||||||
ffi::RGBA,
|
|
||||||
ffi::UNSIGNED_BYTE as u32,
|
|
||||||
image.as_ptr() as *const _,
|
|
||||||
);
|
|
||||||
self.gl.BindTexture(ffi::TEXTURE_2D, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let texture = Gles2Texture(Rc::new(Gles2TextureInternal {
|
|
||||||
texture: tex,
|
|
||||||
texture_kind: 0,
|
|
||||||
is_external: false,
|
|
||||||
y_inverted: false,
|
|
||||||
width: image.width(),
|
|
||||||
height: image.height(),
|
|
||||||
egl_images: None,
|
|
||||||
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
|
||||||
}));
|
|
||||||
self.egl.unbind()?;
|
|
||||||
|
|
||||||
Ok(texture)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render<F, R>(
|
fn render<F, R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
size: Size<i32, Physical>,
|
size: Size<i32, Physical>,
|
||||||
|
@ -1029,6 +1015,9 @@ impl Renderer for Gles2Renderer {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.Viewport(0, 0, size.w, size.h);
|
self.gl.Viewport(0, 0, size.w, size.h);
|
||||||
|
|
||||||
|
self.gl.Scissor(0, 0, size.w, size.h);
|
||||||
|
self.gl.Enable(ffi::SCISSOR_TEST);
|
||||||
|
|
||||||
self.gl.Enable(ffi::BLEND);
|
self.gl.Enable(ffi::BLEND);
|
||||||
self.gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA);
|
self.gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA);
|
||||||
}
|
}
|
||||||
|
@ -1083,6 +1072,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;
|
||||||
|
@ -1100,6 +1096,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
|
||||||
|
@ -1148,7 +1145,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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,20 +254,6 @@ pub trait Renderer {
|
||||||
/// Type representing a currently in-progress frame during the [`Renderer::render`]-call
|
/// Type representing a currently in-progress frame during the [`Renderer::render`]-call
|
||||||
type Frame: Frame<Error = Self::Error, TextureId = Self::TextureId>;
|
type Frame: Frame<Error = Self::Error, TextureId = Self::TextureId>;
|
||||||
|
|
||||||
/// Import a given bitmap into the renderer.
|
|
||||||
///
|
|
||||||
/// Returns a texture_id, which can be used with `render_texture(_at)` or implementation-specific functions.
|
|
||||||
///
|
|
||||||
/// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it,
|
|
||||||
/// and needs to be freed by calling `destroy_texture` on this renderer to avoid a resource leak.
|
|
||||||
///
|
|
||||||
/// This operation needs no bound or default rendering target.
|
|
||||||
#[cfg(feature = "image")]
|
|
||||||
fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
|
|
||||||
&mut self,
|
|
||||||
image: &image::ImageBuffer<image::Rgba<u8>, C>,
|
|
||||||
) -> Result<Self::TextureId, Self::Error>;
|
|
||||||
|
|
||||||
/// Initialize a rendering context on the current rendering target with given dimensions and transformation.
|
/// Initialize a rendering context on the current rendering target with given dimensions and transformation.
|
||||||
///
|
///
|
||||||
/// This function *may* error, if:
|
/// This function *may* error, if:
|
||||||
|
|
|
@ -260,12 +260,7 @@ where
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = Dmabuf::builder(
|
let mut buf = Dmabuf::builder((width, height), format, DmabufFlags::from_bits_truncate(flags));
|
||||||
width as u32,
|
|
||||||
height as u32,
|
|
||||||
format,
|
|
||||||
DmabufFlags::from_bits_truncate(flags),
|
|
||||||
);
|
|
||||||
let planes = std::mem::take(&mut self.pending_planes);
|
let planes = std::mem::take(&mut self.pending_planes);
|
||||||
for (i, plane) in planes.into_iter().enumerate() {
|
for (i, plane) in planes.into_iter().enumerate() {
|
||||||
let offset = plane.offset;
|
let offset = plane.offset;
|
||||||
|
@ -350,12 +345,7 @@ where
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = Dmabuf::builder(
|
let mut buf = Dmabuf::builder((width, height), format, DmabufFlags::from_bits_truncate(flags));
|
||||||
width as u32,
|
|
||||||
height as u32,
|
|
||||||
format,
|
|
||||||
DmabufFlags::from_bits_truncate(flags),
|
|
||||||
);
|
|
||||||
let planes = ::std::mem::take(&mut self.pending_planes);
|
let planes = ::std::mem::take(&mut self.pending_planes);
|
||||||
for (i, plane) in planes.into_iter().enumerate() {
|
for (i, plane) in planes.into_iter().enumerate() {
|
||||||
let offset = plane.offset;
|
let offset = plane.offset;
|
||||||
|
|
Loading…
Reference in New Issue