1
0
Fork 0
forked from wry/wry

wayland: add support for NV12 format

This commit is contained in:
Julian Orth 2022-05-28 22:04:00 +02:00
parent 95327685c1
commit 97e8d487a0
15 changed files with 182 additions and 119 deletions

View file

@ -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', ' ', ' '),

View file

@ -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(())
} }

View file

@ -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 {

View file

@ -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);
} }
} }

View file

@ -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,
} }

View file

@ -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))
} }

View file

@ -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 {

View file

@ -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(),

View file

@ -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);

View file

@ -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;

View file

@ -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,
}) })
} }
} }

View file

@ -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")),

View file

@ -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);
} }
} }

View 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);
}

View 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);
}