renderer: Remove `Frame` trait and merge into `Renderer`
Tracking of Frames, so that only one unique one can exist at a time (gles does not allow multiple frames being rendered in parallel) lead to very unfriendly lifetime-heavy code. A renderer is already *unique*, just move the code there and add an error variant to catch misuses.
This commit is contained in:
parent
66fbb3eb06
commit
2c9c150e5e
|
@ -14,17 +14,16 @@ use smithay::{
|
|||
|
||||
use crate::shell::{MyCompositorToken, MyWindowMap, SurfaceData};
|
||||
|
||||
pub fn draw_cursor<R, E, T, F>(
|
||||
|
||||
pub fn draw_cursor<R, E, T>(
|
||||
renderer: &mut R,
|
||||
frame: &mut F,
|
||||
surface: &wl_surface::WlSurface,
|
||||
(x, y): (i32, i32),
|
||||
token: MyCompositorToken,
|
||||
log: &Logger,
|
||||
)
|
||||
where
|
||||
R: Renderer<Error=E, Texture=T, Frame=F>,
|
||||
F: Frame<Error=E, Texture=T>,
|
||||
R: Renderer<Error=E, Texture=T>,
|
||||
E: std::error::Error,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -38,27 +37,25 @@ pub fn draw_cursor<R, E, T, F>(
|
|||
(0, 0)
|
||||
}
|
||||
};
|
||||
draw_surface_tree(renderer, frame, surface, (x - dx, y - dy), token, log);
|
||||
draw_surface_tree(renderer, surface, (x - dx, y - dy), token, log);
|
||||
}
|
||||
|
||||
fn draw_surface_tree<R, E, T, F>(
|
||||
fn draw_surface_tree<R, E, T>(
|
||||
renderer: &mut R,
|
||||
frame: &mut F,
|
||||
root: &wl_surface::WlSurface,
|
||||
location: (i32, i32),
|
||||
compositor_token: MyCompositorToken,
|
||||
log: &Logger,
|
||||
)
|
||||
where
|
||||
R: Renderer<Error=E, Texture=T, Frame=F>,
|
||||
F: Frame<Error=E, Texture=T>,
|
||||
R: Renderer<Error=E, Texture=T>,
|
||||
E: std::error::Error,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
compositor_token.with_surface_tree_upward(
|
||||
root,
|
||||
location,
|
||||
|_surface, attributes, role, &(mut x, mut y)| {
|
||||
(),
|
||||
|_surface, attributes, role, _| {
|
||||
// Pull a new buffer if available
|
||||
if let Some(data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
|
||||
let mut data = data.borrow_mut();
|
||||
|
@ -76,6 +73,29 @@ fn draw_surface_tree<R, E, T, F>(
|
|||
}
|
||||
}
|
||||
// Now, should we be drawn ?
|
||||
if data.texture.is_some() {
|
||||
TraversalAction::DoChildren(())
|
||||
} else {
|
||||
// we are not displayed, so our children are neither
|
||||
TraversalAction::SkipChildren
|
||||
}
|
||||
} else {
|
||||
// we are not displayed, so our children are neither
|
||||
TraversalAction::SkipChildren
|
||||
}
|
||||
},
|
||||
|_, _, _, _| {},
|
||||
|_, _, _, _| true,
|
||||
);
|
||||
|
||||
compositor_token.with_surface_tree_upward(
|
||||
root,
|
||||
location,
|
||||
|_surface, attributes, role, &(mut x, mut y)| {
|
||||
// Pull a new buffer if available
|
||||
if let Some(data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
|
||||
let mut data = data.borrow_mut();
|
||||
// Now, should we be drawn ?
|
||||
if data.texture.is_some() {
|
||||
// if yes, also process the children
|
||||
if Role::<SubsurfaceRole>::has(role) {
|
||||
|
@ -103,7 +123,7 @@ fn draw_surface_tree<R, E, T, F>(
|
|||
x += sub_x;
|
||||
y += sub_y;
|
||||
}
|
||||
frame.render_texture_at(&*buffer_texture, (x, y), Transform::Normal /* TODO */, 1.0);
|
||||
renderer.render_texture_at(&*buffer_texture, (x, y), Transform::Normal /* TODO */, 1.0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -111,17 +131,15 @@ fn draw_surface_tree<R, E, T, F>(
|
|||
);
|
||||
}
|
||||
|
||||
pub fn draw_windows<R, E, T, F>(
|
||||
pub fn draw_windows<R, E, T>(
|
||||
renderer: &mut R,
|
||||
frame: &mut F,
|
||||
window_map: &MyWindowMap,
|
||||
output_rect: Option<Rectangle>,
|
||||
compositor_token: MyCompositorToken,
|
||||
log: &::slog::Logger,
|
||||
)
|
||||
where
|
||||
R: Renderer<Error=E, Texture=T, Frame=F>,
|
||||
F: Frame<Error=E, Texture=T>,
|
||||
R: Renderer<Error=E, Texture=T>,
|
||||
E: std::error::Error,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -140,7 +158,6 @@ pub fn draw_windows<R, E, T, F>(
|
|||
// this surface is a root of a subsurface tree that needs to be drawn
|
||||
draw_surface_tree(
|
||||
renderer,
|
||||
frame,
|
||||
&wl_surface,
|
||||
initial_place,
|
||||
compositor_token,
|
||||
|
@ -152,17 +169,15 @@ pub fn draw_windows<R, E, T, F>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn draw_dnd_icon<R, E, T, F>(
|
||||
pub fn draw_dnd_icon<R, E, T>(
|
||||
renderer: &mut R,
|
||||
frame: &mut F,
|
||||
surface: &wl_surface::WlSurface,
|
||||
(x, y): (i32, i32),
|
||||
token: MyCompositorToken,
|
||||
log: &::slog::Logger,
|
||||
)
|
||||
where
|
||||
R: Renderer<Error=E, Texture=T, Frame=F>,
|
||||
F: Frame<Error=E, Texture=T>,
|
||||
R: Renderer<Error=E, Texture=T>,
|
||||
E: std::error::Error,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -172,7 +187,7 @@ pub fn draw_dnd_icon<R, E, T, F>(
|
|||
"Trying to display as a dnd icon a surface that does not have the DndIcon role."
|
||||
);
|
||||
}
|
||||
draw_surface_tree(renderer, frame, surface, (x, y), token, log);
|
||||
draw_surface_tree(renderer, surface, (x, y), token, log);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::{cell::RefCell, rc::Rc, sync::atomic::Ordering, time::Duration};
|
|||
//#[cfg(feature = "egl")]
|
||||
//use smithay::backend::egl::EGLGraphicsBackend;
|
||||
use smithay::{
|
||||
backend::{renderer::Frame, input::InputBackend, winit, SwapBuffersError},
|
||||
backend::{renderer::Renderer, input::InputBackend, winit, SwapBuffersError},
|
||||
reexports::{
|
||||
calloop::EventLoop,
|
||||
wayland_server::{protocol::wl_output, Display},
|
||||
|
@ -112,11 +112,11 @@ pub fn run_winit(
|
|||
|
||||
// drawing logic
|
||||
{
|
||||
let mut frame = renderer.begin().expect("Failed to render frame");
|
||||
frame.clear([0.8, 0.8, 0.9, 1.0]);
|
||||
renderer.begin().expect("Failed to render frame");
|
||||
renderer.clear([0.8, 0.8, 0.9, 1.0]).expect("Failed to clear frame");
|
||||
|
||||
// draw the windows
|
||||
draw_windows(&mut renderer, &mut frame, &*state.window_map.borrow(), None, state.ctoken, &log);
|
||||
draw_windows(&mut renderer, &*state.window_map.borrow(), None, state.ctoken, &log);
|
||||
|
||||
let (x, y) = *state.pointer_location.borrow();
|
||||
// draw the dnd icon if any
|
||||
|
@ -124,7 +124,7 @@ pub fn run_winit(
|
|||
let guard = state.dnd_icon.lock().unwrap();
|
||||
if let Some(ref surface) = *guard {
|
||||
if surface.as_ref().is_alive() {
|
||||
draw_dnd_icon(&mut renderer, &mut frame, surface, (x as i32, y as i32), state.ctoken, &log);
|
||||
draw_dnd_icon(&mut renderer, surface, (x as i32, y as i32), state.ctoken, &log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,13 +143,13 @@ pub fn run_winit(
|
|||
// draw as relevant
|
||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||
renderer.window().set_cursor_visible(false);
|
||||
draw_cursor(&mut renderer, &mut frame, surface, (x as i32, y as i32), state.ctoken, &log);
|
||||
draw_cursor(&mut renderer, surface, (x as i32, y as i32), state.ctoken, &log);
|
||||
} else {
|
||||
renderer.window().set_cursor_visible(true);
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(SwapBuffersError::ContextLost(err)) = frame.finish() {
|
||||
if let Err(SwapBuffersError::ContextLost(err)) = renderer.finish() {
|
||||
error!(log, "Critical Rendering Error: {}", err);
|
||||
state.running.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
use std::collections::HashSet;
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::rc::Rc;
|
||||
|
||||
use cgmath::{prelude::*, Matrix3, Vector2};
|
||||
|
||||
mod shaders;
|
||||
use crate::backend::SwapBuffersError;
|
||||
use crate::backend::allocator::{dmabuf::{Dmabuf, WeakDmabuf}, Format};
|
||||
use crate::backend::egl::{EGLContext, EGLSurface, ffi::egl::types::EGLImage};
|
||||
use super::{Renderer, Frame, Bind, Unbind, Transform, Texture};
|
||||
use crate::backend::egl::{EGLContext, EGLSurface, ffi::egl::types::EGLImage, MakeCurrentError};
|
||||
use super::{Renderer, Bind, Unbind, Transform, Texture};
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
use wayland_server::protocol::{wl_shm, wl_buffer};
|
||||
|
@ -30,6 +30,7 @@ struct Gles2Program {
|
|||
attrib_tex_coords: ffi::types::GLint,
|
||||
}
|
||||
|
||||
// TODO: drop?
|
||||
pub struct Gles2Texture {
|
||||
texture: ffi::types::GLuint,
|
||||
texture_kind: usize,
|
||||
|
@ -62,22 +63,16 @@ struct Gles2Buffer {
|
|||
}
|
||||
|
||||
pub struct Gles2Renderer {
|
||||
internal: Arc<Gles2RendererInternal>,
|
||||
buffers: Vec<WeakGles2Buffer>,
|
||||
current_buffer: Option<Gles2Buffer>,
|
||||
}
|
||||
|
||||
struct Gles2RendererInternal {
|
||||
gl: ffi::Gles2,
|
||||
egl: EGLContext,
|
||||
target_buffer: Option<Gles2Buffer>,
|
||||
target_surface: Option<Rc<EGLSurface>>,
|
||||
current_projection: Option<Matrix3<f32>>,
|
||||
extensions: Vec<String>,
|
||||
programs: [Gles2Program; shaders::FRAGMENT_COUNT],
|
||||
gl: ffi::Gles2,
|
||||
egl: EGLContext,
|
||||
logger: Option<*mut ::slog::Logger>,
|
||||
}
|
||||
|
||||
pub struct Gles2Frame {
|
||||
internal: Arc<Gles2RendererInternal>,
|
||||
projection: Matrix3<f32>,
|
||||
_not_send: *mut (),
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
|
@ -103,6 +98,8 @@ pub enum Gles2Error {
|
|||
#[error("Error accessing the buffer ({0:?})")]
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
BufferAccessError(crate::wayland::shm::BufferAccessError),
|
||||
#[error("Call begin before doing any rendering operations")]
|
||||
UnconstraintRenderingOperation,
|
||||
}
|
||||
|
||||
impl From<Gles2Error> for SwapBuffersError {
|
||||
|
@ -112,6 +109,7 @@ impl From<Gles2Error> for SwapBuffersError {
|
|||
| x @ Gles2Error::ProgramLinkError
|
||||
| x @ Gles2Error::GLFunctionLoaderError
|
||||
| x @ Gles2Error::GLExtensionNotSupported(_)
|
||||
| x @ Gles2Error::UnconstraintRenderingOperation
|
||||
=> SwapBuffersError::ContextLost(Box::new(x)),
|
||||
Gles2Error::ContextActivationError(err) => err.into(),
|
||||
x @ Gles2Error::FramebufferBindingError
|
||||
|
@ -205,15 +203,15 @@ unsafe fn texture_program(gl: &ffi::Gles2, frag: &'static str) -> Result<Gles2Pr
|
|||
}
|
||||
|
||||
impl Gles2Renderer {
|
||||
pub fn new<L>(context: EGLContext, logger: L) -> Result<Gles2Renderer, Gles2Error>
|
||||
pub unsafe fn new<L>(context: EGLContext, logger: L) -> Result<Gles2Renderer, Gles2Error>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>
|
||||
{
|
||||
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "renderer_gles2"));
|
||||
|
||||
unsafe { context.make_current()? };
|
||||
context.make_current()?;
|
||||
|
||||
let (gl, exts, logger) = unsafe {
|
||||
let (gl, exts, logger) = {
|
||||
let gl = ffi::Gles2::load_with(|s| crate::backend::egl::get_proc_address(s) as *const _);
|
||||
let ext_ptr = gl.GetString(ffi::EXTENSIONS) as *const i8;
|
||||
if ext_ptr.is_null() {
|
||||
|
@ -252,52 +250,55 @@ impl Gles2Renderer {
|
|||
(gl, exts, logger)
|
||||
};
|
||||
|
||||
let programs = {
|
||||
unsafe { [
|
||||
let programs = [
|
||||
texture_program(&gl, shaders::FRAGMENT_SHADER_ABGR)?,
|
||||
texture_program(&gl, shaders::FRAGMENT_SHADER_XBGR)?,
|
||||
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRA)?,
|
||||
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRX)?,
|
||||
texture_program(&gl, shaders::FRAGMENT_SHADER_EXTERNAL)?,
|
||||
] }
|
||||
};
|
||||
];
|
||||
|
||||
Ok(Gles2Renderer {
|
||||
internal: Arc::new(Gles2RendererInternal {
|
||||
let renderer = Gles2Renderer {
|
||||
gl,
|
||||
egl: context,
|
||||
extensions: exts,
|
||||
programs,
|
||||
logger,
|
||||
}),
|
||||
target_buffer: None,
|
||||
target_surface: None,
|
||||
buffers: Vec::new(),
|
||||
current_buffer: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Bind<&EGLSurface> for Gles2Renderer {
|
||||
fn bind(&mut self, surface: &EGLSurface) -> Result<(), Gles2Error> {
|
||||
if self.current_buffer.is_some() {
|
||||
self.unbind()?;
|
||||
current_projection: None,
|
||||
_not_send: std::ptr::null_mut(),
|
||||
};
|
||||
renderer.egl.unbind()?;
|
||||
Ok(renderer)
|
||||
}
|
||||
|
||||
fn make_current(&self) -> Result<(), MakeCurrentError> {
|
||||
unsafe {
|
||||
self.internal.egl.make_current_with_surface(&surface)?;
|
||||
if let Some(surface) = self.target_surface.as_ref() {
|
||||
self.egl.make_current_with_surface(surface)?;
|
||||
} else {
|
||||
self.egl.make_current()?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Bind<Rc<EGLSurface>> for Gles2Renderer {
|
||||
fn bind(&mut self, surface: Rc<EGLSurface>) -> Result<(), Gles2Error> {
|
||||
self.unbind()?;
|
||||
self.target_surface = Some(surface);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Bind<Dmabuf> for Gles2Renderer {
|
||||
fn bind(&mut self, dmabuf: Dmabuf) -> Result<(), Gles2Error> {
|
||||
if self.current_buffer.is_some() {
|
||||
self.unbind()?;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
self.internal.egl.make_current()?;
|
||||
self.egl.make_current()?;
|
||||
}
|
||||
|
||||
// Free outdated buffer resources
|
||||
|
@ -323,21 +324,21 @@ impl Bind<Dmabuf> for Gles2Renderer {
|
|||
})
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
let image = self.internal.egl.display.create_image_from_dmabuf(&dmabuf).map_err(Gles2Error::BindBufferEGLError)?;
|
||||
let image = self.egl.display.create_image_from_dmabuf(&dmabuf).map_err(Gles2Error::BindBufferEGLError)?;
|
||||
|
||||
unsafe {
|
||||
let mut rbo = 0;
|
||||
self.internal.gl.GenRenderbuffers(1, &mut rbo as *mut _);
|
||||
self.internal.gl.BindRenderbuffer(ffi::RENDERBUFFER, rbo);
|
||||
self.internal.gl.EGLImageTargetRenderbufferStorageOES(ffi::RENDERBUFFER, image);
|
||||
self.internal.gl.BindRenderbuffer(ffi::RENDERBUFFER, 0);
|
||||
self.gl.GenRenderbuffers(1, &mut rbo as *mut _);
|
||||
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, rbo);
|
||||
self.gl.EGLImageTargetRenderbufferStorageOES(ffi::RENDERBUFFER, image);
|
||||
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, 0);
|
||||
|
||||
let mut fbo = 0;
|
||||
self.internal.gl.GenFramebuffers(1, &mut fbo as *mut _);
|
||||
self.internal.gl.BindFramebuffer(ffi::FRAMEBUFFER, fbo);
|
||||
self.internal.gl.FramebufferRenderbuffer(ffi::FRAMEBUFFER, ffi::COLOR_ATTACHMENT0, ffi::RENDERBUFFER, rbo);
|
||||
let status = self.internal.gl.CheckFramebufferStatus(ffi::FRAMEBUFFER);
|
||||
self.internal.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
|
||||
self.gl.GenFramebuffers(1, &mut fbo as *mut _);
|
||||
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, fbo);
|
||||
self.gl.FramebufferRenderbuffer(ffi::FRAMEBUFFER, ffi::COLOR_ATTACHMENT0, ffi::RENDERBUFFER, rbo);
|
||||
let status = self.gl.CheckFramebufferStatus(ffi::FRAMEBUFFER);
|
||||
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
|
||||
|
||||
if status != ffi::FRAMEBUFFER_COMPLETE {
|
||||
//TODO wrap image and drop here
|
||||
|
@ -361,146 +362,36 @@ impl Bind<Dmabuf> for Gles2Renderer {
|
|||
})?;
|
||||
|
||||
unsafe {
|
||||
self.internal.gl.BindFramebuffer(ffi::FRAMEBUFFER, buffer.internal.fbo);
|
||||
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, buffer.internal.fbo);
|
||||
}
|
||||
self.current_buffer = Some(buffer);
|
||||
|
||||
self.target_buffer = Some(buffer);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn supported_formats(&self) -> Option<HashSet<Format>> {
|
||||
Some(self.internal.egl.display.dmabuf_render_formats.clone())
|
||||
Some(self.egl.display.dmabuf_render_formats.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Unbind for Gles2Renderer {
|
||||
fn unbind(&mut self) -> Result<(), Gles2Error> {
|
||||
fn unbind(&mut self) -> Result<(), <Self as Renderer>::Error> {
|
||||
unsafe {
|
||||
self.internal.egl.make_current()?;
|
||||
self.internal.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
|
||||
self.egl.make_current()?;
|
||||
}
|
||||
self.current_buffer = None;
|
||||
let _ = self.internal.egl.unbind();
|
||||
unsafe { self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0) };
|
||||
self.target_buffer = None;
|
||||
self.target_surface = None;
|
||||
self.egl.unbind()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for Gles2Renderer {
|
||||
type Error = Gles2Error;
|
||||
type Texture = Gles2Texture;
|
||||
type Frame = Gles2Frame;
|
||||
|
||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<Gles2Frame, Gles2Error> {
|
||||
if !self.internal.egl.is_current() {
|
||||
// Do not call this unconditionally.
|
||||
// If surfaces are in use (e.g. for winit) this would unbind them.
|
||||
unsafe { self.internal.egl.make_current()?; }
|
||||
}
|
||||
unsafe {
|
||||
self.internal.gl.Viewport(0, 0, width as i32, height as i32);
|
||||
|
||||
self.internal.gl.Enable(ffi::BLEND);
|
||||
self.internal.gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
// output transformation passed in by the user
|
||||
let mut projection = Matrix3::<f32>::identity();
|
||||
projection = projection * Matrix3::from_translation(Vector2::new(width as f32 / 2.0, height as f32 / 2.0));
|
||||
projection = projection * transform.matrix();
|
||||
let (transformed_width, transformed_height) = transform.transform_size(width, height);
|
||||
projection = projection * Matrix3::from_translation(Vector2::new(-(transformed_width as f32) / 2.0, -(transformed_height as f32) / 2.0));
|
||||
|
||||
// replicate https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml
|
||||
// glOrtho(0, width, 0, height, 1, 1);
|
||||
let mut renderer = Matrix3::<f32>::identity();
|
||||
let t = Matrix3::<f32>::identity();
|
||||
let x = 2.0 / (width as f32);
|
||||
let y = 2.0 / (height as f32);
|
||||
|
||||
// Rotation & Reflection
|
||||
renderer[0][0] = x * t[0][0];
|
||||
renderer[1][0] = x * t[0][1];
|
||||
renderer[0][1] = y * -t[1][0];
|
||||
renderer[1][1] = y * -t[1][1];
|
||||
|
||||
//Translation
|
||||
renderer[2][0] = -(1.0f32.copysign(renderer[0][0] + renderer[1][0]));
|
||||
renderer[2][1] = -(1.0f32.copysign(renderer[0][1] + renderer[1][1]));
|
||||
|
||||
Ok(Gles2Frame {
|
||||
internal: self.internal.clone(),
|
||||
projection: projection * renderer,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||
&[
|
||||
wl_shm::Format::Abgr8888,
|
||||
wl_shm::Format::Xbgr8888,
|
||||
wl_shm::Format::Argb8888,
|
||||
wl_shm::Format::Xrgb8888,
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn import_shm(&self, buffer: &wl_buffer::WlBuffer) -> Result<Self::Texture, Self::Error> {
|
||||
use crate::wayland::shm::with_buffer_contents;
|
||||
|
||||
with_buffer_contents(&buffer, |slice, data| {
|
||||
if !self.internal.egl.is_current() {
|
||||
unsafe { self.internal.egl.make_current()?; }
|
||||
}
|
||||
|
||||
let offset = data.offset as i32;
|
||||
let width = data.width as i32;
|
||||
let height = data.height as i32;
|
||||
let stride = data.stride as i32;
|
||||
|
||||
// number of bytes per pixel
|
||||
// TODO: compute from data.format
|
||||
let pixelsize = 4i32;
|
||||
|
||||
// ensure consistency, the SHM handler of smithay should ensure this
|
||||
assert!((offset + (height - 1) * stride + width * pixelsize) as usize <= slice.len());
|
||||
|
||||
let (gl_format, shader_idx) = match data.format {
|
||||
wl_shm::Format::Abgr8888 => (ffi::RGBA, 0),
|
||||
wl_shm::Format::Xbgr8888 => (ffi::RGBA, 1),
|
||||
wl_shm::Format::Argb8888 => (ffi::BGRA_EXT, 2),
|
||||
wl_shm::Format::Xrgb8888 => (ffi::BGRA_EXT, 3),
|
||||
format => return Err(Gles2Error::UnsupportedPixelFormat(format)),
|
||||
};
|
||||
|
||||
let mut tex = 0;
|
||||
unsafe {
|
||||
self.internal.gl.GenTextures(1, &mut tex);
|
||||
self.internal.gl.BindTexture(ffi::TEXTURE_2D, tex);
|
||||
|
||||
self.internal.gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
|
||||
self.internal.gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
||||
self.internal.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize);
|
||||
self.internal.gl.TexImage2D(ffi::TEXTURE_2D, 0, gl_format as i32, width, height, 0, gl_format, ffi::UNSIGNED_BYTE as u32, slice.as_ptr() as *const _);
|
||||
|
||||
self.internal.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, 0);
|
||||
self.internal.gl.BindTexture(ffi::TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
Ok(Gles2Texture {
|
||||
texture: tex,
|
||||
texture_kind: shader_idx,
|
||||
is_external: false,
|
||||
y_inverted: false,
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
})
|
||||
}).map_err(Gles2Error::BufferAccessError)?
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Gles2RendererInternal {
|
||||
impl Drop for Gles2Renderer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.egl.make_current().is_ok() {
|
||||
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
|
||||
for program in &self.programs {
|
||||
self.gl.DeleteProgram(program.program);
|
||||
}
|
||||
|
@ -533,60 +424,171 @@ static TEX_COORDS: [ffi::types::GLfloat; 8] = [
|
|||
0.0, 1.0, // bottom left
|
||||
];
|
||||
|
||||
impl Frame for Gles2Frame {
|
||||
impl Renderer for Gles2Renderer {
|
||||
type Error = Gles2Error;
|
||||
type Texture = Gles2Texture;
|
||||
|
||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||
&[
|
||||
wl_shm::Format::Abgr8888,
|
||||
wl_shm::Format::Xbgr8888,
|
||||
wl_shm::Format::Argb8888,
|
||||
wl_shm::Format::Xrgb8888,
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::Texture, Self::Error> {
|
||||
use crate::wayland::shm::with_buffer_contents;
|
||||
|
||||
with_buffer_contents(&buffer, |slice, data| {
|
||||
self.make_current()?;
|
||||
|
||||
let offset = data.offset as i32;
|
||||
let width = data.width as i32;
|
||||
let height = data.height as i32;
|
||||
let stride = data.stride as i32;
|
||||
|
||||
// number of bytes per pixel
|
||||
// TODO: compute from data.format
|
||||
let pixelsize = 4i32;
|
||||
|
||||
// ensure consistency, the SHM handler of smithay should ensure this
|
||||
assert!((offset + (height - 1) * stride + width * pixelsize) as usize <= slice.len());
|
||||
|
||||
let (gl_format, shader_idx) = match data.format {
|
||||
wl_shm::Format::Abgr8888 => (ffi::RGBA, 0),
|
||||
wl_shm::Format::Xbgr8888 => (ffi::RGBA, 1),
|
||||
wl_shm::Format::Argb8888 => (ffi::BGRA_EXT, 2),
|
||||
wl_shm::Format::Xrgb8888 => (ffi::BGRA_EXT, 3),
|
||||
format => return Err(Gles2Error::UnsupportedPixelFormat(format)),
|
||||
};
|
||||
|
||||
let mut tex = 0;
|
||||
unsafe {
|
||||
self.internal.gl.ClearColor(color[0], color[1], color[2], color[3]);
|
||||
self.internal.gl.Clear(ffi::COLOR_BUFFER_BIT);
|
||||
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.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize);
|
||||
self.gl.TexImage2D(ffi::TEXTURE_2D, 0, gl_format as i32, width, height, 0, gl_format, ffi::UNSIGNED_BYTE as u32, slice.as_ptr() as *const _);
|
||||
|
||||
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, 0);
|
||||
self.gl.BindTexture(ffi::TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
let texture = Gles2Texture {
|
||||
texture: tex,
|
||||
texture_kind: shader_idx,
|
||||
is_external: false,
|
||||
y_inverted: false,
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
};
|
||||
self.egl.unbind()?;
|
||||
|
||||
Ok(texture)
|
||||
}).map_err(Gles2Error::BufferAccessError)?
|
||||
}
|
||||
|
||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Gles2Error> {
|
||||
self.make_current()?;
|
||||
unsafe {
|
||||
self.gl.Viewport(0, 0, width as i32, height as i32);
|
||||
|
||||
self.gl.Enable(ffi::BLEND);
|
||||
self.gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
// output transformation passed in by the user
|
||||
let mut projection = Matrix3::<f32>::identity();
|
||||
//projection = projection * Matrix3::from_translation(Vector2::new(width as f32 / 2.0, height as f32 / 2.0));
|
||||
projection = projection * transform.matrix();
|
||||
//let (transformed_width, transformed_height) = transform.transform_size(width, height);
|
||||
//projection = projection * Matrix3::from_translation(Vector2::new(-(transformed_width as f32) / 2.0, -(transformed_height as f32) / 2.0));
|
||||
|
||||
// replicate https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml
|
||||
// glOrtho(0, width, 0, height, 1, 1);
|
||||
let mut renderer = Matrix3::<f32>::identity();
|
||||
let t = Matrix3::<f32>::identity();
|
||||
let x = 2.0 / (width as f32);
|
||||
let y = 2.0 / (height as f32);
|
||||
|
||||
// Rotation & Reflection
|
||||
renderer[0][0] = x * t[0][0];
|
||||
renderer[1][0] = x * t[0][1];
|
||||
renderer[0][1] = y * -t[1][0];
|
||||
renderer[1][1] = y * -t[1][1];
|
||||
|
||||
//Translation
|
||||
renderer[2][0] = -(1.0f32.copysign(renderer[0][0] + renderer[1][0]));
|
||||
renderer[2][1] = -(1.0f32.copysign(renderer[0][1] + renderer[1][1]));
|
||||
|
||||
self.current_projection = Some(projection * renderer);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
||||
self.make_current()?;
|
||||
unsafe {
|
||||
self.gl.ClearColor(color[0], color[1], color[2], color[3]);
|
||||
self.gl.Clear(ffi::COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_texture(&mut self, tex: &Self::Texture, mut matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error> {
|
||||
self.make_current()?;
|
||||
if self.current_projection.is_none() {
|
||||
return Err(Gles2Error::UnconstraintRenderingOperation);
|
||||
}
|
||||
|
||||
//apply output transformation
|
||||
matrix = self.projection * matrix;
|
||||
matrix = self.current_projection.as_ref().unwrap() * matrix;
|
||||
|
||||
let target = if tex.is_external { ffi::TEXTURE_EXTERNAL_OES } else { ffi::TEXTURE_2D };
|
||||
|
||||
// render
|
||||
unsafe {
|
||||
self.internal.gl.ActiveTexture(ffi::TEXTURE0);
|
||||
self.internal.gl.BindTexture(target, tex.texture);
|
||||
self.internal.gl.TexParameteri(target, ffi::TEXTURE_MIN_FILTER, ffi::LINEAR as i32);
|
||||
self.internal.gl.UseProgram(self.internal.programs[tex.texture_kind].program);
|
||||
self.gl.ActiveTexture(ffi::TEXTURE0);
|
||||
self.gl.BindTexture(target, tex.texture);
|
||||
self.gl.TexParameteri(target, ffi::TEXTURE_MIN_FILTER, ffi::LINEAR as i32);
|
||||
self.gl.UseProgram(self.programs[tex.texture_kind].program);
|
||||
|
||||
self.internal.gl.Uniform1i(self.internal.programs[tex.texture_kind].uniform_tex, 0);
|
||||
self.internal.gl.UniformMatrix3fv(self.internal.programs[tex.texture_kind].uniform_matrix, 1, ffi::FALSE, matrix.as_ptr());
|
||||
self.internal.gl.Uniform1i(self.internal.programs[tex.texture_kind].uniform_invert_y, if tex.y_inverted { 1 } else { 0 });
|
||||
self.internal.gl.Uniform1f(self.internal.programs[tex.texture_kind].uniform_alpha, alpha);
|
||||
self.gl.Uniform1i(self.programs[tex.texture_kind].uniform_tex, 0);
|
||||
self.gl.UniformMatrix3fv(self.programs[tex.texture_kind].uniform_matrix, 1, ffi::FALSE, matrix.as_ptr());
|
||||
self.gl.Uniform1i(self.programs[tex.texture_kind].uniform_invert_y, if tex.y_inverted { 1 } else { 0 });
|
||||
self.gl.Uniform1f(self.programs[tex.texture_kind].uniform_alpha, alpha);
|
||||
|
||||
self.internal.gl.VertexAttribPointer(self.internal.programs[tex.texture_kind].attrib_position as u32, 2, ffi::FLOAT, ffi::FALSE, 0, VERTS.as_ptr() as *const _);
|
||||
self.internal.gl.VertexAttribPointer(self.internal.programs[tex.texture_kind].attrib_tex_coords as u32, 2, ffi::FLOAT, ffi::FALSE, 0, TEX_COORDS.as_ptr() as *const _);
|
||||
self.gl.VertexAttribPointer(self.programs[tex.texture_kind].attrib_position as u32, 2, ffi::FLOAT, ffi::FALSE, 0, VERTS.as_ptr() as *const _);
|
||||
self.gl.VertexAttribPointer(self.programs[tex.texture_kind].attrib_tex_coords as u32, 2, ffi::FLOAT, ffi::FALSE, 0, TEX_COORDS.as_ptr() as *const _);
|
||||
|
||||
self.internal.gl.EnableVertexAttribArray(self.internal.programs[tex.texture_kind].attrib_position as u32);
|
||||
self.internal.gl.EnableVertexAttribArray(self.internal.programs[tex.texture_kind].attrib_tex_coords as u32);
|
||||
self.gl.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32);
|
||||
self.gl.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32);
|
||||
|
||||
self.internal.gl.DrawArrays(ffi::TRIANGLE_STRIP, 0, 4);
|
||||
self.gl.DrawArrays(ffi::TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
self.internal.gl.DisableVertexAttribArray(self.internal.programs[tex.texture_kind].attrib_position as u32);
|
||||
self.internal.gl.DisableVertexAttribArray(self.internal.programs[tex.texture_kind].attrib_tex_coords as u32);
|
||||
self.gl.DisableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32);
|
||||
self.gl.DisableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32);
|
||||
|
||||
self.internal.gl.BindTexture(target, 0);
|
||||
self.gl.BindTexture(target, 0);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn finish(self) -> Result<(), crate::backend::SwapBuffersError> {
|
||||
fn finish(&mut self) -> Result<(), crate::backend::SwapBuffersError> {
|
||||
self.make_current()?;
|
||||
unsafe {
|
||||
self.internal.gl.Flush();
|
||||
self.internal.gl.Disable(ffi::BLEND);
|
||||
self.gl.Flush();
|
||||
self.gl.Disable(ffi::BLEND);
|
||||
}
|
||||
|
||||
self.current_projection = None;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,10 +133,6 @@ pub trait Texture {
|
|||
pub trait Renderer {
|
||||
type Error: Error;
|
||||
type Texture: Texture;
|
||||
type Frame: Frame<Error=Self::Error, Texture=Self::Texture>;
|
||||
|
||||
#[must_use]
|
||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<Self::Frame, Self::Error>;
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||
|
@ -144,12 +140,10 @@ pub trait Renderer {
|
|||
&[wl_shm::Format::Argb8888, wl_shm::Format::Xrgb8888]
|
||||
}
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn import_shm(&self, buffer: &wl_buffer::WlBuffer) -> Result<Self::Texture, Self::Error>;
|
||||
}
|
||||
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::Texture, Self::Error>;
|
||||
|
||||
pub trait Frame {
|
||||
type Error: Error;
|
||||
type Texture: Texture;
|
||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), <Self as Renderer>::Error>;
|
||||
fn finish(&mut self) -> Result<(), SwapBuffersError>;
|
||||
|
||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>;
|
||||
fn render_texture(&mut self, texture: &Self::Texture, matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error>;
|
||||
|
@ -173,5 +167,4 @@ pub trait Frame {
|
|||
self.render_texture(texture, mat, alpha)
|
||||
}
|
||||
|
||||
fn finish(self) -> Result<(), SwapBuffersError>;
|
||||
}
|
|
@ -4,8 +4,8 @@ use crate::backend::egl::display::EGLDisplay;
|
|||
use crate::backend::{
|
||||
egl::{context::GlAttributes, native, EGLContext, EGLSurface, Error as EGLError},
|
||||
renderer::{
|
||||
Renderer, Bind, Transform, Frame,
|
||||
gles2::{Gles2Renderer, Gles2Error, Gles2Texture, Gles2Frame},
|
||||
Renderer, Bind, Transform,
|
||||
gles2::{Gles2Renderer, Gles2Error, Gles2Texture},
|
||||
},
|
||||
input::{
|
||||
Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
|
||||
|
@ -73,11 +73,6 @@ pub struct WinitGraphicsBackend {
|
|||
size: Rc<RefCell<WindowSize>>,
|
||||
}
|
||||
|
||||
pub struct WinitFrame {
|
||||
frame: Gles2Frame,
|
||||
egl: Rc<EGLSurface>,
|
||||
}
|
||||
|
||||
/// Abstracted event loop of a [`WinitWindow`] implementing the [`InputBackend`] trait
|
||||
///
|
||||
/// You need to call [`dispatch_new_events`](InputBackend::dispatch_new_events)
|
||||
|
@ -173,6 +168,8 @@ where
|
|||
unreachable!("No backends for winit other then Wayland and X11 are supported")
|
||||
};
|
||||
|
||||
context.unbind();
|
||||
|
||||
(
|
||||
display,
|
||||
context,
|
||||
|
@ -187,13 +184,14 @@ where
|
|||
|
||||
let window = Rc::new(winit_window);
|
||||
let egl = Rc::new(surface);
|
||||
let mut renderer = unsafe { Gles2Renderer::new(context, log.clone())? };
|
||||
|
||||
Ok((
|
||||
WinitGraphicsBackend {
|
||||
window: window.clone(),
|
||||
display,
|
||||
egl: egl.clone(),
|
||||
renderer: Gles2Renderer::new(context, log.clone())?,
|
||||
renderer,
|
||||
size: size.clone(),
|
||||
},
|
||||
WinitInputBackend {
|
||||
|
@ -247,55 +245,46 @@ impl WinitGraphicsBackend {
|
|||
&*self.window
|
||||
}
|
||||
|
||||
pub fn begin(&mut self) -> Result<WinitFrame, Gles2Error> {
|
||||
pub fn begin(&mut self) -> Result<(), Gles2Error> {
|
||||
let (width, height) = {
|
||||
let size = self.size.borrow();
|
||||
size.physical_size.into()
|
||||
};
|
||||
Renderer::begin(self, width, height, Transform::Normal)
|
||||
|
||||
self.renderer.bind(self.egl.clone())?;
|
||||
self.renderer.begin(width, height, Transform::Normal)
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for WinitGraphicsBackend {
|
||||
type Error = Gles2Error;
|
||||
type Texture = Gles2Texture;
|
||||
type Frame = WinitFrame;
|
||||
|
||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<Self::Frame, Self::Error> {
|
||||
self.renderer.bind(&*self.egl)?;
|
||||
let frame = self.renderer.begin(width, height, transform)?;
|
||||
|
||||
Ok(WinitFrame {
|
||||
frame,
|
||||
egl: self.egl.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||
self.renderer.shm_formats()
|
||||
Renderer::shm_formats(&self.renderer)
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn import_shm(&self, buffer: &wl_buffer::WlBuffer) -> Result<Self::Texture, Self::Error> {
|
||||
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::Texture, Self::Error> {
|
||||
self.renderer.import_shm(buffer)
|
||||
}
|
||||
|
||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), <Self as Renderer>::Error> {
|
||||
self.renderer.bind(self.egl.clone())?;
|
||||
self.renderer.begin(width, height, transform)
|
||||
}
|
||||
|
||||
impl Frame for WinitFrame {
|
||||
type Error = Gles2Error;
|
||||
type Texture = Gles2Texture;
|
||||
|
||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
||||
self.frame.clear(color)
|
||||
self.renderer.clear(color)
|
||||
}
|
||||
|
||||
fn render_texture(&mut self, texture: &Self::Texture, matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error> {
|
||||
self.frame.render_texture(texture, matrix, alpha)
|
||||
self.renderer.render_texture(texture, matrix, alpha)
|
||||
}
|
||||
|
||||
fn finish(self) -> Result<(), crate::backend::SwapBuffersError> {
|
||||
self.frame.finish()?;
|
||||
fn finish(&mut self) -> Result<(), crate::backend::SwapBuffersError> {
|
||||
self.renderer.finish()?;
|
||||
self.egl.swap_buffers()?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue