wayland: add support for NV12 format
This commit is contained in:
parent
95327685c1
commit
97e8d487a0
15 changed files with 182 additions and 119 deletions
|
|
@ -16,7 +16,9 @@ pub struct Format {
|
||||||
pub gl_type: GLint,
|
pub gl_type: GLint,
|
||||||
pub drm: u32,
|
pub drm: u32,
|
||||||
pub wl_id: Option<u32>,
|
pub wl_id: Option<u32>,
|
||||||
|
pub external_only_guess: bool,
|
||||||
pub has_alpha: bool,
|
pub has_alpha: bool,
|
||||||
|
pub shm_supported: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
static FORMATS_MAP: Lazy<AHashMap<u32, &'static Format>> = Lazy::new(|| {
|
static FORMATS_MAP: Lazy<AHashMap<u32, &'static Format>> = Lazy::new(|| {
|
||||||
|
|
@ -72,7 +74,9 @@ pub static FORMATS: &[Format] = &[
|
||||||
gl_type: GL_UNSIGNED_BYTE,
|
gl_type: GL_UNSIGNED_BYTE,
|
||||||
drm: ARGB8888_DRM,
|
drm: ARGB8888_DRM,
|
||||||
wl_id: Some(ARGB8888_ID),
|
wl_id: Some(ARGB8888_ID),
|
||||||
|
external_only_guess: false,
|
||||||
has_alpha: true,
|
has_alpha: true,
|
||||||
|
shm_supported: true,
|
||||||
},
|
},
|
||||||
Format {
|
Format {
|
||||||
name: "xrgb8888",
|
name: "xrgb8888",
|
||||||
|
|
@ -81,7 +85,20 @@ pub static FORMATS: &[Format] = &[
|
||||||
gl_type: GL_UNSIGNED_BYTE,
|
gl_type: GL_UNSIGNED_BYTE,
|
||||||
drm: XRGB8888_DRM,
|
drm: XRGB8888_DRM,
|
||||||
wl_id: Some(XRGB8888_ID),
|
wl_id: Some(XRGB8888_ID),
|
||||||
|
external_only_guess: false,
|
||||||
has_alpha: false,
|
has_alpha: false,
|
||||||
|
shm_supported: true,
|
||||||
|
},
|
||||||
|
Format {
|
||||||
|
name: "nv12",
|
||||||
|
bpp: 1, // wrong but only used for shm
|
||||||
|
gl_format: 0, // wrong but only used for shm
|
||||||
|
gl_type: GL_UNSIGNED_BYTE, // wrong but only used for shm
|
||||||
|
drm: fourcc_code('N', 'V', '1', '2'),
|
||||||
|
wl_id: None,
|
||||||
|
external_only_guess: true,
|
||||||
|
has_alpha: false,
|
||||||
|
shm_supported: false,
|
||||||
},
|
},
|
||||||
// Format {
|
// Format {
|
||||||
// id: fourcc_code('C', '8', ' ', ' '),
|
// id: fourcc_code('C', '8', ' ', ' '),
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,12 @@ impl WlShmGlobal {
|
||||||
track!(client, obj);
|
track!(client, obj);
|
||||||
client.add_client_obj(&obj)?;
|
client.add_client_obj(&obj)?;
|
||||||
for format in FORMATS {
|
for format in FORMATS {
|
||||||
client.event(Format {
|
if format.shm_supported {
|
||||||
self_id: id,
|
client.event(Format {
|
||||||
format: format.wl_id.unwrap_or(format.drm),
|
self_id: id,
|
||||||
});
|
format: format.wl_id.unwrap_or(format.drm),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ impl WlShmPool {
|
||||||
let req: CreateBuffer = self.client.parse(self, parser)?;
|
let req: CreateBuffer = self.client.parse(self, parser)?;
|
||||||
let drm_format = map_wayland_format_id(req.format);
|
let drm_format = map_wayland_format_id(req.format);
|
||||||
let format = match formats().get(&drm_format) {
|
let format = match formats().get(&drm_format) {
|
||||||
Some(f) => *f,
|
Some(f) if f.shm_supported => *f,
|
||||||
_ => return Err(WlShmPoolError::InvalidFormat(req.format)),
|
_ => return Err(WlShmPoolError::InvalidFormat(req.format)),
|
||||||
};
|
};
|
||||||
if req.height < 0 || req.width < 0 || req.stride < 0 || req.offset < 0 {
|
if req.height < 0 || req.width < 0 || req.stride < 0 || req.offset < 0 {
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,15 @@ impl ZwpLinuxDmabufV1Global {
|
||||||
if let Some(ctx) = client.state.render_ctx.get() {
|
if let Some(ctx) = client.state.render_ctx.get() {
|
||||||
let formats = ctx.formats();
|
let formats = ctx.formats();
|
||||||
for format in formats.values() {
|
for format in formats.values() {
|
||||||
|
if format.implicit_external_only && !ctx.supports_external_texture() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
obj.send_format(format.format.drm);
|
obj.send_format(format.format.drm);
|
||||||
if version >= MODIFIERS_SINCE_VERSION {
|
if version >= MODIFIERS_SINCE_VERSION {
|
||||||
for modifier in format.modifiers.values() {
|
for modifier in format.modifiers.values() {
|
||||||
|
if modifier.external_only && !ctx.supports_external_texture() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
obj.send_modifier(format.format.drm, modifier.modifier);
|
obj.send_modifier(format.format.drm, modifier.modifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,4 +88,12 @@ pub enum RenderError {
|
||||||
XRGB888,
|
XRGB888,
|
||||||
#[error("The DRM device does not have a render node")]
|
#[error("The DRM device does not have a render node")]
|
||||||
NoRenderNode,
|
NoRenderNode,
|
||||||
|
#[error("The requested format is not supported")]
|
||||||
|
UnsupportedFormat,
|
||||||
|
#[error("The requested modifier is not supported")]
|
||||||
|
UnsupportedModifier,
|
||||||
|
#[error("Image is external only and cannot be rendered to")]
|
||||||
|
ExternalOnly,
|
||||||
|
#[error("OpenGL context does not support external textures")]
|
||||||
|
ExternalUnsupported,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ use {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EglFormat {
|
pub struct EglFormat {
|
||||||
pub format: &'static Format,
|
pub format: &'static Format,
|
||||||
|
pub implicit_external_only: bool,
|
||||||
pub modifiers: AHashMap<u64, EglModifier>,
|
pub modifiers: AHashMap<u64, EglModifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,6 +143,13 @@ impl EglDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn import_dmabuf(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<EglImage>, RenderError> {
|
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 {
|
struct PlaneKey {
|
||||||
fd: EGLint,
|
fd: EGLint,
|
||||||
offset: EGLint,
|
offset: EGLint,
|
||||||
|
|
@ -212,6 +220,7 @@ impl EglDisplay {
|
||||||
img,
|
img,
|
||||||
width: buf.width,
|
width: buf.width,
|
||||||
height: buf.height,
|
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();
|
let formats = formats();
|
||||||
for fmt in vec {
|
for fmt in vec {
|
||||||
if let Some(format) = formats.get(&(fmt as u32)) {
|
if let Some(format) = formats.get(&(fmt as u32)) {
|
||||||
|
let (modifiers, external_only) = query_modifiers(dpy, fmt, format)?;
|
||||||
res.insert(
|
res.insert(
|
||||||
format.drm,
|
format.drm,
|
||||||
EglFormat {
|
EglFormat {
|
||||||
format: *format,
|
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(
|
unsafe fn query_modifiers(
|
||||||
dpy: EGLDisplay,
|
dpy: EGLDisplay,
|
||||||
format: EGLint,
|
gl_format: EGLint,
|
||||||
) -> Result<AHashMap<u64, EglModifier>, RenderError> {
|
format: &'static Format,
|
||||||
|
) -> Result<(AHashMap<u64, EglModifier>, bool), RenderError> {
|
||||||
let mut mods = vec![];
|
let mut mods = vec![];
|
||||||
let mut ext_only = vec![];
|
let mut ext_only = vec![];
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
let res = PROCS.eglQueryDmaBufModifiersEXT(
|
let res = PROCS.eglQueryDmaBufModifiersEXT(
|
||||||
dpy,
|
dpy,
|
||||||
format,
|
gl_format,
|
||||||
num,
|
num,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
|
|
@ -277,7 +289,7 @@ unsafe fn query_modifiers(
|
||||||
ext_only.reserve_exact(num as usize);
|
ext_only.reserve_exact(num as usize);
|
||||||
let res = PROCS.eglQueryDmaBufModifiersEXT(
|
let res = PROCS.eglQueryDmaBufModifiersEXT(
|
||||||
dpy,
|
dpy,
|
||||||
format,
|
gl_format,
|
||||||
num,
|
num,
|
||||||
mods.as_mut_ptr(),
|
mods.as_mut_ptr(),
|
||||||
ext_only.as_mut_ptr(),
|
ext_only.as_mut_ptr(),
|
||||||
|
|
@ -289,13 +301,6 @@ unsafe fn query_modifiers(
|
||||||
mods.set_len(num as usize);
|
mods.set_len(num as usize);
|
||||||
ext_only.set_len(num as usize);
|
ext_only.set_len(num as usize);
|
||||||
let mut res = AHashMap::new();
|
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()) {
|
for (modifier, ext_only) in mods.iter().copied().zip(ext_only.iter().copied()) {
|
||||||
res.insert(
|
res.insert(
|
||||||
modifier as _,
|
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 img: EGLImageKHR,
|
||||||
pub width: i32,
|
pub width: i32,
|
||||||
pub height: i32,
|
pub height: i32,
|
||||||
|
pub external_only: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for EglImage {
|
impl Drop for EglImage {
|
||||||
|
|
|
||||||
|
|
@ -118,11 +118,18 @@ pub(super) unsafe fn get_display_ext(dpy: EGLDisplay) -> DisplayExt {
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
pub struct GlExt: u32 {
|
pub struct GlExt: u32 {
|
||||||
const GL_OES_EGL_IMAGE = 1 << 0;
|
const GL_OES_EGL_IMAGE = 1 << 0;
|
||||||
|
const GL_OES_EGL_IMAGE_EXTERNAL = 1 << 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_gl_ext() -> GlExt {
|
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 _) } {
|
match unsafe { get_extensions(glGetString(GL_EXTENSIONS) as _) } {
|
||||||
Some(exts) => get_typed_ext(&exts, GlExt::empty(), &map),
|
Some(exts) => get_typed_ext(&exts, GlExt::empty(), &map),
|
||||||
_ => GlExt::empty(),
|
_ => GlExt::empty(),
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ impl GlRenderBuffer {
|
||||||
img: &Rc<EglImage>,
|
img: &Rc<EglImage>,
|
||||||
ctx: &Rc<EglContext>,
|
ctx: &Rc<EglContext>,
|
||||||
) -> Result<Rc<GlRenderBuffer>, RenderError> {
|
) -> Result<Rc<GlRenderBuffer>, RenderError> {
|
||||||
|
if img.external_only {
|
||||||
|
return Err(RenderError::ExternalOnly);
|
||||||
|
}
|
||||||
let mut rbo = 0;
|
let mut rbo = 0;
|
||||||
glGenRenderbuffers(1, &mut rbo);
|
glGenRenderbuffers(1, &mut rbo);
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, 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_SCISSOR_TEST: GLenum = 0x0C11;
|
||||||
pub const GL_TEXTURE0: GLenum = 0x84C0;
|
pub const GL_TEXTURE0: GLenum = 0x84C0;
|
||||||
pub const GL_TEXTURE_2D: GLenum = 0x0DE1;
|
pub const GL_TEXTURE_2D: GLenum = 0x0DE1;
|
||||||
|
pub const GL_TEXTURE_EXTERNAL_OES: GLenum = 0x8D65;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub const GL_TEXTURE_MAG_FILTER: GLenum = 0x2800;
|
pub const GL_TEXTURE_MAG_FILTER: GLenum = 0x2800;
|
||||||
pub const GL_TEXTURE_MIN_FILTER: GLenum = 0x2801;
|
pub const GL_TEXTURE_MIN_FILTER: GLenum = 0x2801;
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,17 @@ use {
|
||||||
format::Format,
|
format::Format,
|
||||||
render::{
|
render::{
|
||||||
egl::{context::EglContext, image::EglImage, PROCS},
|
egl::{context::EglContext, image::EglImage, PROCS},
|
||||||
gl::{
|
ext::GlExt,
|
||||||
frame_buffer::GlFrameBuffer,
|
gl::sys::{
|
||||||
sys::{
|
glBindTexture, glDeleteTextures, glGenTextures, glPixelStorei, glTexImage2D,
|
||||||
glBindFramebuffer, glBindTexture, glCheckFramebufferStatus, glDeleteTextures,
|
glTexParameteri, GLint, GLuint, GL_CLAMP_TO_EDGE, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
|
||||||
glFramebufferTexture2D, glGenFramebuffers, glGenTextures, glPixelStorei,
|
GL_TEXTURE_WRAP_T, GL_UNPACK_ROW_LENGTH_EXT,
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
sys::GLeglImageOES,
|
sys::{GLeglImageOES, GLenum, GL_TEXTURE_EXTERNAL_OES},
|
||||||
RenderError,
|
RenderError,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, ptr, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct GlTexture {
|
pub struct GlTexture {
|
||||||
|
|
@ -27,84 +22,30 @@ pub struct GlTexture {
|
||||||
pub tex: GLuint,
|
pub tex: GLuint,
|
||||||
pub width: i32,
|
pub width: i32,
|
||||||
pub height: 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 {
|
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> {
|
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 tex = ctx.with_current(|| unsafe {
|
||||||
let mut tex = 0;
|
let mut tex = 0;
|
||||||
glGenTextures(1, &mut tex);
|
glGenTextures(1, &mut tex);
|
||||||
glBindTexture(GL_TEXTURE_2D, tex);
|
glBindTexture(target, tex);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
PROCS.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, GLeglImageOES(img.img.0));
|
PROCS.glEGLImageTargetTexture2DOES(target, GLeglImageOES(img.img.0));
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(target, 0);
|
||||||
Ok(tex)
|
Ok(tex)
|
||||||
})?;
|
})?;
|
||||||
Ok(GlTexture {
|
Ok(GlTexture {
|
||||||
|
|
@ -113,6 +54,7 @@ impl GlTexture {
|
||||||
tex,
|
tex,
|
||||||
width: img.width,
|
width: img.width,
|
||||||
height: img.height,
|
height: img.height,
|
||||||
|
external_only: img.external_only,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,6 +97,7 @@ impl GlTexture {
|
||||||
tex,
|
tex,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
external_only: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use {
|
||||||
context::EglContext,
|
context::EglContext,
|
||||||
display::{EglDisplay, EglFormat},
|
display::{EglDisplay, EglFormat},
|
||||||
},
|
},
|
||||||
|
ext::GlExt,
|
||||||
gl::{
|
gl::{
|
||||||
program::GlProgram, render_buffer::GlRenderBuffer, sys::GLint, texture::GlTexture,
|
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 struct RenderContext {
|
||||||
pub(super) ctx: Rc<EglContext>,
|
pub(super) ctx: Rc<EglContext>,
|
||||||
pub gbm: Rc<GbmDevice>,
|
pub gbm: Rc<GbmDevice>,
|
||||||
|
|
||||||
pub(super) render_node: Rc<CString>,
|
pub(super) render_node: Rc<CString>,
|
||||||
|
|
||||||
pub(super) tex_prog: TexProg,
|
pub(super) tex_internal: TexProgs,
|
||||||
pub(super) tex_alpha_prog: TexProg,
|
pub(super) tex_external: Option<TexProgs>,
|
||||||
|
|
||||||
pub(super) fill_prog: GlProgram,
|
pub(super) fill_prog: GlProgram,
|
||||||
pub(super) fill_prog_pos: GLint,
|
pub(super) fill_prog_pos: GLint,
|
||||||
|
|
@ -79,6 +85,10 @@ impl RenderContext {
|
||||||
self.ctx.reset_status()
|
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> {
|
pub fn from_drm_device(drm: &Drm) -> Result<Self, RenderError> {
|
||||||
let nodes = drm.get_nodes()?;
|
let nodes = drm.get_nodes()?;
|
||||||
let node = match nodes
|
let node = match nodes
|
||||||
|
|
@ -97,16 +107,32 @@ impl RenderContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn new(ctx: &Rc<EglContext>, node: &Rc<CString>) -> Result<Self, RenderError> {
|
unsafe fn new(ctx: &Rc<EglContext>, node: &Rc<CString>) -> Result<Self, RenderError> {
|
||||||
let tex_prog = GlProgram::from_shaders(
|
let tex_vert = include_str!("../shaders/tex.vert.glsl");
|
||||||
ctx,
|
let tex_prog =
|
||||||
include_str!("../shaders/tex.vert.glsl"),
|
GlProgram::from_shaders(ctx, tex_vert, include_str!("../shaders/tex.frag.glsl"))?;
|
||||||
include_str!("../shaders/tex.frag.glsl"),
|
|
||||||
)?;
|
|
||||||
let tex_alpha_prog = GlProgram::from_shaders(
|
let tex_alpha_prog = GlProgram::from_shaders(
|
||||||
ctx,
|
ctx,
|
||||||
include_str!("../shaders/tex.vert.glsl"),
|
tex_vert,
|
||||||
include_str!("../shaders/tex-alpha.frag.glsl"),
|
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(
|
let fill_prog = GlProgram::from_shaders(
|
||||||
ctx,
|
ctx,
|
||||||
include_str!("../shaders/fill.vert.glsl"),
|
include_str!("../shaders/fill.vert.glsl"),
|
||||||
|
|
@ -118,8 +144,11 @@ impl RenderContext {
|
||||||
|
|
||||||
render_node: node.clone(),
|
render_node: node.clone(),
|
||||||
|
|
||||||
tex_prog: TexProg::from(tex_prog),
|
tex_internal: TexProgs {
|
||||||
tex_alpha_prog: TexProg::from(tex_alpha_prog),
|
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_pos: fill_prog.get_attrib_location(ustr!("pos")),
|
||||||
fill_prog_color: fill_prog.get_uniform_location(ustr!("color")),
|
fill_prog_color: fill_prog.get_uniform_location(ustr!("color")),
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@ use {
|
||||||
glActiveTexture, glBindTexture, glDisableVertexAttribArray, glDrawArrays,
|
glActiveTexture, glBindTexture, glDisableVertexAttribArray, glDrawArrays,
|
||||||
glEnableVertexAttribArray, glTexParameteri, glUniform1i, glUniform4f,
|
glEnableVertexAttribArray, glTexParameteri, glUniform1i, glUniform4f,
|
||||||
glUseProgram, glVertexAttribPointer, GL_FALSE, GL_FLOAT, GL_LINEAR,
|
glUseProgram, glVertexAttribPointer, GL_FALSE, GL_FLOAT, GL_LINEAR,
|
||||||
GL_TEXTURE0, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_TRIANGLES,
|
GL_TEXTURE0, GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP,
|
||||||
GL_TRIANGLE_STRIP,
|
|
||||||
},
|
},
|
||||||
|
texture::image_target,
|
||||||
},
|
},
|
||||||
renderer::context::RenderContext,
|
renderer::context::RenderContext,
|
||||||
sys::{glDisable, glEnable, GL_BLEND},
|
sys::{glDisable, glEnable, GL_BLEND},
|
||||||
|
|
@ -359,17 +359,29 @@ impl Renderer<'_> {
|
||||||
unsafe {
|
unsafe {
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture.gl.tex);
|
let target = image_target(texture.gl.external_only);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
|
|
||||||
|
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 {
|
let prog = match format.has_alpha {
|
||||||
true => {
|
true => {
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
&self.ctx.tex_alpha_prog
|
&progs.alpha
|
||||||
}
|
}
|
||||||
false => {
|
false => {
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
&self.ctx.tex_prog
|
&progs.solid
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -423,7 +435,7 @@ impl Renderer<'_> {
|
||||||
glDisableVertexAttribArray(prog.texcoord as _);
|
glDisableVertexAttribArray(prog.texcoord as _);
|
||||||
glDisableVertexAttribArray(prog.pos 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