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};
|
use crate::shell::{MyCompositorToken, MyWindowMap, SurfaceData};
|
||||||
|
|
||||||
pub fn draw_cursor<R, E, T, F>(
|
|
||||||
|
pub fn draw_cursor<R, E, T>(
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
frame: &mut F,
|
|
||||||
surface: &wl_surface::WlSurface,
|
surface: &wl_surface::WlSurface,
|
||||||
(x, y): (i32, i32),
|
(x, y): (i32, i32),
|
||||||
token: MyCompositorToken,
|
token: MyCompositorToken,
|
||||||
log: &Logger,
|
log: &Logger,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
R: Renderer<Error=E, Texture=T, Frame=F>,
|
R: Renderer<Error=E, Texture=T>,
|
||||||
F: Frame<Error=E, Texture=T>,
|
|
||||||
E: std::error::Error,
|
E: std::error::Error,
|
||||||
T: Texture + 'static,
|
T: Texture + 'static,
|
||||||
{
|
{
|
||||||
|
@ -38,27 +37,25 @@ pub fn draw_cursor<R, E, T, F>(
|
||||||
(0, 0)
|
(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,
|
renderer: &mut R,
|
||||||
frame: &mut F,
|
|
||||||
root: &wl_surface::WlSurface,
|
root: &wl_surface::WlSurface,
|
||||||
location: (i32, i32),
|
location: (i32, i32),
|
||||||
compositor_token: MyCompositorToken,
|
compositor_token: MyCompositorToken,
|
||||||
log: &Logger,
|
log: &Logger,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
R: Renderer<Error=E, Texture=T, Frame=F>,
|
R: Renderer<Error=E, Texture=T>,
|
||||||
F: Frame<Error=E, Texture=T>,
|
|
||||||
E: std::error::Error,
|
E: std::error::Error,
|
||||||
T: Texture + 'static,
|
T: Texture + 'static,
|
||||||
{
|
{
|
||||||
compositor_token.with_surface_tree_upward(
|
compositor_token.with_surface_tree_upward(
|
||||||
root,
|
root,
|
||||||
location,
|
(),
|
||||||
|_surface, attributes, role, &(mut x, mut y)| {
|
|_surface, attributes, role, _| {
|
||||||
// Pull a new buffer if available
|
// Pull a new buffer if available
|
||||||
if let Some(data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
|
if let Some(data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
|
||||||
let mut data = data.borrow_mut();
|
let mut data = data.borrow_mut();
|
||||||
|
@ -76,6 +73,29 @@ fn draw_surface_tree<R, E, T, F>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Now, should we be drawn ?
|
// 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 data.texture.is_some() {
|
||||||
// if yes, also process the children
|
// if yes, also process the children
|
||||||
if Role::<SubsurfaceRole>::has(role) {
|
if Role::<SubsurfaceRole>::has(role) {
|
||||||
|
@ -103,7 +123,7 @@ fn draw_surface_tree<R, E, T, F>(
|
||||||
x += sub_x;
|
x += sub_x;
|
||||||
y += sub_y;
|
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,
|
renderer: &mut R,
|
||||||
frame: &mut F,
|
|
||||||
window_map: &MyWindowMap,
|
window_map: &MyWindowMap,
|
||||||
output_rect: Option<Rectangle>,
|
output_rect: Option<Rectangle>,
|
||||||
compositor_token: MyCompositorToken,
|
compositor_token: MyCompositorToken,
|
||||||
log: &::slog::Logger,
|
log: &::slog::Logger,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
R: Renderer<Error=E, Texture=T, Frame=F>,
|
R: Renderer<Error=E, Texture=T>,
|
||||||
F: Frame<Error=E, Texture=T>,
|
|
||||||
E: std::error::Error,
|
E: std::error::Error,
|
||||||
T: Texture + 'static,
|
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
|
// this surface is a root of a subsurface tree that needs to be drawn
|
||||||
draw_surface_tree(
|
draw_surface_tree(
|
||||||
renderer,
|
renderer,
|
||||||
frame,
|
|
||||||
&wl_surface,
|
&wl_surface,
|
||||||
initial_place,
|
initial_place,
|
||||||
compositor_token,
|
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,
|
renderer: &mut R,
|
||||||
frame: &mut F,
|
|
||||||
surface: &wl_surface::WlSurface,
|
surface: &wl_surface::WlSurface,
|
||||||
(x, y): (i32, i32),
|
(x, y): (i32, i32),
|
||||||
token: MyCompositorToken,
|
token: MyCompositorToken,
|
||||||
log: &::slog::Logger,
|
log: &::slog::Logger,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
R: Renderer<Error=E, Texture=T, Frame=F>,
|
R: Renderer<Error=E, Texture=T>,
|
||||||
F: Frame<Error=E, Texture=T>,
|
|
||||||
E: std::error::Error,
|
E: std::error::Error,
|
||||||
T: Texture + 'static,
|
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."
|
"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")]
|
//#[cfg(feature = "egl")]
|
||||||
//use smithay::backend::egl::EGLGraphicsBackend;
|
//use smithay::backend::egl::EGLGraphicsBackend;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{renderer::Frame, input::InputBackend, winit, SwapBuffersError},
|
backend::{renderer::Renderer, input::InputBackend, winit, SwapBuffersError},
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::EventLoop,
|
calloop::EventLoop,
|
||||||
wayland_server::{protocol::wl_output, Display},
|
wayland_server::{protocol::wl_output, Display},
|
||||||
|
@ -112,11 +112,11 @@ pub fn run_winit(
|
||||||
|
|
||||||
// drawing logic
|
// drawing logic
|
||||||
{
|
{
|
||||||
let mut frame = renderer.begin().expect("Failed to render frame");
|
renderer.begin().expect("Failed to render frame");
|
||||||
frame.clear([0.8, 0.8, 0.9, 1.0]);
|
renderer.clear([0.8, 0.8, 0.9, 1.0]).expect("Failed to clear frame");
|
||||||
|
|
||||||
// draw the windows
|
// 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();
|
let (x, y) = *state.pointer_location.borrow();
|
||||||
// draw the dnd icon if any
|
// draw the dnd icon if any
|
||||||
|
@ -124,7 +124,7 @@ pub fn run_winit(
|
||||||
let guard = state.dnd_icon.lock().unwrap();
|
let guard = state.dnd_icon.lock().unwrap();
|
||||||
if let Some(ref surface) = *guard {
|
if let Some(ref surface) = *guard {
|
||||||
if surface.as_ref().is_alive() {
|
if surface.as_ref().is_alive() {
|
||||||
draw_dnd_icon(&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
|
// draw as relevant
|
||||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||||
renderer.window().set_cursor_visible(false);
|
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 {
|
} else {
|
||||||
renderer.window().set_cursor_visible(true);
|
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);
|
error!(log, "Critical Rendering Error: {}", err);
|
||||||
state.running.store(false, Ordering::SeqCst);
|
state.running.store(false, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::Arc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use cgmath::{prelude::*, Matrix3, Vector2};
|
use cgmath::{prelude::*, Matrix3, Vector2};
|
||||||
|
|
||||||
mod shaders;
|
mod shaders;
|
||||||
use crate::backend::SwapBuffersError;
|
use crate::backend::SwapBuffersError;
|
||||||
use crate::backend::allocator::{dmabuf::{Dmabuf, WeakDmabuf}, Format};
|
use crate::backend::allocator::{dmabuf::{Dmabuf, WeakDmabuf}, Format};
|
||||||
use crate::backend::egl::{EGLContext, EGLSurface, ffi::egl::types::EGLImage};
|
use crate::backend::egl::{EGLContext, EGLSurface, ffi::egl::types::EGLImage, MakeCurrentError};
|
||||||
use super::{Renderer, Frame, Bind, Unbind, Transform, Texture};
|
use super::{Renderer, Bind, Unbind, Transform, Texture};
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use wayland_server::protocol::{wl_shm, wl_buffer};
|
use wayland_server::protocol::{wl_shm, wl_buffer};
|
||||||
|
@ -30,6 +30,7 @@ struct Gles2Program {
|
||||||
attrib_tex_coords: ffi::types::GLint,
|
attrib_tex_coords: ffi::types::GLint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: drop?
|
||||||
pub struct Gles2Texture {
|
pub struct Gles2Texture {
|
||||||
texture: ffi::types::GLuint,
|
texture: ffi::types::GLuint,
|
||||||
texture_kind: usize,
|
texture_kind: usize,
|
||||||
|
@ -62,22 +63,16 @@ struct Gles2Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Gles2Renderer {
|
pub struct Gles2Renderer {
|
||||||
internal: Arc<Gles2RendererInternal>,
|
|
||||||
buffers: Vec<WeakGles2Buffer>,
|
buffers: Vec<WeakGles2Buffer>,
|
||||||
current_buffer: Option<Gles2Buffer>,
|
target_buffer: Option<Gles2Buffer>,
|
||||||
}
|
target_surface: Option<Rc<EGLSurface>>,
|
||||||
|
current_projection: Option<Matrix3<f32>>,
|
||||||
struct Gles2RendererInternal {
|
|
||||||
gl: ffi::Gles2,
|
|
||||||
egl: EGLContext,
|
|
||||||
extensions: Vec<String>,
|
extensions: Vec<String>,
|
||||||
programs: [Gles2Program; shaders::FRAGMENT_COUNT],
|
programs: [Gles2Program; shaders::FRAGMENT_COUNT],
|
||||||
|
gl: ffi::Gles2,
|
||||||
|
egl: EGLContext,
|
||||||
logger: Option<*mut ::slog::Logger>,
|
logger: Option<*mut ::slog::Logger>,
|
||||||
}
|
_not_send: *mut (),
|
||||||
|
|
||||||
pub struct Gles2Frame {
|
|
||||||
internal: Arc<Gles2RendererInternal>,
|
|
||||||
projection: Matrix3<f32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
@ -103,6 +98,8 @@ pub enum Gles2Error {
|
||||||
#[error("Error accessing the buffer ({0:?})")]
|
#[error("Error accessing the buffer ({0:?})")]
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
BufferAccessError(crate::wayland::shm::BufferAccessError),
|
BufferAccessError(crate::wayland::shm::BufferAccessError),
|
||||||
|
#[error("Call begin before doing any rendering operations")]
|
||||||
|
UnconstraintRenderingOperation,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Gles2Error> for SwapBuffersError {
|
impl From<Gles2Error> for SwapBuffersError {
|
||||||
|
@ -112,6 +109,7 @@ impl From<Gles2Error> for SwapBuffersError {
|
||||||
| x @ Gles2Error::ProgramLinkError
|
| x @ Gles2Error::ProgramLinkError
|
||||||
| x @ Gles2Error::GLFunctionLoaderError
|
| x @ Gles2Error::GLFunctionLoaderError
|
||||||
| x @ Gles2Error::GLExtensionNotSupported(_)
|
| x @ Gles2Error::GLExtensionNotSupported(_)
|
||||||
|
| x @ Gles2Error::UnconstraintRenderingOperation
|
||||||
=> SwapBuffersError::ContextLost(Box::new(x)),
|
=> SwapBuffersError::ContextLost(Box::new(x)),
|
||||||
Gles2Error::ContextActivationError(err) => err.into(),
|
Gles2Error::ContextActivationError(err) => err.into(),
|
||||||
x @ Gles2Error::FramebufferBindingError
|
x @ Gles2Error::FramebufferBindingError
|
||||||
|
@ -205,15 +203,15 @@ unsafe fn texture_program(gl: &ffi::Gles2, frag: &'static str) -> Result<Gles2Pr
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gles2Renderer {
|
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
|
where
|
||||||
L: Into<Option<::slog::Logger>>
|
L: Into<Option<::slog::Logger>>
|
||||||
{
|
{
|
||||||
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "renderer_gles2"));
|
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 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;
|
let ext_ptr = gl.GetString(ffi::EXTENSIONS) as *const i8;
|
||||||
if ext_ptr.is_null() {
|
if ext_ptr.is_null() {
|
||||||
|
@ -252,52 +250,55 @@ impl Gles2Renderer {
|
||||||
(gl, exts, logger)
|
(gl, exts, logger)
|
||||||
};
|
};
|
||||||
|
|
||||||
let programs = {
|
let programs = [
|
||||||
unsafe { [
|
|
||||||
texture_program(&gl, shaders::FRAGMENT_SHADER_ABGR)?,
|
texture_program(&gl, shaders::FRAGMENT_SHADER_ABGR)?,
|
||||||
texture_program(&gl, shaders::FRAGMENT_SHADER_XBGR)?,
|
texture_program(&gl, shaders::FRAGMENT_SHADER_XBGR)?,
|
||||||
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRA)?,
|
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRA)?,
|
||||||
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRX)?,
|
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRX)?,
|
||||||
texture_program(&gl, shaders::FRAGMENT_SHADER_EXTERNAL)?,
|
texture_program(&gl, shaders::FRAGMENT_SHADER_EXTERNAL)?,
|
||||||
] }
|
];
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Gles2Renderer {
|
let renderer = Gles2Renderer {
|
||||||
internal: Arc::new(Gles2RendererInternal {
|
gl,
|
||||||
gl,
|
egl: context,
|
||||||
egl: context,
|
extensions: exts,
|
||||||
extensions: exts,
|
programs,
|
||||||
programs,
|
logger,
|
||||||
logger,
|
target_buffer: None,
|
||||||
}),
|
target_surface: None,
|
||||||
buffers: Vec::new(),
|
buffers: Vec::new(),
|
||||||
current_buffer: None,
|
current_projection: None,
|
||||||
})
|
_not_send: std::ptr::null_mut(),
|
||||||
|
};
|
||||||
|
renderer.egl.unbind()?;
|
||||||
|
Ok(renderer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_current(&self) -> Result<(), MakeCurrentError> {
|
||||||
|
unsafe {
|
||||||
|
if let Some(surface) = self.target_surface.as_ref() {
|
||||||
|
self.egl.make_current_with_surface(surface)?;
|
||||||
|
} else {
|
||||||
|
self.egl.make_current()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bind<&EGLSurface> for Gles2Renderer {
|
impl Bind<Rc<EGLSurface>> for Gles2Renderer {
|
||||||
fn bind(&mut self, surface: &EGLSurface) -> Result<(), Gles2Error> {
|
fn bind(&mut self, surface: Rc<EGLSurface>) -> Result<(), Gles2Error> {
|
||||||
if self.current_buffer.is_some() {
|
self.unbind()?;
|
||||||
self.unbind()?;
|
self.target_surface = Some(surface);
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
self.internal.egl.make_current_with_surface(&surface)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bind<Dmabuf> for Gles2Renderer {
|
impl Bind<Dmabuf> for Gles2Renderer {
|
||||||
fn bind(&mut self, dmabuf: Dmabuf) -> Result<(), Gles2Error> {
|
fn bind(&mut self, dmabuf: Dmabuf) -> Result<(), Gles2Error> {
|
||||||
if self.current_buffer.is_some() {
|
self.unbind()?;
|
||||||
self.unbind()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.internal.egl.make_current()?;
|
self.egl.make_current()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free outdated buffer resources
|
// Free outdated buffer resources
|
||||||
|
@ -323,21 +324,21 @@ impl Bind<Dmabuf> for Gles2Renderer {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.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 {
|
unsafe {
|
||||||
let mut rbo = 0;
|
let mut rbo = 0;
|
||||||
self.internal.gl.GenRenderbuffers(1, &mut rbo as *mut _);
|
self.gl.GenRenderbuffers(1, &mut rbo as *mut _);
|
||||||
self.internal.gl.BindRenderbuffer(ffi::RENDERBUFFER, rbo);
|
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, rbo);
|
||||||
self.internal.gl.EGLImageTargetRenderbufferStorageOES(ffi::RENDERBUFFER, image);
|
self.gl.EGLImageTargetRenderbufferStorageOES(ffi::RENDERBUFFER, image);
|
||||||
self.internal.gl.BindRenderbuffer(ffi::RENDERBUFFER, 0);
|
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, 0);
|
||||||
|
|
||||||
let mut fbo = 0;
|
let mut fbo = 0;
|
||||||
self.internal.gl.GenFramebuffers(1, &mut fbo as *mut _);
|
self.gl.GenFramebuffers(1, &mut fbo as *mut _);
|
||||||
self.internal.gl.BindFramebuffer(ffi::FRAMEBUFFER, fbo);
|
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, fbo);
|
||||||
self.internal.gl.FramebufferRenderbuffer(ffi::FRAMEBUFFER, ffi::COLOR_ATTACHMENT0, ffi::RENDERBUFFER, rbo);
|
self.gl.FramebufferRenderbuffer(ffi::FRAMEBUFFER, ffi::COLOR_ATTACHMENT0, ffi::RENDERBUFFER, rbo);
|
||||||
let status = self.internal.gl.CheckFramebufferStatus(ffi::FRAMEBUFFER);
|
let status = self.gl.CheckFramebufferStatus(ffi::FRAMEBUFFER);
|
||||||
self.internal.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
|
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
|
||||||
|
|
||||||
if status != ffi::FRAMEBUFFER_COMPLETE {
|
if status != ffi::FRAMEBUFFER_COMPLETE {
|
||||||
//TODO wrap image and drop here
|
//TODO wrap image and drop here
|
||||||
|
@ -361,146 +362,36 @@ impl Bind<Dmabuf> for Gles2Renderer {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
unsafe {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supported_formats(&self) -> Option<HashSet<Format>> {
|
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 {
|
impl Unbind for Gles2Renderer {
|
||||||
fn unbind(&mut self) -> Result<(), Gles2Error> {
|
fn unbind(&mut self) -> Result<(), <Self as Renderer>::Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.internal.egl.make_current()?;
|
self.egl.make_current()?;
|
||||||
self.internal.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
|
|
||||||
}
|
}
|
||||||
self.current_buffer = None;
|
unsafe { self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0) };
|
||||||
let _ = self.internal.egl.unbind();
|
self.target_buffer = None;
|
||||||
|
self.target_surface = None;
|
||||||
|
self.egl.unbind()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for Gles2Renderer {
|
impl Drop 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 {
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if self.egl.make_current().is_ok() {
|
if self.egl.make_current().is_ok() {
|
||||||
|
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
|
||||||
for program in &self.programs {
|
for program in &self.programs {
|
||||||
self.gl.DeleteProgram(program.program);
|
self.gl.DeleteProgram(program.program);
|
||||||
}
|
}
|
||||||
|
@ -533,60 +424,171 @@ static TEX_COORDS: [ffi::types::GLfloat; 8] = [
|
||||||
0.0, 1.0, // bottom left
|
0.0, 1.0, // bottom left
|
||||||
];
|
];
|
||||||
|
|
||||||
impl Frame for Gles2Frame {
|
impl Renderer for Gles2Renderer {
|
||||||
type Error = Gles2Error;
|
type Error = Gles2Error;
|
||||||
type Texture = Gles2Texture;
|
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.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 {
|
unsafe {
|
||||||
self.internal.gl.ClearColor(color[0], color[1], color[2], color[3]);
|
self.gl.Viewport(0, 0, width as i32, height as i32);
|
||||||
self.internal.gl.Clear(ffi::COLOR_BUFFER_BIT);
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_texture(&mut self, tex: &Self::Texture, mut matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error> {
|
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
|
//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 };
|
let target = if tex.is_external { ffi::TEXTURE_EXTERNAL_OES } else { ffi::TEXTURE_2D };
|
||||||
|
|
||||||
// render
|
// render
|
||||||
unsafe {
|
unsafe {
|
||||||
self.internal.gl.ActiveTexture(ffi::TEXTURE0);
|
self.gl.ActiveTexture(ffi::TEXTURE0);
|
||||||
self.internal.gl.BindTexture(target, tex.texture);
|
self.gl.BindTexture(target, tex.texture);
|
||||||
self.internal.gl.TexParameteri(target, ffi::TEXTURE_MIN_FILTER, ffi::LINEAR as i32);
|
self.gl.TexParameteri(target, ffi::TEXTURE_MIN_FILTER, ffi::LINEAR as i32);
|
||||||
self.internal.gl.UseProgram(self.internal.programs[tex.texture_kind].program);
|
self.gl.UseProgram(self.programs[tex.texture_kind].program);
|
||||||
|
|
||||||
self.internal.gl.Uniform1i(self.internal.programs[tex.texture_kind].uniform_tex, 0);
|
self.gl.Uniform1i(self.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.gl.UniformMatrix3fv(self.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.gl.Uniform1i(self.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.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.gl.VertexAttribPointer(self.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_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.gl.EnableVertexAttribArray(self.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_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.gl.DisableVertexAttribArray(self.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_tex_coords as u32);
|
||||||
|
|
||||||
self.internal.gl.BindTexture(target, 0);
|
self.gl.BindTexture(target, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self) -> Result<(), crate::backend::SwapBuffersError> {
|
fn finish(&mut self) -> Result<(), crate::backend::SwapBuffersError> {
|
||||||
|
self.make_current()?;
|
||||||
unsafe {
|
unsafe {
|
||||||
self.internal.gl.Flush();
|
self.gl.Flush();
|
||||||
self.internal.gl.Disable(ffi::BLEND);
|
self.gl.Disable(ffi::BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.current_projection = None;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,10 +133,6 @@ pub trait Texture {
|
||||||
pub trait Renderer {
|
pub trait Renderer {
|
||||||
type Error: Error;
|
type Error: Error;
|
||||||
type Texture: Texture;
|
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")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||||
|
@ -144,13 +140,11 @@ pub trait Renderer {
|
||||||
&[wl_shm::Format::Argb8888, wl_shm::Format::Xrgb8888]
|
&[wl_shm::Format::Argb8888, wl_shm::Format::Xrgb8888]
|
||||||
}
|
}
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[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>;
|
||||||
}
|
|
||||||
|
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), <Self as Renderer>::Error>;
|
||||||
pub trait Frame {
|
fn finish(&mut self) -> Result<(), SwapBuffersError>;
|
||||||
type Error: Error;
|
|
||||||
type Texture: Texture;
|
|
||||||
|
|
||||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>;
|
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>;
|
fn render_texture(&mut self, texture: &Self::Texture, matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error>;
|
||||||
fn render_texture_at(&mut self, texture: &Self::Texture, pos: (i32, i32), transform: Transform, alpha: f32) -> Result<(), Self::Error> {
|
fn render_texture_at(&mut self, texture: &Self::Texture, pos: (i32, i32), transform: Transform, alpha: f32) -> Result<(), Self::Error> {
|
||||||
|
@ -173,5 +167,4 @@ pub trait Frame {
|
||||||
self.render_texture(texture, mat, alpha)
|
self.render_texture(texture, mat, alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self) -> Result<(), SwapBuffersError>;
|
|
||||||
}
|
}
|
|
@ -4,8 +4,8 @@ use crate::backend::egl::display::EGLDisplay;
|
||||||
use crate::backend::{
|
use crate::backend::{
|
||||||
egl::{context::GlAttributes, native, EGLContext, EGLSurface, Error as EGLError},
|
egl::{context::GlAttributes, native, EGLContext, EGLSurface, Error as EGLError},
|
||||||
renderer::{
|
renderer::{
|
||||||
Renderer, Bind, Transform, Frame,
|
Renderer, Bind, Transform,
|
||||||
gles2::{Gles2Renderer, Gles2Error, Gles2Texture, Gles2Frame},
|
gles2::{Gles2Renderer, Gles2Error, Gles2Texture},
|
||||||
},
|
},
|
||||||
input::{
|
input::{
|
||||||
Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
|
Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
|
||||||
|
@ -73,11 +73,6 @@ pub struct WinitGraphicsBackend {
|
||||||
size: Rc<RefCell<WindowSize>>,
|
size: Rc<RefCell<WindowSize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WinitFrame {
|
|
||||||
frame: Gles2Frame,
|
|
||||||
egl: Rc<EGLSurface>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Abstracted event loop of a [`WinitWindow`] implementing the [`InputBackend`] trait
|
/// Abstracted event loop of a [`WinitWindow`] implementing the [`InputBackend`] trait
|
||||||
///
|
///
|
||||||
/// You need to call [`dispatch_new_events`](InputBackend::dispatch_new_events)
|
/// You need to call [`dispatch_new_events`](InputBackend::dispatch_new_events)
|
||||||
|
@ -172,6 +167,8 @@ where
|
||||||
} else {
|
} else {
|
||||||
unreachable!("No backends for winit other then Wayland and X11 are supported")
|
unreachable!("No backends for winit other then Wayland and X11 are supported")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
context.unbind();
|
||||||
|
|
||||||
(
|
(
|
||||||
display,
|
display,
|
||||||
|
@ -187,13 +184,14 @@ where
|
||||||
|
|
||||||
let window = Rc::new(winit_window);
|
let window = Rc::new(winit_window);
|
||||||
let egl = Rc::new(surface);
|
let egl = Rc::new(surface);
|
||||||
|
let mut renderer = unsafe { Gles2Renderer::new(context, log.clone())? };
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
WinitGraphicsBackend {
|
WinitGraphicsBackend {
|
||||||
window: window.clone(),
|
window: window.clone(),
|
||||||
display,
|
display,
|
||||||
egl: egl.clone(),
|
egl: egl.clone(),
|
||||||
renderer: Gles2Renderer::new(context, log.clone())?,
|
renderer,
|
||||||
size: size.clone(),
|
size: size.clone(),
|
||||||
},
|
},
|
||||||
WinitInputBackend {
|
WinitInputBackend {
|
||||||
|
@ -247,55 +245,46 @@ impl WinitGraphicsBackend {
|
||||||
&*self.window
|
&*self.window
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn begin(&mut self) -> Result<WinitFrame, Gles2Error> {
|
pub fn begin(&mut self) -> Result<(), Gles2Error> {
|
||||||
let (width, height) = {
|
let (width, height) = {
|
||||||
let size = self.size.borrow();
|
let size = self.size.borrow();
|
||||||
size.physical_size.into()
|
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 {
|
impl Renderer for WinitGraphicsBackend {
|
||||||
type Error = Gles2Error;
|
type Error = Gles2Error;
|
||||||
type Texture = Gles2Texture;
|
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")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||||
self.renderer.shm_formats()
|
Renderer::shm_formats(&self.renderer)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[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)
|
self.renderer.import_shm(buffer)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame for WinitFrame {
|
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), <Self as Renderer>::Error> {
|
||||||
type Error = Gles2Error;
|
self.renderer.bind(self.egl.clone())?;
|
||||||
type Texture = Gles2Texture;
|
self.renderer.begin(width, height, transform)
|
||||||
|
}
|
||||||
|
|
||||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
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> {
|
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> {
|
fn finish(&mut self) -> Result<(), crate::backend::SwapBuffersError> {
|
||||||
self.frame.finish()?;
|
self.renderer.finish()?;
|
||||||
self.egl.swap_buffers()?;
|
self.egl.swap_buffers()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue