361 lines
11 KiB
Rust
361 lines
11 KiB
Rust
use {
|
|
crate::{
|
|
allocator::Allocator,
|
|
cpu_worker::CpuWorker,
|
|
format::{Format, XRGB8888},
|
|
gfx_api::{
|
|
AsyncShmGfxTexture, BufferResvUser, GfxApi, GfxBlendBuffer, GfxContext, GfxError,
|
|
GfxFormat, GfxFramebuffer, GfxImage, GfxInternalFramebuffer, ResetStatus,
|
|
ShmGfxTexture,
|
|
},
|
|
gfx_apis::gl::{
|
|
GfxGlState, RenderError, Texture,
|
|
egl::{context::EglContext, display::EglDisplay, image::EglImage},
|
|
ext::GL_OES_EGL_IMAGE_EXTERNAL,
|
|
gl::{
|
|
program::GlProgram, render_buffer::GlRenderBuffer, sys::GLint, texture::GlTexture,
|
|
},
|
|
renderer::{framebuffer::Framebuffer, image::Image},
|
|
},
|
|
rect::Rect,
|
|
video::{
|
|
dmabuf::DmaBuf,
|
|
drm::{Drm, syncobj::SyncobjCtx},
|
|
gbm::GbmDevice,
|
|
},
|
|
},
|
|
ahash::AHashMap,
|
|
linearize::{Linearize, StaticMap, static_map},
|
|
std::{
|
|
cell::{Cell, RefCell},
|
|
ffi::CString,
|
|
fmt::{Debug, Formatter},
|
|
rc::Rc,
|
|
},
|
|
};
|
|
|
|
pub(crate) struct TexProg {
|
|
pub(crate) prog: GlProgram,
|
|
pub(crate) pos: GLint,
|
|
pub(crate) texcoord: GLint,
|
|
pub(crate) tex: GLint,
|
|
pub(crate) alpha: GLint,
|
|
}
|
|
|
|
impl TexProg {
|
|
unsafe fn from(prog: GlProgram, alpha_multiplier: bool) -> Self {
|
|
unsafe {
|
|
let alpha = match alpha_multiplier {
|
|
true => prog.get_uniform_location(c"alpha"),
|
|
false => 0,
|
|
};
|
|
Self {
|
|
pos: prog.get_attrib_location(c"pos"),
|
|
texcoord: prog.get_attrib_location(c"texcoord"),
|
|
tex: prog.get_uniform_location(c"tex"),
|
|
alpha,
|
|
prog,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Linearize)]
|
|
pub(in crate::gfx_apis::gl) enum TexCopyType {
|
|
Identity,
|
|
Multiply,
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Linearize)]
|
|
pub(in crate::gfx_apis::gl) enum TexSourceType {
|
|
Opaque,
|
|
HasAlpha,
|
|
}
|
|
|
|
pub(in crate::gfx_apis::gl) struct GlRenderContext {
|
|
pub(crate) ctx: Rc<EglContext>,
|
|
pub gbm: Rc<GbmDevice>,
|
|
pub sync_ctx: Rc<SyncobjCtx>,
|
|
|
|
pub(crate) render_node: Rc<CString>,
|
|
|
|
pub(crate) tex_internal: StaticMap<TexCopyType, StaticMap<TexSourceType, TexProg>>,
|
|
pub(crate) tex_external: Option<StaticMap<TexCopyType, StaticMap<TexSourceType, TexProg>>>,
|
|
|
|
pub(crate) fill_prog: GlProgram,
|
|
pub(crate) fill_prog_pos: GLint,
|
|
pub(crate) fill_prog_color: GLint,
|
|
|
|
pub(in crate::gfx_apis::gl) gl_state: RefCell<GfxGlState>,
|
|
|
|
pub(in crate::gfx_apis::gl) buffer_resv_user: BufferResvUser,
|
|
}
|
|
|
|
impl Debug for GlRenderContext {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("RenderContext").finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
impl GlRenderContext {
|
|
pub fn reset_status(&self) -> Option<ResetStatus> {
|
|
self.ctx.reset_status()
|
|
}
|
|
|
|
pub(in crate::gfx_apis::gl) fn from_drm_device(
|
|
drm: &Drm,
|
|
software: bool,
|
|
) -> Result<Self, RenderError> {
|
|
let node = drm
|
|
.get_render_node()?
|
|
.ok_or(RenderError::NoRenderNode)
|
|
.map(Rc::new)?;
|
|
let dpy = EglDisplay::create(drm, software)?;
|
|
if !dpy.formats.contains_key(&XRGB8888.drm) {
|
|
return Err(RenderError::XRGB888);
|
|
}
|
|
let ctx = dpy.create_context()?;
|
|
ctx.with_current(|| unsafe { Self::new(&ctx, &node) })
|
|
}
|
|
|
|
unsafe fn new(ctx: &Rc<EglContext>, node: &Rc<CString>) -> Result<Self, RenderError> {
|
|
let tex_vert = include_str!("../shaders/tex.vert.glsl");
|
|
let tex_frag = include_str!("../shaders/tex.frag.glsl");
|
|
let create_programs = |external: bool| {
|
|
let create_program = |alpha_multiplier: bool, alpha: bool| {
|
|
let mut tex_frac_src = String::new();
|
|
if external {
|
|
tex_frac_src.push_str("#define EXTERNAL\n");
|
|
}
|
|
if alpha_multiplier {
|
|
tex_frac_src.push_str("#define ALPHA_MULTIPLIER\n");
|
|
}
|
|
if alpha {
|
|
tex_frac_src.push_str("#define ALPHA\n");
|
|
}
|
|
tex_frac_src.push_str(tex_frag);
|
|
unsafe {
|
|
let prog = GlProgram::from_shaders(ctx, tex_vert, &tex_frac_src)?;
|
|
Ok::<_, RenderError>(TexProg::from(prog, alpha_multiplier))
|
|
}
|
|
};
|
|
Ok::<_, RenderError>(static_map! {
|
|
TexCopyType::Identity => static_map! {
|
|
TexSourceType::Opaque => create_program(false, false)?,
|
|
TexSourceType::HasAlpha => create_program(false, true)?,
|
|
},
|
|
TexCopyType::Multiply => static_map! {
|
|
TexSourceType::Opaque => create_program(true, false)?,
|
|
TexSourceType::HasAlpha => create_program(true, true)?,
|
|
},
|
|
})
|
|
};
|
|
let tex_internal = create_programs(false)?;
|
|
let tex_external = if ctx.ext.contains(GL_OES_EGL_IMAGE_EXTERNAL) {
|
|
Some(create_programs(true)?)
|
|
} else {
|
|
None
|
|
};
|
|
let fill_prog = unsafe {
|
|
GlProgram::from_shaders(
|
|
ctx,
|
|
include_str!("../shaders/fill.vert.glsl"),
|
|
include_str!("../shaders/fill.frag.glsl"),
|
|
)?
|
|
};
|
|
Ok(Self {
|
|
ctx: ctx.clone(),
|
|
gbm: ctx.dpy.gbm.clone(),
|
|
sync_ctx: Rc::new(SyncobjCtx::new(ctx.dpy.gbm.drm.fd())),
|
|
|
|
render_node: node.clone(),
|
|
|
|
tex_internal,
|
|
tex_external,
|
|
|
|
fill_prog_pos: unsafe { fill_prog.get_attrib_location(c"pos") },
|
|
fill_prog_color: unsafe { fill_prog.get_uniform_location(c"color") },
|
|
fill_prog,
|
|
|
|
gl_state: Default::default(),
|
|
|
|
buffer_resv_user: Default::default(),
|
|
})
|
|
}
|
|
|
|
pub fn render_node(&self) -> Rc<CString> {
|
|
self.render_node.clone()
|
|
}
|
|
|
|
pub fn formats(&self) -> &Rc<AHashMap<u32, GfxFormat>> {
|
|
&self.ctx.formats
|
|
}
|
|
|
|
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,
|
|
}))
|
|
})
|
|
}
|
|
|
|
fn dmabuf_img(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<Image>, RenderError> {
|
|
self.ctx.with_current(|| {
|
|
let img = self.ctx.dpy.import_dmabuf(buf)?;
|
|
Ok(Rc::new(Image {
|
|
ctx: self.clone(),
|
|
gl: img,
|
|
}))
|
|
})
|
|
}
|
|
|
|
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_shm(&self.ctx, data, format, width, height, stride)?;
|
|
Ok(Rc::new(Texture {
|
|
ctx: self.clone(),
|
|
gl,
|
|
format,
|
|
}))
|
|
}
|
|
|
|
pub fn image_to_fb(
|
|
self: &Rc<Self>,
|
|
img: &Rc<EglImage>,
|
|
) -> Result<Rc<Framebuffer>, RenderError> {
|
|
self.ctx.with_current(|| unsafe {
|
|
let rb = GlRenderBuffer::from_image(img, &self.ctx)?;
|
|
let fb = rb.create_framebuffer()?;
|
|
Ok(Rc::new(Framebuffer {
|
|
ctx: self.clone(),
|
|
gl: fb,
|
|
}))
|
|
})
|
|
}
|
|
}
|
|
|
|
impl GfxContext for GlRenderContext {
|
|
fn reset_status(&self) -> Option<ResetStatus> {
|
|
self.reset_status()
|
|
}
|
|
|
|
fn render_node(&self) -> Option<Rc<CString>> {
|
|
Some(self.render_node())
|
|
}
|
|
|
|
fn formats(&self) -> &Rc<AHashMap<u32, GfxFormat>> {
|
|
self.formats()
|
|
}
|
|
|
|
fn fast_ram_access(&self) -> bool {
|
|
self.ctx.dpy.fast_ram_access
|
|
}
|
|
|
|
fn dmabuf_fb(self: Rc<Self>, buf: &DmaBuf) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
|
(&self)
|
|
.dmabuf_fb(buf)
|
|
.map(|w| w as Rc<dyn GfxFramebuffer>)
|
|
.map_err(|e| e.into())
|
|
}
|
|
|
|
fn dmabuf_img(self: Rc<Self>, buf: &DmaBuf) -> Result<Rc<dyn GfxImage>, GfxError> {
|
|
(&self)
|
|
.dmabuf_img(buf)
|
|
.map(|w| w as Rc<dyn GfxImage>)
|
|
.map_err(|e| e.into())
|
|
}
|
|
|
|
fn shmem_texture(
|
|
self: Rc<Self>,
|
|
_old: Option<Rc<dyn ShmGfxTexture>>,
|
|
data: &[Cell<u8>],
|
|
format: &'static Format,
|
|
width: i32,
|
|
height: i32,
|
|
stride: i32,
|
|
_damage: Option<&[Rect]>,
|
|
) -> Result<Rc<dyn ShmGfxTexture>, GfxError> {
|
|
(&self)
|
|
.shmem_texture(data, format, width, height, stride)
|
|
.map(|w| w as Rc<dyn ShmGfxTexture>)
|
|
.map_err(|e| e.into())
|
|
}
|
|
|
|
fn async_shmem_texture(
|
|
self: Rc<Self>,
|
|
format: &'static Format,
|
|
width: i32,
|
|
height: i32,
|
|
stride: i32,
|
|
_cpu_worker: &Rc<CpuWorker>,
|
|
) -> Result<Rc<dyn AsyncShmGfxTexture>, GfxError> {
|
|
let tex = self.ctx.with_current(|| unsafe {
|
|
let mut tex = 0;
|
|
(self.ctx.dpy.gles.glGenTextures)(1, &mut tex);
|
|
Ok(tex)
|
|
})?;
|
|
Ok(Rc::new(Texture {
|
|
gl: GlTexture {
|
|
ctx: self.ctx.clone(),
|
|
img: None,
|
|
tex,
|
|
width,
|
|
height,
|
|
stride,
|
|
external_only: false,
|
|
format,
|
|
contents_valid: Cell::new(false),
|
|
},
|
|
ctx: self,
|
|
format,
|
|
}))
|
|
}
|
|
|
|
fn allocator(&self) -> Rc<dyn Allocator> {
|
|
self.gbm.clone()
|
|
}
|
|
|
|
fn gfx_api(&self) -> GfxApi {
|
|
GfxApi::OpenGl
|
|
}
|
|
|
|
fn create_internal_fb(
|
|
self: Rc<Self>,
|
|
_cpu_worker: &Rc<CpuWorker>,
|
|
width: i32,
|
|
height: i32,
|
|
stride: i32,
|
|
format: &'static Format,
|
|
) -> Result<Rc<dyn GfxInternalFramebuffer>, GfxError> {
|
|
let fb = self.ctx.with_current(|| unsafe {
|
|
GlRenderBuffer::new(&self.ctx, width, height, stride, format)?.create_framebuffer()
|
|
})?;
|
|
Ok(Rc::new(Framebuffer { ctx: self, gl: fb }))
|
|
}
|
|
|
|
fn syncobj_ctx(&self) -> Option<&Rc<SyncobjCtx>> {
|
|
Some(&self.sync_ctx)
|
|
}
|
|
|
|
fn acquire_blend_buffer(
|
|
&self,
|
|
_width: i32,
|
|
_height: i32,
|
|
) -> Result<Rc<dyn GfxBlendBuffer>, GfxError> {
|
|
Err(GfxError(Box::new(RenderError::NoBlendBuffer)))
|
|
}
|
|
|
|
fn supports_invalid_modifier(&self) -> bool {
|
|
true
|
|
}
|
|
}
|