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
6
build.rs
6
build.rs
|
|
@ -147,7 +147,8 @@ fn write_egl_procs<W: Write>(f: &mut W) -> anyhow::Result<()> {
|
|||
];
|
||||
|
||||
writeln!(f, "use std::ptr;")?;
|
||||
writeln!(f, "use super::sys::*;")?;
|
||||
writeln!(f, "use super::gl::sys::*;")?;
|
||||
writeln!(f, "use super::egl::sys::*;")?;
|
||||
writeln!(f)?;
|
||||
writeln!(f, "#[derive(Copy, Clone, Debug)]")?;
|
||||
writeln!(f, "pub struct ExtProc {{")?;
|
||||
|
|
@ -156,6 +157,9 @@ fn write_egl_procs<W: Write>(f: &mut W) -> anyhow::Result<()> {
|
|||
}
|
||||
writeln!(f, "}}")?;
|
||||
writeln!(f)?;
|
||||
writeln!(f, "unsafe impl Sync for ExtProc {{ }}")?;
|
||||
writeln!(f, "unsafe impl Send for ExtProc {{ }}")?;
|
||||
writeln!(f)?;
|
||||
writeln!(f, "impl ExtProc {{")?;
|
||||
writeln!(f, " pub fn load() -> Self {{")?;
|
||||
writeln!(f, " Self {{")?;
|
||||
|
|
|
|||
|
|
@ -4,31 +4,21 @@ use crate::backend::{
|
|||
use crate::drm::drm::{Drm, DrmError};
|
||||
use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING};
|
||||
use crate::drm::{ModifiedFormat, INVALID_MODIFIER};
|
||||
use crate::egl::{EglContext, EglImage};
|
||||
use crate::event_loop::{EventLoopDispatcher, EventLoopId};
|
||||
use crate::fixed::Fixed;
|
||||
use crate::format::XRGB8888;
|
||||
use crate::gles2::gl::{GlFrameBuffer, GlRenderBuffer, GlTexture};
|
||||
use crate::gles2::sys::{glBindFramebuffer, glFlush, glViewport, GL_FRAMEBUFFER};
|
||||
use crate::gles2::GlesError;
|
||||
use crate::pixman::{Image, PixmanError};
|
||||
use crate::render::gles::{GlesRenderer, RENDERDOC};
|
||||
use crate::render::pixman::PixmanRenderer;
|
||||
use crate::render::Renderer;
|
||||
use crate::servermem::{ServerMem, ServerMemError};
|
||||
use crate::tree::Node;
|
||||
use crate::render::{Framebuffer, RenderContext, RenderError};
|
||||
use crate::servermem::ServerMemError;
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::utils::ptr_ext::PtrExt;
|
||||
use crate::wheel::{WheelDispatcher, WheelId};
|
||||
use crate::{gles2, pixman, EventLoopError, NumCell, State, WheelError};
|
||||
use gles2::egl;
|
||||
use crate::{EventLoopError, NumCell, State, WheelError};
|
||||
use isnt::std_1::primitive::IsntConstPtrExt;
|
||||
use rand::Rng;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::VecDeque;
|
||||
use std::error::Error;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
|
|
@ -45,16 +35,12 @@ pub enum XorgBackendError {
|
|||
DrmError(#[from] DrmError),
|
||||
#[error("The gbm subsystem returned an error")]
|
||||
GbmError(#[from] GbmError),
|
||||
#[error("Could not find an EGL device that matches the display's DRM device")]
|
||||
MissingEglDevice,
|
||||
#[error("Could not import a dma-buf")]
|
||||
ImportBuffer(#[source] XcbError),
|
||||
#[error("The EGL device does not support the XRGB8888 format")]
|
||||
XRGB8888,
|
||||
#[error("Could not create an EGL context")]
|
||||
CreateEgl(#[source] Box<Self>),
|
||||
#[error(transparent)]
|
||||
EglError(#[from] GlesError),
|
||||
CreateEgl(#[source] RenderError),
|
||||
#[error("Could not create a framebuffer from a dma-buf")]
|
||||
CreateFramebuffer(#[source] RenderError),
|
||||
#[error("Could not select input events")]
|
||||
CannotSelectInputEvents(#[source] XcbError),
|
||||
#[error("Could not select present events")]
|
||||
|
|
@ -69,10 +55,6 @@ pub enum XorgBackendError {
|
|||
WheelError(#[source] Box<WheelError>),
|
||||
#[error("Could not allocate and map image memory")]
|
||||
ServerMemError(#[source] Box<ServerMemError>),
|
||||
#[error("Pixman returned an error")]
|
||||
PixmanError(#[source] Box<PixmanError>),
|
||||
#[error("dupfd failed")]
|
||||
DupfdFailed(#[source] std::io::Error),
|
||||
#[error("Could not create a window")]
|
||||
CreateWindow(#[source] XcbError),
|
||||
#[error("Could not set WM_CLASS")]
|
||||
|
|
@ -86,7 +68,6 @@ pub enum XorgBackendError {
|
|||
}
|
||||
efrom!(XorgBackendError, EventLoopError, EventLoopError);
|
||||
efrom!(XorgBackendError, ServerMemError, ServerMemError);
|
||||
efrom!(XorgBackendError, PixmanError, PixmanError);
|
||||
efrom!(XorgBackendError, WheelError, WheelError);
|
||||
|
||||
struct XcbCon {
|
||||
|
|
@ -221,8 +202,7 @@ pub struct XorgBackend {
|
|||
outputs: CopyHashMap<ffi::xcb_window_t, Rc<XorgOutput>>,
|
||||
seats: CopyHashMap<ffi::xcb_input_device_id_t, Rc<XorgSeat>>,
|
||||
mouse_seats: CopyHashMap<ffi::xcb_input_device_id_t, Rc<XorgSeat>>,
|
||||
ctx: Rc<EglContext>,
|
||||
renderer: GlesRenderer,
|
||||
ctx: Rc<RenderContext>,
|
||||
gbm: GbmDevice,
|
||||
r: Cell<f32>,
|
||||
g: Cell<f32>,
|
||||
|
|
@ -251,24 +231,11 @@ impl XorgBackend {
|
|||
let con = XcbCon::new()?;
|
||||
|
||||
let drm = get_drm(&con)?;
|
||||
let res = (|| {
|
||||
let egl_dev = match egl::find_drm_device(&drm)? {
|
||||
Some(d) => d,
|
||||
None => return Err(XorgBackendError::MissingEglDevice),
|
||||
};
|
||||
let dpy = egl_dev.create_display()?;
|
||||
if !dpy.formats.contains_key(&XRGB8888.drm) {
|
||||
return Err(XorgBackendError::XRGB8888);
|
||||
}
|
||||
let ctx = dpy.create_context()?;
|
||||
Ok(ctx)
|
||||
})();
|
||||
let ctx = match res {
|
||||
Ok(r) => r,
|
||||
Err(e) => return Err(XorgBackendError::CreateEgl(Box::new(e))),
|
||||
};
|
||||
let renderer = ctx.with_current(|| GlesRenderer::new(&ctx))?;
|
||||
let gbm = GbmDevice::new(&drm)?;
|
||||
let ctx = match RenderContext::from_drm_device(&drm) {
|
||||
Ok(r) => Rc::new(r),
|
||||
Err(e) => return Err(XorgBackendError::CreateEgl(e)),
|
||||
};
|
||||
|
||||
let fd = con.xcb.xcb_get_file_descriptor(con.c);
|
||||
|
||||
|
|
@ -283,7 +250,6 @@ impl XorgBackend {
|
|||
seats: Default::default(),
|
||||
mouse_seats: Default::default(),
|
||||
ctx: ctx.clone(),
|
||||
renderer,
|
||||
gbm,
|
||||
r: Cell::new(0.0),
|
||||
g: Cell::new(0.0),
|
||||
|
|
@ -311,7 +277,7 @@ impl XorgBackend {
|
|||
slf.query_devices(ffi::XCB_INPUT_DEVICE_ALL_MASTER as _)?;
|
||||
slf.handle_events()?;
|
||||
|
||||
state.egl.set(Some(ctx.clone()));
|
||||
state.render_ctx.set(Some(ctx.clone()));
|
||||
|
||||
Ok(slf)
|
||||
}
|
||||
|
|
@ -337,12 +303,9 @@ impl XorgBackend {
|
|||
let plane = dma.planes.first().unwrap();
|
||||
let size = plane.stride * dma.height as u32;
|
||||
let fd = uapi::fcntl_dupfd_cloexec(plane.fd.raw(), 0).unwrap();
|
||||
let fb = if RENDERDOC {
|
||||
unsafe { GlTexture::new(&self.ctx, XRGB8888, width, height)?.to_framebuffer()? }
|
||||
} else {
|
||||
let egl_img = self.ctx.dpy.import_dmabuf(dma)?;
|
||||
let rb = GlRenderBuffer::from_image(&egl_img, &self.ctx)?;
|
||||
rb.create_framebuffer()?
|
||||
let fb = match self.ctx.dmabuf_fb(dma) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return Err(XorgBackendError::CreateFramebuffer(e)),
|
||||
};
|
||||
let pixmap = unsafe {
|
||||
let pixmap = self.con.xcb.xcb_generate_id(self.con.c);
|
||||
|
|
@ -416,7 +379,6 @@ impl XorgBackend {
|
|||
serial: Default::default(),
|
||||
next_msc: Cell::new(0),
|
||||
next_image: Default::default(),
|
||||
image: RefCell::new(None),
|
||||
cb: CloneCell::new(None),
|
||||
images,
|
||||
});
|
||||
|
|
@ -695,17 +657,7 @@ impl XorgBackend {
|
|||
|
||||
if let Some(node) = self.state.root.outputs.get(&output.id) {
|
||||
let fb = image.fb.get();
|
||||
let mut renderer = self.renderer.render_fb(&fb);
|
||||
self.ctx
|
||||
.with_current(|| unsafe {
|
||||
fb.bind();
|
||||
glViewport(0, 0, fb.width, fb.height);
|
||||
// fb.clear(0.0, 0.0, 0.0, 1.0);
|
||||
renderer.render_output(&node);
|
||||
glFlush();
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
fb.render(&*node);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
|
|
@ -890,7 +842,6 @@ impl XorgBackend {
|
|||
_ => return Ok(()),
|
||||
};
|
||||
output.removed.set(true);
|
||||
*output.image.borrow_mut() = None;
|
||||
output.changed();
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -911,87 +862,12 @@ impl XorgBackend {
|
|||
unsafe {
|
||||
let images = self.create_images(output.window, width, height).unwrap();
|
||||
for (new, old) in images.iter().zip(output.images.iter()) {
|
||||
unsafe {
|
||||
self.con.xcb.xcb_free_pixmap(self.con.c, old.pixmap.get());
|
||||
}
|
||||
self.con.xcb.xcb_free_pixmap(self.con.c, old.pixmap.get());
|
||||
old.fb.set(new.fb.get());
|
||||
old.pixmap.set(new.pixmap.get());
|
||||
}
|
||||
}
|
||||
// let shm = Rc::new(ServerMem::new((width * height * 4) as usize)?);
|
||||
// let fd = shm.fd();
|
||||
// let image = Image::new(shm, pixman::X8R8G8B8, width, height, width * 4)?;
|
||||
// *output.image.borrow_mut() = Some(image);
|
||||
// unsafe {
|
||||
// let fd = match uapi::fcntl_dupfd_cloexec(fd, 0) {
|
||||
// Ok(fd) => fd,
|
||||
// Err(e) => return Err(XorgBackendError::DupfdFailed(e.into())),
|
||||
// };
|
||||
// let shmseg = self.con.xcb.xcb_generate_id(self.con.c);
|
||||
// let cookie =
|
||||
// self.con
|
||||
// .shm
|
||||
// .xcb_shm_attach_fd_checked(self.con.c, shmseg, fd.unwrap(), 0);
|
||||
// self.con.check_cookie(cookie)?;
|
||||
// let pixmap = self.con.xcb.xcb_generate_id(self.con.c);
|
||||
// let cookie = self.con.shm.xcb_shm_create_pixmap(
|
||||
// self.con.c,
|
||||
// pixmap,
|
||||
// output.window,
|
||||
// width as _,
|
||||
// height as _,
|
||||
// 24,
|
||||
// shmseg,
|
||||
// 0,
|
||||
// );
|
||||
// self.con.check_cookie(cookie)?;
|
||||
// let cookie = self.con.xcb.xcb_change_window_attributes_checked(
|
||||
// self.con.c,
|
||||
// output.window,
|
||||
// ffi::XCB_CW_BACK_PIXMAP,
|
||||
// &pixmap as *const _ as _,
|
||||
// );
|
||||
// self.con.check_cookie(cookie)?;
|
||||
// self.con.xcb.xcb_free_pixmap(self.con.c, pixmap);
|
||||
// self.con.shm.xcb_shm_detach(self.con.c, shmseg);
|
||||
// }
|
||||
output.changed();
|
||||
// self.render()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render(&self) -> Result<(), XorgBackendError> {
|
||||
return Ok(());
|
||||
let outputs = self.outputs.lock();
|
||||
for output in outputs.values() {
|
||||
let image = output.image.borrow();
|
||||
let image = match image.deref() {
|
||||
Some(i) => i,
|
||||
None => continue,
|
||||
};
|
||||
let _ = image.fill(0, 0, 0, 255);
|
||||
let node = match self.state.root.outputs.get(&output.id) {
|
||||
Some(n) => n,
|
||||
_ => continue,
|
||||
};
|
||||
let pos = node.position.get();
|
||||
let mut renderer = PixmanRenderer::new(image);
|
||||
renderer.render_output(&node);
|
||||
for floating in self.state.root.floaters.iter() {
|
||||
let fpos = floating.position.get();
|
||||
if floating.visible.get() && fpos.intersects(&pos) {
|
||||
let (x, y) = pos.translate(fpos.x1(), fpos.x2());
|
||||
floating.render(&mut renderer, x, y);
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
let cookie =
|
||||
self.con
|
||||
.xcb
|
||||
.xcb_clear_area_checked(self.con.c, 0, output.window, 0, 0, 0, 0);
|
||||
self.con.check_cookie(cookie)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1009,8 +885,6 @@ impl EventLoopDispatcher for XorgBackend {
|
|||
|
||||
impl WheelDispatcher for XorgBackend {
|
||||
fn dispatch(self: Rc<Self>) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
self.render()?;
|
||||
self.handle_events()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1033,13 +907,12 @@ struct XorgOutput {
|
|||
next_msc: Cell<u64>,
|
||||
next_image: NumCell<usize>,
|
||||
images: [XorgImage; 2],
|
||||
image: RefCell<Option<Image<Rc<ServerMem>>>>,
|
||||
cb: CloneCell<Option<Rc<dyn Fn()>>>,
|
||||
}
|
||||
|
||||
struct XorgImage {
|
||||
pixmap: Cell<ffi::xcb_pixmap_t>,
|
||||
fb: CloneCell<Rc<GlFrameBuffer>>,
|
||||
fb: CloneCell<Rc<Framebuffer>>,
|
||||
idle: Cell<bool>,
|
||||
render_on_idle: Cell<bool>,
|
||||
last_serial: Cell<u32>,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use crate::pixman::PixmanMemory;
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
|
|
@ -165,14 +164,3 @@ pub fn init() -> Result<(), ClientMemError> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl PixmanMemory for ClientMemOffset {
|
||||
type E = ClientMemError;
|
||||
|
||||
fn access<T, F>(&self, f: F) -> Result<T, Self::E>
|
||||
where
|
||||
F: FnOnce(&[Cell<u8>]) -> T,
|
||||
{
|
||||
ClientMemOffset::access(self, f)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ use uapi::{c, Errno, OwnedFd, Ustring};
|
|||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DrmError {
|
||||
#[error("Could not create a lease")]
|
||||
CreateLeaseError(#[source] std::io::Error),
|
||||
#[error("Could not reopen a node")]
|
||||
ReopenNode(#[source] std::io::Error),
|
||||
#[error("Could not retrieve the render node name")]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::gles2::sys::{GLint, GL_BGRA_EXT, GL_UNSIGNED_BYTE};
|
||||
use crate::pixman;
|
||||
use crate::render::sys::{GLint, GL_BGRA_EXT, GL_UNSIGNED_BYTE};
|
||||
use ahash::AHashMap;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
|
|
|
|||
487
src/gles2/egl.rs
487
src/gles2/egl.rs
|
|
@ -1,487 +0,0 @@
|
|||
use super::ext::{get_client_ext, ClientExt};
|
||||
use super::ext_proc::ExtProc;
|
||||
use super::sys::{
|
||||
eglBindAPI, EGLAttrib, EGLLabelKHR, EGLenum, EGLint, EGL_BAD_ACCESS, EGL_BAD_ALLOC,
|
||||
EGL_BAD_ATTRIBUTE, EGL_BAD_CONFIG, EGL_BAD_CONTEXT, EGL_BAD_CURRENT_SURFACE,
|
||||
EGL_BAD_DEVICE_EXT, EGL_BAD_DISPLAY, EGL_BAD_MATCH, EGL_BAD_NATIVE_PIXMAP,
|
||||
EGL_BAD_NATIVE_WINDOW, EGL_BAD_PARAMETER, EGL_BAD_SURFACE, EGL_CONTEXT_LOST,
|
||||
EGL_DEBUG_MSG_CRITICAL_KHR, EGL_DEBUG_MSG_ERROR_KHR, EGL_DEBUG_MSG_INFO_KHR,
|
||||
EGL_DEBUG_MSG_WARN_KHR, EGL_NONE, EGL_NOT_INITIALIZED, EGL_OPENGL_ES_API, EGL_SUCCESS,
|
||||
EGL_TRUE,
|
||||
};
|
||||
use super::GlesError;
|
||||
use crate::drm::dma::DmaBuf;
|
||||
use crate::drm::drm::Drm;
|
||||
use crate::drm::INVALID_MODIFIER;
|
||||
use crate::format::{formats, Format};
|
||||
use crate::gles2::ext::{
|
||||
get_device_ext, get_display_ext, get_gl_ext, DeviceExt, DisplayExt, GlExt,
|
||||
};
|
||||
use crate::gles2::gl::GlTexture;
|
||||
use crate::gles2::sys::{
|
||||
eglCreateContext, eglDestroyContext, eglInitialize, eglMakeCurrent, eglTerminate,
|
||||
glBindFramebuffer, glBindRenderbuffer, glBindTexture, glCheckFramebufferStatus, glClear,
|
||||
glClearColor, glDeleteFramebuffers, glDeleteRenderbuffers, glFlush, glFramebufferRenderbuffer,
|
||||
glGenFramebuffers, glGenRenderbuffers, glGenTextures, glPixelStorei, glTexImage2D,
|
||||
glTexParameteri, EGLClientBuffer, EGLConfig, EGLContext, EGLDeviceEXT, EGLDisplay, EGLImageKHR,
|
||||
EGLSurface, GLeglImageOES, GLint, GLuint, EGL_CONTEXT_CLIENT_VERSION,
|
||||
EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
|
||||
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE0_OFFSET_EXT,
|
||||
EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE1_FD_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
|
||||
EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT,
|
||||
EGL_DMA_BUF_PLANE1_PITCH_EXT, EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
|
||||
EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE2_OFFSET_EXT,
|
||||
EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE3_FD_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
|
||||
EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE3_OFFSET_EXT,
|
||||
EGL_DMA_BUF_PLANE3_PITCH_EXT, EGL_DRM_DEVICE_FILE_EXT, EGL_FALSE, EGL_HEIGHT,
|
||||
EGL_IMAGE_PRESERVED_KHR, EGL_LINUX_DMA_BUF_EXT, EGL_LINUX_DRM_FOURCC_EXT,
|
||||
EGL_PLATFORM_DEVICE_EXT, EGL_WIDTH, GL_CLAMP_TO_EDGE, GL_COLOR_ATTACHMENT0,
|
||||
GL_COLOR_BUFFER_BIT, GL_FRAMEBUFFER, GL_FRAMEBUFFER_COMPLETE, GL_RENDERBUFFER, GL_TEXTURE_2D,
|
||||
GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_UNPACK_ROW_LENGTH_EXT,
|
||||
};
|
||||
use crate::rect::Rect;
|
||||
use ahash::AHashMap;
|
||||
use bstr::ByteSlice;
|
||||
use log::Level;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::cell::Cell;
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use uapi::c;
|
||||
|
||||
#[thread_local]
|
||||
pub(super) static PROCS: Lazy<ExtProc> = Lazy::new(|| ExtProc::load());
|
||||
|
||||
#[thread_local]
|
||||
pub(super) static EXTS: Lazy<ClientExt> = Lazy::new(|| get_client_ext());
|
||||
|
||||
pub fn init() -> Result<(), GlesError> {
|
||||
if !EXTS.contains(ClientExt::EXT_PLATFORM_BASE) {
|
||||
return Err(GlesError::ExtPlatformBase);
|
||||
}
|
||||
if !EXTS.device_query() {
|
||||
return Err(GlesError::DeviceQuery);
|
||||
}
|
||||
if !EXTS.device_enumeration() {
|
||||
return Err(GlesError::DeviceEnumeration);
|
||||
}
|
||||
if EXTS.contains(ClientExt::KHR_DEBUG) {
|
||||
let attrib: &[EGLAttrib] = &[
|
||||
EGL_DEBUG_MSG_CRITICAL_KHR as _,
|
||||
EGL_TRUE as _,
|
||||
EGL_DEBUG_MSG_ERROR_KHR as _,
|
||||
EGL_TRUE as _,
|
||||
EGL_DEBUG_MSG_WARN_KHR as _,
|
||||
EGL_TRUE as _,
|
||||
EGL_DEBUG_MSG_INFO_KHR as _,
|
||||
EGL_TRUE as _,
|
||||
EGL_NONE as _,
|
||||
];
|
||||
unsafe {
|
||||
PROCS.eglDebugMessageControlKHR(egl_log, attrib.as_ptr());
|
||||
}
|
||||
}
|
||||
if unsafe { eglBindAPI(EGL_OPENGL_ES_API) } != EGL_TRUE {
|
||||
return Err(GlesError::BindFailed);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn find_drm_device(drm: &Drm) -> Result<Option<EglDevice>, GlesError> {
|
||||
let drm_dev = drm.get_device()?;
|
||||
for device in query_devices()? {
|
||||
if device.exts.contains(DeviceExt::EXT_DEVICE_DRM) {
|
||||
let device_file = device.query_string(EGL_DRM_DEVICE_FILE_EXT)?;
|
||||
for (_, name) in drm_dev.nodes() {
|
||||
if device_file == name {
|
||||
return Ok(Some(device));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn query_devices() -> Result<Vec<EglDevice>, GlesError> {
|
||||
if !EXTS.device_enumeration() {
|
||||
return Err(GlesError::DeviceEnumeration);
|
||||
}
|
||||
unsafe {
|
||||
let mut devices = vec![];
|
||||
let mut num_devices = 0;
|
||||
let res = PROCS.eglQueryDevicesEXT(num_devices, ptr::null_mut(), &mut num_devices);
|
||||
if res != EGL_TRUE {
|
||||
return Err(GlesError::QueryDevices);
|
||||
}
|
||||
devices.reserve_exact(num_devices as usize);
|
||||
let res = PROCS.eglQueryDevicesEXT(num_devices, devices.as_mut_ptr(), &mut num_devices);
|
||||
if res != EGL_TRUE {
|
||||
return Err(GlesError::QueryDevices);
|
||||
}
|
||||
devices.set_len(num_devices as usize);
|
||||
Ok(devices
|
||||
.into_iter()
|
||||
.map(|d| EglDevice {
|
||||
exts: get_device_ext(d),
|
||||
dev: d,
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct EglDevice {
|
||||
pub exts: DeviceExt,
|
||||
dev: EGLDeviceEXT,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EglDisplay {
|
||||
pub exts: DisplayExt,
|
||||
pub formats: AHashMap<u32, &'static Format>,
|
||||
dev: EglDevice,
|
||||
dpy: EGLDisplay,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EglContext {
|
||||
pub dpy: Rc<EglDisplay>,
|
||||
pub ext: GlExt,
|
||||
ctx: EGLContext,
|
||||
|
||||
pub tex_prog: GLuint,
|
||||
pub tex_tex: GLint,
|
||||
pub tex_texcoord: GLint,
|
||||
pub tex_pos: GLint,
|
||||
}
|
||||
|
||||
impl EglDisplay {
|
||||
pub fn create_context(self: &Rc<Self>) -> Result<Rc<EglContext>, GlesError> {
|
||||
let attrib = [EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE];
|
||||
unsafe {
|
||||
let ctx = eglCreateContext(
|
||||
self.dpy,
|
||||
EGLConfig::none(),
|
||||
EGLContext::none(),
|
||||
attrib.as_ptr(),
|
||||
);
|
||||
if ctx.is_none() {
|
||||
return Err(GlesError::CreateContext);
|
||||
}
|
||||
let mut ctx = EglContext {
|
||||
dpy: self.clone(),
|
||||
ext: GlExt::empty(),
|
||||
ctx,
|
||||
tex_prog: 0,
|
||||
tex_tex: 0,
|
||||
tex_texcoord: 0,
|
||||
tex_pos: 0,
|
||||
};
|
||||
ctx.ext = ctx.with_current(|| Ok(get_gl_ext()))?;
|
||||
// if !ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE) {
|
||||
// return Err(GlesError::OesEglImage);
|
||||
// }
|
||||
Ok(Rc::new(ctx))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn import_dmabuf(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<EglImage>, GlesError> {
|
||||
struct PlaneKey {
|
||||
fd: EGLint,
|
||||
offset: EGLint,
|
||||
pitch: EGLint,
|
||||
mod_lo: EGLint,
|
||||
mod_hi: EGLint,
|
||||
}
|
||||
const PLANE_KEYS: [PlaneKey; 4] = [
|
||||
PlaneKey {
|
||||
fd: EGL_DMA_BUF_PLANE0_FD_EXT,
|
||||
offset: EGL_DMA_BUF_PLANE0_OFFSET_EXT,
|
||||
pitch: EGL_DMA_BUF_PLANE0_PITCH_EXT,
|
||||
mod_lo: EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
|
||||
mod_hi: EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
|
||||
},
|
||||
PlaneKey {
|
||||
fd: EGL_DMA_BUF_PLANE1_FD_EXT,
|
||||
offset: EGL_DMA_BUF_PLANE1_OFFSET_EXT,
|
||||
pitch: EGL_DMA_BUF_PLANE1_PITCH_EXT,
|
||||
mod_lo: EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
|
||||
mod_hi: EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
|
||||
},
|
||||
PlaneKey {
|
||||
fd: EGL_DMA_BUF_PLANE2_FD_EXT,
|
||||
offset: EGL_DMA_BUF_PLANE2_OFFSET_EXT,
|
||||
pitch: EGL_DMA_BUF_PLANE2_PITCH_EXT,
|
||||
mod_lo: EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
|
||||
mod_hi: EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
|
||||
},
|
||||
PlaneKey {
|
||||
fd: EGL_DMA_BUF_PLANE3_FD_EXT,
|
||||
offset: EGL_DMA_BUF_PLANE3_OFFSET_EXT,
|
||||
pitch: EGL_DMA_BUF_PLANE3_PITCH_EXT,
|
||||
mod_lo: EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
|
||||
mod_hi: EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
|
||||
},
|
||||
];
|
||||
|
||||
let mut attribs = vec![];
|
||||
attribs.extend_from_slice(&[EGL_WIDTH, buf.width]);
|
||||
attribs.extend_from_slice(&[EGL_HEIGHT, buf.height]);
|
||||
attribs.extend_from_slice(&[EGL_LINUX_DRM_FOURCC_EXT, buf.format.drm as _]);
|
||||
attribs.extend_from_slice(&[EGL_IMAGE_PRESERVED_KHR, EGL_TRUE as _]);
|
||||
for (key, plane) in PLANE_KEYS.iter().zip(buf.planes.iter()) {
|
||||
attribs.extend_from_slice(&[key.fd, plane.fd.raw()]);
|
||||
attribs.extend_from_slice(&[key.pitch, plane.stride as _]);
|
||||
attribs.extend_from_slice(&[key.offset, plane.offset as _]);
|
||||
if buf.modifier != INVALID_MODIFIER {
|
||||
attribs.extend_from_slice(&[key.mod_lo, buf.modifier as i32]);
|
||||
attribs.extend_from_slice(&[key.mod_hi, (buf.modifier >> 32) as i32]);
|
||||
}
|
||||
}
|
||||
attribs.push(EGL_NONE);
|
||||
let img = unsafe {
|
||||
PROCS.eglCreateImageKHR(
|
||||
self.dpy,
|
||||
EGLContext::none(),
|
||||
EGL_LINUX_DMA_BUF_EXT as _,
|
||||
EGLClientBuffer::none(),
|
||||
attribs.as_ptr(),
|
||||
)
|
||||
};
|
||||
if img.is_none() {
|
||||
return Err(GlesError::CreateImage);
|
||||
}
|
||||
Ok(Rc::new(EglImage {
|
||||
dpy: self.clone(),
|
||||
img,
|
||||
width: buf.width,
|
||||
height: buf.height,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EglImage {
|
||||
dpy: Rc<EglDisplay>,
|
||||
pub(super) img: EGLImageKHR,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
impl Drop for EglImage {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if PROCS.eglDestroyImageKHR(self.dpy.dpy, self.img) == EGL_FALSE {
|
||||
log::warn!("`eglDestroyImageKHR` failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for EglContext {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if eglDestroyContext(self.dpy.dpy, self.ctx) != EGL_TRUE {
|
||||
log::warn!("`eglDestroyContext` failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[thread_local]
|
||||
static mut CURRENT: EGLContext = EGLContext::none();
|
||||
|
||||
impl EglContext {
|
||||
#[inline]
|
||||
pub fn with_current<T, F: FnOnce() -> Result<T, GlesError>>(
|
||||
&self,
|
||||
f: F,
|
||||
) -> Result<T, GlesError> {
|
||||
unsafe {
|
||||
if CURRENT == self.ctx {
|
||||
return f();
|
||||
}
|
||||
self.with_current_slow(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cold]
|
||||
unsafe fn with_current_slow<T, F: FnOnce() -> Result<T, GlesError>>(
|
||||
&self,
|
||||
f: F,
|
||||
) -> Result<T, GlesError> {
|
||||
if eglMakeCurrent(
|
||||
self.dpy.dpy,
|
||||
EGLSurface::none(),
|
||||
EGLSurface::none(),
|
||||
self.ctx,
|
||||
) == EGL_FALSE
|
||||
{
|
||||
return Err(GlesError::MakeCurrent);
|
||||
}
|
||||
let prev = CURRENT;
|
||||
CURRENT = self.ctx;
|
||||
let res = f();
|
||||
if eglMakeCurrent(self.dpy.dpy, EGLSurface::none(), EGLSurface::none(), prev) == EGL_FALSE {
|
||||
panic!("Could not restore EGLContext");
|
||||
}
|
||||
CURRENT = prev;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for EglDisplay {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if eglTerminate(self.dpy) != EGL_TRUE {
|
||||
log::warn!("`eglTerminate` failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EglDevice {
|
||||
pub fn query_string(&self, name: EGLint) -> Result<&'static CStr, GlesError> {
|
||||
unsafe {
|
||||
let res = PROCS.eglQueryDeviceStringEXT(self.dev, name);
|
||||
if res.is_null() {
|
||||
return Err(GlesError::DeviceQueryString);
|
||||
}
|
||||
Ok(CStr::from_ptr(res))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_display(&self) -> Result<Rc<EglDisplay>, GlesError> {
|
||||
unsafe {
|
||||
let dpy = PROCS.eglGetPlatformDisplayEXT(
|
||||
EGL_PLATFORM_DEVICE_EXT as _,
|
||||
self.dev.0,
|
||||
ptr::null(),
|
||||
);
|
||||
if dpy.is_none() {
|
||||
return Err(GlesError::GetDisplay);
|
||||
}
|
||||
let mut dpy = EglDisplay {
|
||||
exts: DisplayExt::empty(),
|
||||
formats: AHashMap::new(),
|
||||
dev: *self,
|
||||
dpy,
|
||||
};
|
||||
let mut major = 0;
|
||||
let mut minor = 0;
|
||||
if eglInitialize(dpy.dpy, &mut major, &mut minor) != EGL_TRUE {
|
||||
return Err(GlesError::Initialize);
|
||||
}
|
||||
dpy.exts = get_display_ext(dpy.dpy);
|
||||
if !dpy.exts.intersects(DisplayExt::KHR_IMAGE_BASE) {
|
||||
return Err(GlesError::ImageBase);
|
||||
}
|
||||
if !dpy
|
||||
.exts
|
||||
.intersects(DisplayExt::EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS)
|
||||
{
|
||||
return Err(GlesError::DmaBufImport);
|
||||
}
|
||||
if !dpy
|
||||
.exts
|
||||
.intersects(DisplayExt::KHR_NO_CONFIG_CONTEXT | DisplayExt::MESA_CONFIGLESS_CONTEXT)
|
||||
{
|
||||
return Err(GlesError::ConfiglessContext);
|
||||
}
|
||||
if !dpy.exts.intersects(DisplayExt::KHR_SURFACELESS_CONTEXT) {
|
||||
return Err(GlesError::SurfacelessContext);
|
||||
}
|
||||
dpy.formats = query_formats(dpy.dpy)?;
|
||||
|
||||
Ok(Rc::new(dpy))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn query_formats(dpy: EGLDisplay) -> Result<AHashMap<u32, &'static Format>, GlesError> {
|
||||
let mut vec = vec![];
|
||||
let mut num = 0;
|
||||
let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, ptr::null_mut(), &mut num);
|
||||
if res != EGL_TRUE {
|
||||
return Err(GlesError::QueryDmaBufFormats);
|
||||
}
|
||||
vec.reserve_exact(num as usize);
|
||||
let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, vec.as_mut_ptr(), &mut num);
|
||||
if res != EGL_TRUE {
|
||||
return Err(GlesError::QueryDmaBufFormats);
|
||||
}
|
||||
vec.set_len(num as usize);
|
||||
let mut res = AHashMap::new();
|
||||
let formats = formats();
|
||||
for fmt in vec {
|
||||
if let Some(format) = formats.get(&(fmt as u32)) {
|
||||
res.insert(format.drm, *format);
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
unsafe extern "C" fn egl_log(
|
||||
error: EGLenum,
|
||||
command: *const c::c_char,
|
||||
message_type: EGLint,
|
||||
_thread_label: EGLLabelKHR,
|
||||
_object_label: EGLLabelKHR,
|
||||
message: *const c::c_char,
|
||||
) {
|
||||
let level = match message_type {
|
||||
EGL_DEBUG_MSG_CRITICAL_KHR => Level::Error,
|
||||
EGL_DEBUG_MSG_ERROR_KHR => Level::Error,
|
||||
EGL_DEBUG_MSG_WARN_KHR => Level::Warn,
|
||||
EGL_DEBUG_MSG_INFO_KHR => Level::Info,
|
||||
_ => Level::Warn,
|
||||
};
|
||||
let command = if !command.is_null() {
|
||||
CStr::from_ptr(command).to_bytes()
|
||||
} else {
|
||||
b"none"
|
||||
};
|
||||
let message = if !message.is_null() {
|
||||
CStr::from_ptr(message).to_bytes()
|
||||
} else {
|
||||
b"none"
|
||||
};
|
||||
let err_name = error_name(error);
|
||||
log::log!(
|
||||
level,
|
||||
"EGL: command: {}, error: {} (0x{:x}), message: {}",
|
||||
command.as_bstr(),
|
||||
err_name,
|
||||
error,
|
||||
message.as_bstr()
|
||||
);
|
||||
}
|
||||
|
||||
fn error_name(error: EGLenum) -> &'static str {
|
||||
macro_rules! en {
|
||||
($($name:ident,)*) => {
|
||||
match error as _ {
|
||||
$($name => stringify!($name),)*
|
||||
_ => "unknown",
|
||||
}
|
||||
}
|
||||
}
|
||||
en! {
|
||||
EGL_SUCCESS,
|
||||
EGL_NOT_INITIALIZED,
|
||||
EGL_BAD_ACCESS,
|
||||
EGL_BAD_ALLOC,
|
||||
EGL_BAD_ATTRIBUTE,
|
||||
EGL_BAD_CONTEXT,
|
||||
EGL_BAD_CONFIG,
|
||||
EGL_BAD_CURRENT_SURFACE,
|
||||
EGL_BAD_DISPLAY,
|
||||
EGL_BAD_DEVICE_EXT,
|
||||
EGL_BAD_SURFACE,
|
||||
EGL_BAD_MATCH,
|
||||
EGL_BAD_PARAMETER,
|
||||
EGL_BAD_NATIVE_PIXMAP,
|
||||
EGL_BAD_NATIVE_WINDOW,
|
||||
EGL_CONTEXT_LOST,
|
||||
}
|
||||
}
|
||||
363
src/gles2/gl.rs
363
src/gles2/gl.rs
|
|
@ -1,363 +0,0 @@
|
|||
use crate::egl::{EglContext, EglImage, PROCS};
|
||||
use crate::format::Format;
|
||||
use crate::gles2::sys::{
|
||||
glAttachShader, glBindFramebuffer, glBindRenderbuffer, glBindTexture, glCheckFramebufferStatus,
|
||||
glClear, glClearColor, glCompileShader, glCreateProgram, glCreateShader, glDeleteFramebuffers,
|
||||
glDeleteProgram, glDeleteRenderbuffers, glDeleteShader, glDeleteTextures, glDetachShader,
|
||||
glDisable, glEnable, glFramebufferRenderbuffer, glFramebufferTexture2D, glGenFramebuffers,
|
||||
glGenRenderbuffers, glGenTextures, glGetAttribLocation, glGetProgramiv, glGetShaderiv,
|
||||
glGetUniformLocation, glLinkProgram, glPixelStorei, glScissor, glShaderSource, glTexImage2D,
|
||||
glTexParameteri, glUseProgram, EGLContext, GLeglImageOES, GLenum, GLint, GLuint,
|
||||
GL_CLAMP_TO_EDGE, GL_COLOR_ATTACHMENT0, GL_COLOR_BUFFER_BIT, GL_COMPILE_STATUS, GL_FALSE,
|
||||
GL_FRAMEBUFFER, GL_FRAMEBUFFER_COMPLETE, GL_LINEAR, GL_LINK_STATUS, GL_RENDERBUFFER,
|
||||
GL_SCISSOR_TEST, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MIN_FILTER,
|
||||
GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_UNPACK_ROW_LENGTH_EXT,
|
||||
};
|
||||
use crate::gles2::GlesError;
|
||||
use crate::rect::Rect;
|
||||
use crate::utils::ptr_ext::PtrExt;
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use uapi::{ustr, Ustr};
|
||||
|
||||
pub struct GlTexture {
|
||||
pub(super) ctx: Rc<EglContext>,
|
||||
pub tex: GLuint,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
impl GlTexture {
|
||||
pub fn new(
|
||||
ctx: &Rc<EglContext>,
|
||||
format: &'static Format,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Result<Rc<GlTexture>, GlesError> {
|
||||
let tex = ctx.with_current(|| unsafe {
|
||||
let mut tex = 0;
|
||||
glGenTextures(1, &mut tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
format.gl_format,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
format.gl_format as _,
|
||||
format.gl_type as _,
|
||||
ptr::null(),
|
||||
);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
Ok(tex)
|
||||
})?;
|
||||
Ok(Rc::new(GlTexture {
|
||||
ctx: ctx.clone(),
|
||||
tex,
|
||||
width,
|
||||
height,
|
||||
}))
|
||||
}
|
||||
|
||||
pub unsafe fn to_framebuffer(self: &Rc<Self>) -> Result<Rc<GlFrameBuffer>, GlesError> {
|
||||
self.ctx.with_current(|| unsafe {
|
||||
let mut fbo = 0;
|
||||
glGenFramebuffers(1, &mut fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D,
|
||||
self.tex,
|
||||
0,
|
||||
);
|
||||
let fb = GlFrameBuffer {
|
||||
_rb: None,
|
||||
_tex: Some(self.clone()),
|
||||
ctx: self.ctx.clone(),
|
||||
fbo,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
};
|
||||
let status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
if status != GL_FRAMEBUFFER_COMPLETE {
|
||||
return Err(GlesError::CreateFramebuffer);
|
||||
}
|
||||
Ok(Rc::new(fb))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn import_texture(
|
||||
ctx: &Rc<EglContext>,
|
||||
data: &[Cell<u8>],
|
||||
format: &'static Format,
|
||||
width: i32,
|
||||
height: i32,
|
||||
stride: i32,
|
||||
) -> Result<Rc<GlTexture>, GlesError> {
|
||||
if (stride * height) as usize > data.len() {
|
||||
return Err(GlesError::SmallImageBuffer);
|
||||
}
|
||||
let tex = ctx.with_current(|| unsafe {
|
||||
let mut tex = 0;
|
||||
glGenTextures(1, &mut tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format.bpp as GLint);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
format.gl_format,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
format.gl_format as _,
|
||||
format.gl_type as _,
|
||||
data.as_ptr() as _,
|
||||
);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
Ok(tex)
|
||||
})?;
|
||||
Ok(Rc::new(GlTexture {
|
||||
ctx: ctx.clone(),
|
||||
tex,
|
||||
width,
|
||||
height,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlTexture {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.ctx.with_current(|| {
|
||||
glDeleteTextures(1, &self.tex);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_scissor<T, F: FnOnce() -> T>(scissor: &Rect, f: F) -> T {
|
||||
return f();
|
||||
|
||||
#[thread_local]
|
||||
static mut SCISSOR: *const Rect = ptr::null();
|
||||
|
||||
unsafe {
|
||||
let prev = SCISSOR;
|
||||
if prev.is_null() {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
glScissor(
|
||||
scissor.x1(),
|
||||
scissor.x2(),
|
||||
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.x2(), prev.width(), prev.height());
|
||||
}
|
||||
SCISSOR = prev;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GlShader {
|
||||
_ctx: Rc<EglContext>,
|
||||
shader: GLuint,
|
||||
}
|
||||
|
||||
impl GlShader {
|
||||
pub unsafe fn compile(ctx: &Rc<EglContext>, ty: GLenum, src: &str) -> Result<Self, GlesError> {
|
||||
let shader = glCreateShader(ty);
|
||||
let res = GlShader {
|
||||
_ctx: ctx.clone(),
|
||||
shader,
|
||||
};
|
||||
let len = src.len() as _;
|
||||
glShaderSource(shader, 1, &(src.as_ptr() as _), &len);
|
||||
glCompileShader(shader);
|
||||
|
||||
let mut ok = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &mut ok);
|
||||
if ok == GL_FALSE as _ {
|
||||
return Err(GlesError::ShaderCompileFailed);
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlShader {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self._ctx.with_current(|| {
|
||||
glDeleteShader(self.shader);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GlProgram {
|
||||
_ctx: Rc<EglContext>,
|
||||
prog: GLuint,
|
||||
}
|
||||
|
||||
impl GlProgram {
|
||||
pub unsafe fn link(vert: &GlShader, frag: &GlShader) -> Result<Self, GlesError> {
|
||||
let res = GlProgram {
|
||||
_ctx: vert._ctx.clone(),
|
||||
prog: glCreateProgram(),
|
||||
};
|
||||
glAttachShader(res.prog, vert.shader);
|
||||
glAttachShader(res.prog, frag.shader);
|
||||
glLinkProgram(res.prog);
|
||||
glDetachShader(res.prog, vert.shader);
|
||||
glDetachShader(res.prog, frag.shader);
|
||||
|
||||
let mut ok = 0;
|
||||
glGetProgramiv(res.prog, GL_LINK_STATUS, &mut ok);
|
||||
if ok == GL_FALSE as _ {
|
||||
return Err(GlesError::ProgramLink);
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub unsafe fn get_uniform_location(&self, name: &Ustr) -> GLint {
|
||||
glGetUniformLocation(self.prog, name.as_ptr() as _)
|
||||
}
|
||||
|
||||
pub unsafe fn get_attrib_location(&self, name: &Ustr) -> GLint {
|
||||
glGetAttribLocation(self.prog, name.as_ptr() as _)
|
||||
}
|
||||
|
||||
pub unsafe fn use_(&self) {
|
||||
glUseProgram(self.prog);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlProgram {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self._ctx.with_current(|| {
|
||||
glDeleteProgram(self.prog);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GlRenderBuffer {
|
||||
pub img: Rc<EglImage>,
|
||||
pub ctx: Rc<EglContext>,
|
||||
rbo: GLuint,
|
||||
}
|
||||
|
||||
impl GlRenderBuffer {
|
||||
pub fn from_image(
|
||||
img: &Rc<EglImage>,
|
||||
ctx: &Rc<EglContext>,
|
||||
) -> Result<Rc<GlRenderBuffer>, GlesError> {
|
||||
ctx.with_current(|| unsafe {
|
||||
let mut rbo = 0;
|
||||
glGenRenderbuffers(1, &mut rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
PROCS.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, GLeglImageOES(img.img.0));
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
Ok(Rc::new(GlRenderBuffer {
|
||||
img: img.clone(),
|
||||
ctx: ctx.clone(),
|
||||
rbo,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_framebuffer(self: &Rc<Self>) -> Result<Rc<GlFrameBuffer>, GlesError> {
|
||||
self.ctx.with_current(|| unsafe {
|
||||
let mut fbo = 0;
|
||||
glGenFramebuffers(1, &mut fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferRenderbuffer(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER,
|
||||
self.rbo,
|
||||
);
|
||||
let status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
let fb = GlFrameBuffer {
|
||||
_rb: Some(self.clone()),
|
||||
_tex: None,
|
||||
ctx: self.ctx.clone(),
|
||||
fbo,
|
||||
width: self.img.width,
|
||||
height: self.img.height,
|
||||
};
|
||||
if status != GL_FRAMEBUFFER_COMPLETE {
|
||||
return Err(GlesError::CreateFramebuffer);
|
||||
}
|
||||
Ok(Rc::new(fb))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlRenderBuffer {
|
||||
fn drop(&mut self) {
|
||||
self.ctx.with_current(|| {
|
||||
unsafe {
|
||||
glDeleteRenderbuffers(1, &self.rbo);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GlFrameBuffer {
|
||||
pub _rb: Option<Rc<GlRenderBuffer>>,
|
||||
pub _tex: Option<Rc<GlTexture>>,
|
||||
pub ctx: Rc<EglContext>,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
fbo: GLuint,
|
||||
}
|
||||
|
||||
impl GlFrameBuffer {
|
||||
pub unsafe fn bind(&self) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self.fbo);
|
||||
}
|
||||
|
||||
pub fn clear(&self, r: f32, g: f32, b: f32, a: f32) -> Result<(), GlesError> {
|
||||
self.ctx.with_current(|| unsafe {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self.fbo);
|
||||
glClearColor(r, g, b, a);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
// glFlush();
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlFrameBuffer {
|
||||
fn drop(&mut self) {
|
||||
self.ctx.with_current(|| {
|
||||
unsafe {
|
||||
glDeleteFramebuffers(1, &self.fbo);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
pub mod egl;
|
||||
pub mod ext;
|
||||
mod ext_proc;
|
||||
pub mod gl;
|
||||
pub mod sys;
|
||||
|
||||
use crate::drm::drm::DrmError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GlesError {
|
||||
#[error("EGL library does not support `EGL_EXT_platform_base`")]
|
||||
ExtPlatformBase,
|
||||
#[error("Could not compile a shader")]
|
||||
ShaderCompileFailed,
|
||||
#[error("Could not link a program")]
|
||||
ProgramLink,
|
||||
#[error("Could not bind to `EGL_OPENGL_ES_API`")]
|
||||
BindFailed,
|
||||
#[error("EGL library does not support device enumeration")]
|
||||
DeviceEnumeration,
|
||||
#[error("EGL library does not support device querying")]
|
||||
DeviceQuery,
|
||||
#[error("`eglQueryDeviceStringEXT` failed")]
|
||||
DeviceQueryString,
|
||||
#[error("`eglCreateContext` failed")]
|
||||
CreateContext,
|
||||
#[error("`eglMakeCurrent` failed")]
|
||||
MakeCurrent,
|
||||
#[error("`eglCreateImageKHR` failed")]
|
||||
CreateImage,
|
||||
#[error("Image buffer is too small")]
|
||||
SmallImageBuffer,
|
||||
#[error("Binding a renderbuffer to a framebuffer failed")]
|
||||
CreateFramebuffer,
|
||||
#[error("`eglQueryDevicesEXT` failed")]
|
||||
QueryDevices,
|
||||
#[error("`eglGetPlatformDisplayEXT` failed")]
|
||||
GetDisplay,
|
||||
#[error("`eglInitialize` failed")]
|
||||
Initialize,
|
||||
#[error("EGL display does not support `EGL_EXT_image_dma_buf_import_modifiers`")]
|
||||
DmaBufImport,
|
||||
#[error("GLES driver does not support `GL_OES_EGL_image`")]
|
||||
OesEglImage,
|
||||
#[error("EGL display does not support `EGL_KHR_image_base`")]
|
||||
ImageBase,
|
||||
#[error(
|
||||
"EGL display does not support `EGL_KHR_no_config_context` or `EGL_MESA_configless_context`"
|
||||
)]
|
||||
ConfiglessContext,
|
||||
#[error("EGL display does not support `EGL_KHR_surfaceless_context`")]
|
||||
SurfacelessContext,
|
||||
#[error("`eglQueryDmaBufFormatsEXT` failed")]
|
||||
QueryDmaBufFormats,
|
||||
#[error(transparent)]
|
||||
DrmError(#[from] DrmError),
|
||||
}
|
||||
|
|
@ -3,11 +3,10 @@ mod types;
|
|||
use crate::client::{Client, DynEventFormatter};
|
||||
use crate::clientmem::{ClientMem, ClientMemOffset};
|
||||
use crate::format::Format;
|
||||
use crate::gles2::gl::GlTexture;
|
||||
use crate::ifs::wl_surface::{WlSurface, WlSurfaceId};
|
||||
use crate::object::{Interface, Object, ObjectId};
|
||||
use crate::pixman;
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Texture;
|
||||
use crate::utils::buffd::MsgParser;
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
|
|
@ -27,9 +26,8 @@ pub struct WlBuffer {
|
|||
pub rect: Rect,
|
||||
stride: i32,
|
||||
format: &'static Format,
|
||||
pub image: Rc<pixman::Image<ClientMemOffset>>,
|
||||
mem: ClientMemOffset,
|
||||
pub texture: CloneCell<Option<Rc<GlTexture>>>,
|
||||
pub texture: CloneCell<Option<Rc<Texture>>>,
|
||||
pub(super) surfaces: CopyHashMap<WlSurfaceId, Rc<WlSurface>>,
|
||||
width: i32,
|
||||
height: i32,
|
||||
|
|
@ -57,13 +55,6 @@ impl WlBuffer {
|
|||
if (stride as u64) < min_row_size {
|
||||
return Err(WlBufferError::StrideTooSmall);
|
||||
}
|
||||
let image = pixman::Image::new(
|
||||
mem.clone(),
|
||||
format.pixman.unwrap(),
|
||||
width as u32,
|
||||
height as u32,
|
||||
stride as u32,
|
||||
)?;
|
||||
Ok(Self {
|
||||
id,
|
||||
client: client.clone(),
|
||||
|
|
@ -71,7 +62,6 @@ impl WlBuffer {
|
|||
rect: Rect::new_sized(0, 0, width, height).unwrap(),
|
||||
stride,
|
||||
format,
|
||||
image: Rc::new(image),
|
||||
mem,
|
||||
width,
|
||||
height,
|
||||
|
|
@ -82,9 +72,9 @@ impl WlBuffer {
|
|||
|
||||
pub fn update_texture(&self) -> Result<(), WlBufferError> {
|
||||
self.texture.set(None);
|
||||
let ctx = self.client.state.egl.get().unwrap();
|
||||
let ctx = self.client.state.render_ctx.get().unwrap();
|
||||
let tex = self.mem.access(|mem| {
|
||||
GlTexture::import_texture(&ctx, mem, self.format, self.width, self.height, self.stride)
|
||||
ctx.shmem_texture(mem, self.format, self.width, self.height, self.stride)
|
||||
})??;
|
||||
self.texture.set(Some(tex));
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use crate::client::{ClientError, EventFormatter, RequestParser};
|
||||
use crate::gles2::GlesError;
|
||||
use crate::ifs::wl_buffer::{WlBuffer, RELEASE};
|
||||
use crate::object::Object;
|
||||
use crate::pixman::PixmanError;
|
||||
use crate::render::RenderError;
|
||||
use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError};
|
||||
use crate::ClientMemError;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
|
@ -17,16 +16,13 @@ pub enum WlBufferError {
|
|||
StrideTooSmall,
|
||||
#[error("Could not handle a `destroy` request")]
|
||||
DestroyError(#[from] DestroyError),
|
||||
#[error("Pixman returned an error")]
|
||||
PixmanError(#[source] Box<PixmanError>),
|
||||
#[error("Could not access the client memory")]
|
||||
ClientMemError(#[source] Box<ClientMemError>),
|
||||
#[error("GLES could not import the client image")]
|
||||
GlesError(#[source] Box<GlesError>),
|
||||
GlesError(#[source] Box<RenderError>),
|
||||
}
|
||||
efrom!(WlBufferError, PixmanError, PixmanError);
|
||||
efrom!(WlBufferError, ClientMemError, ClientMemError);
|
||||
efrom!(WlBufferError, GlesError, GlesError);
|
||||
efrom!(WlBufferError, GlesError, RenderError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DestroyError {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ pub mod xdg_surface;
|
|||
use crate::backend::{KeyState, ScrollAxis};
|
||||
use crate::client::{Client, RequestParser};
|
||||
use crate::fixed::Fixed;
|
||||
use crate::gles2::gl::GlTexture;
|
||||
use crate::ifs::wl_buffer::WlBuffer;
|
||||
use crate::ifs::wl_callback::WlCallback;
|
||||
use crate::ifs::wl_seat::WlSeatGlobal;
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ impl Node for XdgToplevel {
|
|||
}
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut dyn Renderer, x: i32, y: i32) {
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_toplevel(self, x, y)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use crate::backends::xorg::{XorgBackend, XorgBackendError};
|
|||
use crate::client::Clients;
|
||||
use crate::clientmem::ClientMemError;
|
||||
use crate::event_loop::EventLoopError;
|
||||
use crate::gles2::egl;
|
||||
use crate::globals::{AddGlobal, Globals};
|
||||
use crate::ifs::wl_compositor::WlCompositorGlobal;
|
||||
use crate::ifs::wl_data_device_manager::WlDataDeviceManagerGlobal;
|
||||
|
|
@ -27,6 +26,7 @@ use crate::ifs::wl_shm::WlShmGlobal;
|
|||
use crate::ifs::wl_subcompositor::WlSubcompositorGlobal;
|
||||
use crate::ifs::wl_surface::NoneSurfaceExt;
|
||||
use crate::ifs::xdg_wm_base::XdgWmBaseGlobal;
|
||||
use crate::render::RenderError;
|
||||
use crate::sighand::SighandError;
|
||||
use crate::state::State;
|
||||
use crate::tree::{DisplayNode, NodeIds};
|
||||
|
|
@ -54,7 +54,6 @@ mod drm;
|
|||
mod event_loop;
|
||||
mod fixed;
|
||||
mod format;
|
||||
mod gles2;
|
||||
mod globals;
|
||||
mod ifs;
|
||||
mod object;
|
||||
|
|
@ -97,10 +96,12 @@ enum MainError {
|
|||
AsyncError(#[from] AsyncError),
|
||||
#[error("The xorg backend caused an error")]
|
||||
XorgBackendError(#[from] XorgBackendError),
|
||||
#[error("The render backend caused an error")]
|
||||
RenderError(#[from] RenderError),
|
||||
}
|
||||
|
||||
fn main_() -> Result<(), MainError> {
|
||||
egl::init();
|
||||
render::init()?;
|
||||
|
||||
clientmem::init()?;
|
||||
let el = EventLoop::new()?;
|
||||
|
|
@ -117,7 +118,7 @@ fn main_() -> Result<(), MainError> {
|
|||
let state = Rc::new(State {
|
||||
eng: engine.clone(),
|
||||
el: el.clone(),
|
||||
egl: Default::default(),
|
||||
render_ctx: Default::default(),
|
||||
wheel,
|
||||
clients: Clients::new(),
|
||||
next_name: NumCell::new(1),
|
||||
|
|
|
|||
|
|
@ -2,13 +2,8 @@ mod consts;
|
|||
|
||||
include!(concat!(env!("OUT_DIR"), "/pixman_tys.rs"));
|
||||
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Border;
|
||||
use crate::ClientMemError;
|
||||
pub use consts::*;
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
use thiserror::Error;
|
||||
use uapi::c;
|
||||
|
||||
#[link(name = "pixman-1")]
|
||||
|
|
@ -26,37 +21,6 @@ extern "C" {
|
|||
fn pixman_region32_copy(dst: *mut Region, src: *const Region);
|
||||
fn pixman_region32_union(dst: *mut Region, a: *const Region, b: *const Region);
|
||||
fn pixman_region32_subtract(dst: *mut Region, a: *const Region, b: *const Region);
|
||||
fn pixman_image_set_clip_region32(image: *mut PixmanImage, region: *const Region);
|
||||
fn pixman_image_create_bits_no_clear(
|
||||
format: PixmanFormat,
|
||||
width: c::c_int,
|
||||
height: c::c_int,
|
||||
bits: *mut u32,
|
||||
stride: c::c_int,
|
||||
) -> *mut PixmanImage;
|
||||
fn pixman_image_unref(image: *mut PixmanImage) -> c::c_int;
|
||||
// fn pixman_image_ref(image: *mut PixmanImage) -> *mut PixmanImage;
|
||||
fn pixman_image_fill_boxes(
|
||||
op: PixmanOp,
|
||||
dest: *mut PixmanImage,
|
||||
color: *const Color,
|
||||
nboxes: c::c_int,
|
||||
boxes: *const Box32,
|
||||
) -> c::c_int;
|
||||
fn pixman_image_composite32(
|
||||
op: PixmanOp,
|
||||
src: *mut PixmanImage,
|
||||
mask: *mut PixmanImage,
|
||||
dest: *mut PixmanImage,
|
||||
src_x: i32,
|
||||
src_y: i32,
|
||||
mask_x: i32,
|
||||
mask_y: i32,
|
||||
dest_x: i32,
|
||||
dest_y: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
|
@ -144,244 +108,3 @@ impl Drop for Region {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe trait PixmanMemory: Clone {
|
||||
type E;
|
||||
|
||||
fn access<T, F>(&self, f: F) -> Result<T, Self::E>
|
||||
where
|
||||
F: FnOnce(&[Cell<u8>]) -> T;
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum PixmanError {
|
||||
#[error("The image size values cannot be represented in c_int")]
|
||||
SizeOverflow,
|
||||
#[error("The pixman memory does not contain enough memory to hold the image")]
|
||||
InsufficientMemory,
|
||||
#[error("The stride does not contain enough bytes to contain a row")]
|
||||
RowOverflow,
|
||||
#[error("Pixman images must be aligned at a 4 byte boundary")]
|
||||
UnalignedMemory,
|
||||
#[error("Internal pixman error")]
|
||||
Internal,
|
||||
#[error(transparent)]
|
||||
ClientMemError(Box<ClientMemError>),
|
||||
}
|
||||
efrom!(PixmanError, ClientMemError, ClientMemError);
|
||||
|
||||
impl From<!> for PixmanError {
|
||||
fn from(_: !) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
struct PixmanImage;
|
||||
|
||||
pub struct Image<T> {
|
||||
data: *mut PixmanImage,
|
||||
width: u32,
|
||||
height: u32,
|
||||
memory: T,
|
||||
clip: Cell<Option<Region>>,
|
||||
}
|
||||
|
||||
impl<T: PixmanMemory> Image<T>
|
||||
where
|
||||
PixmanError: From<<T as PixmanMemory>::E>,
|
||||
{
|
||||
pub fn new(
|
||||
memory: T,
|
||||
format: Format,
|
||||
width: u32,
|
||||
height: u32,
|
||||
stride: u32,
|
||||
) -> Result<Self, PixmanError> {
|
||||
let data = memory.access(|m| {
|
||||
if format_bpp(format.raw()) as u64 * width as u64 > stride as u64 * 8 {
|
||||
return Err(PixmanError::RowOverflow);
|
||||
}
|
||||
if (m.len() as u64) < height as u64 * stride as u64 {
|
||||
return Err(PixmanError::InsufficientMemory);
|
||||
}
|
||||
let (width, height, stride) =
|
||||
match (width.try_into(), height.try_into(), stride.try_into()) {
|
||||
(Ok(w), Ok(h), Ok(s)) => (w, h, s),
|
||||
_ => return Err(PixmanError::SizeOverflow),
|
||||
};
|
||||
if m.as_ptr() as usize % 4 != 0 {
|
||||
return Err(PixmanError::UnalignedMemory);
|
||||
}
|
||||
let data = unsafe {
|
||||
pixman_image_create_bits_no_clear(
|
||||
format.raw() as _,
|
||||
width,
|
||||
height,
|
||||
m.as_ptr() as _,
|
||||
stride,
|
||||
)
|
||||
};
|
||||
if data.is_null() {
|
||||
return Err(PixmanError::Internal);
|
||||
}
|
||||
Ok(data)
|
||||
})??;
|
||||
Ok(Self {
|
||||
data,
|
||||
width,
|
||||
height,
|
||||
memory,
|
||||
clip: Cell::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_clip<F: FnOnce()>(&self, clip: Rect, f: F) {
|
||||
let region = Region::rect(clip.x1(), clip.y1(), clip.width(), clip.height());
|
||||
unsafe {
|
||||
pixman_image_set_clip_region32(self.data, ®ion);
|
||||
}
|
||||
let region = self.clip.replace(Some(region));
|
||||
f();
|
||||
unsafe {
|
||||
let region = region
|
||||
.as_ref()
|
||||
.map(|p| p as *const _)
|
||||
.unwrap_or(ptr::null());
|
||||
pixman_image_set_clip_region32(self.data, region);
|
||||
}
|
||||
self.clip.set(region);
|
||||
}
|
||||
|
||||
pub fn fill(&self, r: u8, g: u8, b: u8, a: u8) -> Result<(), PixmanError> {
|
||||
self.fill_rect(r, g, b, a, 0, 0, self.width as _, self.height as _)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn fill_rect(
|
||||
&self,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
a: u8,
|
||||
x1: i32,
|
||||
y1: i32,
|
||||
x2: i32,
|
||||
y2: i32,
|
||||
) -> Result<(), PixmanError> {
|
||||
self.memory.access(|_| {
|
||||
let bx = Box32 {
|
||||
x1: x1.max(0),
|
||||
y1: y1.max(0),
|
||||
x2: x2.min(self.width as i32),
|
||||
y2: y2.min(self.height as i32),
|
||||
};
|
||||
let color = Color {
|
||||
red: (r as u16) << 8,
|
||||
green: (g as u16) << 8,
|
||||
blue: (b as u16) << 8,
|
||||
alpha: (a as u16) << 8,
|
||||
};
|
||||
unsafe {
|
||||
pixman_image_fill_boxes(OP_SRC.raw() as PixmanOp, self.data, &color, 1, &bx);
|
||||
}
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn fill_inner_border(
|
||||
&self,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
a: u8,
|
||||
x1: i32,
|
||||
y1: i32,
|
||||
x2: i32,
|
||||
y2: i32,
|
||||
width: i32,
|
||||
borders: Border,
|
||||
) -> Result<(), PixmanError> {
|
||||
self.memory.access(|_| {
|
||||
let mut bx = [
|
||||
Box32 { x1, y1, x2, y2: y1 },
|
||||
Box32 { x1: x2, y1, x2, y2 },
|
||||
Box32 { x1, y1, x2: x1, y2 },
|
||||
Box32 { x1, y1: y2, x2, y2 },
|
||||
];
|
||||
if borders.contains(Border::TOP) {
|
||||
bx[0].y2 += width;
|
||||
}
|
||||
if borders.contains(Border::RIGHT) {
|
||||
bx[1].x1 -= width;
|
||||
}
|
||||
if borders.contains(Border::LEFT) {
|
||||
bx[2].x2 += width;
|
||||
}
|
||||
if borders.contains(Border::BOTTOM) {
|
||||
bx[3].y1 -= width;
|
||||
}
|
||||
for bx in &mut bx {
|
||||
bx.x1 = bx.x1.max(0).min(self.width as i32);
|
||||
bx.x2 = bx.x2.max(0).min(self.width as i32);
|
||||
bx.y1 = bx.y1.max(0).min(self.height as i32);
|
||||
bx.y2 = bx.y2.max(0).min(self.height as i32);
|
||||
}
|
||||
let color = Color {
|
||||
red: (r as u16) << 8,
|
||||
green: (g as u16) << 8,
|
||||
blue: (b as u16) << 8,
|
||||
alpha: (a as u16) << 8,
|
||||
};
|
||||
unsafe {
|
||||
pixman_image_fill_boxes(
|
||||
OP_SRC.raw() as PixmanOp,
|
||||
self.data,
|
||||
&color,
|
||||
bx.len() as _,
|
||||
bx.as_ptr(),
|
||||
);
|
||||
}
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_image<U>(&self, over: &Image<U>, x: i32, y: i32) -> Result<(), PixmanError>
|
||||
where
|
||||
U: PixmanMemory,
|
||||
PixmanError: From<<U as PixmanMemory>::E>,
|
||||
{
|
||||
self.memory.access(|_| {
|
||||
over.memory.access(|_| unsafe {
|
||||
pixman_image_composite32(
|
||||
OP_OVER.raw(),
|
||||
over.data,
|
||||
ptr::null_mut(),
|
||||
self.data,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
x,
|
||||
y,
|
||||
over.width as _,
|
||||
over.height as _,
|
||||
);
|
||||
})
|
||||
})??;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn memory(&self) -> &T {
|
||||
&self.memory
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for Image<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
pixman_image_unref(self.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
72
src/render/egl/context.rs
Normal file
72
src/render/egl/context.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
use crate::render::egl::display::EglDisplay;
|
||||
use crate::render::egl::sys::{
|
||||
eglDestroyContext, eglMakeCurrent, EGLContext, EGLSurface, EGL_FALSE, EGL_TRUE,
|
||||
};
|
||||
use crate::render::ext::GlExt;
|
||||
use crate::render::gl::sys::{GLint, GLuint};
|
||||
use crate::render::RenderError;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EglContext {
|
||||
pub dpy: Rc<EglDisplay>,
|
||||
pub ext: GlExt,
|
||||
pub ctx: EGLContext,
|
||||
|
||||
pub tex_prog: GLuint,
|
||||
pub tex_tex: GLint,
|
||||
pub tex_texcoord: GLint,
|
||||
pub tex_pos: GLint,
|
||||
}
|
||||
|
||||
impl Drop for EglContext {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if eglDestroyContext(self.dpy.dpy, self.ctx) != EGL_TRUE {
|
||||
log::warn!("`eglDestroyContext` failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[thread_local]
|
||||
static mut CURRENT: EGLContext = EGLContext::none();
|
||||
|
||||
impl EglContext {
|
||||
#[inline]
|
||||
pub fn with_current<T, F: FnOnce() -> Result<T, RenderError>>(
|
||||
&self,
|
||||
f: F,
|
||||
) -> Result<T, RenderError> {
|
||||
unsafe {
|
||||
if CURRENT == self.ctx {
|
||||
return f();
|
||||
}
|
||||
self.with_current_slow(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cold]
|
||||
unsafe fn with_current_slow<T, F: FnOnce() -> Result<T, RenderError>>(
|
||||
&self,
|
||||
f: F,
|
||||
) -> Result<T, RenderError> {
|
||||
if eglMakeCurrent(
|
||||
self.dpy.dpy,
|
||||
EGLSurface::none(),
|
||||
EGLSurface::none(),
|
||||
self.ctx,
|
||||
) == EGL_FALSE
|
||||
{
|
||||
return Err(RenderError::MakeCurrent);
|
||||
}
|
||||
let prev = CURRENT;
|
||||
CURRENT = self.ctx;
|
||||
let res = f();
|
||||
if eglMakeCurrent(self.dpy.dpy, EGLSurface::none(), EGLSurface::none(), prev) == EGL_FALSE {
|
||||
panic!("Could not restore EGLContext");
|
||||
}
|
||||
CURRENT = prev;
|
||||
res
|
||||
}
|
||||
}
|
||||
99
src/render/egl/device.rs
Normal file
99
src/render/egl/device.rs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
use crate::format::{formats, Format};
|
||||
use crate::render::egl::display::EglDisplay;
|
||||
use crate::render::egl::sys::{
|
||||
eglInitialize, EGLDeviceEXT, EGLDisplay, EGLint, EGL_PLATFORM_DEVICE_EXT, EGL_TRUE,
|
||||
};
|
||||
use crate::render::egl::PROCS;
|
||||
use crate::render::ext::{get_display_ext, DeviceExt, DisplayExt};
|
||||
use crate::render::RenderError;
|
||||
use ahash::AHashMap;
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct EglDevice {
|
||||
pub exts: DeviceExt,
|
||||
pub dev: EGLDeviceEXT,
|
||||
}
|
||||
|
||||
impl EglDevice {
|
||||
pub fn query_string(&self, name: EGLint) -> Result<&'static CStr, RenderError> {
|
||||
unsafe {
|
||||
let res = PROCS.eglQueryDeviceStringEXT(self.dev, name);
|
||||
if res.is_null() {
|
||||
return Err(RenderError::DeviceQueryString);
|
||||
}
|
||||
Ok(CStr::from_ptr(res))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_display(&self) -> Result<Rc<EglDisplay>, RenderError> {
|
||||
unsafe {
|
||||
let dpy = PROCS.eglGetPlatformDisplayEXT(
|
||||
EGL_PLATFORM_DEVICE_EXT as _,
|
||||
self.dev.0,
|
||||
ptr::null(),
|
||||
);
|
||||
if dpy.is_none() {
|
||||
return Err(RenderError::GetDisplay);
|
||||
}
|
||||
let mut dpy = EglDisplay {
|
||||
exts: DisplayExt::empty(),
|
||||
formats: AHashMap::new(),
|
||||
dev: *self,
|
||||
dpy,
|
||||
};
|
||||
let mut major = 0;
|
||||
let mut minor = 0;
|
||||
if eglInitialize(dpy.dpy, &mut major, &mut minor) != EGL_TRUE {
|
||||
return Err(RenderError::Initialize);
|
||||
}
|
||||
dpy.exts = get_display_ext(dpy.dpy);
|
||||
if !dpy.exts.intersects(DisplayExt::KHR_IMAGE_BASE) {
|
||||
return Err(RenderError::ImageBase);
|
||||
}
|
||||
if !dpy
|
||||
.exts
|
||||
.intersects(DisplayExt::EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS)
|
||||
{
|
||||
return Err(RenderError::DmaBufImport);
|
||||
}
|
||||
if !dpy
|
||||
.exts
|
||||
.intersects(DisplayExt::KHR_NO_CONFIG_CONTEXT | DisplayExt::MESA_CONFIGLESS_CONTEXT)
|
||||
{
|
||||
return Err(RenderError::ConfiglessContext);
|
||||
}
|
||||
if !dpy.exts.intersects(DisplayExt::KHR_SURFACELESS_CONTEXT) {
|
||||
return Err(RenderError::SurfacelessContext);
|
||||
}
|
||||
dpy.formats = query_formats(dpy.dpy)?;
|
||||
|
||||
Ok(Rc::new(dpy))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn query_formats(dpy: EGLDisplay) -> Result<AHashMap<u32, &'static Format>, RenderError> {
|
||||
let mut vec = vec![];
|
||||
let mut num = 0;
|
||||
let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, ptr::null_mut(), &mut num);
|
||||
if res != EGL_TRUE {
|
||||
return Err(RenderError::QueryDmaBufFormats);
|
||||
}
|
||||
vec.reserve_exact(num as usize);
|
||||
let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, vec.as_mut_ptr(), &mut num);
|
||||
if res != EGL_TRUE {
|
||||
return Err(RenderError::QueryDmaBufFormats);
|
||||
}
|
||||
vec.set_len(num as usize);
|
||||
let mut res = AHashMap::new();
|
||||
let formats = formats();
|
||||
for fmt in vec {
|
||||
if let Some(format) = formats.get(&(fmt as u32)) {
|
||||
res.insert(format.drm, *format);
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
147
src/render/egl/display.rs
Normal file
147
src/render/egl/display.rs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
use crate::drm::dma::DmaBuf;
|
||||
use crate::drm::INVALID_MODIFIER;
|
||||
use crate::format::Format;
|
||||
use crate::render::egl::context::EglContext;
|
||||
use crate::render::egl::device::EglDevice;
|
||||
use crate::render::egl::image::EglImage;
|
||||
use crate::render::egl::sys::{
|
||||
eglCreateContext, eglTerminate, EGLClientBuffer, EGLConfig, EGLContext, EGLDisplay, EGLint,
|
||||
EGL_CONTEXT_CLIENT_VERSION, EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
|
||||
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE0_OFFSET_EXT,
|
||||
EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE1_FD_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
|
||||
EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT,
|
||||
EGL_DMA_BUF_PLANE1_PITCH_EXT, EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
|
||||
EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE2_OFFSET_EXT,
|
||||
EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE3_FD_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
|
||||
EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE3_OFFSET_EXT,
|
||||
EGL_DMA_BUF_PLANE3_PITCH_EXT, EGL_HEIGHT, EGL_IMAGE_PRESERVED_KHR, EGL_LINUX_DMA_BUF_EXT,
|
||||
EGL_LINUX_DRM_FOURCC_EXT, EGL_NONE, EGL_TRUE, EGL_WIDTH,
|
||||
};
|
||||
use crate::render::egl::PROCS;
|
||||
use crate::render::ext::{get_gl_ext, DisplayExt, GlExt};
|
||||
use crate::render::RenderError;
|
||||
use ahash::AHashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EglDisplay {
|
||||
pub exts: DisplayExt,
|
||||
pub formats: AHashMap<u32, &'static Format>,
|
||||
pub dev: EglDevice,
|
||||
pub dpy: EGLDisplay,
|
||||
}
|
||||
|
||||
impl EglDisplay {
|
||||
pub fn create_context(self: &Rc<Self>) -> Result<Rc<EglContext>, RenderError> {
|
||||
let attrib = [EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE];
|
||||
unsafe {
|
||||
let ctx = eglCreateContext(
|
||||
self.dpy,
|
||||
EGLConfig::none(),
|
||||
EGLContext::none(),
|
||||
attrib.as_ptr(),
|
||||
);
|
||||
if ctx.is_none() {
|
||||
return Err(RenderError::CreateContext);
|
||||
}
|
||||
let mut ctx = EglContext {
|
||||
dpy: self.clone(),
|
||||
ext: GlExt::empty(),
|
||||
ctx,
|
||||
tex_prog: 0,
|
||||
tex_tex: 0,
|
||||
tex_texcoord: 0,
|
||||
tex_pos: 0,
|
||||
};
|
||||
ctx.ext = ctx.with_current(|| Ok(get_gl_ext()))?;
|
||||
// if !ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE) {
|
||||
// return Err(GlesError::OesEglImage);
|
||||
// }
|
||||
Ok(Rc::new(ctx))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn import_dmabuf(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<EglImage>, RenderError> {
|
||||
struct PlaneKey {
|
||||
fd: EGLint,
|
||||
offset: EGLint,
|
||||
pitch: EGLint,
|
||||
mod_lo: EGLint,
|
||||
mod_hi: EGLint,
|
||||
}
|
||||
const PLANE_KEYS: [PlaneKey; 4] = [
|
||||
PlaneKey {
|
||||
fd: EGL_DMA_BUF_PLANE0_FD_EXT,
|
||||
offset: EGL_DMA_BUF_PLANE0_OFFSET_EXT,
|
||||
pitch: EGL_DMA_BUF_PLANE0_PITCH_EXT,
|
||||
mod_lo: EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
|
||||
mod_hi: EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
|
||||
},
|
||||
PlaneKey {
|
||||
fd: EGL_DMA_BUF_PLANE1_FD_EXT,
|
||||
offset: EGL_DMA_BUF_PLANE1_OFFSET_EXT,
|
||||
pitch: EGL_DMA_BUF_PLANE1_PITCH_EXT,
|
||||
mod_lo: EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
|
||||
mod_hi: EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
|
||||
},
|
||||
PlaneKey {
|
||||
fd: EGL_DMA_BUF_PLANE2_FD_EXT,
|
||||
offset: EGL_DMA_BUF_PLANE2_OFFSET_EXT,
|
||||
pitch: EGL_DMA_BUF_PLANE2_PITCH_EXT,
|
||||
mod_lo: EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
|
||||
mod_hi: EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
|
||||
},
|
||||
PlaneKey {
|
||||
fd: EGL_DMA_BUF_PLANE3_FD_EXT,
|
||||
offset: EGL_DMA_BUF_PLANE3_OFFSET_EXT,
|
||||
pitch: EGL_DMA_BUF_PLANE3_PITCH_EXT,
|
||||
mod_lo: EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
|
||||
mod_hi: EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
|
||||
},
|
||||
];
|
||||
|
||||
let mut attribs = vec![];
|
||||
attribs.extend_from_slice(&[EGL_WIDTH, buf.width]);
|
||||
attribs.extend_from_slice(&[EGL_HEIGHT, buf.height]);
|
||||
attribs.extend_from_slice(&[EGL_LINUX_DRM_FOURCC_EXT, buf.format.drm as _]);
|
||||
attribs.extend_from_slice(&[EGL_IMAGE_PRESERVED_KHR, EGL_TRUE as _]);
|
||||
for (key, plane) in PLANE_KEYS.iter().zip(buf.planes.iter()) {
|
||||
attribs.extend_from_slice(&[key.fd, plane.fd.raw()]);
|
||||
attribs.extend_from_slice(&[key.pitch, plane.stride as _]);
|
||||
attribs.extend_from_slice(&[key.offset, plane.offset as _]);
|
||||
if buf.modifier != INVALID_MODIFIER {
|
||||
attribs.extend_from_slice(&[key.mod_lo, buf.modifier as i32]);
|
||||
attribs.extend_from_slice(&[key.mod_hi, (buf.modifier >> 32) as i32]);
|
||||
}
|
||||
}
|
||||
attribs.push(EGL_NONE);
|
||||
let img = unsafe {
|
||||
PROCS.eglCreateImageKHR(
|
||||
self.dpy,
|
||||
EGLContext::none(),
|
||||
EGL_LINUX_DMA_BUF_EXT as _,
|
||||
EGLClientBuffer::none(),
|
||||
attribs.as_ptr(),
|
||||
)
|
||||
};
|
||||
if img.is_none() {
|
||||
return Err(RenderError::CreateImage);
|
||||
}
|
||||
Ok(Rc::new(EglImage {
|
||||
dpy: self.clone(),
|
||||
img,
|
||||
width: buf.width,
|
||||
height: buf.height,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for EglDisplay {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if eglTerminate(self.dpy) != EGL_TRUE {
|
||||
log::warn!("`eglTerminate` failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
src/render/egl/image.rs
Normal file
21
src/render/egl/image.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
use crate::render::egl::display::EglDisplay;
|
||||
use crate::render::egl::sys::{EGLImageKHR, EGL_FALSE};
|
||||
use crate::render::egl::PROCS;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct EglImage {
|
||||
pub dpy: Rc<EglDisplay>,
|
||||
pub img: EGLImageKHR,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
impl Drop for EglImage {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if PROCS.eglDestroyImageKHR(self.dpy.dpy, self.img) == EGL_FALSE {
|
||||
log::warn!("`eglDestroyImageKHR` failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
171
src/render/egl/mod.rs
Normal file
171
src/render/egl/mod.rs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
use crate::drm::drm::Drm;
|
||||
use crate::render::egl::device::EglDevice;
|
||||
use crate::render::egl::sys::{
|
||||
eglBindAPI, EGLAttrib, EGLLabelKHR, EGLenum, EGLint, EGL_DEBUG_MSG_CRITICAL_KHR,
|
||||
EGL_DEBUG_MSG_ERROR_KHR, EGL_DEBUG_MSG_INFO_KHR, EGL_DEBUG_MSG_WARN_KHR,
|
||||
EGL_DRM_DEVICE_FILE_EXT, EGL_NONE, EGL_OPENGL_ES_API, EGL_TRUE,
|
||||
};
|
||||
use crate::render::ext::{get_client_ext, get_device_ext, ClientExt, DeviceExt};
|
||||
use crate::render::proc::ExtProc;
|
||||
use crate::render::RenderError;
|
||||
use bstr::ByteSlice;
|
||||
use log::Level;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use sys::{
|
||||
EGL_BAD_ACCESS, EGL_BAD_ALLOC, EGL_BAD_ATTRIBUTE, EGL_BAD_CONFIG, EGL_BAD_CONTEXT,
|
||||
EGL_BAD_CURRENT_SURFACE, EGL_BAD_DEVICE_EXT, EGL_BAD_DISPLAY, EGL_BAD_MATCH,
|
||||
EGL_BAD_NATIVE_PIXMAP, EGL_BAD_NATIVE_WINDOW, EGL_BAD_PARAMETER, EGL_BAD_SURFACE,
|
||||
EGL_CONTEXT_LOST, EGL_NOT_INITIALIZED, EGL_SUCCESS,
|
||||
};
|
||||
use uapi::c;
|
||||
|
||||
pub mod context;
|
||||
pub mod device;
|
||||
pub mod display;
|
||||
pub mod image;
|
||||
pub mod sys;
|
||||
|
||||
pub(super) static PROCS: Lazy<ExtProc> = Lazy::new(|| ExtProc::load());
|
||||
|
||||
pub(super) static EXTS: Lazy<ClientExt> = Lazy::new(|| get_client_ext());
|
||||
|
||||
pub fn init() -> Result<(), RenderError> {
|
||||
if !EXTS.contains(ClientExt::EXT_PLATFORM_BASE) {
|
||||
return Err(RenderError::ExtPlatformBase);
|
||||
}
|
||||
if !EXTS.device_query() {
|
||||
return Err(RenderError::DeviceQuery);
|
||||
}
|
||||
if !EXTS.device_enumeration() {
|
||||
return Err(RenderError::DeviceEnumeration);
|
||||
}
|
||||
if EXTS.contains(ClientExt::KHR_DEBUG) {
|
||||
let attrib: &[EGLAttrib] = &[
|
||||
EGL_DEBUG_MSG_CRITICAL_KHR as _,
|
||||
EGL_TRUE as _,
|
||||
EGL_DEBUG_MSG_ERROR_KHR as _,
|
||||
EGL_TRUE as _,
|
||||
EGL_DEBUG_MSG_WARN_KHR as _,
|
||||
EGL_TRUE as _,
|
||||
EGL_DEBUG_MSG_INFO_KHR as _,
|
||||
EGL_TRUE as _,
|
||||
EGL_NONE as _,
|
||||
];
|
||||
unsafe {
|
||||
PROCS.eglDebugMessageControlKHR(egl_log, attrib.as_ptr());
|
||||
}
|
||||
}
|
||||
if unsafe { eglBindAPI(EGL_OPENGL_ES_API) } != EGL_TRUE {
|
||||
return Err(RenderError::BindFailed);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn find_drm_device(drm: &Drm) -> Result<Option<EglDevice>, RenderError> {
|
||||
let drm_dev = drm.get_device()?;
|
||||
for device in query_devices()? {
|
||||
if device.exts.contains(DeviceExt::EXT_DEVICE_DRM) {
|
||||
let device_file = device.query_string(EGL_DRM_DEVICE_FILE_EXT)?;
|
||||
for (_, name) in drm_dev.nodes() {
|
||||
if device_file == name {
|
||||
return Ok(Some(device));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn query_devices() -> Result<Vec<EglDevice>, RenderError> {
|
||||
if !EXTS.device_enumeration() {
|
||||
return Err(RenderError::DeviceEnumeration);
|
||||
}
|
||||
unsafe {
|
||||
let mut devices = vec![];
|
||||
let mut num_devices = 0;
|
||||
let res = PROCS.eglQueryDevicesEXT(num_devices, ptr::null_mut(), &mut num_devices);
|
||||
if res != EGL_TRUE {
|
||||
return Err(RenderError::QueryDevices);
|
||||
}
|
||||
devices.reserve_exact(num_devices as usize);
|
||||
let res = PROCS.eglQueryDevicesEXT(num_devices, devices.as_mut_ptr(), &mut num_devices);
|
||||
if res != EGL_TRUE {
|
||||
return Err(RenderError::QueryDevices);
|
||||
}
|
||||
devices.set_len(num_devices as usize);
|
||||
Ok(devices
|
||||
.into_iter()
|
||||
.map(|d| EglDevice {
|
||||
exts: get_device_ext(d),
|
||||
dev: d,
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn egl_log(
|
||||
error: EGLenum,
|
||||
command: *const c::c_char,
|
||||
message_type: EGLint,
|
||||
_thread_label: EGLLabelKHR,
|
||||
_object_label: EGLLabelKHR,
|
||||
message: *const c::c_char,
|
||||
) {
|
||||
let level = match message_type {
|
||||
EGL_DEBUG_MSG_CRITICAL_KHR => Level::Error,
|
||||
EGL_DEBUG_MSG_ERROR_KHR => Level::Error,
|
||||
EGL_DEBUG_MSG_WARN_KHR => Level::Warn,
|
||||
EGL_DEBUG_MSG_INFO_KHR => Level::Info,
|
||||
_ => Level::Warn,
|
||||
};
|
||||
let command = if !command.is_null() {
|
||||
CStr::from_ptr(command).to_bytes()
|
||||
} else {
|
||||
b"none"
|
||||
};
|
||||
let message = if !message.is_null() {
|
||||
CStr::from_ptr(message).to_bytes()
|
||||
} else {
|
||||
b"none"
|
||||
};
|
||||
let err_name = error_name(error);
|
||||
log::log!(
|
||||
level,
|
||||
"EGL: command: {}, error: {} (0x{:x}), message: {}",
|
||||
command.as_bstr(),
|
||||
err_name,
|
||||
error,
|
||||
message.as_bstr()
|
||||
);
|
||||
}
|
||||
|
||||
fn error_name(error: EGLenum) -> &'static str {
|
||||
macro_rules! en {
|
||||
($($name:ident,)*) => {
|
||||
match error as _ {
|
||||
$($name => stringify!($name),)*
|
||||
_ => "unknown",
|
||||
}
|
||||
}
|
||||
}
|
||||
en! {
|
||||
EGL_SUCCESS,
|
||||
EGL_NOT_INITIALIZED,
|
||||
EGL_BAD_ACCESS,
|
||||
EGL_BAD_ALLOC,
|
||||
EGL_BAD_ATTRIBUTE,
|
||||
EGL_BAD_CONTEXT,
|
||||
EGL_BAD_CONFIG,
|
||||
EGL_BAD_CURRENT_SURFACE,
|
||||
EGL_BAD_DISPLAY,
|
||||
EGL_BAD_DEVICE_EXT,
|
||||
EGL_BAD_SURFACE,
|
||||
EGL_BAD_MATCH,
|
||||
EGL_BAD_PARAMETER,
|
||||
EGL_BAD_NATIVE_PIXMAP,
|
||||
EGL_BAD_NATIVE_WINDOW,
|
||||
EGL_CONTEXT_LOST,
|
||||
}
|
||||
}
|
||||
102
src/render/egl/sys.rs
Normal file
102
src/render/egl/sys.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
use uapi::c;
|
||||
|
||||
pub type EGLint = i32;
|
||||
pub type EGLenum = c::c_uint;
|
||||
pub type EGLBoolean = c::c_uint;
|
||||
pub type EGLuint64KHR = u64;
|
||||
pub type EGLAttrib = isize;
|
||||
|
||||
egl_transparent!(EGLDisplay);
|
||||
egl_transparent!(EGLSurface);
|
||||
egl_transparent!(EGLConfig);
|
||||
egl_transparent!(EGLImageKHR);
|
||||
egl_transparent!(EGLContext);
|
||||
egl_transparent!(EGLClientBuffer);
|
||||
egl_transparent!(EGLLabelKHR);
|
||||
egl_transparent!(EGLDeviceEXT);
|
||||
|
||||
pub type EGLDEBUGPROCKHR = unsafe extern "C" fn(
|
||||
error: EGLenum,
|
||||
command: *const c::c_char,
|
||||
message_type: EGLint,
|
||||
thread_label: EGLLabelKHR,
|
||||
object_label: EGLLabelKHR,
|
||||
message: *const c::c_char,
|
||||
);
|
||||
|
||||
pub const EGL_EXTENSIONS: EGLint = 0x3055;
|
||||
pub const EGL_DEBUG_MSG_CRITICAL_KHR: EGLint = 0x33B9;
|
||||
pub const EGL_DEBUG_MSG_ERROR_KHR: EGLint = 0x33BA;
|
||||
pub const EGL_DEBUG_MSG_WARN_KHR: EGLint = 0x33BB;
|
||||
pub const EGL_DEBUG_MSG_INFO_KHR: EGLint = 0x33BC;
|
||||
pub const EGL_TRUE: EGLBoolean = 1;
|
||||
pub const EGL_FALSE: EGLBoolean = 0;
|
||||
pub const EGL_NONE: EGLint = 0x3038;
|
||||
pub const EGL_SUCCESS: EGLint = 0x3000;
|
||||
pub const EGL_NOT_INITIALIZED: EGLint = 0x3001;
|
||||
pub const EGL_BAD_ACCESS: EGLint = 0x3002;
|
||||
pub const EGL_BAD_ALLOC: EGLint = 0x3003;
|
||||
pub const EGL_BAD_ATTRIBUTE: EGLint = 0x3004;
|
||||
pub const EGL_BAD_CONFIG: EGLint = 0x3005;
|
||||
pub const EGL_BAD_CONTEXT: EGLint = 0x3006;
|
||||
pub const EGL_BAD_CURRENT_SURFACE: EGLint = 0x3007;
|
||||
pub const EGL_BAD_DISPLAY: EGLint = 0x3008;
|
||||
pub const EGL_BAD_MATCH: EGLint = 0x3009;
|
||||
pub const EGL_BAD_NATIVE_PIXMAP: EGLint = 0x300A;
|
||||
pub const EGL_BAD_NATIVE_WINDOW: EGLint = 0x300B;
|
||||
pub const EGL_BAD_PARAMETER: EGLint = 0x300C;
|
||||
pub const EGL_BAD_SURFACE: EGLint = 0x300D;
|
||||
pub const EGL_CONTEXT_LOST: EGLint = 0x300E;
|
||||
pub const EGL_BAD_DEVICE_EXT: EGLint = 0x322B;
|
||||
pub const EGL_OPENGL_ES_API: EGLenum = 0x30A0;
|
||||
pub const EGL_DRM_DEVICE_FILE_EXT: EGLint = 0x3233;
|
||||
pub const EGL_PLATFORM_DEVICE_EXT: EGLint = 0x313F;
|
||||
pub const EGL_CONTEXT_CLIENT_VERSION: EGLint = 0x3098;
|
||||
|
||||
pub const EGL_WIDTH: EGLint = 0x3057;
|
||||
pub const EGL_HEIGHT: EGLint = 0x3056;
|
||||
pub const EGL_LINUX_DRM_FOURCC_EXT: EGLint = 0x3271;
|
||||
pub const EGL_DMA_BUF_PLANE0_FD_EXT: EGLint = 0x3272;
|
||||
pub const EGL_DMA_BUF_PLANE0_OFFSET_EXT: EGLint = 0x3273;
|
||||
pub const EGL_DMA_BUF_PLANE0_PITCH_EXT: EGLint = 0x3274;
|
||||
pub const EGL_DMA_BUF_PLANE1_FD_EXT: EGLint = 0x3275;
|
||||
pub const EGL_DMA_BUF_PLANE1_OFFSET_EXT: EGLint = 0x3276;
|
||||
pub const EGL_DMA_BUF_PLANE1_PITCH_EXT: EGLint = 0x3277;
|
||||
pub const EGL_DMA_BUF_PLANE2_FD_EXT: EGLint = 0x3278;
|
||||
pub const EGL_DMA_BUF_PLANE2_OFFSET_EXT: EGLint = 0x3279;
|
||||
pub const EGL_DMA_BUF_PLANE2_PITCH_EXT: EGLint = 0x327A;
|
||||
pub const EGL_DMA_BUF_PLANE3_FD_EXT: EGLint = 0x3440;
|
||||
pub const EGL_DMA_BUF_PLANE3_OFFSET_EXT: EGLint = 0x3441;
|
||||
pub const EGL_DMA_BUF_PLANE3_PITCH_EXT: EGLint = 0x3442;
|
||||
pub const EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT: EGLint = 0x3443;
|
||||
pub const EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT: EGLint = 0x3444;
|
||||
pub const EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT: EGLint = 0x3445;
|
||||
pub const EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT: EGLint = 0x3446;
|
||||
pub const EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT: EGLint = 0x3447;
|
||||
pub const EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT: EGLint = 0x3448;
|
||||
pub const EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT: EGLint = 0x3449;
|
||||
pub const EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT: EGLint = 0x344A;
|
||||
pub const EGL_IMAGE_PRESERVED_KHR: EGLint = 0x30D2;
|
||||
pub const EGL_LINUX_DMA_BUF_EXT: EGLint = 0x3270;
|
||||
|
||||
#[link(name = "EGL")]
|
||||
extern "C" {
|
||||
pub fn eglQueryString(dpy: EGLDisplay, name: EGLint) -> *const c::c_char;
|
||||
pub fn eglGetProcAddress(procname: *const c::c_char) -> *mut u8;
|
||||
pub fn eglBindAPI(api: EGLenum) -> EGLBoolean;
|
||||
pub fn eglTerminate(dpy: EGLDisplay) -> EGLBoolean;
|
||||
pub fn eglInitialize(dpy: EGLDisplay, major: *mut EGLint, minor: *mut EGLint) -> EGLBoolean;
|
||||
pub fn eglCreateContext(
|
||||
dpy: EGLDisplay,
|
||||
config: EGLConfig,
|
||||
share_context: EGLContext,
|
||||
attrib_list: *const EGLint,
|
||||
) -> EGLContext;
|
||||
pub fn eglDestroyContext(dpy: EGLDisplay, ctx: EGLContext) -> EGLBoolean;
|
||||
pub fn eglMakeCurrent(
|
||||
dpy: EGLDisplay,
|
||||
draw: EGLSurface,
|
||||
read: EGLSurface,
|
||||
ctx: EGLContext,
|
||||
) -> EGLBoolean;
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
use crate::gles2::egl::PROCS;
|
||||
use crate::gles2::sys::{
|
||||
eglQueryString, glGetString, EGLDeviceEXT, EGLDisplay, EGL_EXTENSIONS, GL_EXTENSIONS,
|
||||
};
|
||||
use crate::render::egl::sys::{eglQueryString, EGLDeviceEXT, EGLDisplay, EGL_EXTENSIONS};
|
||||
use crate::render::egl::PROCS;
|
||||
use crate::render::gl::sys::{glGetString, GL_EXTENSIONS};
|
||||
use ahash::AHashSet;
|
||||
use bstr::ByteSlice;
|
||||
use std::ffi::CStr;
|
||||
55
src/render/gl/frame_buffer.rs
Normal file
55
src/render/gl/frame_buffer.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
use crate::rect::Rect;
|
||||
use crate::render::egl::context::EglContext;
|
||||
use crate::render::gl::render_buffer::GlRenderBuffer;
|
||||
use crate::render::gl::sys::{glDeleteFramebuffers, GLuint};
|
||||
use crate::render::gl::texture::GlTexture;
|
||||
use crate::render::sys::{glDisable, glEnable, glScissor, GL_SCISSOR_TEST};
|
||||
use crate::utils::ptr_ext::PtrExt;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct GlFrameBuffer {
|
||||
pub _rb: Option<Rc<GlRenderBuffer>>,
|
||||
pub _tex: Option<Rc<GlTexture>>,
|
||||
pub ctx: Rc<EglContext>,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
pub fbo: GLuint,
|
||||
}
|
||||
|
||||
impl Drop for GlFrameBuffer {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.ctx.with_current(|| {
|
||||
unsafe {
|
||||
glDeleteFramebuffers(1, &self.fbo);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
6
src/render/gl/mod.rs
Normal file
6
src/render/gl/mod.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
pub mod frame_buffer;
|
||||
pub mod program;
|
||||
pub mod render_buffer;
|
||||
pub mod shader;
|
||||
pub mod sys;
|
||||
pub mod texture;
|
||||
66
src/render/gl/program.rs
Normal file
66
src/render/gl/program.rs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
use crate::render::egl::context::EglContext;
|
||||
use crate::render::gl::shader::GlShader;
|
||||
use crate::render::gl::sys::{
|
||||
glAttachShader, glCreateProgram, glDeleteProgram, glDetachShader, glGetAttribLocation,
|
||||
glGetProgramiv, glGetUniformLocation, glLinkProgram, GLint, GLuint, GL_FALSE, GL_LINK_STATUS,
|
||||
};
|
||||
use crate::render::gl::sys::{GL_FRAGMENT_SHADER, GL_VERTEX_SHADER};
|
||||
use crate::render::RenderError;
|
||||
use std::rc::Rc;
|
||||
use uapi::Ustr;
|
||||
|
||||
pub struct GlProgram {
|
||||
pub _ctx: Rc<EglContext>,
|
||||
pub prog: GLuint,
|
||||
}
|
||||
|
||||
impl GlProgram {
|
||||
pub unsafe fn from_shaders(
|
||||
ctx: &Rc<EglContext>,
|
||||
vert: &str,
|
||||
frag: &str,
|
||||
) -> Result<Self, RenderError> {
|
||||
let vert = GlShader::compile(ctx, GL_VERTEX_SHADER, vert)?;
|
||||
let frag = GlShader::compile(ctx, GL_FRAGMENT_SHADER, frag)?;
|
||||
Self::link(&vert, &frag)
|
||||
}
|
||||
|
||||
pub unsafe fn link(vert: &GlShader, frag: &GlShader) -> Result<Self, RenderError> {
|
||||
let res = GlProgram {
|
||||
_ctx: vert.ctx.clone(),
|
||||
prog: glCreateProgram(),
|
||||
};
|
||||
glAttachShader(res.prog, vert.shader);
|
||||
glAttachShader(res.prog, frag.shader);
|
||||
glLinkProgram(res.prog);
|
||||
glDetachShader(res.prog, vert.shader);
|
||||
glDetachShader(res.prog, frag.shader);
|
||||
|
||||
let mut ok = 0;
|
||||
glGetProgramiv(res.prog, GL_LINK_STATUS, &mut ok);
|
||||
if ok == GL_FALSE as _ {
|
||||
return Err(RenderError::ProgramLink);
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub unsafe fn get_uniform_location(&self, name: &Ustr) -> GLint {
|
||||
glGetUniformLocation(self.prog, name.as_ptr() as _)
|
||||
}
|
||||
|
||||
pub unsafe fn get_attrib_location(&self, name: &Ustr) -> GLint {
|
||||
glGetAttribLocation(self.prog, name.as_ptr() as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlProgram {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let _ = self._ctx.with_current(|| {
|
||||
glDeleteProgram(self.prog);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
72
src/render/gl/render_buffer.rs
Normal file
72
src/render/gl/render_buffer.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
use crate::render::egl::context::EglContext;
|
||||
use crate::render::egl::image::EglImage;
|
||||
use crate::render::egl::PROCS;
|
||||
use crate::render::gl::frame_buffer::GlFrameBuffer;
|
||||
use crate::render::gl::sys::{
|
||||
glBindFramebuffer, glBindRenderbuffer, glCheckFramebufferStatus, glDeleteRenderbuffers,
|
||||
glFramebufferRenderbuffer, glGenFramebuffers, glGenRenderbuffers, GLeglImageOES, GLuint,
|
||||
GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER, GL_FRAMEBUFFER_COMPLETE, GL_RENDERBUFFER,
|
||||
};
|
||||
use crate::render::RenderError;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct GlRenderBuffer {
|
||||
pub img: Rc<EglImage>,
|
||||
pub ctx: Rc<EglContext>,
|
||||
rbo: GLuint,
|
||||
}
|
||||
|
||||
impl GlRenderBuffer {
|
||||
pub unsafe fn from_image(
|
||||
img: &Rc<EglImage>,
|
||||
ctx: &Rc<EglContext>,
|
||||
) -> Result<Rc<GlRenderBuffer>, RenderError> {
|
||||
let mut rbo = 0;
|
||||
glGenRenderbuffers(1, &mut rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
PROCS.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, GLeglImageOES(img.img.0));
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
Ok(Rc::new(GlRenderBuffer {
|
||||
img: img.clone(),
|
||||
ctx: ctx.clone(),
|
||||
rbo,
|
||||
}))
|
||||
}
|
||||
|
||||
pub unsafe fn create_framebuffer(self: &Rc<Self>) -> Result<GlFrameBuffer, RenderError> {
|
||||
let mut fbo = 0;
|
||||
glGenFramebuffers(1, &mut fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferRenderbuffer(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER,
|
||||
self.rbo,
|
||||
);
|
||||
let status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
let fb = GlFrameBuffer {
|
||||
_rb: Some(self.clone()),
|
||||
_tex: None,
|
||||
ctx: self.ctx.clone(),
|
||||
fbo,
|
||||
width: self.img.width,
|
||||
height: self.img.height,
|
||||
};
|
||||
if status != GL_FRAMEBUFFER_COMPLETE {
|
||||
return Err(RenderError::CreateFramebuffer);
|
||||
}
|
||||
Ok(fb)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlRenderBuffer {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.ctx.with_current(|| {
|
||||
unsafe {
|
||||
glDeleteRenderbuffers(1, &self.rbo);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
45
src/render/gl/shader.rs
Normal file
45
src/render/gl/shader.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
use crate::render::egl::context::EglContext;
|
||||
use crate::render::gl::sys::{
|
||||
glCompileShader, glCreateShader, glDeleteShader, glGetShaderiv, glShaderSource, GLenum, GLuint,
|
||||
GL_COMPILE_STATUS, GL_FALSE,
|
||||
};
|
||||
use crate::render::RenderError;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct GlShader {
|
||||
pub ctx: Rc<EglContext>,
|
||||
pub shader: GLuint,
|
||||
}
|
||||
|
||||
impl GlShader {
|
||||
pub unsafe fn compile(
|
||||
ctx: &Rc<EglContext>,
|
||||
ty: GLenum,
|
||||
src: &str,
|
||||
) -> Result<Self, RenderError> {
|
||||
let shader = glCreateShader(ty);
|
||||
let res = GlShader {
|
||||
ctx: ctx.clone(),
|
||||
shader,
|
||||
};
|
||||
let len = src.len() as _;
|
||||
glShaderSource(shader, 1, &(src.as_ptr() as _), &len);
|
||||
glCompileShader(shader);
|
||||
|
||||
let mut ok = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &mut ok);
|
||||
if ok == GL_FALSE as _ {
|
||||
return Err(RenderError::ShaderCompileFailed);
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlShader {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.ctx.with_current(|| unsafe {
|
||||
glDeleteShader(self.shader);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,147 +1,43 @@
|
|||
pub use uapi::c;
|
||||
|
||||
macro_rules! egl_transparent {
|
||||
($name:ident) => {
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub struct $name(pub *mut u8);
|
||||
|
||||
impl $name {
|
||||
#[allow(dead_code)]
|
||||
pub const fn none() -> Self {
|
||||
Self(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn is_none(self) -> bool {
|
||||
self.0.is_null()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub type EGLint = i32;
|
||||
pub type EGLenum = c::c_uint;
|
||||
pub type EGLBoolean = c::c_uint;
|
||||
pub type EGLuint64KHR = u64;
|
||||
pub type EGLAttrib = isize;
|
||||
|
||||
egl_transparent!(EGLDisplay);
|
||||
egl_transparent!(EGLSurface);
|
||||
egl_transparent!(EGLConfig);
|
||||
egl_transparent!(EGLImageKHR);
|
||||
egl_transparent!(EGLContext);
|
||||
egl_transparent!(EGLClientBuffer);
|
||||
egl_transparent!(EGLLabelKHR);
|
||||
egl_transparent!(EGLDeviceEXT);
|
||||
|
||||
pub type EGLDEBUGPROCKHR = unsafe extern "C" fn(
|
||||
error: EGLenum,
|
||||
command: *const c::c_char,
|
||||
message_type: EGLint,
|
||||
thread_label: EGLLabelKHR,
|
||||
object_label: EGLLabelKHR,
|
||||
message: *const c::c_char,
|
||||
);
|
||||
|
||||
pub const EGL_EXTENSIONS: EGLint = 0x3055;
|
||||
pub const EGL_DEBUG_MSG_CRITICAL_KHR: EGLint = 0x33B9;
|
||||
pub const EGL_DEBUG_MSG_ERROR_KHR: EGLint = 0x33BA;
|
||||
pub const EGL_DEBUG_MSG_WARN_KHR: EGLint = 0x33BB;
|
||||
pub const EGL_DEBUG_MSG_INFO_KHR: EGLint = 0x33BC;
|
||||
pub const EGL_TRUE: EGLBoolean = 1;
|
||||
pub const EGL_FALSE: EGLBoolean = 0;
|
||||
pub const EGL_NONE: EGLint = 0x3038;
|
||||
pub const EGL_SUCCESS: EGLint = 0x3000;
|
||||
pub const EGL_NOT_INITIALIZED: EGLint = 0x3001;
|
||||
pub const EGL_BAD_ACCESS: EGLint = 0x3002;
|
||||
pub const EGL_BAD_ALLOC: EGLint = 0x3003;
|
||||
pub const EGL_BAD_ATTRIBUTE: EGLint = 0x3004;
|
||||
pub const EGL_BAD_CONFIG: EGLint = 0x3005;
|
||||
pub const EGL_BAD_CONTEXT: EGLint = 0x3006;
|
||||
pub const EGL_BAD_CURRENT_SURFACE: EGLint = 0x3007;
|
||||
pub const EGL_BAD_DISPLAY: EGLint = 0x3008;
|
||||
pub const EGL_BAD_MATCH: EGLint = 0x3009;
|
||||
pub const EGL_BAD_NATIVE_PIXMAP: EGLint = 0x300A;
|
||||
pub const EGL_BAD_NATIVE_WINDOW: EGLint = 0x300B;
|
||||
pub const EGL_BAD_PARAMETER: EGLint = 0x300C;
|
||||
pub const EGL_BAD_SURFACE: EGLint = 0x300D;
|
||||
pub const EGL_CONTEXT_LOST: EGLint = 0x300E;
|
||||
pub const EGL_BAD_DEVICE_EXT: EGLint = 0x322B;
|
||||
pub const EGL_OPENGL_ES_API: EGLenum = 0x30A0;
|
||||
pub const EGL_DRM_DEVICE_FILE_EXT: EGLint = 0x3233;
|
||||
pub const EGL_PLATFORM_DEVICE_EXT: EGLint = 0x313F;
|
||||
pub const EGL_CONTEXT_CLIENT_VERSION: EGLint = 0x3098;
|
||||
|
||||
pub const EGL_WIDTH: EGLint = 0x3057;
|
||||
pub const EGL_HEIGHT: EGLint = 0x3056;
|
||||
pub const EGL_LINUX_DRM_FOURCC_EXT: EGLint = 0x3271;
|
||||
pub const EGL_DMA_BUF_PLANE0_FD_EXT: EGLint = 0x3272;
|
||||
pub const EGL_DMA_BUF_PLANE0_OFFSET_EXT: EGLint = 0x3273;
|
||||
pub const EGL_DMA_BUF_PLANE0_PITCH_EXT: EGLint = 0x3274;
|
||||
pub const EGL_DMA_BUF_PLANE1_FD_EXT: EGLint = 0x3275;
|
||||
pub const EGL_DMA_BUF_PLANE1_OFFSET_EXT: EGLint = 0x3276;
|
||||
pub const EGL_DMA_BUF_PLANE1_PITCH_EXT: EGLint = 0x3277;
|
||||
pub const EGL_DMA_BUF_PLANE2_FD_EXT: EGLint = 0x3278;
|
||||
pub const EGL_DMA_BUF_PLANE2_OFFSET_EXT: EGLint = 0x3279;
|
||||
pub const EGL_DMA_BUF_PLANE2_PITCH_EXT: EGLint = 0x327A;
|
||||
pub const EGL_DMA_BUF_PLANE3_FD_EXT: EGLint = 0x3440;
|
||||
pub const EGL_DMA_BUF_PLANE3_OFFSET_EXT: EGLint = 0x3441;
|
||||
pub const EGL_DMA_BUF_PLANE3_PITCH_EXT: EGLint = 0x3442;
|
||||
pub const EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT: EGLint = 0x3443;
|
||||
pub const EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT: EGLint = 0x3444;
|
||||
pub const EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT: EGLint = 0x3445;
|
||||
pub const EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT: EGLint = 0x3446;
|
||||
pub const EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT: EGLint = 0x3447;
|
||||
pub const EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT: EGLint = 0x3448;
|
||||
pub const EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT: EGLint = 0x3449;
|
||||
pub const EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT: EGLint = 0x344A;
|
||||
pub const EGL_IMAGE_PRESERVED_KHR: EGLint = 0x30D2;
|
||||
pub const EGL_LINUX_DMA_BUF_EXT: EGLint = 0x3270;
|
||||
|
||||
pub type GLenum = c::c_uint;
|
||||
pub type GLbitfield = c::c_uint;
|
||||
pub type GLfloat = f32;
|
||||
pub type GLubyte = u8;
|
||||
pub type GLsizei = c::c_int;
|
||||
pub type GLuint = c::c_uint;
|
||||
pub type GLint = c::c_int;
|
||||
pub type GLchar = c::c_char;
|
||||
pub type GLboolean = c::c_uchar;
|
||||
pub type GLchar = c::c_char;
|
||||
pub type GLenum = c::c_uint;
|
||||
pub type GLfloat = f32;
|
||||
pub type GLint = c::c_int;
|
||||
pub type GLsizei = c::c_int;
|
||||
pub type GLubyte = u8;
|
||||
pub type GLuint = c::c_uint;
|
||||
|
||||
egl_transparent!(GLeglImageOES);
|
||||
|
||||
pub const GL_EXTENSIONS: GLenum = 0x1F03;
|
||||
pub const GL_RENDERBUFFER: GLenum = 0x8D41;
|
||||
pub const GL_FRAMEBUFFER: GLenum = 0x8D40;
|
||||
pub const GL_BGRA_EXT: GLint = 0x80E1;
|
||||
pub const GL_CLAMP_TO_EDGE: GLint = 0x812F;
|
||||
pub const GL_COLOR_ATTACHMENT0: GLenum = 0x8CE0;
|
||||
pub const GL_FRAMEBUFFER_COMPLETE: GLenum = 0x8CD5;
|
||||
|
||||
pub const GL_COLOR_BUFFER_BIT: GLbitfield = 0x00004000;
|
||||
pub const GL_COMPILE_STATUS: GLenum = 0x8B81;
|
||||
pub const GL_EXTENSIONS: GLenum = 0x1F03;
|
||||
pub const GL_FALSE: GLboolean = 0;
|
||||
pub const GL_FLOAT: GLenum = 0x1406;
|
||||
pub const GL_FRAGMENT_SHADER: GLenum = 0x8B30;
|
||||
pub const GL_FRAMEBUFFER_COMPLETE: GLenum = 0x8CD5;
|
||||
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_MAG_FILTER: GLenum = 0x2800;
|
||||
pub const GL_TEXTURE_MIN_FILTER: GLenum = 0x2801;
|
||||
pub const GL_TEXTURE_WRAP_S: GLenum = 0x2802;
|
||||
pub const GL_TEXTURE_WRAP_T: GLenum = 0x2803;
|
||||
pub const GL_CLAMP_TO_EDGE: GLint = 0x812F;
|
||||
pub const GL_UNPACK_ROW_LENGTH_EXT: GLenum = 0x0CF2;
|
||||
|
||||
pub const GL_BGRA_EXT: GLint = 0x80E1;
|
||||
pub const GL_UNSIGNED_BYTE: GLint = 0x1401;
|
||||
pub const GL_SCISSOR_TEST: GLenum = 0x0C11;
|
||||
|
||||
pub const GL_COMPILE_STATUS: GLenum = 0x8B81;
|
||||
pub const GL_LINK_STATUS: GLenum = 0x8B82;
|
||||
|
||||
pub const GL_FALSE: GLboolean = 0;
|
||||
pub const GL_FRAGMENT_SHADER: GLenum = 0x8B30;
|
||||
pub const GL_VERTEX_SHADER: GLenum = 0x8B31;
|
||||
|
||||
pub const GL_TEXTURE0: GLenum = 0x84C0;
|
||||
pub const GL_TEXTURE_MIN_FILTER: GLenum = 0x2801;
|
||||
pub const GL_TEXTURE_MAG_FILTER: GLenum = 0x2800;
|
||||
pub const GL_LINEAR: GLint = 0x2601;
|
||||
pub const GL_FLOAT: GLenum = 0x1406;
|
||||
|
||||
pub const GL_TRIANGLE_STRIP: GLenum = 0x0005;
|
||||
pub const GL_TRIANGLES: GLenum = 0x0004;
|
||||
pub const GL_UNPACK_ROW_LENGTH_EXT: GLenum = 0x0CF2;
|
||||
pub const GL_UNSIGNED_BYTE: GLint = 0x1401;
|
||||
pub const GL_VERTEX_SHADER: GLenum = 0x8B31;
|
||||
|
||||
#[link(name = "GLESv2")]
|
||||
extern "C" {
|
||||
|
|
@ -217,6 +113,7 @@ extern "C" {
|
|||
pub fn glGetAttribLocation(prog: GLuint, name: *const GLchar) -> GLint;
|
||||
pub fn glUniform1i(location: GLint, v0: GLint);
|
||||
pub fn glUniform1f(location: GLint, v0: GLfloat);
|
||||
pub fn glUniform4f(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat, v3: GLfloat);
|
||||
pub fn glVertexAttribPointer(
|
||||
index: GLuint,
|
||||
size: GLint,
|
||||
|
|
@ -232,25 +129,3 @@ extern "C" {
|
|||
pub fn glDisableVertexAttribArray(idx: GLuint);
|
||||
pub fn glDrawArrays(mode: GLenum, first: GLint, count: GLsizei);
|
||||
}
|
||||
|
||||
#[link(name = "EGL")]
|
||||
extern "C" {
|
||||
pub fn eglQueryString(dpy: EGLDisplay, name: EGLint) -> *const c::c_char;
|
||||
pub fn eglGetProcAddress(procname: *const c::c_char) -> *mut u8;
|
||||
pub fn eglBindAPI(api: EGLenum) -> EGLBoolean;
|
||||
pub fn eglTerminate(dpy: EGLDisplay) -> EGLBoolean;
|
||||
pub fn eglInitialize(dpy: EGLDisplay, major: *mut EGLint, minor: *mut EGLint) -> EGLBoolean;
|
||||
pub fn eglCreateContext(
|
||||
dpy: EGLDisplay,
|
||||
config: EGLConfig,
|
||||
share_context: EGLContext,
|
||||
attrib_list: *const EGLint,
|
||||
) -> EGLContext;
|
||||
pub fn eglDestroyContext(dpy: EGLDisplay, ctx: EGLContext) -> EGLBoolean;
|
||||
pub fn eglMakeCurrent(
|
||||
dpy: EGLDisplay,
|
||||
draw: EGLSurface,
|
||||
read: EGLSurface,
|
||||
ctx: EGLContext,
|
||||
) -> EGLBoolean;
|
||||
}
|
||||
138
src/render/gl/texture.rs
Normal file
138
src/render/gl/texture.rs
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
use crate::format::Format;
|
||||
use crate::render::egl::context::EglContext;
|
||||
use crate::render::gl::frame_buffer::GlFrameBuffer;
|
||||
use crate::render::gl::sys::{
|
||||
glBindFramebuffer, glBindTexture, glCheckFramebufferStatus, glDeleteTextures,
|
||||
glFramebufferTexture2D, glGenFramebuffers, glGenTextures, glPixelStorei, glTexImage2D,
|
||||
glTexParameteri, GLint, GLuint, GL_CLAMP_TO_EDGE, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER,
|
||||
GL_FRAMEBUFFER_COMPLETE, GL_LINEAR, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
GL_TEXTURE_MIN_FILTER, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_UNPACK_ROW_LENGTH_EXT,
|
||||
};
|
||||
use crate::render::RenderError;
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct GlTexture {
|
||||
pub(super) ctx: Rc<EglContext>,
|
||||
pub tex: GLuint,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
impl GlTexture {
|
||||
pub fn new(
|
||||
ctx: &Rc<EglContext>,
|
||||
format: &'static Format,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Result<Rc<GlTexture>, RenderError> {
|
||||
let tex = ctx.with_current(|| unsafe {
|
||||
let mut tex = 0;
|
||||
glGenTextures(1, &mut tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
format.gl_format,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
format.gl_format as _,
|
||||
format.gl_type as _,
|
||||
ptr::null(),
|
||||
);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
Ok(tex)
|
||||
})?;
|
||||
Ok(Rc::new(GlTexture {
|
||||
ctx: ctx.clone(),
|
||||
tex,
|
||||
width,
|
||||
height,
|
||||
}))
|
||||
}
|
||||
|
||||
pub unsafe fn to_framebuffer(self: &Rc<Self>) -> Result<Rc<GlFrameBuffer>, RenderError> {
|
||||
self.ctx.with_current(|| unsafe {
|
||||
let mut fbo = 0;
|
||||
glGenFramebuffers(1, &mut fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D,
|
||||
self.tex,
|
||||
0,
|
||||
);
|
||||
let fb = GlFrameBuffer {
|
||||
_rb: None,
|
||||
_tex: Some(self.clone()),
|
||||
ctx: self.ctx.clone(),
|
||||
fbo,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
};
|
||||
let status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
if status != GL_FRAMEBUFFER_COMPLETE {
|
||||
return Err(RenderError::CreateFramebuffer);
|
||||
}
|
||||
Ok(Rc::new(fb))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn import_texture(
|
||||
ctx: &Rc<EglContext>,
|
||||
data: &[Cell<u8>],
|
||||
format: &'static Format,
|
||||
width: i32,
|
||||
height: i32,
|
||||
stride: i32,
|
||||
) -> Result<GlTexture, RenderError> {
|
||||
if (stride * height) as usize > data.len() {
|
||||
return Err(RenderError::SmallImageBuffer);
|
||||
}
|
||||
let tex = ctx.with_current(|| unsafe {
|
||||
let mut tex = 0;
|
||||
glGenTextures(1, &mut tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format.bpp as GLint);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
format.gl_format,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
format.gl_format as _,
|
||||
format.gl_type as _,
|
||||
data.as_ptr() as _,
|
||||
);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
Ok(tex)
|
||||
})?;
|
||||
Ok(GlTexture {
|
||||
ctx: ctx.clone(),
|
||||
tex,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlTexture {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.ctx.with_current(|| {
|
||||
glDeleteTextures(1, &self.tex);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,335 +0,0 @@
|
|||
use crate::egl::EglContext;
|
||||
use crate::gles2::gl::{with_scissor, GlFrameBuffer, GlProgram, GlShader};
|
||||
use crate::gles2::sys::{
|
||||
glActiveTexture, glBindTexture, glClear, glClearColor, glDisableVertexAttribArray,
|
||||
glDrawArrays, glEnableVertexAttribArray, glTexParameteri, glUniform1f, glUniform1i,
|
||||
glVertexAttribPointer, GLint, GL_COLOR_BUFFER_BIT, GL_FALSE, GL_FLOAT, GL_FRAGMENT_SHADER,
|
||||
GL_LINEAR, GL_TEXTURE0, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_TRIANGLE_STRIP,
|
||||
GL_VERTEX_SHADER,
|
||||
};
|
||||
use crate::gles2::GlesError;
|
||||
use crate::ifs::wl_buffer::WlBuffer;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||
use crate::ifs::wl_surface::WlSurface;
|
||||
use crate::pixman::Image;
|
||||
use crate::render::{Border, Renderer};
|
||||
use crate::servermem::ServerMem;
|
||||
use crate::tree::{
|
||||
ContainerFocus, ContainerNode, ContainerSplit, CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT,
|
||||
};
|
||||
use crate::tree::{FloatNode, OutputNode, WorkspaceNode};
|
||||
use renderdoc::{RenderDoc, V100};
|
||||
use std::borrow::BorrowMut;
|
||||
use std::cell::RefCell;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use uapi::ustr;
|
||||
|
||||
pub const RENDERDOC: bool = false;
|
||||
|
||||
pub struct GlesRenderer {
|
||||
ctx: Rc<EglContext>,
|
||||
|
||||
renderdoc: Option<RefCell<RenderDoc<V100>>>,
|
||||
|
||||
tex_prog: GlProgram,
|
||||
tex_prog_pos: GLint,
|
||||
tex_prog_texcoord: GLint,
|
||||
tex_prog_tex: GLint,
|
||||
}
|
||||
|
||||
impl GlesRenderer {
|
||||
pub unsafe fn new(ctx: &Rc<EglContext>) -> Result<Self, GlesError> {
|
||||
let vert = GlShader::compile(ctx, GL_VERTEX_SHADER, include_str!("shaders/tex.vert.glsl"))?;
|
||||
let frag = GlShader::compile(
|
||||
ctx,
|
||||
GL_FRAGMENT_SHADER,
|
||||
include_str!("shaders/tex.frag.glsl"),
|
||||
)?;
|
||||
let prog = GlProgram::link(&vert, &frag)?;
|
||||
Ok(Self {
|
||||
ctx: ctx.clone(),
|
||||
tex_prog_pos: prog.get_attrib_location(ustr!("pos")),
|
||||
tex_prog_texcoord: prog.get_attrib_location(ustr!("texcoord")),
|
||||
tex_prog_tex: prog.get_uniform_location(ustr!("tex")),
|
||||
tex_prog: prog,
|
||||
renderdoc: if RENDERDOC {
|
||||
Some(RefCell::new(RenderDoc::new().unwrap()))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render_fb<'a>(&'a self, fb: &'a GlFrameBuffer) -> GlesImageRenderer<'a> {
|
||||
if let Some(rd) = &self.renderdoc {
|
||||
rd.borrow_mut()
|
||||
.start_frame_capture(ptr::null(), ptr::null());
|
||||
}
|
||||
GlesImageRenderer {
|
||||
renderer: self,
|
||||
image: fb,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GlesImageRenderer<'a> {
|
||||
renderer: &'a GlesRenderer,
|
||||
image: &'a GlFrameBuffer,
|
||||
}
|
||||
|
||||
impl Drop for GlesImageRenderer<'_> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(rd) = &self.renderer.renderdoc {
|
||||
rd.borrow_mut().end_frame_capture(ptr::null(), ptr::null());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const NON_COLOR: (u8, u8, u8) = (100, 100, 100);
|
||||
const CHILD_COLOR: (u8, u8, u8) = (200, 200, 200);
|
||||
const YES_COLOR: (u8, u8, u8) = (0, 0, 255);
|
||||
|
||||
fn focus_color(focus: ContainerFocus) -> (u8, u8, u8) {
|
||||
match focus {
|
||||
ContainerFocus::None => NON_COLOR,
|
||||
ContainerFocus::Child => CHILD_COLOR,
|
||||
ContainerFocus::Yes => YES_COLOR,
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for GlesImageRenderer<'_> {
|
||||
fn render_output(&mut self, output: &OutputNode) {
|
||||
unsafe {
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
if let Some(ws) = output.workspace.get() {
|
||||
self.render_workspace(&ws);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_workspace(&mut self, workspace: &WorkspaceNode) {
|
||||
if let Some(node) = workspace.container.get() {
|
||||
self.render_container(&node, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
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;
|
||||
for child in container.children.iter() {
|
||||
let (r, g, b) = focus_color(child.focus.get());
|
||||
let mut width = space_per_child;
|
||||
if rem > 0 {
|
||||
rem -= 1;
|
||||
width += 1;
|
||||
}
|
||||
// let _ = self.image.fill_rect(
|
||||
// r,
|
||||
// g,
|
||||
// b,
|
||||
// 255,
|
||||
// pos,
|
||||
// y,
|
||||
// pos + width as i32,
|
||||
// y + CONTAINER_TITLE_HEIGHT as i32,
|
||||
// );
|
||||
pos += width as i32;
|
||||
}
|
||||
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();
|
||||
for (i, child) in container.children.iter().enumerate() {
|
||||
let body = child.body.get();
|
||||
if body.x1() >= cwidth || body.y1() >= cheight {
|
||||
break;
|
||||
}
|
||||
let (r, g, b) = focus_color(child.focus.get());
|
||||
// let _ = self.image.fill_rect(
|
||||
// r,
|
||||
// g,
|
||||
// b,
|
||||
// 255,
|
||||
// x + body.x1(),
|
||||
// y + body.y1() - CONTAINER_TITLE_HEIGHT,
|
||||
// x + body.x2(),
|
||||
// y + body.y1(),
|
||||
// );
|
||||
{
|
||||
let mut x1 = x + body.x1();
|
||||
let mut x2 = x + body.x2();
|
||||
let mut y2 = y + body.y2();
|
||||
let mut border = Border::empty();
|
||||
if i < num_children {
|
||||
if split == ContainerSplit::Horizontal {
|
||||
border |= Border::RIGHT;
|
||||
x2 += CONTAINER_BORDER;
|
||||
} else if split == ContainerSplit::Vertical {
|
||||
border |= Border::BOTTOM;
|
||||
y2 += CONTAINER_BORDER;
|
||||
}
|
||||
}
|
||||
if i > 0 && split == ContainerSplit::Horizontal {
|
||||
border |= Border::LEFT;
|
||||
x1 -= CONTAINER_BORDER;
|
||||
}
|
||||
// let _ = self.image.fill_inner_border(
|
||||
// r,
|
||||
// g,
|
||||
// b,
|
||||
// 255,
|
||||
// x1,
|
||||
// y + body.y1() - CONTAINER_TITLE_HEIGHT,
|
||||
// x2,
|
||||
// y2,
|
||||
// CONTAINER_BORDER as i32,
|
||||
// border,
|
||||
// );
|
||||
}
|
||||
with_scissor(&body, || {
|
||||
let content = child.content.get();
|
||||
child.node.render(self, x + content.x1(), y + content.y1());
|
||||
// self.image.fill_inner_border(
|
||||
// 0,
|
||||
// 0,
|
||||
// 255,
|
||||
// 255,
|
||||
// x + body.x1(),
|
||||
// y + body.y1(),
|
||||
// x + body.x1() + body.width(),
|
||||
// y + body.y1() + body.height(),
|
||||
// 2,
|
||||
// Border::all(),
|
||||
// );
|
||||
// self.image.fill_inner_border(
|
||||
// 255,
|
||||
// 0,
|
||||
// 0,
|
||||
// 255,
|
||||
// x + content.x1(),
|
||||
// y + content.y1(),
|
||||
// x + content.x1() + content.width(),
|
||||
// y + content.y1() + content.height(),
|
||||
// 2,
|
||||
// Border::all(),
|
||||
// );
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_buffer(&mut self, buffer: &WlBuffer, x: i32, y: i32) {
|
||||
let texture = match buffer.texture.get() {
|
||||
Some(t) => t,
|
||||
_ => return,
|
||||
};
|
||||
unsafe {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture.tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
self.renderer.tex_prog.use_();
|
||||
|
||||
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.width) as f32 / f_width) - 1.0;
|
||||
let y2 = 2.0 * ((y + texture.height) as f32 / f_height) - 1.0;
|
||||
|
||||
let pos: [f32; 8] = [x2, y1, x1, y1, x2, y2, x1, y2];
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_floating(&mut self, floating: &FloatNode, x: i32, y: i32) {
|
||||
if let Some(child) = floating.child.get() {
|
||||
child.render(self, x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +1,92 @@
|
|||
use crate::ifs::wl_buffer::WlBuffer;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||
use crate::ifs::wl_surface::WlSurface;
|
||||
use crate::tree::ContainerNode;
|
||||
use crate::tree::{FloatNode, OutputNode, WorkspaceNode};
|
||||
macro_rules! egl_transparent {
|
||||
($name:ident) => {
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub struct $name(pub *mut u8);
|
||||
|
||||
pub mod gles;
|
||||
pub mod pixman;
|
||||
impl $name {
|
||||
#[allow(dead_code)]
|
||||
pub const fn none() -> Self {
|
||||
Self(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
pub struct Border: u32 {
|
||||
const NONE = 0b0000;
|
||||
const LEFT = 0b0001;
|
||||
const TOP = 0b0010;
|
||||
const RIGHT = 0b0100;
|
||||
const BOTTOM = 0b1000;
|
||||
const ALL = 0b1111;
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub fn is_none(self) -> bool {
|
||||
self.0.is_null()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub trait Renderer {
|
||||
fn render_output(&mut self, output: &OutputNode);
|
||||
fn render_workspace(&mut self, workspace: &WorkspaceNode);
|
||||
fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32);
|
||||
fn render_toplevel(&mut self, toplevel: &XdgToplevel, x: i32, y: i32);
|
||||
fn render_surface(&mut self, surface: &WlSurface, x: i32, y: i32);
|
||||
fn render_buffer(&mut self, buffer: &WlBuffer, x: i32, y: i32);
|
||||
fn render_floating(&mut self, floating: &FloatNode, x: i32, y: i32);
|
||||
use crate::drm::drm::DrmError;
|
||||
pub use renderer::*;
|
||||
use thiserror::Error;
|
||||
|
||||
mod egl;
|
||||
mod ext;
|
||||
mod gl;
|
||||
mod proc;
|
||||
mod renderer;
|
||||
|
||||
pub mod sys {
|
||||
pub use super::egl::sys::*;
|
||||
pub use super::gl::sys::*;
|
||||
}
|
||||
|
||||
pub fn init() -> Result<(), RenderError> {
|
||||
egl::init()
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RenderError {
|
||||
#[error("EGL library does not support `EGL_EXT_platform_base`")]
|
||||
ExtPlatformBase,
|
||||
#[error("Could not compile a shader")]
|
||||
ShaderCompileFailed,
|
||||
#[error("Could not link a program")]
|
||||
ProgramLink,
|
||||
#[error("Could not bind to `EGL_OPENGL_ES_API`")]
|
||||
BindFailed,
|
||||
#[error("EGL library does not support device enumeration")]
|
||||
DeviceEnumeration,
|
||||
#[error("EGL library does not support device querying")]
|
||||
DeviceQuery,
|
||||
#[error("`eglQueryDeviceStringEXT` failed")]
|
||||
DeviceQueryString,
|
||||
#[error("`eglCreateContext` failed")]
|
||||
CreateContext,
|
||||
#[error("`eglMakeCurrent` failed")]
|
||||
MakeCurrent,
|
||||
#[error("`eglCreateImageKHR` failed")]
|
||||
CreateImage,
|
||||
#[error("Image buffer is too small")]
|
||||
SmallImageBuffer,
|
||||
#[error("Binding a renderbuffer to a framebuffer failed")]
|
||||
CreateFramebuffer,
|
||||
#[error("`eglQueryDevicesEXT` failed")]
|
||||
QueryDevices,
|
||||
#[error("`eglGetPlatformDisplayEXT` failed")]
|
||||
GetDisplay,
|
||||
#[error("`eglInitialize` failed")]
|
||||
Initialize,
|
||||
#[error("EGL display does not support `EGL_EXT_image_dma_buf_import_modifiers`")]
|
||||
DmaBufImport,
|
||||
#[error("GLES driver does not support `GL_OES_EGL_image`")]
|
||||
OesEglImage,
|
||||
#[error("EGL display does not support `EGL_KHR_image_base`")]
|
||||
ImageBase,
|
||||
#[error(
|
||||
"EGL display does not support `EGL_KHR_no_config_context` or `EGL_MESA_configless_context`"
|
||||
)]
|
||||
ConfiglessContext,
|
||||
#[error("EGL display does not support `EGL_KHR_surfaceless_context`")]
|
||||
SurfacelessContext,
|
||||
#[error("`eglQueryDmaBufFormatsEXT` failed")]
|
||||
QueryDmaBufFormats,
|
||||
#[error(transparent)]
|
||||
DrmError(#[from] DrmError),
|
||||
#[error("Could not find the requested DRM device")]
|
||||
UnknownDrmDevice,
|
||||
#[error("The GLES driver does not support the XRGB8888 format")]
|
||||
XRGB888,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,223 +0,0 @@
|
|||
use crate::ifs::wl_buffer::WlBuffer;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||
use crate::ifs::wl_surface::WlSurface;
|
||||
use crate::pixman::Image;
|
||||
use crate::render::{Border, Renderer};
|
||||
use crate::servermem::ServerMem;
|
||||
use crate::tree::{
|
||||
ContainerFocus, ContainerNode, ContainerSplit, CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT,
|
||||
};
|
||||
use crate::tree::{FloatNode, OutputNode, WorkspaceNode};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct PixmanRenderer<'a> {
|
||||
image: &'a Image<Rc<ServerMem>>,
|
||||
}
|
||||
|
||||
const NON_COLOR: (u8, u8, u8) = (100, 100, 100);
|
||||
const CHILD_COLOR: (u8, u8, u8) = (200, 200, 200);
|
||||
const YES_COLOR: (u8, u8, u8) = (0, 0, 255);
|
||||
|
||||
fn focus_color(focus: ContainerFocus) -> (u8, u8, u8) {
|
||||
match focus {
|
||||
ContainerFocus::None => NON_COLOR,
|
||||
ContainerFocus::Child => CHILD_COLOR,
|
||||
ContainerFocus::Yes => YES_COLOR,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PixmanRenderer<'a> {
|
||||
pub fn new(image: &'a Image<Rc<ServerMem>>) -> Self {
|
||||
Self { image }
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for PixmanRenderer<'_> {
|
||||
fn render_output(&mut self, output: &OutputNode) {
|
||||
if let Some(ws) = output.workspace.get() {
|
||||
self.render_workspace(&ws);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_workspace(&mut self, workspace: &WorkspaceNode) {
|
||||
if let Some(node) = workspace.container.get() {
|
||||
self.render_container(&node, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
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;
|
||||
for child in container.children.iter() {
|
||||
let (r, g, b) = focus_color(child.focus.get());
|
||||
let mut width = space_per_child;
|
||||
if rem > 0 {
|
||||
rem -= 1;
|
||||
width += 1;
|
||||
}
|
||||
let _ = self.image.fill_rect(
|
||||
r,
|
||||
g,
|
||||
b,
|
||||
255,
|
||||
pos,
|
||||
y,
|
||||
pos + width as i32,
|
||||
y + CONTAINER_TITLE_HEIGHT as i32,
|
||||
);
|
||||
pos += width as i32;
|
||||
}
|
||||
self.image.with_clip(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();
|
||||
for (i, child) in container.children.iter().enumerate() {
|
||||
let body = child.body.get();
|
||||
if body.x1() >= cwidth || body.y1() >= cheight {
|
||||
break;
|
||||
}
|
||||
let (r, g, b) = focus_color(child.focus.get());
|
||||
let _ = self.image.fill_rect(
|
||||
r,
|
||||
g,
|
||||
b,
|
||||
255,
|
||||
x + body.x1(),
|
||||
y + body.y1() - CONTAINER_TITLE_HEIGHT,
|
||||
x + body.x2(),
|
||||
y + body.y1(),
|
||||
);
|
||||
{
|
||||
let mut x1 = x + body.x1();
|
||||
let mut x2 = x + body.x2();
|
||||
let mut y2 = y + body.y2();
|
||||
let mut border = Border::empty();
|
||||
if i < num_children {
|
||||
if split == ContainerSplit::Horizontal {
|
||||
border |= Border::RIGHT;
|
||||
x2 += CONTAINER_BORDER;
|
||||
} else if split == ContainerSplit::Vertical {
|
||||
border |= Border::BOTTOM;
|
||||
y2 += CONTAINER_BORDER;
|
||||
}
|
||||
}
|
||||
if i > 0 && split == ContainerSplit::Horizontal {
|
||||
border |= Border::LEFT;
|
||||
x1 -= CONTAINER_BORDER;
|
||||
}
|
||||
let _ = self.image.fill_inner_border(
|
||||
r,
|
||||
g,
|
||||
b,
|
||||
255,
|
||||
x1,
|
||||
y + body.y1() - CONTAINER_TITLE_HEIGHT,
|
||||
x2,
|
||||
y2,
|
||||
CONTAINER_BORDER as i32,
|
||||
border,
|
||||
);
|
||||
}
|
||||
self.image.with_clip(body, || {
|
||||
let content = child.content.get();
|
||||
child.node.render(self, x + content.x1(), y + content.y1());
|
||||
self.image.fill_inner_border(
|
||||
0,
|
||||
0,
|
||||
255,
|
||||
255,
|
||||
x + body.x1(),
|
||||
y + body.y1(),
|
||||
x + body.x1() + body.width(),
|
||||
y + body.y1() + body.height(),
|
||||
2,
|
||||
Border::all(),
|
||||
);
|
||||
self.image.fill_inner_border(
|
||||
255,
|
||||
0,
|
||||
0,
|
||||
255,
|
||||
x + content.x1(),
|
||||
y + content.y1(),
|
||||
x + content.x1() + content.width(),
|
||||
y + content.y1() + content.height(),
|
||||
2,
|
||||
Border::all(),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_buffer(&mut self, buffer: &WlBuffer, x: i32, y: i32) {
|
||||
if let Err(e) = self.image.add_image(&buffer.image, x, y) {
|
||||
let client = &buffer.client;
|
||||
log::error!("Could not access client {} memory: {:#}", client.id, e);
|
||||
if let Ok(d) = client.display() {
|
||||
client.fatal_event(
|
||||
d.implementation_error(format!("Could not access memory: {:#}", e)),
|
||||
);
|
||||
} else {
|
||||
client.state.clients.kill(client.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_floating(&mut self, floating: &FloatNode, x: i32, y: i32) {
|
||||
if let Some(child) = floating.child.get() {
|
||||
child.render(self, x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
}
|
||||
6
src/render/shaders/fill.frag.glsl
Normal file
6
src/render/shaders/fill.frag.glsl
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
precision mediump float;
|
||||
uniform vec4 color;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = color;
|
||||
}
|
||||
5
src/render/shaders/fill.vert.glsl
Normal file
5
src/render/shaders/fill.vert.glsl
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
attribute vec2 pos;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
use crate::pixman::PixmanMemory;
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
use thiserror::Error;
|
||||
|
|
@ -80,14 +78,3 @@ impl Drop for ServerMem {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl PixmanMemory for Rc<ServerMem> {
|
||||
type E = !;
|
||||
|
||||
fn access<T, F>(&self, f: F) -> Result<T, Self::E>
|
||||
where
|
||||
F: FnOnce(&[Cell<u8>]) -> T,
|
||||
{
|
||||
Ok(ServerMem::access(self, f))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use crate::async_engine::{AsyncEngine, SpawnedFuture};
|
||||
use crate::backend::{BackendEvent, OutputId, OutputIds, SeatId, SeatIds};
|
||||
use crate::client::{Client, Clients};
|
||||
use crate::egl::EglContext;
|
||||
use crate::event_loop::EventLoop;
|
||||
use crate::globals::{AddGlobal, Globals};
|
||||
use crate::ifs::wl_output::WlOutputGlobal;
|
||||
use crate::ifs::wl_seat::WlSeatGlobal;
|
||||
use crate::ifs::wl_surface::NoneSurfaceExt;
|
||||
use crate::render::RenderContext;
|
||||
use crate::tree::{DisplayNode, NodeIds};
|
||||
use crate::utils::asyncevent::AsyncEvent;
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
|
|
@ -22,7 +22,7 @@ use std::rc::Rc;
|
|||
pub struct State {
|
||||
pub eng: Rc<AsyncEngine>,
|
||||
pub el: Rc<EventLoop>,
|
||||
pub egl: CloneCell<Option<Rc<EglContext>>>,
|
||||
pub render_ctx: CloneCell<Option<Rc<RenderContext>>>,
|
||||
pub wheel: Rc<Wheel>,
|
||||
pub clients: Clients,
|
||||
pub next_name: NumCell<u32>,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::rect::Rect;
|
||||
use crate::render::{Border, Renderer};
|
||||
use crate::render::Renderer;
|
||||
use crate::tree::{FoundNode, Node, NodeId, WorkspaceNode};
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::linkedlist::{LinkedList, LinkedNode, NodeRef};
|
||||
|
|
@ -39,7 +39,6 @@ pub struct ContainerNode {
|
|||
pub height: Cell<i32>,
|
||||
pub content_width: Cell<i32>,
|
||||
pub content_height: Cell<i32>,
|
||||
pub borders: Cell<Border>,
|
||||
num_children: NumCell<usize>,
|
||||
pub children: LinkedList<ContainerChild>,
|
||||
child_nodes: RefCell<AHashMap<NodeId, LinkedNode<ContainerChild>>>,
|
||||
|
|
@ -59,11 +58,13 @@ impl ContainerChild {
|
|||
let body = self.body.get();
|
||||
let width = content.width();
|
||||
let height = content.height();
|
||||
let x1 = body.x1() + (body.width() - width) / 2;
|
||||
let y1 = body.y1() + (body.height() - height) / 2;
|
||||
// let x1 = body.x1() + (body.width() - width) / 2;
|
||||
// let y1 = body.y1() + (body.height() - height) / 2;
|
||||
let x1 = body.x1();
|
||||
let y1 = body.y1();
|
||||
content = Rect::new_sized(x1, y1, width, height).unwrap();
|
||||
log::debug!("body: {:?}", body);
|
||||
log::debug!("content: {:?}", content);
|
||||
// log::debug!("body: {:?}", body);
|
||||
// log::debug!("content: {:?}", content);
|
||||
self.content.set(content);
|
||||
}
|
||||
}
|
||||
|
|
@ -93,7 +94,6 @@ impl ContainerNode {
|
|||
height: Cell::new(0),
|
||||
content_width: Cell::new(0),
|
||||
content_height: Cell::new(0),
|
||||
borders: Cell::new(Border::NONE),
|
||||
num_children: NumCell::new(1),
|
||||
children,
|
||||
child_nodes: RefCell::new(child_nodes),
|
||||
|
|
@ -145,20 +145,8 @@ impl ContainerNode {
|
|||
}),
|
||||
);
|
||||
}
|
||||
match self.split.get() {
|
||||
ContainerSplit::Horizontal => {
|
||||
let new_content_size = self.content_width.get().saturating_sub(CONTAINER_BORDER);
|
||||
self.content_width.set(new_content_size);
|
||||
}
|
||||
ContainerSplit::Vertical => {
|
||||
let new_content_size = self
|
||||
.content_height
|
||||
.get()
|
||||
.saturating_sub(CONTAINER_BORDER + CONTAINER_TITLE_HEIGHT);
|
||||
self.content_height.set(new_content_size);
|
||||
}
|
||||
}
|
||||
let num_children = self.num_children.fetch_add(1) + 1;
|
||||
self.update_content_size();
|
||||
let new_child_factor = 1.0 / num_children as f64;
|
||||
let mut sum_factors = 0.0;
|
||||
for child in self.children.iter() {
|
||||
|
|
@ -198,7 +186,7 @@ impl ContainerNode {
|
|||
child.body.set(body);
|
||||
pos += body_size + CONTAINER_BORDER;
|
||||
if split == ContainerSplit::Vertical {
|
||||
pos += body_size + CONTAINER_BORDER + CONTAINER_TITLE_HEIGHT;
|
||||
pos += CONTAINER_TITLE_HEIGHT;
|
||||
}
|
||||
}
|
||||
if remaining_content_size > 0 {
|
||||
|
|
@ -242,6 +230,29 @@ impl ContainerNode {
|
|||
child.position_content();
|
||||
}
|
||||
}
|
||||
|
||||
fn update_content_size(&self) {
|
||||
let nc = self.num_children.get();
|
||||
match self.split.get() {
|
||||
ContainerSplit::Horizontal => {
|
||||
let new_content_size = self
|
||||
.width
|
||||
.get()
|
||||
.saturating_sub((nc - 1) as i32 * CONTAINER_BORDER);
|
||||
self.content_width.set(new_content_size);
|
||||
self.content_height
|
||||
.set(self.height.get().saturating_sub(CONTAINER_TITLE_HEIGHT));
|
||||
}
|
||||
ContainerSplit::Vertical => {
|
||||
let new_content_size = self.height.get().saturating_sub(
|
||||
CONTAINER_TITLE_HEIGHT
|
||||
+ (nc - 1) as i32 * (CONTAINER_BORDER + CONTAINER_TITLE_HEIGHT),
|
||||
);
|
||||
self.content_height.set(new_content_size);
|
||||
self.content_width.set(self.width.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for ContainerNode {
|
||||
|
|
@ -295,6 +306,7 @@ impl Node for ContainerNode {
|
|||
self.parent.get().remove_child(self);
|
||||
return;
|
||||
}
|
||||
self.update_content_size();
|
||||
let rem = 1.0 - node.factor.get();
|
||||
let mut sum = 0.0;
|
||||
if rem <= 0.0 {
|
||||
|
|
@ -323,7 +335,7 @@ impl Node for ContainerNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut dyn Renderer, x: i32, y: i32) {
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_container(self, x, y);
|
||||
}
|
||||
|
||||
|
|
@ -338,22 +350,7 @@ impl Node for ContainerNode {
|
|||
fn change_size(self: Rc<Self>, width: i32, height: i32) {
|
||||
self.width.set(width);
|
||||
self.height.set(height);
|
||||
let num_children = self.num_children.get();
|
||||
match self.split.get() {
|
||||
ContainerSplit::Horizontal => {
|
||||
self.content_width
|
||||
.set(width.saturating_sub((num_children - 1) as i32 * CONTAINER_BORDER));
|
||||
self.content_height
|
||||
.set(height.saturating_sub(CONTAINER_TITLE_HEIGHT));
|
||||
}
|
||||
ContainerSplit::Vertical => {
|
||||
self.content_width.set(width);
|
||||
self.content_height.set(height.saturating_sub(
|
||||
(num_children - 1) as i32 * CONTAINER_BORDER
|
||||
+ num_children as i32 * CONTAINER_TITLE_HEIGHT,
|
||||
));
|
||||
}
|
||||
}
|
||||
self.update_content_size();
|
||||
self.apply_factors(1.0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ pub trait Node {
|
|||
let _ = y;
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut dyn Renderer, x: i32, y: i32) {
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
let _ = renderer;
|
||||
let _ = x;
|
||||
let _ = y;
|
||||
|
|
@ -229,8 +229,8 @@ impl Node for OutputNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut dyn Renderer, _x: i32, _y: i32) {
|
||||
renderer.render_output(self);
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_output(self, x, y);
|
||||
}
|
||||
|
||||
fn remove_child(&self, _child: &dyn Node) {
|
||||
|
|
@ -277,7 +277,7 @@ impl Node for FloatNode {
|
|||
self.workspace_link.set(None);
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut dyn Renderer, x: i32, y: i32) {
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_floating(self, x, y)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ impl Node for WorkspaceNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut dyn Renderer, _x: i32, _y: i32) {
|
||||
renderer.render_workspace(self);
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_workspace(self, x, y);
|
||||
}
|
||||
|
||||
fn get_workspace(self: Rc<Self>) -> Option<Rc<WorkspaceNode>> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue