Main structure of WLCS integration.

This commit is contained in:
Victor Berger 2021-07-08 17:15:54 +02:00 committed by Victor Berger
parent 56c3f53575
commit bdb257474d
10 changed files with 796 additions and 12 deletions

View File

@ -8,7 +8,7 @@ repository = "https://github.com/Smithay/smithay"
edition = "2018"
[workspace]
members = [ "anvil" ]
members = [ "anvil", "wlcs_anvil" ]
[dependencies]
appendlist = "1.4"

View File

@ -29,7 +29,7 @@ use crate::shell::init_shell;
pub struct AnvilState<BackendData> {
pub backend_data: BackendData,
pub socket_name: String,
pub socket_name: Option<String>,
pub running: Arc<AtomicBool>,
pub display: Rc<RefCell<Display>>,
pub handle: LoopHandle<'static, AnvilState<BackendData>>,
@ -57,6 +57,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
handle: LoopHandle<'static, AnvilState<BackendData>>,
backend_data: BackendData,
log: slog::Logger,
listen_on_socket: bool,
) -> AnvilState<BackendData> {
// init the wayland connection
handle
@ -85,6 +86,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
init_xdg_output_manager(&mut display.borrow_mut(), log.clone());
let socket_name = if listen_on_socket {
let socket_name = display
.borrow_mut()
.add_socket_auto()
@ -93,6 +95,10 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
.unwrap();
info!(log, "Listening on wayland socket"; "name" => socket_name.clone());
::std::env::set_var("WAYLAND_DISPLAY", &socket_name);
Some(socket_name)
} else {
None
};
// init data device

View File

@ -142,7 +142,7 @@ pub fn run_udev(log: Logger) {
pointer_image: crate::cursor::Cursor::load(&log),
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(), true);
// re-render timer
event_loop

View File

@ -94,7 +94,7 @@ pub fn run_winit(log: Logger) {
#[cfg(feature = "debug")]
fps: fps_ticker::Fps::default(),
};
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(), true);
let mode = Mode {
size,

20
wlcs_anvil/Cargo.toml Normal file
View File

@ -0,0 +1,20 @@
[package]
name = "wlcs_anvil"
version = "0.0.1"
authors = ["Victor Berger <victor.berger@m4x.org>", "Drakulix (Victor Brekenfeld)"]
license = "MIT"
publish = false
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
smithay = { path = "..", default-features=false, features=["wayland_frontend"] }
anvil = { path = "../anvil", default-features=false }
wayland-sys = { version = "0.28.6", features=["client"] }
libc = "0.2"
memoffset = "0.6"
slog = "2.0"
cgmath = "0.18"
nix = "0.20"

71
wlcs_anvil/src/ffi_api.rs Normal file
View File

@ -0,0 +1,71 @@
use std::os::raw::{c_char, c_int};
use smithay::reexports::wayland_server::sys::server as ssys;
use wayland_sys::{client::*, common::wl_fixed_t};
#[repr(C)]
pub struct WlcsExtensionDescriptor {
pub name: *const c_char,
pub version: u32,
}
unsafe impl Sync for WlcsExtensionDescriptor {}
unsafe impl Send for WlcsExtensionDescriptor {}
#[repr(C)]
pub struct WlcsIntegrationDescriptor {
pub version: u32,
pub num_extensions: usize,
pub supported_extensions: *const WlcsExtensionDescriptor,
}
unsafe impl Sync for WlcsIntegrationDescriptor {}
unsafe impl Send for WlcsIntegrationDescriptor {}
#[repr(C)]
pub struct WlcsDisplayServer {
pub version: u32,
pub start: unsafe extern "C" fn(*mut WlcsDisplayServer),
pub stop: unsafe extern "C" fn(*mut WlcsDisplayServer),
pub create_client_socket: unsafe extern "C" fn(*mut WlcsDisplayServer) -> c_int,
pub position_window_absolute:
unsafe extern "C" fn(*mut WlcsDisplayServer, *mut wl_display, *mut wl_proxy, c_int, c_int),
pub create_pointer: unsafe extern "C" fn(*mut WlcsDisplayServer) -> *mut WlcsPointer,
pub create_touch: unsafe extern "C" fn(*mut WlcsDisplayServer) -> *mut WlcsTouch,
pub get_descriptor: unsafe extern "C" fn(*const WlcsDisplayServer) -> *const WlcsIntegrationDescriptor,
pub start_on_this_thread: Option<unsafe extern "C" fn(*mut WlcsDisplayServer, *mut ssys::wl_event_loop)>,
}
#[repr(C)]
pub struct WlcsServerIntegration {
pub version: u32,
pub create_server: unsafe extern "C" fn(c_int, *mut *const c_char) -> *mut WlcsDisplayServer,
pub destroy_server: unsafe extern "C" fn(*mut WlcsDisplayServer),
}
/*
* WlcsPointer
*/
#[repr(C)]
pub struct WlcsPointer {
pub version: u32,
pub move_absolute: unsafe extern "C" fn(*mut WlcsPointer, wl_fixed_t, wl_fixed_t),
pub move_relative: unsafe extern "C" fn(*mut WlcsPointer, wl_fixed_t, wl_fixed_t),
pub button_up: unsafe extern "C" fn(*mut WlcsPointer, c_int),
pub button_down: unsafe extern "C" fn(*mut WlcsPointer, c_int),
pub destroy: unsafe extern "C" fn(*mut WlcsPointer),
}
/*
* WlcsTouch
*/
#[repr(C)]
pub struct WlcsTouch {
pub version: u32,
pub touch_down: unsafe extern "C" fn(*mut WlcsTouch, wl_fixed_t, wl_fixed_t),
pub touch_move: unsafe extern "C" fn(*mut WlcsTouch, wl_fixed_t, wl_fixed_t),
pub touch_up: unsafe extern "C" fn(*mut WlcsTouch),
pub destroy: unsafe extern "C" fn(*mut WlcsTouch),
}

View File

@ -0,0 +1,261 @@
use std::{
os::{
raw::{c_char, c_int},
unix::{
net::UnixStream,
prelude::{AsRawFd, IntoRawFd},
},
},
thread::JoinHandle,
};
use smithay::reexports::calloop::channel::{channel, Sender};
use wayland_sys::{
client::*,
common::{wl_fixed_t, wl_fixed_to_double},
ffi_dispatch,
};
use crate::{ffi_api::*, WlcsEvent};
macro_rules! container_of(
($ptr: expr, $container: ident, $field: ident) => {
($ptr as *mut u8).offset(-(memoffset::offset_of!($container, $field) as isize)) as *mut $container
}
);
#[no_mangle]
pub static wlcs_server_integration: WlcsServerIntegration = WlcsServerIntegration {
version: 1,
create_server,
destroy_server,
};
unsafe extern "C" fn create_server(_argc: c_int, _argv: *mut *const c_char) -> *mut WlcsDisplayServer {
// block the SIGPIPE signal here, we are a cdylib so Rust does not do it for us
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal};
sigaction(
Signal::SIGPIPE,
&SigAction::new(SigHandler::SigIgn, SaFlags::empty(), SigSet::empty()),
)
.unwrap();
let handle = Box::into_raw(Box::new(DisplayServerHandle::new()));
&mut (*handle).wlcs_display_server
}
unsafe extern "C" fn destroy_server(ptr: *mut WlcsDisplayServer) {
let _server = Box::from_raw(container_of!(ptr, DisplayServerHandle, wlcs_display_server));
}
struct DisplayServerHandle {
wlcs_display_server: WlcsDisplayServer,
server: Option<(Sender<WlcsEvent>, JoinHandle<()>)>,
next_device_id: u32,
}
impl DisplayServerHandle {
fn new() -> DisplayServerHandle {
DisplayServerHandle {
wlcs_display_server: WlcsDisplayServer {
version: 3,
start: Self::start,
stop: Self::stop,
create_client_socket: Self::create_client_socket,
position_window_absolute: Self::position_window_absolute,
create_pointer: Self::create_pointer,
create_touch: Self::create_touch,
get_descriptor: Self::get_descriptor,
start_on_this_thread: None,
},
server: None,
next_device_id: 1,
}
}
unsafe extern "C" fn start(ptr: *mut WlcsDisplayServer) {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
let (tx, rx) = channel();
let join = crate::start_anvil(rx);
me.server = Some((tx, join));
}
unsafe extern "C" fn stop(ptr: *mut WlcsDisplayServer) {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
if let Some((sender, join)) = me.server.take() {
let _ = sender.send(WlcsEvent::Exit);
let _ = join.join();
}
}
unsafe extern "C" fn create_client_socket(ptr: *mut WlcsDisplayServer) -> c_int {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
if let Some((ref sender, _)) = me.server {
if let Ok((client_side, server_side)) = UnixStream::pair() {
if sender
.send(WlcsEvent::NewClient {
stream: server_side,
client_id: client_side.as_raw_fd(),
})
.is_err()
{
return -1;
}
return client_side.into_raw_fd();
}
}
-1
}
unsafe extern "C" fn position_window_absolute(
ptr: *mut WlcsDisplayServer,
display: *mut wl_display,
surface: *mut wl_proxy,
x: c_int,
y: c_int,
) {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
let client_id = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_get_fd, display);
let surface_id = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_id, surface);
if let Some((ref sender, _)) = me.server {
let _ = sender.send(WlcsEvent::PositionWindow {
client_id,
surface_id,
location: (x, y),
});
}
}
unsafe extern "C" fn create_pointer(ptr: *mut WlcsDisplayServer) -> *mut WlcsPointer {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
if let Some((ref sender, _)) = me.server {
let pointer = Box::into_raw(Box::new(PointerHandle::new(me.next_device_id, sender.clone())));
me.next_device_id += 1;
&mut (*pointer).wlcs_pointer
} else {
std::ptr::null_mut()
}
}
unsafe extern "C" fn create_touch(ptr: *mut WlcsDisplayServer) -> *mut WlcsTouch {
let me = &mut *container_of!(ptr, DisplayServerHandle, wlcs_display_server);
if let Some((ref sender, _)) = me.server {
let pointer = Box::into_raw(Box::new(TouchHandle::new(me.next_device_id, sender.clone())));
me.next_device_id += 1;
&mut (*pointer).wlcs_touch
} else {
std::ptr::null_mut()
}
}
unsafe extern "C" fn get_descriptor(_: *const WlcsDisplayServer) -> *const WlcsIntegrationDescriptor {
&crate::DESCRIPTOR
}
}
struct PointerHandle {
wlcs_pointer: WlcsPointer,
device_id: u32,
sender: Sender<WlcsEvent>,
}
impl PointerHandle {
fn new(device_id: u32, sender: Sender<WlcsEvent>) -> PointerHandle {
PointerHandle {
wlcs_pointer: WlcsPointer {
version: 1,
move_absolute: Self::move_absolute,
move_relative: Self::move_relative,
button_down: Self::button_down,
button_up: Self::button_up,
destroy: Self::destroy,
},
device_id,
sender,
}
}
unsafe extern "C" fn move_absolute(ptr: *mut WlcsPointer, x: wl_fixed_t, y: wl_fixed_t) {
let me = &mut *container_of!(ptr, PointerHandle, wlcs_pointer);
let _ = me.sender.send(WlcsEvent::PointerMoveAbsolute {
device_id: me.device_id,
location: (wl_fixed_to_double(x), wl_fixed_to_double(y)),
});
}
unsafe extern "C" fn move_relative(ptr: *mut WlcsPointer, x: wl_fixed_t, y: wl_fixed_t) {
let me = &mut *container_of!(ptr, PointerHandle, wlcs_pointer);
let _ = me.sender.send(WlcsEvent::PointerMoveRelative {
device_id: me.device_id,
delta: (wl_fixed_to_double(x), wl_fixed_to_double(y)),
});
}
unsafe extern "C" fn button_up(ptr: *mut WlcsPointer, button_id: i32) {
let me = &mut *container_of!(ptr, PointerHandle, wlcs_pointer);
let _ = me.sender.send(WlcsEvent::PointerButtonUp {
device_id: me.device_id,
button_id,
});
}
unsafe extern "C" fn button_down(ptr: *mut WlcsPointer, button_id: i32) {
let me = &mut *container_of!(ptr, PointerHandle, wlcs_pointer);
let _ = me.sender.send(WlcsEvent::PointerButtonDown {
device_id: me.device_id,
button_id,
});
}
unsafe extern "C" fn destroy(ptr: *mut WlcsPointer) {
let _me = Box::from_raw(container_of!(ptr, PointerHandle, wlcs_pointer));
}
}
struct TouchHandle {
wlcs_touch: WlcsTouch,
device_id: u32,
sender: Sender<WlcsEvent>,
}
impl TouchHandle {
fn new(device_id: u32, sender: Sender<WlcsEvent>) -> TouchHandle {
TouchHandle {
wlcs_touch: WlcsTouch {
version: 1,
touch_down: Self::touch_down,
touch_move: Self::touch_move,
touch_up: Self::touch_up,
destroy: Self::destroy,
},
device_id,
sender,
}
}
unsafe extern "C" fn touch_down(ptr: *mut WlcsTouch, x: wl_fixed_t, y: wl_fixed_t) {
let me = &mut *container_of!(ptr, TouchHandle, wlcs_touch);
let _ = me.sender.send(WlcsEvent::TouchDown {
device_id: me.device_id,
location: (wl_fixed_to_double(x), wl_fixed_to_double(y)),
});
}
unsafe extern "C" fn touch_move(ptr: *mut WlcsTouch, x: wl_fixed_t, y: wl_fixed_t) {
let me = &mut *container_of!(ptr, TouchHandle, wlcs_touch);
let _ = me.sender.send(WlcsEvent::TouchMove {
device_id: me.device_id,
location: (wl_fixed_to_double(x), wl_fixed_to_double(y)),
});
}
unsafe extern "C" fn touch_up(ptr: *mut WlcsTouch) {
let me = &mut *container_of!(ptr, TouchHandle, wlcs_touch);
let _ = me.sender.send(WlcsEvent::TouchUp {
device_id: me.device_id,
});
}
unsafe extern "C" fn destroy(ptr: *mut WlcsTouch) {
let _me = Box::from_raw(container_of!(ptr, TouchHandle, wlcs_touch));
}
}

110
wlcs_anvil/src/lib.rs Normal file
View File

@ -0,0 +1,110 @@
mod ffi_api;
mod ffi_wrappers;
mod main_loop;
mod renderer;
use std::{os::unix::net::UnixStream, thread::JoinHandle};
use smithay::reexports::calloop;
use ffi_api::{WlcsExtensionDescriptor, WlcsIntegrationDescriptor};
macro_rules! extension_list {
($(($name: expr, $version: expr)),* $(,)?) => {
&[$(
WlcsExtensionDescriptor {
name: concat!($name, "\0").as_ptr() as *const std::os::raw::c_char,
version: $version
}
),*]
};
}
static SUPPORTED_EXTENSIONS: &[WlcsExtensionDescriptor] = extension_list!(
("wl_compositor", 4),
("wl_subcompositor", 1),
("wl_data_device_manager", 3),
("wl_shell", 1),
("wl_seat", 5),
("wl_output", 3),
("xdg_wm_base", 1),
);
static DESCRIPTOR: WlcsIntegrationDescriptor = WlcsIntegrationDescriptor {
version: 1,
num_extensions: SUPPORTED_EXTENSIONS.len(),
supported_extensions: SUPPORTED_EXTENSIONS.as_ptr(),
};
/// Event sent by WLCS to control the compositor
#[derive(Debug)]
pub enum WlcsEvent {
/// Stop the running server
Exit,
/// Create a new client from given RawFd
NewClient {
stream: UnixStream,
client_id: i32,
},
/// Position this window from the client associated with this Fd on the global space
PositionWindow {
client_id: i32,
surface_id: u32,
location: (i32, i32),
},
/* Pointer related events */
/// A new pointer device is available
NewPointer {
device_id: u32,
},
/// Move the pointer in absolute coordinate space
PointerMoveAbsolute {
device_id: u32,
location: (f64, f64),
},
/// Move the pointer in relative coordinate space
PointerMoveRelative {
device_id: u32,
delta: (f64, f64),
},
/// Press a pointer button
PointerButtonDown {
device_id: u32,
button_id: i32,
},
/// Release a pointer button
PointerButtonUp {
device_id: u32,
button_id: i32,
},
/// A pointer device is removed
PointerRemoved {
device_id: u32,
},
/* Touch related events */
/// A new touch device is available
NewTouch {
device_id: u32,
},
/// A touch point is down
TouchDown {
device_id: u32,
location: (f64, f64),
},
/// A touch point moved
TouchMove {
device_id: u32,
location: (f64, f64),
},
/// A touch point is up
TouchUp {
device_id: u32,
},
TouchRemoved {
device_id: u32,
},
}
fn start_anvil(channel: calloop::channel::Channel<WlcsEvent>) -> JoinHandle<()> {
std::thread::spawn(move || main_loop::run(channel))
}

195
wlcs_anvil/src/main_loop.rs Normal file
View File

@ -0,0 +1,195 @@
use std::{
cell::RefCell, collections::HashMap, os::unix::prelude::IntoRawFd, rc::Rc, sync::atomic::Ordering,
time::Duration,
};
use smithay::{
backend::{
renderer::{Frame, Renderer, Transform},
SwapBuffersError,
},
reexports::{
calloop::{
channel::{Channel, Event as ChannelEvent},
EventLoop,
},
wayland_server::{protocol::wl_output, Client, Display},
},
wayland::{
output::{Mode, PhysicalProperties},
seat::CursorImageStatus,
},
};
use anvil::{
drawing::{draw_cursor, draw_dnd_icon, draw_windows},
state::Backend,
AnvilState,
};
use crate::WlcsEvent;
pub const OUTPUT_NAME: &str = "anvil";
struct TestState {
clients: HashMap<i32, Client>,
}
impl Backend for TestState {
fn seat_name(&self) -> String {
"anvil_wlcs".into()
}
}
pub fn run(channel: Channel<WlcsEvent>) {
let mut event_loop =
EventLoop::<AnvilState<TestState>>::try_new().expect("Failed to init the event loop.");
let display = Rc::new(RefCell::new(Display::new()));
let logger = slog::Logger::root(slog::Discard, slog::o!());
let test_state = TestState {
clients: HashMap::new(),
};
let mut state = AnvilState::init(
display.clone(),
event_loop.handle(),
test_state,
logger.clone(),
false,
);
event_loop
.handle()
.insert_source(channel, move |event, &mut (), state| match event {
ChannelEvent::Msg(evt) => handle_event(evt, state),
ChannelEvent::Closed => handle_event(WlcsEvent::Exit, state),
})
.unwrap();
let mut renderer = crate::renderer::DummyRenderer::new();
let mode = Mode {
size: (800, 600).into(),
refresh: 60_000,
};
state.output_map.borrow_mut().add(
OUTPUT_NAME,
PhysicalProperties {
size: (0, 0).into(),
subpixel: wl_output::Subpixel::Unknown,
make: "Smithay".into(),
model: "Winit".into(),
},
mode,
);
while state.running.load(Ordering::SeqCst) {
// pretend to draw something
{
let output_geometry = state
.output_map
.borrow()
.find_by_name(OUTPUT_NAME)
.unwrap()
.geometry();
renderer
.render((800, 600).into(), Transform::Normal, |renderer, frame| {
frame.clear([0.8, 0.8, 0.9, 1.0])?;
// draw the windows
draw_windows(
renderer,
frame,
&*state.window_map.borrow(),
output_geometry,
1.0,
&logger,
)?;
// draw the dnd icon if any
{
let guard = state.dnd_icon.lock().unwrap();
if let Some(ref surface) = *guard {
if surface.as_ref().is_alive() {
draw_dnd_icon(
renderer,
frame,
surface,
state.pointer_location.to_i32_floor(),
1.0,
&logger,
)?;
}
}
}
// 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 {
draw_cursor(
renderer,
frame,
surface,
state.pointer_location.to_i32_floor(),
1.0,
&logger,
)?;
}
}
Ok(())
})
.map_err(Into::<SwapBuffersError>::into)
.and_then(|x| x)
.unwrap();
}
// Send frame events so that client start drawing their next frame
state
.window_map
.borrow()
.send_frames(state.start_time.elapsed().as_millis() as u32);
display.borrow_mut().flush_clients(&mut state);
if event_loop
.dispatch(Some(Duration::from_millis(16)), &mut state)
.is_err()
{
state.running.store(false, Ordering::SeqCst);
} else {
display.borrow_mut().flush_clients(&mut state);
state.window_map.borrow_mut().refresh();
state.output_map.borrow_mut().refresh();
}
}
}
fn handle_event(event: WlcsEvent, state: &mut AnvilState<TestState>) {
match event {
WlcsEvent::Exit => state.running.store(false, Ordering::SeqCst),
WlcsEvent::NewClient { stream, client_id } => {
let display = state.display.clone();
let client = unsafe { display.borrow_mut().create_client(stream.into_raw_fd(), state) };
state.backend_data.clients.insert(client_id, client);
}
e => {
// TODO: handle the actual events
eprintln!("Unhandled event: {:?}", e);
}
}
}

121
wlcs_anvil/src/renderer.rs Normal file
View File

@ -0,0 +1,121 @@
use std::cell::Cell;
use cgmath::Vector2;
use smithay::{
backend::{
allocator::dmabuf::Dmabuf,
renderer::{Frame, ImportDma, ImportShm, Renderer, Texture, Transform},
SwapBuffersError,
},
reexports::wayland_server::protocol::wl_buffer,
utils::{Buffer, Physical, Rectangle, Size},
wayland::compositor::SurfaceData,
};
pub struct DummyRenderer {}
impl DummyRenderer {
pub fn new() -> DummyRenderer {
DummyRenderer {}
}
}
impl Renderer for DummyRenderer {
type Error = SwapBuffersError;
type TextureId = DummyTexture;
type Frame = DummyFrame;
fn render<F, R>(
&mut self,
_size: Size<i32, Physical>,
_transform: Transform,
rendering: F,
) -> Result<R, Self::Error>
where
F: FnOnce(&mut Self, &mut Self::Frame) -> R,
{
let mut frame = DummyFrame {};
Ok(rendering(self, &mut frame))
}
}
impl ImportShm for DummyRenderer {
fn import_shm_buffer(
&mut self,
buffer: &wl_buffer::WlBuffer,
surface: Option<&SurfaceData>,
_damage: &[Rectangle<i32, Buffer>],
) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error> {
use smithay::wayland::shm::with_buffer_contents;
let ret = with_buffer_contents(&buffer, |slice, data| {
let offset = data.offset as u32;
let width = data.width as u32;
let height = data.height as u32;
let stride = data.stride as u32;
let mut x = 0;
for h in 0..height {
for w in 0..width {
x |= slice[(offset + w + h * stride) as usize];
}
}
if let Some(data) = surface {
data.data_map.insert_if_missing(|| Cell::new(0u8));
data.data_map.get::<Cell<u8>>().unwrap().set(x);
}
(width, height)
});
match ret {
Ok((width, height)) => Ok(DummyTexture { width, height }),
Err(e) => Err(SwapBuffersError::TemporaryFailure(Box::new(e))),
}
}
}
impl ImportDma for DummyRenderer {
fn import_dmabuf(
&mut self,
_dmabuf: &Dmabuf,
) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error> {
unimplemented!()
}
}
pub struct DummyFrame {}
impl Frame for DummyFrame {
type Error = SwapBuffersError;
type TextureId = DummyTexture;
fn clear(&mut self, _color: [f32; 4]) -> Result<(), Self::Error> {
Ok(())
}
fn render_texture(
&mut self,
_texture: &Self::TextureId,
_matrix: cgmath::Matrix3<f32>,
tex_coords: [Vector2<f32>; 4],
_alpha: f32,
) -> Result<(), Self::Error> {
Ok(())
}
}
pub struct DummyTexture {
width: u32,
height: u32,
}
impl Texture for DummyTexture {
fn width(&self) -> u32 {
self.width
}
fn height(&self) -> u32 {
self.height
}
}