autocommit 2022-01-28 19:46:23 CET
This commit is contained in:
parent
a5573b8a3a
commit
b11a36729c
45 changed files with 1646 additions and 2171 deletions
104
src/render/renderer/context.rs
Normal file
104
src/render/renderer/context.rs
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
use crate::drm::dma::DmaBuf;
|
||||
use crate::drm::drm::Drm;
|
||||
use crate::format::{Format, XRGB8888};
|
||||
use crate::render::egl::context::EglContext;
|
||||
use crate::render::egl::find_drm_device;
|
||||
use crate::render::gl::program::GlProgram;
|
||||
use crate::render::gl::render_buffer::GlRenderBuffer;
|
||||
use crate::render::gl::sys::GLint;
|
||||
use crate::render::gl::texture::GlTexture;
|
||||
use crate::render::renderer::framebuffer::Framebuffer;
|
||||
use crate::render::renderer::RENDERDOC;
|
||||
use crate::render::{RenderError, Texture};
|
||||
use renderdoc::{RenderDoc, V100};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use uapi::ustr;
|
||||
|
||||
pub struct RenderContext {
|
||||
pub(super) ctx: Rc<EglContext>,
|
||||
|
||||
pub(super) renderdoc: Option<RefCell<RenderDoc<V100>>>,
|
||||
|
||||
pub(super) tex_prog: GlProgram,
|
||||
pub(super) tex_prog_pos: GLint,
|
||||
pub(super) tex_prog_texcoord: GLint,
|
||||
pub(super) tex_prog_tex: GLint,
|
||||
|
||||
pub(super) fill_prog: GlProgram,
|
||||
pub(super) fill_prog_pos: GLint,
|
||||
pub(super) fill_prog_color: GLint,
|
||||
}
|
||||
|
||||
impl RenderContext {
|
||||
pub fn from_drm_device(drm: &Drm) -> Result<Self, RenderError> {
|
||||
let egl_dev = match find_drm_device(&drm)? {
|
||||
Some(d) => d,
|
||||
None => return Err(RenderError::UnknownDrmDevice),
|
||||
};
|
||||
let dpy = egl_dev.create_display()?;
|
||||
if !dpy.formats.contains_key(&XRGB8888.drm) {
|
||||
return Err(RenderError::XRGB888);
|
||||
}
|
||||
let ctx = dpy.create_context()?;
|
||||
ctx.with_current(|| unsafe { Self::new(&ctx) })
|
||||
}
|
||||
|
||||
unsafe fn new(ctx: &Rc<EglContext>) -> Result<Self, RenderError> {
|
||||
let tex_prog = GlProgram::from_shaders(
|
||||
ctx,
|
||||
include_str!("../shaders/tex.vert.glsl"),
|
||||
include_str!("../shaders/tex.frag.glsl"),
|
||||
)?;
|
||||
let fill_prog = GlProgram::from_shaders(
|
||||
ctx,
|
||||
include_str!("../shaders/fill.vert.glsl"),
|
||||
include_str!("../shaders/fill.frag.glsl"),
|
||||
)?;
|
||||
Ok(Self {
|
||||
ctx: ctx.clone(),
|
||||
|
||||
tex_prog_pos: tex_prog.get_attrib_location(ustr!("pos")),
|
||||
tex_prog_texcoord: tex_prog.get_attrib_location(ustr!("texcoord")),
|
||||
tex_prog_tex: tex_prog.get_uniform_location(ustr!("tex")),
|
||||
tex_prog,
|
||||
|
||||
fill_prog_pos: fill_prog.get_attrib_location(ustr!("pos")),
|
||||
fill_prog_color: fill_prog.get_uniform_location(ustr!("color")),
|
||||
fill_prog,
|
||||
|
||||
renderdoc: if RENDERDOC {
|
||||
Some(RefCell::new(RenderDoc::new().unwrap()))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn dmabuf_fb(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<Framebuffer>, RenderError> {
|
||||
self.ctx.with_current(|| unsafe {
|
||||
let img = self.ctx.dpy.import_dmabuf(buf)?;
|
||||
let rb = GlRenderBuffer::from_image(&img, &self.ctx)?;
|
||||
let fb = rb.create_framebuffer()?;
|
||||
Ok(Rc::new(Framebuffer {
|
||||
ctx: self.clone(),
|
||||
gl: fb,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn shmem_texture(
|
||||
self: &Rc<Self>,
|
||||
data: &[Cell<u8>],
|
||||
format: &'static Format,
|
||||
width: i32,
|
||||
height: i32,
|
||||
stride: i32,
|
||||
) -> Result<Rc<Texture>, RenderError> {
|
||||
let gl = GlTexture::import_texture(&self.ctx, data, format, width, height, stride)?;
|
||||
Ok(Rc::new(Texture {
|
||||
ctx: self.clone(),
|
||||
gl,
|
||||
}))
|
||||
}
|
||||
}
|
||||
40
src/render/renderer/framebuffer.rs
Normal file
40
src/render/renderer/framebuffer.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use crate::render::gl::frame_buffer::GlFrameBuffer;
|
||||
use crate::render::gl::sys::{
|
||||
glBindFramebuffer, glClear, glClearColor, glViewport, GL_COLOR_BUFFER_BIT, GL_FRAMEBUFFER,
|
||||
};
|
||||
use crate::render::renderer::context::RenderContext;
|
||||
use crate::render::renderer::renderer::Renderer;
|
||||
use crate::tree::Node;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Framebuffer {
|
||||
pub(super) ctx: Rc<RenderContext>,
|
||||
pub(super) gl: GlFrameBuffer,
|
||||
}
|
||||
|
||||
impl Framebuffer {
|
||||
pub fn render(&self, node: &dyn Node) {
|
||||
let _ = self.ctx.ctx.with_current(|| {
|
||||
if let Some(rd) = &self.ctx.renderdoc {
|
||||
rd.borrow_mut()
|
||||
.start_frame_capture(ptr::null(), ptr::null());
|
||||
}
|
||||
unsafe {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||
glViewport(0, 0, self.gl.width, self.gl.height);
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
let mut renderer = Renderer {
|
||||
renderer: &self.ctx,
|
||||
image: &self.gl,
|
||||
};
|
||||
node.render(&mut renderer, 0, 0);
|
||||
if let Some(rd) = &self.ctx.renderdoc {
|
||||
rd.borrow_mut().end_frame_capture(ptr::null(), ptr::null());
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
11
src/render/renderer/mod.rs
Normal file
11
src/render/renderer/mod.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
pub use context::*;
|
||||
pub use framebuffer::*;
|
||||
pub use renderer::*;
|
||||
pub use texture::*;
|
||||
|
||||
mod context;
|
||||
mod framebuffer;
|
||||
mod renderer;
|
||||
mod texture;
|
||||
|
||||
pub const RENDERDOC: bool = true;
|
||||
280
src/render/renderer/renderer.rs
Normal file
280
src/render/renderer/renderer.rs
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
use crate::ifs::wl_buffer::WlBuffer;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||
use crate::ifs::wl_surface::WlSurface;
|
||||
use crate::rect::Rect;
|
||||
use crate::render::gl::frame_buffer::{with_scissor, GlFrameBuffer};
|
||||
use crate::render::gl::sys::{
|
||||
glActiveTexture, glBindTexture, glDisableVertexAttribArray, glDrawArrays,
|
||||
glEnableVertexAttribArray, glTexParameteri, glUniform1i, glUniform4f, glUseProgram,
|
||||
glVertexAttribPointer, GL_FALSE, GL_FLOAT, GL_LINEAR, GL_TEXTURE0, GL_TEXTURE_2D,
|
||||
GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP,
|
||||
};
|
||||
use crate::render::renderer::context::RenderContext;
|
||||
use crate::tree::{
|
||||
ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, WorkspaceNode,
|
||||
CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::slice;
|
||||
|
||||
const NON_COLOR: (f32, f32, f32) = (0.2, 0.2, 0.2);
|
||||
const CHILD_COLOR: (f32, f32, f32) = (0.8, 0.8, 0.8);
|
||||
const YES_COLOR: (f32, f32, f32) = (0.0, 0.0, 1.0);
|
||||
|
||||
fn focus_color(focus: ContainerFocus) -> (f32, f32, f32) {
|
||||
match focus {
|
||||
ContainerFocus::None => NON_COLOR,
|
||||
ContainerFocus::Child => CHILD_COLOR,
|
||||
ContainerFocus::Yes => YES_COLOR,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Renderer<'a> {
|
||||
pub(super) renderer: &'a RenderContext,
|
||||
pub(super) image: &'a GlFrameBuffer,
|
||||
}
|
||||
|
||||
impl Renderer<'_> {
|
||||
pub fn render_output(&mut self, output: &OutputNode, x: i32, y: i32) {
|
||||
if let Some(ws) = output.workspace.get() {
|
||||
self.render_workspace(&ws, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_workspace(&mut self, workspace: &WorkspaceNode, x: i32, y: i32) {
|
||||
if let Some(node) = workspace.container.get() {
|
||||
self.render_container(&node, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
fn x_to_f(&self, x: i32) -> f32 {
|
||||
2.0 * (x as f32 / self.image.width as f32) - 1.0
|
||||
}
|
||||
|
||||
fn y_to_f(&self, y: i32) -> f32 {
|
||||
2.0 * (y as f32 / self.image.height as f32) - 1.0
|
||||
}
|
||||
|
||||
fn fill_boxes(&self, boxes: &[Rect], r: f32, g: f32, b: f32, a: f32) {
|
||||
let mut pos = Vec::with_capacity(boxes.len() * 12);
|
||||
for bx in boxes {
|
||||
let x1 = self.x_to_f(bx.x1());
|
||||
let y1 = self.y_to_f(bx.y1());
|
||||
let x2 = self.x_to_f(bx.x2());
|
||||
let y2 = self.y_to_f(bx.y2());
|
||||
pos.extend_from_slice(&[
|
||||
// triangle 1
|
||||
x2, y1, // top right
|
||||
x1, y1, // top left
|
||||
x1, y2, // bottom left
|
||||
// triangle 2
|
||||
x2, y1, // top right
|
||||
x1, y2, // bottom left
|
||||
x2, y2, // bottom right
|
||||
]);
|
||||
}
|
||||
unsafe {
|
||||
glUseProgram(self.renderer.fill_prog.prog);
|
||||
glUniform4f(self.renderer.fill_prog_color, r, g, b, a);
|
||||
glVertexAttribPointer(
|
||||
self.renderer.fill_prog_pos as _,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
0,
|
||||
pos.as_ptr() as _,
|
||||
);
|
||||
glEnableVertexAttribArray(self.renderer.fill_prog_pos as _);
|
||||
glDrawArrays(GL_TRIANGLES, 0, (boxes.len() * 6) as _);
|
||||
glDisableVertexAttribArray(self.renderer.fill_prog_pos as _);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) {
|
||||
let cwidth = container.width.get();
|
||||
let cheight = container.height.get();
|
||||
let num_children = container.num_children();
|
||||
let title_rect =
|
||||
Rect::new_sized(x, y, container.width.get(), CONTAINER_TITLE_HEIGHT).unwrap();
|
||||
if let Some(child) = container.mono_child.get() {
|
||||
let space_per_child = cwidth / num_children as i32;
|
||||
let mut rem = cwidth % num_children as i32;
|
||||
let mut pos = x;
|
||||
let (r, g, b) = focus_color(ContainerFocus::None);
|
||||
self.fill_boxes(slice::from_ref(&title_rect), r, g, b, 1.0);
|
||||
for child in container.children.iter() {
|
||||
let focus = child.focus.get();
|
||||
let (r, g, b) = focus_color(focus);
|
||||
let mut width = space_per_child;
|
||||
if rem > 0 {
|
||||
rem -= 1;
|
||||
width += 1;
|
||||
}
|
||||
if focus != ContainerFocus::None {
|
||||
let rect = Rect::new_sized(pos, y, width, CONTAINER_TITLE_HEIGHT).unwrap();
|
||||
self.fill_boxes(slice::from_ref(&rect), r, g, b, 1.0);
|
||||
}
|
||||
pos += width as i32;
|
||||
}
|
||||
unsafe {
|
||||
with_scissor(&container.mono_body.get(), || {
|
||||
let content = container.mono_content.get();
|
||||
child.node.render(self, x + content.x1(), y + content.y1());
|
||||
});
|
||||
}
|
||||
} else {
|
||||
let split = container.split.get();
|
||||
let mut rects = Vec::with_capacity(num_children);
|
||||
rects.push(title_rect);
|
||||
for (i, child) in container.children.iter().enumerate() {
|
||||
let body = child.body.get();
|
||||
if i + 1 < num_children {
|
||||
let rect = if split == ContainerSplit::Horizontal {
|
||||
Rect::new_sized(
|
||||
x + body.x2(),
|
||||
y + body.y1() - CONTAINER_TITLE_HEIGHT,
|
||||
CONTAINER_BORDER,
|
||||
container.height.get(),
|
||||
)
|
||||
.unwrap()
|
||||
} else {
|
||||
Rect::new_sized(
|
||||
x + body.x1(),
|
||||
y + body.y2(),
|
||||
container.width.get(),
|
||||
CONTAINER_BORDER,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
rects.push(rect);
|
||||
}
|
||||
}
|
||||
let (r, g, b) = focus_color(ContainerFocus::None);
|
||||
self.fill_boxes(&rects, r, g, b, 1.0);
|
||||
for child in container.children.iter() {
|
||||
let body = child.body.get();
|
||||
if body.x1() >= cwidth || body.y1() >= cheight {
|
||||
break;
|
||||
}
|
||||
unsafe {
|
||||
with_scissor(&body, || {
|
||||
let content = child.content.get();
|
||||
child.node.render(self, x + content.x1(), y + content.y1());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_toplevel(&mut self, tl: &XdgToplevel, mut x: i32, mut y: i32) {
|
||||
let surface = &tl.xdg.surface;
|
||||
if let Some(geo) = tl.xdg.geometry() {
|
||||
let (xt, yt) = geo.translate(x, y);
|
||||
x = xt;
|
||||
y = yt;
|
||||
}
|
||||
self.render_surface(surface, x, y);
|
||||
}
|
||||
|
||||
pub fn render_surface(&mut self, surface: &WlSurface, x: i32, y: i32) {
|
||||
let children = surface.children.borrow();
|
||||
let buffer = match surface.buffer.get() {
|
||||
Some(b) => b,
|
||||
_ => {
|
||||
log::warn!("surface has no buffer attached");
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Some(children) = children.deref() {
|
||||
macro_rules! render {
|
||||
($children:expr) => {
|
||||
for child in $children.rev_iter() {
|
||||
if child.pending.get() {
|
||||
continue;
|
||||
}
|
||||
let pos = child.sub_surface.position.get();
|
||||
self.render_surface(&child.sub_surface.surface, x + pos.x1(), y + pos.y1());
|
||||
}
|
||||
};
|
||||
}
|
||||
render!(&children.above);
|
||||
self.render_buffer(&buffer, x, y);
|
||||
render!(&children.below);
|
||||
} else {
|
||||
self.render_buffer(&buffer, x, y);
|
||||
}
|
||||
let mut fr = surface.frame_requests.borrow_mut();
|
||||
for cb in fr.drain(..) {
|
||||
surface.client.dispatch_frame_requests.push(cb);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_buffer(&mut self, buffer: &WlBuffer, x: i32, y: i32) {
|
||||
let texture = match buffer.texture.get() {
|
||||
Some(t) => t,
|
||||
_ => return,
|
||||
};
|
||||
assert!(Rc::ptr_eq(&self.renderer.ctx, &texture.ctx.ctx));
|
||||
unsafe {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture.gl.tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
glUseProgram(self.renderer.tex_prog.prog);
|
||||
|
||||
glUniform1i(self.renderer.tex_prog_tex, 0);
|
||||
|
||||
let texcoord: [f32; 8] = [1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0];
|
||||
|
||||
let f_width = self.image.width as f32;
|
||||
let f_height = self.image.height as f32;
|
||||
|
||||
let x1 = 2.0 * (x as f32 / f_width) - 1.0;
|
||||
let y1 = 2.0 * (y as f32 / f_height) - 1.0;
|
||||
let x2 = 2.0 * ((x + texture.gl.width) as f32 / f_width) - 1.0;
|
||||
let y2 = 2.0 * ((y + texture.gl.height) as f32 / f_height) - 1.0;
|
||||
|
||||
let pos: [f32; 8] = [
|
||||
x2, y1, // top right
|
||||
x1, y1, // top left
|
||||
x2, y2, // bottom right
|
||||
x1, y2, // bottom left
|
||||
];
|
||||
|
||||
glVertexAttribPointer(
|
||||
self.renderer.tex_prog_texcoord as _,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
0,
|
||||
texcoord.as_ptr() as _,
|
||||
);
|
||||
glVertexAttribPointer(
|
||||
self.renderer.tex_prog_pos as _,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
0,
|
||||
pos.as_ptr() as _,
|
||||
);
|
||||
|
||||
glEnableVertexAttribArray(self.renderer.tex_prog_texcoord as _);
|
||||
glEnableVertexAttribArray(self.renderer.tex_prog_pos as _);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glDisableVertexAttribArray(self.renderer.tex_prog_texcoord as _);
|
||||
glDisableVertexAttribArray(self.renderer.tex_prog_pos as _);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_floating(&mut self, floating: &FloatNode, x: i32, y: i32) {
|
||||
if let Some(child) = floating.child.get() {
|
||||
child.render(self, x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
8
src/render/renderer/texture.rs
Normal file
8
src/render/renderer/texture.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
use crate::render::gl::texture::GlTexture;
|
||||
use crate::render::renderer::context::RenderContext;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Texture {
|
||||
pub(super) ctx: Rc<RenderContext>,
|
||||
pub(super) gl: GlTexture,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue