render: split rendering into two phases
In the first phase we collect a list of simple operations (copying textures and filling rectangles.) In the second phase we send this list to the graphics API to be executed. As part of this, we also remove the use of scissors.
This commit is contained in:
parent
a2a04512ed
commit
5e8a6eb86f
27 changed files with 732 additions and 384 deletions
|
|
@ -295,6 +295,8 @@ fn render_img(image: &InstantiatedCursorImage, renderer: &mut Renderer, x: Fixed
|
|||
None,
|
||||
None,
|
||||
scale,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -306,9 +308,17 @@ impl Cursor for StaticCursor {
|
|||
|
||||
fn render_hardware_cursor(&self, renderer: &mut Renderer) {
|
||||
if let Some(img) = self.image.scales.get(&renderer.scale()) {
|
||||
renderer
|
||||
.base
|
||||
.render_texture(&img.tex, 0, 0, ARGB8888, None, None, renderer.scale());
|
||||
renderer.base.render_texture(
|
||||
&img.tex,
|
||||
0,
|
||||
0,
|
||||
ARGB8888,
|
||||
None,
|
||||
None,
|
||||
renderer.scale(),
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -336,9 +346,17 @@ impl Cursor for AnimatedCursor {
|
|||
fn render_hardware_cursor(&self, renderer: &mut Renderer) {
|
||||
let img = &self.images[self.idx.get()];
|
||||
if let Some(img) = img.scales.get(&renderer.scale()) {
|
||||
renderer
|
||||
.base
|
||||
.render_texture(&img.tex, 0, 0, ARGB8888, None, None, renderer.scale());
|
||||
renderer.base.render_texture(
|
||||
&img.tex,
|
||||
0,
|
||||
0,
|
||||
ARGB8888,
|
||||
None,
|
||||
None,
|
||||
renderer.scale(),
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ impl JayScreencast {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn copy_texture(&self, on: &OutputNode, texture: &Texture) {
|
||||
pub fn copy_texture(&self, on: &OutputNode, texture: &Rc<Texture>) {
|
||||
if !self.running.get() {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ impl WlOutputGlobal {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn perform_screencopies(&self, fb: &Framebuffer, tex: &Texture) {
|
||||
pub fn perform_screencopies(&self, fb: &Framebuffer, tex: &Rc<Texture>) {
|
||||
if self.pending_captures.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,10 @@ use {
|
|||
leaks::Tracker,
|
||||
object::Object,
|
||||
rect::{Rect, Region},
|
||||
render::Renderer,
|
||||
render::{
|
||||
gfx_api::{BufferPoint, BufferPoints},
|
||||
Renderer,
|
||||
},
|
||||
tree::{
|
||||
FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, NodeVisitorBase, OutputNode,
|
||||
ToplevelNode,
|
||||
|
|
@ -101,20 +104,6 @@ impl Transform {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct BufferPoint {
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct BufferPoints {
|
||||
top_right: BufferPoint,
|
||||
top_left: BufferPoint,
|
||||
bottom_right: BufferPoint,
|
||||
bottom_left: BufferPoint,
|
||||
}
|
||||
|
||||
impl Transform {
|
||||
fn apply_inv_sized(self, x1: f32, y1: f32, width: f32, height: f32) -> BufferPoints {
|
||||
let x2 = x1 + width;
|
||||
|
|
@ -237,7 +226,7 @@ pub struct WlSurface {
|
|||
input_region: Cell<Option<Rc<Region>>>,
|
||||
opaque_region: Cell<Option<Rc<Region>>>,
|
||||
buffer_points: RefCell<BufferPoints>,
|
||||
pub buffer_points_norm: RefCell<[f32; 8]>,
|
||||
pub buffer_points_norm: RefCell<BufferPoints>,
|
||||
buffer_transform: Cell<Transform>,
|
||||
buffer_scale: Cell<i32>,
|
||||
src_rect: Cell<Option<[Fixed; 4]>>,
|
||||
|
|
@ -817,35 +806,12 @@ impl WlSurface {
|
|||
.buffer_transform
|
||||
.get()
|
||||
.apply_inv_sized(0.0, 0.0, 1.0, 1.0);
|
||||
let points = &*buffer_points;
|
||||
*buffer_points_norm = [
|
||||
points.top_right.x,
|
||||
points.top_right.y,
|
||||
points.top_left.x,
|
||||
points.top_left.y,
|
||||
points.bottom_right.x,
|
||||
points.bottom_right.y,
|
||||
points.bottom_left.x,
|
||||
points.bottom_left.y,
|
||||
];
|
||||
*buffer_points_norm = *buffer_points;
|
||||
} else {
|
||||
let width = buffer.rect.width() as f32;
|
||||
let height = buffer.rect.height() as f32;
|
||||
let points = &*buffer_points;
|
||||
*buffer_points_norm = [
|
||||
points.top_right.x / width,
|
||||
points.top_right.y / height,
|
||||
points.top_left.x / width,
|
||||
points.top_left.y / height,
|
||||
points.bottom_right.x / width,
|
||||
points.bottom_right.y / height,
|
||||
points.bottom_left.x / width,
|
||||
points.bottom_left.y / height,
|
||||
];
|
||||
for &v in buffer_points_norm.iter() {
|
||||
if v > 1.0 {
|
||||
return Err(WlSurfaceError::ViewportOutsideBuffer);
|
||||
}
|
||||
*buffer_points_norm = buffer_points
|
||||
.norm(buffer.rect.width() as f32, buffer.rect.height() as f32);
|
||||
if !buffer_points_norm.is_leq_1() {
|
||||
return Err(WlSurfaceError::ViewportOutsideBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1134,8 +1100,15 @@ impl Node for WlSurface {
|
|||
}
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_surface(self, x, y);
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
max_width: i32,
|
||||
max_height: i32,
|
||||
) {
|
||||
renderer.render_surface(self, x, y, max_width, max_height);
|
||||
}
|
||||
|
||||
fn node_client(&self) -> Option<Rc<Client>> {
|
||||
|
|
|
|||
|
|
@ -76,16 +76,28 @@ impl Cursor for CursorSurface {
|
|||
let (hot_x, hot_y) = (Fixed::from_int(hot_x), Fixed::from_int(hot_y));
|
||||
let x = ((x - hot_x).to_f64() * scale).round() as _;
|
||||
let y = ((y - hot_y).to_f64() * scale).round() as _;
|
||||
renderer.render_surface_scaled(&self.surface, x, y, None);
|
||||
renderer.render_surface_scaled(&self.surface, x, y, None, i32::MAX, i32::MAX);
|
||||
} else {
|
||||
renderer.render_surface(&self.surface, x_int - hot_x, y_int - hot_y);
|
||||
renderer.render_surface(
|
||||
&self.surface,
|
||||
x_int - hot_x,
|
||||
y_int - hot_y,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_hardware_cursor(&self, renderer: &mut Renderer) {
|
||||
let extents = self.surface.extents.get();
|
||||
renderer.render_surface(&self.surface, -extents.x1(), -extents.y1());
|
||||
renderer.render_surface(
|
||||
&self.surface,
|
||||
-extents.x1(),
|
||||
-extents.y1(),
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
|
||||
struct FrameRequests;
|
||||
impl NodeVisitorBase for FrameRequests {
|
||||
|
|
|
|||
|
|
@ -334,8 +334,15 @@ impl Node for Xwindow {
|
|||
FindTreeResult::Other
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_surface(&self.x.surface, x, y)
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
max_width: i32,
|
||||
max_height: i32,
|
||||
) {
|
||||
renderer.render_surface(&self.x.surface, x, y, max_width, max_height)
|
||||
}
|
||||
|
||||
fn node_client(&self) -> Option<Rc<Client>> {
|
||||
|
|
|
|||
|
|
@ -308,8 +308,15 @@ impl Node for XdgPopup {
|
|||
self.xdg.find_tree_at(x, y, tree)
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_xdg_surface(&self.xdg, x, y)
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
max_width: i32,
|
||||
max_height: i32,
|
||||
) {
|
||||
renderer.render_xdg_surface(&self.xdg, x, y, max_width, max_height)
|
||||
}
|
||||
|
||||
fn node_client(&self) -> Option<Rc<Client>> {
|
||||
|
|
|
|||
|
|
@ -425,8 +425,15 @@ impl Node for XdgToplevel {
|
|||
self.xdg.find_tree_at(x, y, tree)
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_xdg_surface(&self.xdg, x, y)
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
max_width: i32,
|
||||
max_height: i32,
|
||||
) {
|
||||
renderer.render_xdg_surface(&self.xdg, x, y, max_width, max_height)
|
||||
}
|
||||
|
||||
fn node_client(&self) -> Option<Rc<Client>> {
|
||||
|
|
|
|||
|
|
@ -394,7 +394,14 @@ impl Node for ZwlrLayerSurfaceV1 {
|
|||
self.surface.find_tree_at_(x, y, tree)
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
_max_width: i32,
|
||||
_max_height: i32,
|
||||
) {
|
||||
renderer.render_layer_surface(self, x, y);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,6 +219,8 @@ impl GuiElement for Button {
|
|||
None,
|
||||
None,
|
||||
r.scale(),
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -315,6 +317,8 @@ impl GuiElement for Label {
|
|||
None,
|
||||
None,
|
||||
r.scale(),
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,13 @@
|
|||
use {
|
||||
crate::{
|
||||
rect::Rect,
|
||||
render::{
|
||||
egl::context::EglContext,
|
||||
gl::{
|
||||
render_buffer::GlRenderBuffer,
|
||||
sys::{glDeleteFramebuffers, GLuint},
|
||||
texture::GlTexture,
|
||||
},
|
||||
sys::{glDisable, glEnable, glScissor, GL_SCISSOR_TEST},
|
||||
crate::render::{
|
||||
egl::context::EglContext,
|
||||
gl::{
|
||||
render_buffer::GlRenderBuffer,
|
||||
sys::{glDeleteFramebuffers, GLuint},
|
||||
texture::GlTexture,
|
||||
},
|
||||
utils::ptr_ext::PtrExt,
|
||||
},
|
||||
std::{ptr, rc::Rc},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct GlFrameBuffer {
|
||||
|
|
@ -34,29 +29,3 @@ impl Drop for GlFrameBuffer {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn with_scissor<T, F: FnOnce() -> T>(scissor: &Rect, f: F) -> T {
|
||||
#[thread_local]
|
||||
static mut SCISSOR: *const Rect = ptr::null();
|
||||
|
||||
let prev = SCISSOR;
|
||||
if prev.is_null() {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
glScissor(
|
||||
scissor.x1(),
|
||||
scissor.y1(),
|
||||
scissor.width(),
|
||||
scissor.height(),
|
||||
);
|
||||
SCISSOR = scissor;
|
||||
let res = f();
|
||||
if prev.is_null() {
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
} else {
|
||||
let prev = prev.deref();
|
||||
glScissor(prev.x1(), prev.y1(), prev.width(), prev.height());
|
||||
}
|
||||
SCISSOR = prev;
|
||||
res
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ pub const GL_FRAMEBUFFER: GLenum = 0x8D40;
|
|||
pub const GL_LINEAR: GLint = 0x2601;
|
||||
pub const GL_LINK_STATUS: GLenum = 0x8B82;
|
||||
pub const GL_RENDERBUFFER: GLenum = 0x8D41;
|
||||
pub const GL_SCISSOR_TEST: GLenum = 0x0C11;
|
||||
pub const GL_TEXTURE0: GLenum = 0x84C0;
|
||||
pub const GL_TEXTURE_2D: GLenum = 0x0DE1;
|
||||
pub const GL_TEXTURE_EXTERNAL_OES: GLenum = 0x8D65;
|
||||
|
|
@ -106,7 +105,6 @@ extern "C" {
|
|||
pixels: *const c::c_void,
|
||||
);
|
||||
|
||||
pub fn glScissor(x: GLint, y: GLint, width: GLsizei, height: GLsizei);
|
||||
pub fn glEnable(cap: GLenum);
|
||||
pub fn glDisable(cap: GLenum);
|
||||
pub fn glViewport(x: GLint, y: GLint, width: GLsizei, height: GLsizei);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ pub use {context::*, framebuffer::*, image::*, renderer::*, renderer_base::*, te
|
|||
|
||||
mod context;
|
||||
mod framebuffer;
|
||||
pub mod gfx_api;
|
||||
mod gfx_apis;
|
||||
mod image;
|
||||
mod renderer;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ use {
|
|||
display::{EglDisplay, EglFormat},
|
||||
},
|
||||
ext::GlExt,
|
||||
gfx_api::GfxApiOpt,
|
||||
gl::{
|
||||
program::GlProgram, render_buffer::GlRenderBuffer, sys::GLint, texture::GlTexture,
|
||||
},
|
||||
renderer::{framebuffer::Framebuffer, image::Image},
|
||||
renderer::{framebuffer::Framebuffer, gfx_apis::gl::GfxGlState, image::Image},
|
||||
RenderError, Texture,
|
||||
},
|
||||
video::{
|
||||
|
|
@ -21,7 +22,7 @@ use {
|
|||
},
|
||||
ahash::AHashMap,
|
||||
std::{
|
||||
cell::Cell,
|
||||
cell::{Cell, RefCell},
|
||||
ffi::CString,
|
||||
fmt::{Debug, Formatter},
|
||||
rc::Rc,
|
||||
|
|
@ -64,6 +65,9 @@ pub struct RenderContext {
|
|||
pub(super) fill_prog: GlProgram,
|
||||
pub(super) fill_prog_pos: GLint,
|
||||
pub(super) fill_prog_color: GLint,
|
||||
|
||||
pub(super) gfx_ops: RefCell<Vec<GfxApiOpt>>,
|
||||
pub(super) gl_state: RefCell<GfxGlState>,
|
||||
}
|
||||
|
||||
impl Debug for RenderContext {
|
||||
|
|
@ -153,6 +157,9 @@ impl RenderContext {
|
|||
fill_prog_pos: fill_prog.get_attrib_location(ustr!("pos")),
|
||||
fill_prog_color: fill_prog.get_uniform_location(ustr!("color")),
|
||||
fill_prog,
|
||||
|
||||
gfx_ops: Default::default(),
|
||||
gl_state: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ use {
|
|||
GL_FRAMEBUFFER,
|
||||
},
|
||||
},
|
||||
renderer::{context::RenderContext, renderer::Renderer, renderer_base::RendererBase},
|
||||
renderer::{
|
||||
context::RenderContext, gfx_apis::gl::run_ops, renderer::Renderer,
|
||||
renderer_base::RendererBase,
|
||||
},
|
||||
sys::{glBlendFunc, glFlush, glReadnPixels, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
||||
RenderResult, Texture,
|
||||
},
|
||||
|
|
@ -55,7 +58,31 @@ impl Framebuffer {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn copy_texture(&self, state: &State, texture: &Texture, x: i32, y: i32, alpha: bool) {
|
||||
pub fn copy_texture(&self, state: &State, texture: &Rc<Texture>, x: i32, y: i32, alpha: bool) {
|
||||
let mut ops = self.ctx.gfx_ops.borrow_mut();
|
||||
ops.clear();
|
||||
let scale = Scale::from_int(1);
|
||||
let extents = Rect::new_sized(0, 0, self.gl.width, self.gl.height).unwrap();
|
||||
let mut renderer = Renderer {
|
||||
base: RendererBase {
|
||||
ops: &mut ops,
|
||||
scaled: false,
|
||||
scale,
|
||||
scalef: 1.0,
|
||||
},
|
||||
state,
|
||||
on_output: false,
|
||||
result: &mut RenderResult::default(),
|
||||
logical_extents: extents,
|
||||
physical_extents: extents,
|
||||
};
|
||||
let format = match alpha {
|
||||
true => ARGB8888,
|
||||
false => XRGB8888,
|
||||
};
|
||||
renderer
|
||||
.base
|
||||
.render_texture(texture, x, y, format, None, None, scale, i32::MAX, i32::MAX);
|
||||
let _ = self.ctx.ctx.with_current(|| {
|
||||
unsafe {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||
|
|
@ -66,27 +93,7 @@ impl Framebuffer {
|
|||
}
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
let scale = Scale::from_int(1);
|
||||
let mut renderer = Renderer {
|
||||
base: RendererBase {
|
||||
ctx: &self.ctx,
|
||||
fb: &self.gl,
|
||||
scaled: false,
|
||||
scale,
|
||||
scalef: 1.0,
|
||||
},
|
||||
state,
|
||||
on_output: false,
|
||||
result: &mut RenderResult::default(),
|
||||
logical_extents: Rect::new_sized(0, 0, self.gl.width, self.gl.height).unwrap(),
|
||||
};
|
||||
let format = match alpha {
|
||||
true => ARGB8888,
|
||||
false => XRGB8888,
|
||||
};
|
||||
renderer
|
||||
.base
|
||||
.render_texture(texture, x, y, format, None, None, scale);
|
||||
run_ops(self, &ops);
|
||||
unsafe {
|
||||
glFlush();
|
||||
}
|
||||
|
|
@ -124,20 +131,22 @@ impl Framebuffer {
|
|||
}
|
||||
|
||||
pub fn render_custom(&self, scale: Scale, f: impl FnOnce(&mut RendererBase)) {
|
||||
let mut ops = self.ctx.gfx_ops.borrow_mut();
|
||||
ops.clear();
|
||||
let mut renderer = RendererBase {
|
||||
ops: &mut ops,
|
||||
scaled: scale != 1,
|
||||
scale,
|
||||
scalef: scale.to_f64(),
|
||||
};
|
||||
f(&mut renderer);
|
||||
let _ = self.ctx.ctx.with_current(|| {
|
||||
unsafe {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||
glViewport(0, 0, self.gl.width, self.gl.height);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
let mut renderer = RendererBase {
|
||||
ctx: &self.ctx,
|
||||
fb: &self.gl,
|
||||
scaled: scale != 1,
|
||||
scale,
|
||||
scalef: scale.to_f64(),
|
||||
};
|
||||
f(&mut renderer);
|
||||
run_ops(self, &ops);
|
||||
unsafe {
|
||||
glFlush();
|
||||
}
|
||||
|
|
@ -155,6 +164,47 @@ impl Framebuffer {
|
|||
scale: Scale,
|
||||
render_hardware_cursor: bool,
|
||||
) {
|
||||
let mut ops = self.ctx.gfx_ops.borrow_mut();
|
||||
ops.clear();
|
||||
let mut renderer = Renderer {
|
||||
base: RendererBase {
|
||||
ops: &mut ops,
|
||||
scaled: scale != 1,
|
||||
scale,
|
||||
scalef: scale.to_f64(),
|
||||
},
|
||||
state,
|
||||
on_output,
|
||||
result,
|
||||
logical_extents: node.node_absolute_position().at_point(0, 0),
|
||||
physical_extents: Rect::new(0, 0, self.gl.width, self.gl.height).unwrap(),
|
||||
};
|
||||
node.node_render(&mut renderer, 0, 0, i32::MAX, i32::MAX);
|
||||
if let Some(rect) = cursor_rect {
|
||||
let seats = state.globals.lock_seats();
|
||||
for seat in seats.values() {
|
||||
if !render_hardware_cursor && seat.hardware_cursor() {
|
||||
continue;
|
||||
}
|
||||
if let Some(cursor) = seat.get_cursor() {
|
||||
let (mut x, mut y) = seat.get_position();
|
||||
if let Some(dnd_icon) = seat.dnd_icon() {
|
||||
let extents = dnd_icon.extents.get().move_(
|
||||
x.round_down() + dnd_icon.buf_x.get(),
|
||||
y.round_down() + dnd_icon.buf_y.get(),
|
||||
);
|
||||
if extents.intersects(&rect) {
|
||||
let (x, y) = rect.translate(extents.x1(), extents.y1());
|
||||
renderer.render_surface(&dnd_icon, x, y, i32::MAX, i32::MAX);
|
||||
}
|
||||
}
|
||||
cursor.tick();
|
||||
x -= Fixed::from_int(rect.x1());
|
||||
y -= Fixed::from_int(rect.y1());
|
||||
cursor.render(&mut renderer, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = self.ctx.ctx.with_current(|| {
|
||||
let c = state.theme.colors.background.get();
|
||||
unsafe {
|
||||
|
|
@ -164,45 +214,7 @@ impl Framebuffer {
|
|||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
let mut renderer = Renderer {
|
||||
base: RendererBase {
|
||||
ctx: &self.ctx,
|
||||
fb: &self.gl,
|
||||
scaled: scale != 1,
|
||||
scale,
|
||||
scalef: scale.to_f64(),
|
||||
},
|
||||
state,
|
||||
on_output,
|
||||
result,
|
||||
logical_extents: node.node_absolute_position().at_point(0, 0),
|
||||
};
|
||||
node.node_render(&mut renderer, 0, 0);
|
||||
if let Some(rect) = cursor_rect {
|
||||
let seats = state.globals.lock_seats();
|
||||
for seat in seats.values() {
|
||||
if !render_hardware_cursor && seat.hardware_cursor() {
|
||||
continue;
|
||||
}
|
||||
if let Some(cursor) = seat.get_cursor() {
|
||||
let (mut x, mut y) = seat.get_position();
|
||||
if let Some(dnd_icon) = seat.dnd_icon() {
|
||||
let extents = dnd_icon.extents.get().move_(
|
||||
x.round_down() + dnd_icon.buf_x.get(),
|
||||
y.round_down() + dnd_icon.buf_y.get(),
|
||||
);
|
||||
if extents.intersects(&rect) {
|
||||
let (x, y) = rect.translate(extents.x1(), extents.y1());
|
||||
renderer.render_surface(&dnd_icon, x, y);
|
||||
}
|
||||
}
|
||||
cursor.tick();
|
||||
x -= Fixed::from_int(rect.x1());
|
||||
y -= Fixed::from_int(rect.y1());
|
||||
cursor.render(&mut renderer, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
run_ops(self, &ops);
|
||||
unsafe {
|
||||
glFlush();
|
||||
}
|
||||
|
|
@ -211,6 +223,23 @@ impl Framebuffer {
|
|||
}
|
||||
|
||||
pub fn render_hardware_cursor(&self, cursor: &dyn Cursor, state: &State, scale: Scale) {
|
||||
let mut ops = self.ctx.gfx_ops.borrow_mut();
|
||||
ops.clear();
|
||||
let mut res = RenderResult::default();
|
||||
let mut renderer = Renderer {
|
||||
base: RendererBase {
|
||||
ops: &mut ops,
|
||||
scaled: scale != 1,
|
||||
scale,
|
||||
scalef: scale.to_f64(),
|
||||
},
|
||||
state,
|
||||
on_output: false,
|
||||
result: &mut res,
|
||||
logical_extents: Rect::new_empty(0, 0),
|
||||
physical_extents: Rect::new(0, 0, self.gl.width, self.gl.height).unwrap(),
|
||||
};
|
||||
cursor.render_hardware_cursor(&mut renderer);
|
||||
let _ = self.ctx.ctx.with_current(|| {
|
||||
unsafe {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||
|
|
@ -219,21 +248,7 @@ impl Framebuffer {
|
|||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
let mut res = RenderResult::default();
|
||||
let mut renderer = Renderer {
|
||||
base: RendererBase {
|
||||
ctx: &self.ctx,
|
||||
fb: &self.gl,
|
||||
scaled: scale != 1,
|
||||
scale,
|
||||
scalef: scale.to_f64(),
|
||||
},
|
||||
state,
|
||||
on_output: false,
|
||||
result: &mut res,
|
||||
logical_extents: Rect::new_empty(0, 0),
|
||||
};
|
||||
cursor.render_hardware_cursor(&mut renderer);
|
||||
run_ops(self, &ops);
|
||||
unsafe {
|
||||
glFlush();
|
||||
}
|
||||
|
|
|
|||
84
src/render/renderer/gfx_api.rs
Normal file
84
src/render/renderer/gfx_api.rs
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
use {
|
||||
crate::{format::Format, render::Texture, theme::Color},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub enum GfxApiOpt {
|
||||
Sync,
|
||||
Clear(Clear),
|
||||
FillRect(FillRect),
|
||||
CopyTexture(CopyTexture),
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone)]
|
||||
pub struct BufferPoint {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
impl BufferPoint {
|
||||
pub fn is_leq_1(&self) -> bool {
|
||||
self.x <= 1.0 && self.y <= 1.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone)]
|
||||
pub struct BufferPoints {
|
||||
pub top_left: BufferPoint,
|
||||
pub top_right: BufferPoint,
|
||||
pub bottom_left: BufferPoint,
|
||||
pub bottom_right: BufferPoint,
|
||||
}
|
||||
|
||||
impl BufferPoints {
|
||||
pub fn norm(&self, width: f32, height: f32) -> Self {
|
||||
Self {
|
||||
top_left: BufferPoint {
|
||||
x: self.top_left.x / width,
|
||||
y: self.top_left.y / height,
|
||||
},
|
||||
top_right: BufferPoint {
|
||||
x: self.top_right.x / width,
|
||||
y: self.top_right.y / height,
|
||||
},
|
||||
bottom_left: BufferPoint {
|
||||
x: self.bottom_left.x / width,
|
||||
y: self.bottom_left.y / height,
|
||||
},
|
||||
bottom_right: BufferPoint {
|
||||
x: self.bottom_right.x / width,
|
||||
y: self.bottom_right.y / height,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_leq_1(&self) -> bool {
|
||||
self.top_left.is_leq_1()
|
||||
&& self.top_right.is_leq_1()
|
||||
&& self.bottom_left.is_leq_1()
|
||||
&& self.bottom_right.is_leq_1()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AbsoluteRect {
|
||||
pub x1: f32,
|
||||
pub x2: f32,
|
||||
pub y1: f32,
|
||||
pub y2: f32,
|
||||
}
|
||||
|
||||
pub struct Clear {
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
pub struct FillRect {
|
||||
pub rect: AbsoluteRect,
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
pub struct CopyTexture {
|
||||
pub tex: Rc<Texture>,
|
||||
pub format: &'static Format,
|
||||
pub source: BufferPoints,
|
||||
pub target: AbsoluteRect,
|
||||
}
|
||||
|
|
@ -1,29 +1,129 @@
|
|||
use crate::{
|
||||
format::Format,
|
||||
render::{
|
||||
gl::{frame_buffer::GlFrameBuffer, texture::image_target},
|
||||
sys::{
|
||||
glActiveTexture, glBindTexture, glClear, glClearColor, glDisable,
|
||||
glDisableVertexAttribArray, glDrawArrays, glEnable, glEnableVertexAttribArray,
|
||||
glTexParameteri, glUniform1i, glUniform4f, glUseProgram, glVertexAttribPointer,
|
||||
GL_BLEND, GL_COLOR_BUFFER_BIT, GL_FALSE, GL_FLOAT, GL_LINEAR, GL_TEXTURE0,
|
||||
GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP,
|
||||
use {
|
||||
crate::{
|
||||
format::Format,
|
||||
render::{
|
||||
gfx_api::{BufferPoints, CopyTexture, FillRect, GfxApiOpt},
|
||||
gl::texture::image_target,
|
||||
sys::{
|
||||
glActiveTexture, glBindTexture, glClear, glClearColor, glDisable,
|
||||
glDisableVertexAttribArray, glDrawArrays, glEnable, glEnableVertexAttribArray,
|
||||
glTexParameteri, glUniform1i, glUniform4f, glUseProgram, glVertexAttribPointer,
|
||||
GL_BLEND, GL_COLOR_BUFFER_BIT, GL_FALSE, GL_FLOAT, GL_LINEAR, GL_TEXTURE0,
|
||||
GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP,
|
||||
},
|
||||
Framebuffer, RenderContext, Texture,
|
||||
},
|
||||
RenderContext, Texture,
|
||||
theme::Color,
|
||||
utils::{rc_eq::rc_eq, vecstorage::VecStorage},
|
||||
},
|
||||
scale::Scale,
|
||||
theme::Color,
|
||||
utils::rc_eq::rc_eq,
|
||||
isnt::std_1::vec::IsntVecExt,
|
||||
std::cell::RefCell,
|
||||
};
|
||||
|
||||
pub fn clear(c: &Color) {
|
||||
#[derive(Default)]
|
||||
pub struct GfxGlState {
|
||||
triangles: RefCell<Vec<f32>>,
|
||||
fill_rect: VecStorage<&'static FillRect>,
|
||||
copy_tex: VecStorage<&'static CopyTexture>,
|
||||
}
|
||||
|
||||
pub fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) {
|
||||
let mut state = fb.ctx.gl_state.borrow_mut();
|
||||
let state = &mut *state;
|
||||
let mut fill_rect = state.fill_rect.take();
|
||||
let fill_rect = &mut *fill_rect;
|
||||
let mut copy_tex = state.copy_tex.take();
|
||||
let copy_tex = &mut *copy_tex;
|
||||
let mut triangles = state.triangles.borrow_mut();
|
||||
let triangles = &mut *triangles;
|
||||
let width = fb.gl.width as f32;
|
||||
let height = fb.gl.height as f32;
|
||||
let mut i = 0;
|
||||
while i < ops.len() {
|
||||
macro_rules! has_ops {
|
||||
() => {
|
||||
fill_rect.is_not_empty() || copy_tex.is_not_empty()
|
||||
};
|
||||
}
|
||||
fill_rect.clear();
|
||||
copy_tex.clear();
|
||||
while i < ops.len() {
|
||||
match &ops[i] {
|
||||
GfxApiOpt::Sync => {
|
||||
i += 1;
|
||||
if has_ops!() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
GfxApiOpt::Clear(c) => {
|
||||
if has_ops!() {
|
||||
break;
|
||||
}
|
||||
clear(&c.color);
|
||||
i += 1;
|
||||
}
|
||||
GfxApiOpt::FillRect(f) => {
|
||||
fill_rect.push(f);
|
||||
i += 1;
|
||||
}
|
||||
GfxApiOpt::CopyTexture(c) => {
|
||||
copy_tex.push(c);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if fill_rect.is_not_empty() {
|
||||
fill_rect.sort_unstable_by_key(|f| f.color);
|
||||
let mut i = 0;
|
||||
while i < fill_rect.len() {
|
||||
triangles.clear();
|
||||
let mut color = None;
|
||||
while i < fill_rect.len() {
|
||||
let fr = fill_rect[i];
|
||||
match color {
|
||||
None => color = Some(fr.color),
|
||||
Some(c) if c == fr.color => {}
|
||||
_ => break,
|
||||
}
|
||||
let x1 = 2.0 * (fr.rect.x1 / width) - 1.0;
|
||||
let x2 = 2.0 * (fr.rect.x2 / width) - 1.0;
|
||||
let y1 = 2.0 * (fr.rect.y1 / height) - 1.0;
|
||||
let y2 = 2.0 * (fr.rect.y2 / height) - 1.0;
|
||||
triangles.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
|
||||
]);
|
||||
i += 1;
|
||||
}
|
||||
if let Some(color) = color {
|
||||
fill_boxes3(&fb.ctx, triangles, &color);
|
||||
}
|
||||
}
|
||||
}
|
||||
for tex in &*copy_tex {
|
||||
let x1 = 2.0 * (tex.target.x1 / width) - 1.0;
|
||||
let y1 = 2.0 * (tex.target.y1 / height) - 1.0;
|
||||
let x2 = 2.0 * (tex.target.x2 / width) - 1.0;
|
||||
let y2 = 2.0 * (tex.target.y2 / height) - 1.0;
|
||||
render_texture(&fb.ctx, &tex.tex, tex.format, x1, y1, x2, y2, &tex.source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clear(c: &Color) {
|
||||
unsafe {
|
||||
glClearColor(c.r, c.g, c.b, c.a);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fill_boxes3(ctx: &RenderContext, boxes: &[f32], color: &Color) {
|
||||
fn fill_boxes3(ctx: &RenderContext, boxes: &[f32], color: &Color) {
|
||||
unsafe {
|
||||
glUseProgram(ctx.fill_prog.prog);
|
||||
glUniform4f(ctx.fill_prog_color, color.r, color.g, color.b, color.a);
|
||||
|
|
@ -41,18 +141,15 @@ pub fn fill_boxes3(ctx: &RenderContext, boxes: &[f32], color: &Color) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn render_texture(
|
||||
fn render_texture(
|
||||
ctx: &RenderContext,
|
||||
fb: &GlFrameBuffer,
|
||||
texture: &Texture,
|
||||
x: i32,
|
||||
y: i32,
|
||||
format: &Format,
|
||||
tpoints: Option<&[f32; 8]>,
|
||||
tsize: Option<(i32, i32)>,
|
||||
tscale: Scale,
|
||||
scale: Scale,
|
||||
scalef: f64,
|
||||
x1: f32,
|
||||
y1: f32,
|
||||
x2: f32,
|
||||
y2: f32,
|
||||
src: &BufferPoints,
|
||||
) {
|
||||
assert!(rc_eq(&ctx.ctx, &texture.ctx.ctx));
|
||||
unsafe {
|
||||
|
|
@ -88,34 +185,18 @@ pub fn render_texture(
|
|||
|
||||
glUniform1i(prog.tex, 0);
|
||||
|
||||
static DEFAULT_TEXCOORD: [f32; 8] = [1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0];
|
||||
let texcoord = [
|
||||
src.top_right.x,
|
||||
src.top_right.y,
|
||||
src.top_left.x,
|
||||
src.top_left.y,
|
||||
src.bottom_right.x,
|
||||
src.bottom_right.y,
|
||||
src.bottom_left.x,
|
||||
src.bottom_left.y,
|
||||
];
|
||||
|
||||
let texcoord: &[f32; 8] = match tpoints {
|
||||
None => &DEFAULT_TEXCOORD,
|
||||
Some(tp) => tp,
|
||||
};
|
||||
|
||||
let f_width = fb.width as f32;
|
||||
let f_height = fb.height as f32;
|
||||
|
||||
let (twidth, theight) = if let Some(size) = tsize {
|
||||
size
|
||||
} else {
|
||||
let (mut w, mut h) = (texture.gl.width, texture.gl.height);
|
||||
if tscale != scale {
|
||||
let tscale = tscale.to_f64();
|
||||
w = (w as f64 * scalef / tscale).round() as _;
|
||||
h = (h as f64 * scalef / tscale).round() as _;
|
||||
}
|
||||
(w, h)
|
||||
};
|
||||
|
||||
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 + twidth) as f32 / f_width) - 1.0;
|
||||
let y2 = 2.0 * ((y + theight) as f32 / f_height) - 1.0;
|
||||
|
||||
let pos: [f32; 8] = [
|
||||
let pos = [
|
||||
x2, y1, // top right
|
||||
x1, y1, // top left
|
||||
x2, y2, // bottom right
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ use {
|
|||
wp_presentation_feedback::WpPresentationFeedback,
|
||||
},
|
||||
rect::Rect,
|
||||
render::{gl::frame_buffer::with_scissor, renderer::renderer_base::RendererBase},
|
||||
render::{
|
||||
gfx_api::GfxApiOpt,
|
||||
renderer::{gfx_api::BufferPoints, renderer_base::RendererBase},
|
||||
},
|
||||
scale::Scale,
|
||||
state::State,
|
||||
theme::Color,
|
||||
|
|
@ -45,6 +48,7 @@ pub struct Renderer<'a> {
|
|||
pub(super) on_output: bool,
|
||||
pub(super) result: &'a mut RenderResult,
|
||||
pub(super) logical_extents: Rect,
|
||||
pub(super) physical_extents: Rect,
|
||||
}
|
||||
|
||||
impl Renderer<'_> {
|
||||
|
|
@ -53,7 +57,7 @@ impl Renderer<'_> {
|
|||
}
|
||||
|
||||
pub fn physical_extents(&self) -> Rect {
|
||||
self.base.physical_extents()
|
||||
self.physical_extents
|
||||
}
|
||||
|
||||
pub fn logical_extents(&self) -> Rect {
|
||||
|
|
@ -74,7 +78,7 @@ impl Renderer<'_> {
|
|||
if self.state.lock.locked.get() {
|
||||
if let Some(surface) = output.lock_surface.get() {
|
||||
if surface.surface.buffer.get().is_some() {
|
||||
self.render_surface(&surface.surface, x, y);
|
||||
self.render_surface(&surface.surface, x, y, i32::MAX, i32::MAX);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
@ -94,7 +98,7 @@ impl Renderer<'_> {
|
|||
}
|
||||
if let Some(ws) = output.workspace.get() {
|
||||
if let Some(fs) = ws.fullscreen.get() {
|
||||
fs.tl_as_node().node_render(self, x, y);
|
||||
fs.tl_as_node().node_render(self, x, y, i32::MAX, i32::MAX);
|
||||
render_layer!(output.layers[2]);
|
||||
render_layer!(output.layers[3]);
|
||||
return;
|
||||
|
|
@ -136,13 +140,31 @@ impl Renderer<'_> {
|
|||
let scale = output.preferred_scale.get();
|
||||
for title in &rd.titles {
|
||||
let (x, y) = self.base.scale_point(x + title.tex_x, y + title.tex_y);
|
||||
self.base
|
||||
.render_texture(&title.tex, x, y, ARGB8888, None, None, scale);
|
||||
self.base.render_texture(
|
||||
&title.tex,
|
||||
x,
|
||||
y,
|
||||
ARGB8888,
|
||||
None,
|
||||
None,
|
||||
scale,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
if let Some(status) = &rd.status {
|
||||
let (x, y) = self.base.scale_point(x + status.tex_x, y + status.tex_y);
|
||||
self.base
|
||||
.render_texture(&status.tex, x, y, ARGB8888, None, None, scale);
|
||||
self.base.render_texture(
|
||||
&status.tex,
|
||||
x,
|
||||
y,
|
||||
ARGB8888,
|
||||
None,
|
||||
None,
|
||||
scale,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(ws) = output.workspace.get() {
|
||||
|
|
@ -150,10 +172,11 @@ impl Renderer<'_> {
|
|||
}
|
||||
for stacked in self.state.root.stacked.iter() {
|
||||
if stacked.node_visible() {
|
||||
self.base.ops.push(GfxApiOpt::Sync);
|
||||
let pos = stacked.node_absolute_position();
|
||||
if pos.intersects(&opos) {
|
||||
let (x, y) = opos.translate(pos.x1(), pos.y1());
|
||||
stacked.node_render(self, x, y);
|
||||
stacked.node_render(self, x, y, i32::MAX, i32::MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -176,8 +199,17 @@ impl Renderer<'_> {
|
|||
if let Some(tex) = placeholder.textures.get(&self.base.scale) {
|
||||
let x = x + (pos.width() - tex.width()) / 2;
|
||||
let y = y + (pos.height() - tex.height()) / 2;
|
||||
self.base
|
||||
.render_texture(&tex, x, y, ARGB8888, None, None, self.base.scale);
|
||||
self.base.render_texture(
|
||||
&tex,
|
||||
x,
|
||||
y,
|
||||
ARGB8888,
|
||||
None,
|
||||
None,
|
||||
self.base.scale,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,21 +244,23 @@ impl Renderer<'_> {
|
|||
None,
|
||||
None,
|
||||
self.base.scale,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(child) = container.mono_child.get() {
|
||||
unsafe {
|
||||
let body = container.mono_body.get().move_(x, y);
|
||||
let body = self.base.scale_rect(body);
|
||||
with_scissor(&body, || {
|
||||
let content = container.mono_content.get();
|
||||
child
|
||||
.node
|
||||
.node_render(self, x + content.x1(), y + content.y1());
|
||||
});
|
||||
}
|
||||
let body = container.mono_body.get().move_(x, y);
|
||||
let body = self.base.scale_rect(body);
|
||||
let content = container.mono_content.get();
|
||||
child.node.node_render(
|
||||
self,
|
||||
x + content.x1(),
|
||||
y + content.y1(),
|
||||
body.width(),
|
||||
body.height(),
|
||||
);
|
||||
} else {
|
||||
for child in container.children.iter() {
|
||||
let body = child.body.get();
|
||||
|
|
@ -235,31 +269,45 @@ impl Renderer<'_> {
|
|||
}
|
||||
let body = body.move_(x, y);
|
||||
let body = self.base.scale_rect(body);
|
||||
unsafe {
|
||||
with_scissor(&body, || {
|
||||
let content = child.content.get();
|
||||
child
|
||||
.node
|
||||
.node_render(self, x + content.x1(), y + content.y1());
|
||||
});
|
||||
}
|
||||
let content = child.content.get();
|
||||
child.node.node_render(
|
||||
self,
|
||||
x + content.x1(),
|
||||
y + content.y1(),
|
||||
body.width(),
|
||||
body.height(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_xdg_surface(&mut self, xdg: &XdgSurface, mut x: i32, mut y: i32) {
|
||||
pub fn render_xdg_surface(
|
||||
&mut self,
|
||||
xdg: &XdgSurface,
|
||||
mut x: i32,
|
||||
mut y: i32,
|
||||
max_width: i32,
|
||||
max_height: i32,
|
||||
) {
|
||||
let surface = &xdg.surface;
|
||||
if let Some(geo) = xdg.geometry() {
|
||||
let (xt, yt) = geo.translate(x, y);
|
||||
x = xt;
|
||||
y = yt;
|
||||
}
|
||||
self.render_surface(surface, x, y);
|
||||
self.render_surface(surface, x, y, max_width, max_height);
|
||||
}
|
||||
|
||||
pub fn render_surface(&mut self, surface: &WlSurface, x: i32, y: i32) {
|
||||
pub fn render_surface(
|
||||
&mut self,
|
||||
surface: &WlSurface,
|
||||
x: i32,
|
||||
y: i32,
|
||||
max_width: i32,
|
||||
max_height: i32,
|
||||
) {
|
||||
let (x, y) = self.base.scale_point(x, y);
|
||||
self.render_surface_scaled(surface, x, y, None);
|
||||
self.render_surface_scaled(surface, x, y, None, max_width, max_height);
|
||||
}
|
||||
|
||||
pub fn render_surface_scaled(
|
||||
|
|
@ -268,6 +316,8 @@ impl Renderer<'_> {
|
|||
x: i32,
|
||||
y: i32,
|
||||
pos_rel: Option<(i32, i32)>,
|
||||
max_width: i32,
|
||||
max_height: i32,
|
||||
) {
|
||||
let children = surface.children.borrow();
|
||||
let buffer = match surface.buffer.get() {
|
||||
|
|
@ -302,15 +352,17 @@ impl Renderer<'_> {
|
|||
x + x1,
|
||||
y + y1,
|
||||
Some((pos.x1(), pos.y1())),
|
||||
max_width,
|
||||
max_height,
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
render!(&children.below);
|
||||
self.render_buffer(&buffer, x, y, &tpoints, size);
|
||||
self.render_buffer(&buffer, x, y, *tpoints, size, max_width, max_height);
|
||||
render!(&children.above);
|
||||
} else {
|
||||
self.render_buffer(&buffer, x, y, &tpoints, size);
|
||||
self.render_buffer(&buffer, x, y, *tpoints, size, max_width, max_height);
|
||||
}
|
||||
if self.on_output {
|
||||
{
|
||||
|
|
@ -329,8 +381,10 @@ impl Renderer<'_> {
|
|||
buffer: &WlBuffer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
tpoints: &[f32; 8],
|
||||
tpoints: BufferPoints,
|
||||
tsize: (i32, i32),
|
||||
max_width: i32,
|
||||
max_height: i32,
|
||||
) {
|
||||
if let Some(tex) = buffer.texture.get() {
|
||||
self.base.render_texture(
|
||||
|
|
@ -341,6 +395,8 @@ impl Renderer<'_> {
|
|||
Some(tpoints),
|
||||
Some(tsize),
|
||||
self.base.scale,
|
||||
max_width,
|
||||
max_height,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -374,8 +430,17 @@ impl Renderer<'_> {
|
|||
self.base.fill_boxes(&title_underline, &uc);
|
||||
if let Some(title) = floating.title_textures.get(&self.base.scale) {
|
||||
let (x, y) = self.base.scale_point(x + bw, y + bw);
|
||||
self.base
|
||||
.render_texture(&title, x, y, ARGB8888, None, None, self.base.scale);
|
||||
self.base.render_texture(
|
||||
&title,
|
||||
x,
|
||||
y,
|
||||
ARGB8888,
|
||||
None,
|
||||
None,
|
||||
self.base.scale,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
);
|
||||
}
|
||||
let body = Rect::new_sized(
|
||||
x + bw,
|
||||
|
|
@ -385,20 +450,18 @@ impl Renderer<'_> {
|
|||
)
|
||||
.unwrap();
|
||||
let scissor_body = self.base.scale_rect(body);
|
||||
unsafe {
|
||||
with_scissor(&scissor_body, || {
|
||||
child.node_render(self, body.x1(), body.y1());
|
||||
});
|
||||
}
|
||||
child.node_render(
|
||||
self,
|
||||
body.x1(),
|
||||
body.y1(),
|
||||
scissor_body.width(),
|
||||
scissor_body.height(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn render_layer_surface(&mut self, surface: &ZwlrLayerSurfaceV1, x: i32, y: i32) {
|
||||
unsafe {
|
||||
let body = surface.position().at_point(x, y);
|
||||
let body = self.base.scale_rect(body);
|
||||
with_scissor(&body, || {
|
||||
self.render_surface(&surface.surface, x, y);
|
||||
});
|
||||
}
|
||||
let body = surface.position().at_point(x, y);
|
||||
let body = self.base.scale_rect(body);
|
||||
self.render_surface(&surface.surface, x, y, body.width(), body.height());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ use {
|
|||
format::Format,
|
||||
rect::Rect,
|
||||
render::{
|
||||
gl::frame_buffer::GlFrameBuffer,
|
||||
renderer::{context::RenderContext, gfx_apis::gl},
|
||||
gfx_api::Clear,
|
||||
renderer::gfx_api::{
|
||||
AbsoluteRect, BufferPoint, BufferPoints, CopyTexture, FillRect, GfxApiOpt,
|
||||
},
|
||||
Texture,
|
||||
},
|
||||
scale::Scale,
|
||||
|
|
@ -14,8 +16,7 @@ use {
|
|||
};
|
||||
|
||||
pub struct RendererBase<'a> {
|
||||
pub(super) ctx: &'a Rc<RenderContext>,
|
||||
pub(super) fb: &'a GlFrameBuffer,
|
||||
pub(super) ops: &'a mut Vec<GfxApiOpt>,
|
||||
pub(super) scaled: bool,
|
||||
pub(super) scale: Scale,
|
||||
pub(super) scalef: f64,
|
||||
|
|
@ -26,10 +27,6 @@ impl RendererBase<'_> {
|
|||
self.scale
|
||||
}
|
||||
|
||||
pub fn physical_extents(&self) -> Rect {
|
||||
Rect::new_sized(0, 0, self.fb.width, self.fb.height).unwrap()
|
||||
}
|
||||
|
||||
pub fn scale_point(&self, mut x: i32, mut y: i32) -> (i32, i32) {
|
||||
if self.scaled {
|
||||
x = (x as f64 * self.scalef).round() as _;
|
||||
|
|
@ -68,112 +65,138 @@ impl RendererBase<'_> {
|
|||
rect
|
||||
}
|
||||
|
||||
fn xf_to_f(&self, x: f32) -> f32 {
|
||||
2.0 * (x / self.fb.width as f32) - 1.0
|
||||
pub fn clear(&mut self, c: &Color) {
|
||||
self.ops.push(GfxApiOpt::Clear(Clear { color: *c }))
|
||||
}
|
||||
|
||||
fn yf_to_f(&self, y: f32) -> f32 {
|
||||
2.0 * (y / self.fb.height as f32) - 1.0
|
||||
}
|
||||
|
||||
fn x_to_f(&self, x: i32) -> f32 {
|
||||
2.0 * (x as f32 / self.fb.width as f32) - 1.0
|
||||
}
|
||||
|
||||
fn y_to_f(&self, y: i32) -> f32 {
|
||||
2.0 * (y as f32 / self.fb.height as f32) - 1.0
|
||||
}
|
||||
|
||||
pub fn clear(&self, c: &Color) {
|
||||
gl::clear(c);
|
||||
}
|
||||
|
||||
pub fn fill_boxes(&self, boxes: &[Rect], color: &Color) {
|
||||
pub fn fill_boxes(&mut self, boxes: &[Rect], color: &Color) {
|
||||
self.fill_boxes2(boxes, color, 0, 0);
|
||||
}
|
||||
|
||||
pub fn fill_boxes2(&self, boxes: &[Rect], color: &Color, dx: i32, dy: i32) {
|
||||
pub fn fill_boxes2(&mut self, boxes: &[Rect], color: &Color, dx: i32, dy: i32) {
|
||||
if boxes.is_empty() {
|
||||
return;
|
||||
}
|
||||
let (dx, dy) = self.scale_point(dx, dy);
|
||||
let mut pos = Vec::with_capacity(boxes.len() * 12);
|
||||
for bx in boxes {
|
||||
let bx = self.scale_rect(*bx);
|
||||
let x1 = self.x_to_f(bx.x1() + dx);
|
||||
let y1 = self.y_to_f(bx.y1() + dy);
|
||||
let x2 = self.x_to_f(bx.x2() + dx);
|
||||
let y2 = self.y_to_f(bx.y2() + dy);
|
||||
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
|
||||
]);
|
||||
self.ops.push(GfxApiOpt::FillRect(FillRect {
|
||||
rect: AbsoluteRect {
|
||||
x1: (bx.x1() + dx) as f32,
|
||||
y1: (bx.y1() + dy) as f32,
|
||||
x2: (bx.x2() + dx) as f32,
|
||||
y2: (bx.y2() + dy) as f32,
|
||||
},
|
||||
color: *color,
|
||||
}));
|
||||
}
|
||||
self.fill_boxes3(&pos, color)
|
||||
}
|
||||
|
||||
pub fn fill_boxes_f(&self, boxes: &[(f32, f32, f32, f32)], color: &Color) {
|
||||
pub fn fill_boxes_f(&mut self, boxes: &[(f32, f32, f32, f32)], color: &Color) {
|
||||
self.fill_boxes2_f(boxes, color, 0.0, 0.0);
|
||||
}
|
||||
|
||||
pub fn fill_boxes2_f(&self, boxes: &[(f32, f32, f32, f32)], color: &Color, dx: f32, dy: f32) {
|
||||
pub fn fill_boxes2_f(
|
||||
&mut self,
|
||||
boxes: &[(f32, f32, f32, f32)],
|
||||
color: &Color,
|
||||
dx: f32,
|
||||
dy: f32,
|
||||
) {
|
||||
if boxes.is_empty() {
|
||||
return;
|
||||
}
|
||||
let (dx, dy) = self.scale_point_f(dx, dy);
|
||||
let mut pos = Vec::with_capacity(boxes.len() * 12);
|
||||
for bx in boxes {
|
||||
let (x1, y1, x2, y2) = self.scale_rect_f(*bx);
|
||||
let x1 = self.xf_to_f(x1 + dx);
|
||||
let y1 = self.yf_to_f(y1 + dy);
|
||||
let x2 = self.xf_to_f(x2 + dx);
|
||||
let y2 = self.yf_to_f(y2 + dy);
|
||||
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
|
||||
]);
|
||||
self.ops.push(GfxApiOpt::FillRect(FillRect {
|
||||
rect: AbsoluteRect {
|
||||
x1: x1 + dx,
|
||||
y1: y1 + dy,
|
||||
x2: x2 + dx,
|
||||
y2: y2 + dy,
|
||||
},
|
||||
color: *color,
|
||||
}));
|
||||
}
|
||||
self.fill_boxes3(&pos, color)
|
||||
}
|
||||
|
||||
fn fill_boxes3(&self, boxes: &[f32], color: &Color) {
|
||||
gl::fill_boxes3(&self.ctx, boxes, color);
|
||||
}
|
||||
|
||||
pub fn render_texture(
|
||||
&mut self,
|
||||
texture: &Texture,
|
||||
texture: &Rc<Texture>,
|
||||
x: i32,
|
||||
y: i32,
|
||||
format: &Format,
|
||||
tpoints: Option<&[f32; 8]>,
|
||||
format: &'static Format,
|
||||
tpoints: Option<BufferPoints>,
|
||||
tsize: Option<(i32, i32)>,
|
||||
tscale: Scale,
|
||||
max_width: i32,
|
||||
max_height: i32,
|
||||
) {
|
||||
gl::render_texture(
|
||||
&self.ctx,
|
||||
&self.fb,
|
||||
texture,
|
||||
x,
|
||||
y,
|
||||
let mut texcoord = tpoints.unwrap_or(BufferPoints {
|
||||
top_left: BufferPoint { x: 0.0, y: 0.0 },
|
||||
top_right: BufferPoint { x: 1.0, y: 0.0 },
|
||||
bottom_left: BufferPoint { x: 0.0, y: 1.0 },
|
||||
bottom_right: BufferPoint { x: 1.0, y: 1.0 },
|
||||
});
|
||||
|
||||
let (twidth, theight) = if let Some(size) = tsize {
|
||||
size
|
||||
} else {
|
||||
let (mut w, mut h) = (texture.gl.width, texture.gl.height);
|
||||
if tscale != self.scale {
|
||||
let tscale = tscale.to_f64();
|
||||
w = (w as f64 * self.scalef / tscale).round() as _;
|
||||
h = (h as f64 * self.scalef / tscale).round() as _;
|
||||
}
|
||||
(w, h)
|
||||
};
|
||||
|
||||
macro_rules! clamp {
|
||||
($desired:ident, $max:ident, $([$far:ident, $near:ident]),*) => {
|
||||
if $desired > $max {
|
||||
let $desired = $desired as f32;
|
||||
let $max = $max as f32;
|
||||
let factor = $max / $desired;
|
||||
$(
|
||||
let dx = (texcoord.$far.x - texcoord.$near.x) * factor;
|
||||
texcoord.$far.x = texcoord.$near.x + dx;
|
||||
let dy = (texcoord.$far.y - texcoord.$near.y) * factor;
|
||||
texcoord.$far.y = texcoord.$near.y + dy;
|
||||
)*
|
||||
$max
|
||||
} else {
|
||||
$desired as f32
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let twidth = clamp!(
|
||||
twidth,
|
||||
max_width,
|
||||
[top_right, top_left],
|
||||
[bottom_right, bottom_left]
|
||||
);
|
||||
let theight = clamp!(
|
||||
theight,
|
||||
max_height,
|
||||
[bottom_left, top_left],
|
||||
[bottom_right, top_right]
|
||||
);
|
||||
|
||||
let x = x as f32;
|
||||
let y = y as f32;
|
||||
|
||||
self.ops.push(GfxApiOpt::CopyTexture(CopyTexture {
|
||||
tex: texture.clone(),
|
||||
format,
|
||||
tpoints,
|
||||
tsize,
|
||||
tscale,
|
||||
self.scale,
|
||||
self.scalef,
|
||||
)
|
||||
source: texcoord,
|
||||
target: AbsoluteRect {
|
||||
x1: x,
|
||||
y1: y,
|
||||
x2: x + twidth,
|
||||
y2: y + theight,
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
src/theme.rs
25
src/theme.rs
|
|
@ -1,6 +1,9 @@
|
|||
use std::cell::{Cell, RefCell};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
cmp::Ordering,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct Color {
|
||||
pub r: f32,
|
||||
pub g: f32,
|
||||
|
|
@ -8,6 +11,24 @@ pub struct Color {
|
|||
pub a: f32,
|
||||
}
|
||||
|
||||
impl Eq for Color {}
|
||||
|
||||
impl Ord for Color {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.r
|
||||
.total_cmp(&other.r)
|
||||
.then_with(|| self.g.total_cmp(&other.g))
|
||||
.then_with(|| self.b.total_cmp(&other.b))
|
||||
.then_with(|| self.a.total_cmp(&other.a))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Color {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
fn to_f32(c: u8) -> f32 {
|
||||
c as f32 / 255f32
|
||||
}
|
||||
|
|
|
|||
11
src/tree.rs
11
src/tree.rs
|
|
@ -137,10 +137,19 @@ pub trait Node: 'static {
|
|||
let _ = (child, active, depth);
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
max_width: i32,
|
||||
max_height: i32,
|
||||
) {
|
||||
let _ = renderer;
|
||||
let _ = x;
|
||||
let _ = y;
|
||||
let _ = max_width;
|
||||
let _ = max_height;
|
||||
}
|
||||
|
||||
fn node_client(&self) -> Option<Rc<Client>> {
|
||||
|
|
|
|||
|
|
@ -1085,7 +1085,14 @@ impl Node for ContainerNode {
|
|||
.node_child_active_changed(self.deref(), active, depth + 1);
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
_max_width: i32,
|
||||
_max_height: i32,
|
||||
) {
|
||||
renderer.render_container(self, x, y);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,14 @@ impl Node for DisplayNode {
|
|||
FindTreeResult::AcceptsInput
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
_max_width: i32,
|
||||
_max_height: i32,
|
||||
) {
|
||||
renderer.render_display(self, x, y);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -420,7 +420,14 @@ impl Node for FloatNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
_max_width: i32,
|
||||
_max_height: i32,
|
||||
) {
|
||||
renderer.render_floating(self, x, y)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ pub async fn output_render_data(state: Rc<State>) {
|
|||
}
|
||||
|
||||
impl OutputNode {
|
||||
pub fn perform_screencopies(&self, fb: &Framebuffer, tex: &Texture) {
|
||||
pub fn perform_screencopies(&self, fb: &Framebuffer, tex: &Rc<Texture>) {
|
||||
if let Some(workspace) = self.workspace.get() {
|
||||
if !workspace.capture.get() {
|
||||
return;
|
||||
|
|
@ -620,7 +620,14 @@ impl Node for OutputNode {
|
|||
FindTreeResult::AcceptsInput
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
_max_width: i32,
|
||||
_max_height: i32,
|
||||
) {
|
||||
renderer.render_output(self, x, y);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,14 @@ impl Node for PlaceholderNode {
|
|||
FindTreeResult::AcceptsInput
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
_max_width: i32,
|
||||
_max_height: i32,
|
||||
) {
|
||||
renderer.render_placeholder(self, x, y);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,14 @@ impl Node for WorkspaceNode {
|
|||
FindTreeResult::AcceptsInput
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
fn node_render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
x: i32,
|
||||
y: i32,
|
||||
_max_width: i32,
|
||||
_max_height: i32,
|
||||
) {
|
||||
renderer.render_workspace(self, x, y);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue