wayland: add support for NV12 format
This commit is contained in:
parent
95327685c1
commit
97e8d487a0
15 changed files with 182 additions and 119 deletions
|
|
@ -38,6 +38,7 @@ use {
|
|||
#[derive(Debug)]
|
||||
pub struct EglFormat {
|
||||
pub format: &'static Format,
|
||||
pub implicit_external_only: bool,
|
||||
pub modifiers: AHashMap<u64, EglModifier>,
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +143,13 @@ impl EglDisplay {
|
|||
}
|
||||
|
||||
pub fn import_dmabuf(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<EglImage>, RenderError> {
|
||||
let format = match self.formats.get(&buf.format.drm) {
|
||||
Some(fmt) => match fmt.modifiers.get(&buf.modifier) {
|
||||
Some(fmt) => fmt,
|
||||
_ => return Err(RenderError::UnsupportedModifier),
|
||||
},
|
||||
_ => return Err(RenderError::UnsupportedFormat),
|
||||
};
|
||||
struct PlaneKey {
|
||||
fd: EGLint,
|
||||
offset: EGLint,
|
||||
|
|
@ -212,6 +220,7 @@ impl EglDisplay {
|
|||
img,
|
||||
width: buf.width,
|
||||
height: buf.height,
|
||||
external_only: format.external_only,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
@ -243,11 +252,13 @@ unsafe fn query_formats(dpy: EGLDisplay) -> Result<AHashMap<u32, EglFormat>, Ren
|
|||
let formats = formats();
|
||||
for fmt in vec {
|
||||
if let Some(format) = formats.get(&(fmt as u32)) {
|
||||
let (modifiers, external_only) = query_modifiers(dpy, fmt, format)?;
|
||||
res.insert(
|
||||
format.drm,
|
||||
EglFormat {
|
||||
format: *format,
|
||||
modifiers: query_modifiers(dpy, fmt)?,
|
||||
implicit_external_only: external_only,
|
||||
modifiers,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -257,14 +268,15 @@ unsafe fn query_formats(dpy: EGLDisplay) -> Result<AHashMap<u32, EglFormat>, Ren
|
|||
|
||||
unsafe fn query_modifiers(
|
||||
dpy: EGLDisplay,
|
||||
format: EGLint,
|
||||
) -> Result<AHashMap<u64, EglModifier>, RenderError> {
|
||||
gl_format: EGLint,
|
||||
format: &'static Format,
|
||||
) -> Result<(AHashMap<u64, EglModifier>, bool), RenderError> {
|
||||
let mut mods = vec![];
|
||||
let mut ext_only = vec![];
|
||||
let mut num = 0;
|
||||
let res = PROCS.eglQueryDmaBufModifiersEXT(
|
||||
dpy,
|
||||
format,
|
||||
gl_format,
|
||||
num,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
|
|
@ -277,7 +289,7 @@ unsafe fn query_modifiers(
|
|||
ext_only.reserve_exact(num as usize);
|
||||
let res = PROCS.eglQueryDmaBufModifiersEXT(
|
||||
dpy,
|
||||
format,
|
||||
gl_format,
|
||||
num,
|
||||
mods.as_mut_ptr(),
|
||||
ext_only.as_mut_ptr(),
|
||||
|
|
@ -289,13 +301,6 @@ unsafe fn query_modifiers(
|
|||
mods.set_len(num as usize);
|
||||
ext_only.set_len(num as usize);
|
||||
let mut res = AHashMap::new();
|
||||
res.insert(
|
||||
INVALID_MODIFIER,
|
||||
EglModifier {
|
||||
modifier: INVALID_MODIFIER,
|
||||
external_only: false,
|
||||
},
|
||||
);
|
||||
for (modifier, ext_only) in mods.iter().copied().zip(ext_only.iter().copied()) {
|
||||
res.insert(
|
||||
modifier as _,
|
||||
|
|
@ -305,5 +310,16 @@ unsafe fn query_modifiers(
|
|||
},
|
||||
);
|
||||
}
|
||||
Ok(res)
|
||||
let mut external_only = format.external_only_guess;
|
||||
if res.len() > 0 {
|
||||
external_only = res.values().any(|f| f.external_only);
|
||||
}
|
||||
res.insert(
|
||||
INVALID_MODIFIER,
|
||||
EglModifier {
|
||||
modifier: INVALID_MODIFIER,
|
||||
external_only,
|
||||
},
|
||||
);
|
||||
Ok((res, external_only))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ pub struct EglImage {
|
|||
pub img: EGLImageKHR,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
pub external_only: bool,
|
||||
}
|
||||
|
||||
impl Drop for EglImage {
|
||||
|
|
|
|||
|
|
@ -118,11 +118,18 @@ pub(super) unsafe fn get_display_ext(dpy: EGLDisplay) -> DisplayExt {
|
|||
bitflags::bitflags! {
|
||||
pub struct GlExt: u32 {
|
||||
const GL_OES_EGL_IMAGE = 1 << 0;
|
||||
const GL_OES_EGL_IMAGE_EXTERNAL = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gl_ext() -> GlExt {
|
||||
let map = [("GL_OES_EGL_image", GlExt::GL_OES_EGL_IMAGE)];
|
||||
let map = [
|
||||
("GL_OES_EGL_image", GlExt::GL_OES_EGL_IMAGE),
|
||||
(
|
||||
"GL_OES_EGL_image_external",
|
||||
GlExt::GL_OES_EGL_IMAGE_EXTERNAL,
|
||||
),
|
||||
];
|
||||
match unsafe { get_extensions(glGetString(GL_EXTENSIONS) as _) } {
|
||||
Some(exts) => get_typed_ext(&exts, GlExt::empty(), &map),
|
||||
_ => GlExt::empty(),
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ impl GlRenderBuffer {
|
|||
img: &Rc<EglImage>,
|
||||
ctx: &Rc<EglContext>,
|
||||
) -> Result<Rc<GlRenderBuffer>, RenderError> {
|
||||
if img.external_only {
|
||||
return Err(RenderError::ExternalOnly);
|
||||
}
|
||||
let mut rbo = 0;
|
||||
glGenRenderbuffers(1, &mut rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ pub const GL_RENDERBUFFER: GLenum = 0x8D41;
|
|||
pub const GL_SCISSOR_TEST: GLenum = 0x0C11;
|
||||
pub const GL_TEXTURE0: GLenum = 0x84C0;
|
||||
pub const GL_TEXTURE_2D: GLenum = 0x0DE1;
|
||||
pub const GL_TEXTURE_EXTERNAL_OES: GLenum = 0x8D65;
|
||||
#[allow(dead_code)]
|
||||
pub const GL_TEXTURE_MAG_FILTER: GLenum = 0x2800;
|
||||
pub const GL_TEXTURE_MIN_FILTER: GLenum = 0x2801;
|
||||
|
|
|
|||
|
|
@ -3,22 +3,17 @@ use {
|
|||
format::Format,
|
||||
render::{
|
||||
egl::{context::EglContext, image::EglImage, PROCS},
|
||||
gl::{
|
||||
frame_buffer::GlFrameBuffer,
|
||||
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,
|
||||
},
|
||||
ext::GlExt,
|
||||
gl::sys::{
|
||||
glBindTexture, glDeleteTextures, glGenTextures, glPixelStorei, glTexImage2D,
|
||||
glTexParameteri, GLint, GLuint, GL_CLAMP_TO_EDGE, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
|
||||
GL_TEXTURE_WRAP_T, GL_UNPACK_ROW_LENGTH_EXT,
|
||||
},
|
||||
sys::GLeglImageOES,
|
||||
sys::{GLeglImageOES, GLenum, GL_TEXTURE_EXTERNAL_OES},
|
||||
RenderError,
|
||||
},
|
||||
},
|
||||
std::{cell::Cell, ptr, rc::Rc},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct GlTexture {
|
||||
|
|
@ -27,84 +22,30 @@ pub struct GlTexture {
|
|||
pub tex: GLuint,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
pub external_only: bool,
|
||||
}
|
||||
|
||||
pub fn image_target(external_only: bool) -> GLenum {
|
||||
match external_only {
|
||||
true => GL_TEXTURE_EXTERNAL_OES,
|
||||
false => GL_TEXTURE_2D,
|
||||
}
|
||||
}
|
||||
|
||||
impl GlTexture {
|
||||
#[allow(dead_code)]
|
||||
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(),
|
||||
img: None,
|
||||
tex,
|
||||
width,
|
||||
height,
|
||||
}))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn to_framebuffer(self: &Rc<Self>) -> Result<Rc<GlFrameBuffer>, RenderError> {
|
||||
self.ctx.with_current(|| {
|
||||
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_img(ctx: &Rc<EglContext>, img: &Rc<EglImage>) -> Result<GlTexture, RenderError> {
|
||||
if !ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE_EXTERNAL) {
|
||||
return Err(RenderError::ExternalUnsupported);
|
||||
}
|
||||
let target = image_target(img.external_only);
|
||||
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);
|
||||
PROCS.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, GLeglImageOES(img.img.0));
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindTexture(target, tex);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
PROCS.glEGLImageTargetTexture2DOES(target, GLeglImageOES(img.img.0));
|
||||
glBindTexture(target, 0);
|
||||
Ok(tex)
|
||||
})?;
|
||||
Ok(GlTexture {
|
||||
|
|
@ -113,6 +54,7 @@ impl GlTexture {
|
|||
tex,
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
external_only: img.external_only,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -155,6 +97,7 @@ impl GlTexture {
|
|||
tex,
|
||||
width,
|
||||
height,
|
||||
external_only: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use {
|
|||
context::EglContext,
|
||||
display::{EglDisplay, EglFormat},
|
||||
},
|
||||
ext::GlExt,
|
||||
gl::{
|
||||
program::GlProgram, render_buffer::GlRenderBuffer, sys::GLint, texture::GlTexture,
|
||||
},
|
||||
|
|
@ -46,14 +47,19 @@ impl TexProg {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) struct TexProgs {
|
||||
pub alpha: TexProg,
|
||||
pub solid: TexProg,
|
||||
}
|
||||
|
||||
pub struct RenderContext {
|
||||
pub(super) ctx: Rc<EglContext>,
|
||||
pub gbm: Rc<GbmDevice>,
|
||||
|
||||
pub(super) render_node: Rc<CString>,
|
||||
|
||||
pub(super) tex_prog: TexProg,
|
||||
pub(super) tex_alpha_prog: TexProg,
|
||||
pub(super) tex_internal: TexProgs,
|
||||
pub(super) tex_external: Option<TexProgs>,
|
||||
|
||||
pub(super) fill_prog: GlProgram,
|
||||
pub(super) fill_prog_pos: GLint,
|
||||
|
|
@ -79,6 +85,10 @@ impl RenderContext {
|
|||
self.ctx.reset_status()
|
||||
}
|
||||
|
||||
pub fn supports_external_texture(&self) -> bool {
|
||||
self.ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE_EXTERNAL)
|
||||
}
|
||||
|
||||
pub fn from_drm_device(drm: &Drm) -> Result<Self, RenderError> {
|
||||
let nodes = drm.get_nodes()?;
|
||||
let node = match nodes
|
||||
|
|
@ -97,16 +107,32 @@ impl RenderContext {
|
|||
}
|
||||
|
||||
unsafe fn new(ctx: &Rc<EglContext>, node: &Rc<CString>) -> Result<Self, RenderError> {
|
||||
let tex_prog = GlProgram::from_shaders(
|
||||
ctx,
|
||||
include_str!("../shaders/tex.vert.glsl"),
|
||||
include_str!("../shaders/tex.frag.glsl"),
|
||||
)?;
|
||||
let tex_vert = include_str!("../shaders/tex.vert.glsl");
|
||||
let tex_prog =
|
||||
GlProgram::from_shaders(ctx, tex_vert, include_str!("../shaders/tex.frag.glsl"))?;
|
||||
let tex_alpha_prog = GlProgram::from_shaders(
|
||||
ctx,
|
||||
include_str!("../shaders/tex.vert.glsl"),
|
||||
tex_vert,
|
||||
include_str!("../shaders/tex-alpha.frag.glsl"),
|
||||
)?;
|
||||
let tex_external = if ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE_EXTERNAL) {
|
||||
let solid = GlProgram::from_shaders(
|
||||
ctx,
|
||||
tex_vert,
|
||||
include_str!("../shaders/tex-external.frag.glsl"),
|
||||
)?;
|
||||
let alpha = GlProgram::from_shaders(
|
||||
ctx,
|
||||
tex_vert,
|
||||
include_str!("../shaders/tex-external-alpha.frag.glsl"),
|
||||
)?;
|
||||
Some(TexProgs {
|
||||
alpha: TexProg::from(alpha),
|
||||
solid: TexProg::from(solid),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let fill_prog = GlProgram::from_shaders(
|
||||
ctx,
|
||||
include_str!("../shaders/fill.vert.glsl"),
|
||||
|
|
@ -118,8 +144,11 @@ impl RenderContext {
|
|||
|
||||
render_node: node.clone(),
|
||||
|
||||
tex_prog: TexProg::from(tex_prog),
|
||||
tex_alpha_prog: TexProg::from(tex_alpha_prog),
|
||||
tex_internal: TexProgs {
|
||||
solid: TexProg::from(tex_prog),
|
||||
alpha: TexProg::from(tex_alpha_prog),
|
||||
},
|
||||
tex_external,
|
||||
|
||||
fill_prog_pos: fill_prog.get_attrib_location(ustr!("pos")),
|
||||
fill_prog_color: fill_prog.get_uniform_location(ustr!("color")),
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ use {
|
|||
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,
|
||||
GL_TEXTURE0, GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP,
|
||||
},
|
||||
texture::image_target,
|
||||
},
|
||||
renderer::context::RenderContext,
|
||||
sys::{glDisable, glEnable, GL_BLEND},
|
||||
|
|
@ -359,17 +359,29 @@ impl Renderer<'_> {
|
|||
unsafe {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture.gl.tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
let target = image_target(texture.gl.external_only);
|
||||
|
||||
glBindTexture(target, texture.gl.tex);
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
let progs = match texture.gl.external_only {
|
||||
true => match &self.ctx.tex_external {
|
||||
Some(p) => p,
|
||||
_ => {
|
||||
log::error!("Trying to render an external-only texture but context does not support the required extension");
|
||||
return;
|
||||
}
|
||||
},
|
||||
false => &self.ctx.tex_internal,
|
||||
};
|
||||
let prog = match format.has_alpha {
|
||||
true => {
|
||||
glEnable(GL_BLEND);
|
||||
&self.ctx.tex_alpha_prog
|
||||
&progs.alpha
|
||||
}
|
||||
false => {
|
||||
glDisable(GL_BLEND);
|
||||
&self.ctx.tex_prog
|
||||
&progs.solid
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -423,7 +435,7 @@ impl Renderer<'_> {
|
|||
glDisableVertexAttribArray(prog.texcoord as _);
|
||||
glDisableVertexAttribArray(prog.pos as _);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindTexture(target, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
9
src/render/shaders/tex-external-alpha.frag.glsl
Normal file
9
src/render/shaders/tex-external-alpha.frag.glsl
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#extension GL_OES_EGL_image_external : require
|
||||
|
||||
precision mediump float;
|
||||
varying vec2 v_texcoord;
|
||||
uniform samplerExternalOES tex;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture2D(tex, v_texcoord);
|
||||
}
|
||||
9
src/render/shaders/tex-external.frag.glsl
Normal file
9
src/render/shaders/tex-external.frag.glsl
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#extension GL_OES_EGL_image_external : require
|
||||
|
||||
precision mediump float;
|
||||
varying vec2 v_texcoord;
|
||||
uniform samplerExternalOES tex;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue