1
0
Fork 0
forked from wry/wry

render: load libEGL and libGLESv2 at runtime

This commit is contained in:
Julian Orth 2024-02-22 21:14:40 +01:00
parent aa9ca29996
commit 0c82f02b26
15 changed files with 337 additions and 259 deletions

View file

@ -97,16 +97,17 @@ fn write_egl_procs<W: Write>(f: &mut W) -> anyhow::Result<()> {
writeln!(f, "unsafe impl Send for ExtProc {{ }}")?;
writeln!(f)?;
writeln!(f, "impl ExtProc {{")?;
writeln!(f, " pub fn load() -> Self {{")?;
writeln!(f, " Self {{")?;
writeln!(f, " pub fn load() -> Option<Self> {{")?;
writeln!(f, " let egl = EGL.as_ref()?;")?;
writeln!(f, " Some(Self {{")?;
for (name, _, _) in map.iter().copied() {
writeln!(
f,
" {}: unsafe {{ eglGetProcAddress(\"{}\\0\".as_ptr() as _) }},",
" {}: unsafe {{ (egl.eglGetProcAddress)(\"{}\\0\".as_ptr() as _) }},",
name, name
)?;
}
writeln!(f, " }}")?;
writeln!(f, " }})")?;
writeln!(f, " }}")?;
for (name, ret, args) in map.iter().copied() {
let mut args_names = String::new();

View file

@ -18,6 +18,53 @@ macro_rules! egl_transparent {
};
}
macro_rules! dynload {
(
$item:ident: $container:ident from $name:literal {
$(
$fun:ident: $ty:ty,
)*
}
) => {
#[allow(non_snake_case)]
#[derive(Debug)]
pub struct $container {
_lib: libloading::Library,
$(
pub $fun: $ty,
)*
}
pub static $item: once_cell::sync::Lazy<Option<$container>> = once_cell::sync::Lazy::new(|| unsafe {
use crate::utils::errorfmt::ErrorFmt;
let lib = match libloading::Library::new($name) {
Ok(l) => l,
Err(e) => {
log::error!("Could not load lib{}: {}", $name, ErrorFmt(e));
return None;
}
};
$(
#[allow(non_snake_case)]
let $fun: $ty =
match lib.get(stringify!($fun).as_bytes()) {
Ok(s) => *s,
Err(e) => {
log::error!("Could not load {} from {}: {}", stringify!($fun), $name, ErrorFmt(e));
return None;
}
};
)*
Some($container {
_lib: lib,
$(
$fun,
)*
})
});
};
}
use {
crate::{
gfx_api::{
@ -27,10 +74,8 @@ use {
gl::texture::image_target,
renderer::{context::GlRenderContext, framebuffer::Framebuffer, texture::Texture},
sys::{
glActiveTexture, glBindTexture, glDisable, glDisableVertexAttribArray,
glDrawArrays, glEnable, glEnableVertexAttribArray, glTexParameteri, glUniform1i,
glUniform4f, glUseProgram, glVertexAttribPointer, GL_BLEND, GL_FALSE, GL_FLOAT,
GL_LINEAR, GL_TEXTURE0, GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP,
GL_BLEND, GL_FALSE, GL_FLOAT, GL_LINEAR, GL_TEXTURE0, GL_TEXTURE_MIN_FILTER,
GL_TRIANGLES, GL_TRIANGLE_STRIP,
},
},
theme::Color,
@ -69,6 +114,12 @@ pub(super) fn create_gfx_context(drm: &Drm) -> Result<Rc<dyn GfxContext>, GfxErr
#[derive(Debug, Error)]
enum RenderError {
#[error("Could not load libEGL")]
LoadEgl,
#[error("Could not load libGLESv2")]
LoadGlesV2,
#[error("Could not load extension functions from libEGL")]
LoadEglProcs,
#[error("EGL library does not support `EGL_EXT_platform_base`")]
ExtPlatformBase,
#[error("Could not compile a shader")]
@ -221,10 +272,11 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) {
}
fn fill_boxes3(ctx: &GlRenderContext, boxes: &[f32], color: &Color) {
let gles = ctx.ctx.dpy.gles;
unsafe {
glUseProgram(ctx.fill_prog.prog);
glUniform4f(ctx.fill_prog_color, color.r, color.g, color.b, color.a);
glVertexAttribPointer(
(gles.glUseProgram)(ctx.fill_prog.prog);
(gles.glUniform4f)(ctx.fill_prog_color, color.r, color.g, color.b, color.a);
(gles.glVertexAttribPointer)(
ctx.fill_prog_pos as _,
2,
GL_FLOAT,
@ -232,9 +284,9 @@ fn fill_boxes3(ctx: &GlRenderContext, boxes: &[f32], color: &Color) {
0,
boxes.as_ptr() as _,
);
glEnableVertexAttribArray(ctx.fill_prog_pos as _);
glDrawArrays(GL_TRIANGLES, 0, (boxes.len() / 2) as _);
glDisableVertexAttribArray(ctx.fill_prog_pos as _);
(gles.glEnableVertexAttribArray)(ctx.fill_prog_pos as _);
(gles.glDrawArrays)(GL_TRIANGLES, 0, (boxes.len() / 2) as _);
(gles.glDisableVertexAttribArray)(ctx.fill_prog_pos as _);
}
}
@ -248,13 +300,14 @@ fn render_texture(
src: &BufferPoints,
) {
assert!(rc_eq(&ctx.ctx, &texture.ctx.ctx));
let gles = ctx.ctx.dpy.gles;
unsafe {
glActiveTexture(GL_TEXTURE0);
(gles.glActiveTexture)(GL_TEXTURE0);
let target = image_target(texture.gl.external_only);
glBindTexture(target, texture.gl.tex);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
(gles.glBindTexture)(target, texture.gl.tex);
(gles.glTexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
let progs = match texture.gl.external_only {
true => match &ctx.tex_external {
@ -268,18 +321,18 @@ fn render_texture(
};
let prog = match texture.gl.format.has_alpha {
true => {
glEnable(GL_BLEND);
(gles.glEnable)(GL_BLEND);
&progs.alpha
}
false => {
glDisable(GL_BLEND);
(gles.glDisable)(GL_BLEND);
&progs.solid
}
};
glUseProgram(prog.prog.prog);
(gles.glUseProgram)(prog.prog.prog);
glUniform1i(prog.tex, 0);
(gles.glUniform1i)(prog.tex, 0);
let texcoord = [
src.top_right.x,
@ -299,7 +352,7 @@ fn render_texture(
x1, y2, // bottom left
];
glVertexAttribPointer(
(gles.glVertexAttribPointer)(
prog.texcoord as _,
2,
GL_FLOAT,
@ -307,17 +360,17 @@ fn render_texture(
0,
texcoord.as_ptr() as _,
);
glVertexAttribPointer(prog.pos as _, 2, GL_FLOAT, GL_FALSE, 0, pos.as_ptr() as _);
(gles.glVertexAttribPointer)(prog.pos as _, 2, GL_FLOAT, GL_FALSE, 0, pos.as_ptr() as _);
glEnableVertexAttribArray(prog.texcoord as _);
glEnableVertexAttribArray(prog.pos as _);
(gles.glEnableVertexAttribArray)(prog.texcoord as _);
(gles.glEnableVertexAttribArray)(prog.pos as _);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
(gles.glDrawArrays)(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(prog.texcoord as _);
glDisableVertexAttribArray(prog.pos as _);
(gles.glDisableVertexAttribArray)(prog.texcoord as _);
(gles.glDisableVertexAttribArray)(prog.pos as _);
glBindTexture(target, 0);
(gles.glBindTexture)(target, 0);
}
}

View file

@ -1,12 +1,13 @@
use {
crate::gfx_apis::gl::{
egl::sys::{
eglBindAPI, EGLAttrib, EGLLabelKHR, EGLenum, EGLint, EGL_DEBUG_MSG_CRITICAL_KHR,
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_NONE,
EGL_OPENGL_ES_API, EGL_TRUE,
},
ext::{get_client_ext, ClientExt, EXT_PLATFORM_BASE, KHR_DEBUG, KHR_PLATFORM_GBM},
proc::ExtProc,
sys::EGL,
RenderError,
},
bstr::ByteSlice,
@ -27,11 +28,17 @@ pub mod display;
pub mod image;
pub mod sys;
pub(crate) static PROCS: Lazy<ExtProc> = Lazy::new(ExtProc::load);
pub(crate) static PROCS: Lazy<Option<ExtProc>> = Lazy::new(ExtProc::load);
pub(crate) static EXTS: Lazy<ClientExt> = Lazy::new(get_client_ext);
pub(in crate::gfx_apis::gl) fn init() -> Result<(), RenderError> {
let Some(egl) = EGL.as_ref() else {
return Err(RenderError::LoadEgl);
};
let Some(procs) = PROCS.as_ref() else {
return Err(RenderError::LoadEglProcs);
};
if !EXTS.contains(EXT_PLATFORM_BASE) {
return Err(RenderError::ExtPlatformBase);
}
@ -51,10 +58,10 @@ pub(in crate::gfx_apis::gl) fn init() -> Result<(), RenderError> {
EGL_NONE as _,
];
unsafe {
PROCS.eglDebugMessageControlKHR(egl_log, attrib.as_ptr());
procs.eglDebugMessageControlKHR(egl_log, attrib.as_ptr());
}
}
if unsafe { eglBindAPI(EGL_OPENGL_ES_API) } != EGL_TRUE {
if unsafe { (egl.eglBindAPI)(EGL_OPENGL_ES_API) } != EGL_TRUE {
return Err(RenderError::BindFailed);
}
Ok(())

View file

@ -4,10 +4,7 @@ use {
gfx_apis::gl::{
egl::{
display::EglDisplay,
sys::{
eglDestroyContext, eglMakeCurrent, EGLContext, EGLSurface, EGL_FALSE, EGL_TRUE,
},
PROCS,
sys::{EGLContext, EGLSurface, EGL_FALSE, EGL_TRUE},
},
ext::{GlExt, EXT_CREATE_CONTEXT_ROBUSTNESS},
sys::{
@ -32,7 +29,7 @@ pub struct EglContext {
impl Drop for EglContext {
fn drop(&mut self) {
unsafe {
if eglDestroyContext(self.dpy.dpy, self.ctx) != EGL_TRUE {
if (self.dpy.egl.eglDestroyContext)(self.dpy.dpy, self.ctx) != EGL_TRUE {
log::warn!("`eglDestroyContext` failed");
}
}
@ -48,7 +45,7 @@ impl EglContext {
return None;
}
let status = self.with_current(|| unsafe {
let status = match PROCS.glGetGraphicsResetStatusKHR() {
let status = match self.dpy.procs.glGetGraphicsResetStatusKHR() {
0 => return Ok(None),
GL_GUILTY_CONTEXT_RESET_ARB => ResetStatus::Guilty,
GL_INNOCENT_CONTEXT_RESET_ARB => ResetStatus::Innocent,
@ -78,7 +75,7 @@ impl EglContext {
&self,
f: F,
) -> Result<T, RenderError> {
if eglMakeCurrent(
if (self.dpy.egl.eglMakeCurrent)(
self.dpy.dpy,
EGLSurface::none(),
EGLSurface::none(),
@ -90,7 +87,9 @@ impl EglContext {
let prev = CURRENT;
CURRENT = self.ctx;
let res = f();
if eglMakeCurrent(self.dpy.dpy, EGLSurface::none(), EGLSurface::none(), prev) == EGL_FALSE {
if (self.dpy.egl.eglMakeCurrent)(self.dpy.dpy, EGLSurface::none(), EGLSurface::none(), prev)
== EGL_FALSE
{
panic!("Could not restore EGLContext");
}
CURRENT = prev;

View file

@ -7,8 +7,8 @@ use {
context::EglContext,
image::EglImage,
sys::{
eglCreateContext, eglTerminate, EGLClientBuffer, EGLConfig, EGLContext,
EGLDisplay, EGLint, EGL_CONTEXT_CLIENT_VERSION, EGL_DMA_BUF_PLANE0_FD_EXT,
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,
@ -29,9 +29,10 @@ use {
KHR_IMAGE_BASE, KHR_NO_CONFIG_CONTEXT, KHR_SURFACELESS_CONTEXT,
MESA_CONFIGLESS_CONTEXT,
},
proc::ExtProc,
sys::{
eglInitialize, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
EGL_LOSE_CONTEXT_ON_RESET_EXT, EGL_PLATFORM_GBM_KHR,
Egl, GlesV2, EGL, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
EGL_LOSE_CONTEXT_ON_RESET_EXT, EGL_PLATFORM_GBM_KHR, GLESV2,
},
RenderError,
},
@ -57,6 +58,9 @@ pub struct EglModifier {
#[derive(Debug)]
pub struct EglDisplay {
pub egl: &'static Egl,
pub gles: &'static GlesV2,
pub procs: &'static ExtProc,
pub exts: DisplayExt,
pub formats: AHashMap<u32, EglFormat>,
pub gbm: Rc<GbmDevice>,
@ -66,11 +70,20 @@ pub struct EglDisplay {
impl EglDisplay {
pub(in crate::gfx_apis::gl) fn create(drm: &Drm) -> Result<Rc<Self>, RenderError> {
unsafe {
let Some(egl) = EGL.as_ref() else {
return Err(RenderError::LoadEgl);
};
let Some(gles) = GLESV2.as_ref() else {
return Err(RenderError::LoadGlesV2);
};
let Some(procs) = PROCS.as_ref() else {
return Err(RenderError::LoadEglProcs);
};
let gbm = match GbmDevice::new(drm) {
Ok(gbm) => gbm,
Err(e) => return Err(RenderError::Gbm(e)),
};
let dpy = PROCS.eglGetPlatformDisplayEXT(
let dpy = procs.eglGetPlatformDisplayEXT(
EGL_PLATFORM_GBM_KHR as _,
gbm.raw() as _,
ptr::null(),
@ -79,6 +92,9 @@ impl EglDisplay {
return Err(RenderError::GetDisplay);
}
let mut dpy = EglDisplay {
egl,
gles,
procs,
exts: DisplayExt::none(),
formats: AHashMap::new(),
gbm: Rc::new(gbm),
@ -86,7 +102,7 @@ impl EglDisplay {
};
let mut major = 0;
let mut minor = 0;
if eglInitialize(dpy.dpy, &mut major, &mut minor) != EGL_TRUE {
if (egl.eglInitialize)(dpy.dpy, &mut major, &mut minor) != EGL_TRUE {
return Err(RenderError::Initialize);
}
dpy.exts = get_display_ext(dpy.dpy);
@ -105,7 +121,7 @@ impl EglDisplay {
if !dpy.exts.intersects(KHR_SURFACELESS_CONTEXT) {
return Err(RenderError::SurfacelessContext);
}
dpy.formats = query_formats(dpy.dpy)?;
dpy.formats = query_formats(procs, dpy.dpy)?;
Ok(Rc::new(dpy))
}
@ -123,7 +139,7 @@ impl EglDisplay {
}
attrib.push(EGL_NONE);
let ctx = unsafe {
eglCreateContext(
(self.egl.eglCreateContext)(
self.dpy,
EGLConfig::none(),
EGLContext::none(),
@ -139,7 +155,7 @@ impl EglDisplay {
ctx,
formats: Default::default(),
};
ctx.ext = ctx.with_current(|| Ok(get_gl_ext()))?;
ctx.ext = ctx.with_current(get_gl_ext)?;
if !ctx.ext.contains(GL_OES_EGL_IMAGE) {
return Err(RenderError::OesEglImage);
}
@ -245,7 +261,7 @@ impl EglDisplay {
}
attribs.push(EGL_NONE);
let img = unsafe {
PROCS.eglCreateImageKHR(
self.procs.eglCreateImageKHR(
self.dpy,
EGLContext::none(),
EGL_LINUX_DMA_BUF_EXT as _,
@ -268,22 +284,25 @@ impl EglDisplay {
impl Drop for EglDisplay {
fn drop(&mut self) {
unsafe {
if eglTerminate(self.dpy) != EGL_TRUE {
if (self.egl.eglTerminate)(self.dpy) != EGL_TRUE {
log::warn!("`eglTerminate` failed");
}
}
}
}
unsafe fn query_formats(dpy: EGLDisplay) -> Result<AHashMap<u32, EglFormat>, RenderError> {
unsafe fn query_formats(
procs: &ExtProc,
dpy: EGLDisplay,
) -> Result<AHashMap<u32, EglFormat>, RenderError> {
let mut vec = vec![];
let mut num = 0;
let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, ptr::null_mut(), &mut num);
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);
let res = procs.eglQueryDmaBufFormatsEXT(dpy, num, vec.as_mut_ptr(), &mut num);
if res != EGL_TRUE {
return Err(RenderError::QueryDmaBufFormats);
}
@ -292,7 +311,7 @@ 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)?;
let (modifiers, external_only) = query_modifiers(procs, dpy, fmt, format)?;
res.insert(
format.drm,
EglFormat {
@ -307,6 +326,7 @@ unsafe fn query_formats(dpy: EGLDisplay) -> Result<AHashMap<u32, EglFormat>, Ren
}
unsafe fn query_modifiers(
procs: &ExtProc,
dpy: EGLDisplay,
gl_format: EGLint,
format: &'static Format,
@ -314,7 +334,7 @@ unsafe fn query_modifiers(
let mut mods = vec![];
let mut ext_only = vec![];
let mut num = 0;
let res = PROCS.eglQueryDmaBufModifiersEXT(
let res = procs.eglQueryDmaBufModifiersEXT(
dpy,
gl_format,
num,
@ -327,7 +347,7 @@ unsafe fn query_modifiers(
}
mods.reserve_exact(num as usize);
ext_only.reserve_exact(num as usize);
let res = PROCS.eglQueryDmaBufModifiersEXT(
let res = procs.eglQueryDmaBufModifiersEXT(
dpy,
gl_format,
num,

View file

@ -3,7 +3,6 @@ use {
gfx_apis::gl::egl::{
display::EglDisplay,
sys::{EGLImageKHR, EGL_FALSE},
PROCS,
},
video::dmabuf::DmaBuf,
},
@ -20,7 +19,7 @@ pub struct EglImage {
impl Drop for EglImage {
fn drop(&mut self) {
unsafe {
if PROCS.eglDestroyImageKHR(self.dpy.dpy, self.img) == EGL_FALSE {
if self.dpy.procs.eglDestroyImageKHR(self.dpy.dpy, self.img) == EGL_FALSE {
log::warn!("`eglDestroyImageKHR` failed");
}
}

View file

@ -84,24 +84,25 @@ 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;
dynload! {
EGL: Egl from "libEGL.so" {
eglQueryString: unsafe fn(dpy: EGLDisplay, name: EGLint) -> *const c::c_char,
eglGetProcAddress: unsafe fn(procname: *const c::c_char) -> *mut u8,
eglBindAPI: unsafe fn(api: EGLenum) -> EGLBoolean,
eglTerminate: unsafe fn(dpy: EGLDisplay) -> EGLBoolean,
eglInitialize: unsafe fn(dpy: EGLDisplay, major: *mut EGLint, minor: *mut EGLint) -> EGLBoolean,
eglCreateContext: unsafe fn(
dpy: EGLDisplay,
config: EGLConfig,
share_context: EGLContext,
attrib_list: *const EGLint,
) -> EGLContext,
eglDestroyContext: unsafe fn(dpy: EGLDisplay, ctx: EGLContext) -> EGLBoolean,
eglMakeCurrent: unsafe fn(
dpy: EGLDisplay,
draw: EGLSurface,
read: EGLSurface,
ctx: EGLContext,
) -> EGLBoolean,
}
}

View file

@ -1,8 +1,10 @@
use {
crate::{
gfx_apis::gl::{
egl::sys::{eglQueryString, EGLDisplay, EGL_EXTENSIONS},
gl::sys::{glGetString, GL_EXTENSIONS},
egl::sys::{EGLDisplay, EGL_EXTENSIONS},
gl::sys::GL_EXTENSIONS,
sys::{EGL, GLESV2},
RenderError,
},
utils::trim::AsciiTrim,
},
@ -30,7 +32,7 @@ unsafe fn get_extensions(ext: *const c::c_char) -> Option<AHashSet<String>> {
}
unsafe fn get_dpy_extensions(dpy: EGLDisplay) -> Option<AHashSet<String>> {
let ext = eglQueryString(dpy, EGL_EXTENSIONS);
let ext = (EGL.as_ref()?.eglQueryString)(dpy, EGL_EXTENSIONS);
get_extensions(ext)
}
@ -107,13 +109,16 @@ bitflags! {
GL_OES_EGL_IMAGE_EXTERNAL = 1 << 1,
}
pub fn get_gl_ext() -> GlExt {
pub fn get_gl_ext() -> Result<GlExt, RenderError> {
let map = [
("GL_OES_EGL_image", GL_OES_EGL_IMAGE),
("GL_OES_EGL_image_external", GL_OES_EGL_IMAGE_EXTERNAL),
];
match unsafe { get_extensions(glGetString(GL_EXTENSIONS) as _) } {
Some(exts) => get_typed_ext(&exts, GlExt::none(), &map),
_ => GlExt::none(),
let Some(gles) = GLESV2.as_ref() else {
return Err(RenderError::LoadGlesV2);
};
match unsafe { get_extensions((gles.glGetString)(GL_EXTENSIONS) as _) } {
Some(exts) => Ok(get_typed_ext(&exts, GlExt::none(), &map)),
_ => Ok(GlExt::none()),
}
}

View file

@ -1,11 +1,7 @@
use {
crate::gfx_apis::gl::{
egl::context::EglContext,
gl::{
render_buffer::GlRenderBuffer,
sys::{glDeleteFramebuffers, GLuint},
texture::GlTexture,
},
gl::{render_buffer::GlRenderBuffer, sys::GLuint, texture::GlTexture},
},
std::rc::Rc,
};
@ -23,7 +19,7 @@ impl Drop for GlFrameBuffer {
fn drop(&mut self) {
let _ = self.ctx.with_current(|| {
unsafe {
glDeleteFramebuffers(1, &self.fbo);
(self.ctx.dpy.gles.glDeleteFramebuffers)(1, &self.fbo);
}
Ok(())
});

View file

@ -3,11 +3,7 @@ use {
egl::context::EglContext,
gl::{
shader::GlShader,
sys::{
glAttachShader, glCreateProgram, glDeleteProgram, glDetachShader,
glGetAttribLocation, glGetProgramiv, glGetUniformLocation, glLinkProgram, GLint,
GLuint, GL_FALSE, GL_FRAGMENT_SHADER, GL_LINK_STATUS, GL_VERTEX_SHADER,
},
sys::{GLint, GLuint, GL_FALSE, GL_FRAGMENT_SHADER, GL_LINK_STATUS, GL_VERTEX_SHADER},
},
RenderError,
},
@ -16,7 +12,7 @@ use {
};
pub struct GlProgram {
pub _ctx: Rc<EglContext>,
pub ctx: Rc<EglContext>,
pub prog: GLuint,
}
@ -35,18 +31,19 @@ impl GlProgram {
vert: &GlShader,
frag: &GlShader,
) -> Result<Self, RenderError> {
let gles = vert.ctx.dpy.gles;
let res = GlProgram {
_ctx: vert.ctx.clone(),
prog: glCreateProgram(),
ctx: vert.ctx.clone(),
prog: (gles.glCreateProgram)(),
};
glAttachShader(res.prog, vert.shader);
glAttachShader(res.prog, frag.shader);
glLinkProgram(res.prog);
glDetachShader(res.prog, vert.shader);
glDetachShader(res.prog, frag.shader);
(gles.glAttachShader)(res.prog, vert.shader);
(gles.glAttachShader)(res.prog, frag.shader);
(gles.glLinkProgram)(res.prog);
(gles.glDetachShader)(res.prog, vert.shader);
(gles.glDetachShader)(res.prog, frag.shader);
let mut ok = 0;
glGetProgramiv(res.prog, GL_LINK_STATUS, &mut ok);
(gles.glGetProgramiv)(res.prog, GL_LINK_STATUS, &mut ok);
if ok == GL_FALSE as GLint {
return Err(RenderError::ProgramLink);
}
@ -55,19 +52,19 @@ impl GlProgram {
}
pub unsafe fn get_uniform_location(&self, name: &Ustr) -> GLint {
glGetUniformLocation(self.prog, name.as_ptr() as _)
(self.ctx.dpy.gles.glGetUniformLocation)(self.prog, name.as_ptr() as _)
}
pub unsafe fn get_attrib_location(&self, name: &Ustr) -> GLint {
glGetAttribLocation(self.prog, name.as_ptr() as _)
(self.ctx.dpy.gles.glGetAttribLocation)(self.prog, name.as_ptr() as _)
}
}
impl Drop for GlProgram {
fn drop(&mut self) {
unsafe {
let _ = self._ctx.with_current(|| {
glDeleteProgram(self.prog);
let _ = self.ctx.with_current(|| {
(self.ctx.dpy.gles.glDeleteProgram)(self.prog);
Ok(())
});
}

View file

@ -1,12 +1,10 @@
use {
crate::gfx_apis::gl::{
egl::{context::EglContext, image::EglImage, PROCS},
egl::{context::EglContext, image::EglImage},
gl::{
frame_buffer::GlFrameBuffer,
sys::{
glBindFramebuffer, glBindRenderbuffer, glCheckFramebufferStatus,
glDeleteRenderbuffers, glFramebufferRenderbuffer, glGenFramebuffers,
glGenRenderbuffers, GLeglImageOES, GLuint, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER,
GLeglImageOES, GLuint, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER,
GL_FRAMEBUFFER_COMPLETE, GL_RENDERBUFFER,
},
},
@ -29,11 +27,14 @@ impl GlRenderBuffer {
if img.external_only {
return Err(RenderError::ExternalOnly);
}
let gles = ctx.dpy.gles;
let mut rbo = 0;
glGenRenderbuffers(1, &mut rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
PROCS.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, GLeglImageOES(img.img.0));
glBindRenderbuffer(GL_RENDERBUFFER, 0);
(gles.glGenRenderbuffers)(1, &mut rbo);
(gles.glBindRenderbuffer)(GL_RENDERBUFFER, rbo);
ctx.dpy
.procs
.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, GLeglImageOES(img.img.0));
(gles.glBindRenderbuffer)(GL_RENDERBUFFER, 0);
Ok(Rc::new(GlRenderBuffer {
img: img.clone(),
ctx: ctx.clone(),
@ -44,17 +45,18 @@ impl GlRenderBuffer {
pub(in crate::gfx_apis::gl) unsafe fn create_framebuffer(
self: &Rc<Self>,
) -> Result<GlFrameBuffer, RenderError> {
let gles = self.ctx.dpy.gles;
let mut fbo = 0;
glGenFramebuffers(1, &mut fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(
(gles.glGenFramebuffers)(1, &mut fbo);
(gles.glBindFramebuffer)(GL_FRAMEBUFFER, fbo);
(gles.glFramebufferRenderbuffer)(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
self.rbo,
);
let status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
let status = (gles.glCheckFramebufferStatus)(GL_FRAMEBUFFER);
(gles.glBindFramebuffer)(GL_FRAMEBUFFER, 0);
let fb = GlFrameBuffer {
rb: self.clone(),
_tex: None,
@ -74,7 +76,7 @@ impl Drop for GlRenderBuffer {
fn drop(&mut self) {
let _ = self.ctx.with_current(|| {
unsafe {
glDeleteRenderbuffers(1, &self.rbo);
(self.ctx.dpy.gles.glDeleteRenderbuffers)(1, &self.rbo);
}
Ok(())
});

View file

@ -1,10 +1,7 @@
use {
crate::gfx_apis::gl::{
egl::context::EglContext,
gl::sys::{
glCompileShader, glCreateShader, glDeleteShader, glGetShaderiv, glShaderSource, GLenum,
GLuint, GL_COMPILE_STATUS, GL_FALSE,
},
gl::sys::{GLenum, GLuint, GL_COMPILE_STATUS, GL_FALSE},
sys::GLint,
RenderError,
},
@ -22,17 +19,18 @@ impl GlShader {
ty: GLenum,
src: &str,
) -> Result<Self, RenderError> {
let shader = glCreateShader(ty);
let gles = ctx.dpy.gles;
let shader = (gles.glCreateShader)(ty);
let res = GlShader {
ctx: ctx.clone(),
shader,
};
let len = src.len() as _;
glShaderSource(shader, 1, &(src.as_ptr() as _), &len);
glCompileShader(shader);
(gles.glShaderSource)(shader, 1, &(src.as_ptr() as _), &len);
(gles.glCompileShader)(shader);
let mut ok = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &mut ok);
(gles.glGetShaderiv)(shader, GL_COMPILE_STATUS, &mut ok);
if ok == GL_FALSE as GLint {
return Err(RenderError::ShaderCompileFailed);
}
@ -43,7 +41,7 @@ impl GlShader {
impl Drop for GlShader {
fn drop(&mut self) {
let _ = self.ctx.with_current(|| unsafe {
glDeleteShader(self.shader);
(self.ctx.dpy.gles.glDeleteShader)(self.shader);
Ok(())
});
}

View file

@ -45,107 +45,105 @@ pub const GL_BLEND: GLenum = 0x0BE2;
pub const GL_ONE: GLenum = 1;
pub const GL_ONE_MINUS_SRC_ALPHA: GLenum = 0x0303;
#[link(name = "GLESv2")]
extern "C" {
pub fn glGetString(name: GLenum) -> *const u8;
pub fn glGenRenderbuffers(n: GLsizei, renderbuffers: *mut GLuint);
pub fn glDeleteRenderbuffers(n: GLsizei, renderbuffers: *const GLuint);
pub fn glBindRenderbuffer(target: GLenum, renderbuffer: GLuint);
pub fn glGenFramebuffers(n: GLsizei, framebuffers: *mut GLuint);
pub fn glDeleteFramebuffers(n: GLsizei, framebuffers: *const GLuint);
pub fn glBindFramebuffer(target: GLenum, framebuffer: GLuint);
pub fn glFramebufferRenderbuffer(
target: GLenum,
attachment: GLenum,
renderbuffertarget: GLenum,
renderbuffer: GLuint,
);
#[allow(dead_code)]
pub fn glFramebufferTexture2D(
target: GLenum,
attachment: GLenum,
textarget: GLenum,
texture: GLenum,
level: GLint,
);
pub fn glCheckFramebufferStatus(target: GLenum) -> GLenum;
pub fn glClear(mask: GLbitfield);
pub fn glBlendFunc(sfactor: GLenum, dfactor: GLenum);
pub fn glClearColor(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat);
#[allow(dead_code)]
pub fn glFlush();
dynload! {
GLESV2: GlesV2 from "libGLESv2.so" {
glGetString: unsafe fn(name: GLenum) -> *const u8,
glGenRenderbuffers: unsafe fn(n: GLsizei, renderbuffers: *mut GLuint),
glDeleteRenderbuffers: unsafe fn(n: GLsizei, renderbuffers: *const GLuint),
glBindRenderbuffer: unsafe fn(target: GLenum, renderbuffer: GLuint),
glGenFramebuffers: unsafe fn(n: GLsizei, framebuffers: *mut GLuint),
glDeleteFramebuffers: unsafe fn(n: GLsizei, framebuffers: *const GLuint),
glBindFramebuffer: unsafe fn(target: GLenum, framebuffer: GLuint),
glFramebufferRenderbuffer: unsafe fn(
target: GLenum,
attachment: GLenum,
renderbuffertarget: GLenum,
renderbuffer: GLuint,
),
glFramebufferTexture2D: unsafe fn(
target: GLenum,
attachment: GLenum,
textarget: GLenum,
texture: GLenum,
level: GLint,
),
glCheckFramebufferStatus: unsafe fn(target: GLenum) -> GLenum,
glClear: unsafe fn(mask: GLbitfield),
glBlendFunc: unsafe fn(sfactor: GLenum, dfactor: GLenum),
glClearColor: unsafe fn(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat),
glFlush: unsafe fn(),
pub fn glReadnPixels(
x: GLint,
y: GLint,
width: GLsizei,
height: GLsizei,
format: GLenum,
ty: GLenum,
buf_size: GLsizei,
data: *mut c::c_void,
);
glReadnPixels: unsafe fn(
x: GLint,
y: GLint,
width: GLsizei,
height: GLsizei,
format: GLenum,
ty: GLenum,
buf_size: GLsizei,
data: *mut c::c_void,
),
pub fn glGenTextures(n: GLsizei, textures: *mut GLuint);
pub fn glDeleteTextures(n: GLsizei, textures: *const GLuint);
pub fn glBindTexture(target: GLenum, texture: GLuint);
pub fn glTexParameteri(target: GLenum, pname: GLenum, param: GLint);
glGenTextures: unsafe fn(n: GLsizei, textures: *mut GLuint),
glDeleteTextures: unsafe fn(n: GLsizei, textures: *const GLuint),
glBindTexture: unsafe fn(target: GLenum, texture: GLuint),
glTexParameteri: unsafe fn(target: GLenum, pname: GLenum, param: GLint),
pub fn glPixelStorei(pname: GLenum, param: GLint);
glPixelStorei: unsafe fn(pname: GLenum, param: GLint),
pub fn glTexImage2D(
target: GLenum,
level: GLint,
internalformat: GLint,
width: GLsizei,
height: GLsizei,
border: GLint,
format: GLenum,
ty: GLenum,
pixels: *const c::c_void,
);
glTexImage2D: unsafe fn(
target: GLenum,
level: GLint,
internalformat: GLint,
width: GLsizei,
height: GLsizei,
border: GLint,
format: GLenum,
ty: GLenum,
pixels: *const c::c_void,
),
pub fn glEnable(cap: GLenum);
pub fn glDisable(cap: GLenum);
pub fn glViewport(x: GLint, y: GLint, width: GLsizei, height: GLsizei);
glEnable: unsafe fn(cap: GLenum),
glDisable: unsafe fn(cap: GLenum),
glViewport: unsafe fn(x: GLint, y: GLint, width: GLsizei, height: GLsizei),
pub fn glCreateShader(ty: GLenum) -> GLuint;
pub fn glDeleteShader(shader: GLuint);
pub fn glShaderSource(
shader: GLuint,
count: GLsizei,
string: *const *const GLchar,
length: *const GLint,
);
pub fn glCompileShader(shader: GLuint);
pub fn glGetShaderiv(shader: GLuint, pname: GLenum, params: *mut GLint);
glCreateShader: unsafe fn(ty: GLenum) -> GLuint,
glDeleteShader: unsafe fn(shader: GLuint),
glShaderSource: unsafe fn(
shader: GLuint,
count: GLsizei,
string: *const *const GLchar,
length: *const GLint,
),
glCompileShader: unsafe fn(shader: GLuint),
glGetShaderiv: unsafe fn(shader: GLuint, pname: GLenum, params: *mut GLint),
pub fn glCreateProgram() -> GLuint;
pub fn glDeleteProgram(prog: GLuint);
pub fn glAttachShader(prog: GLuint, shader: GLuint);
pub fn glDetachShader(prog: GLuint, shader: GLuint);
pub fn glLinkProgram(prog: GLuint);
pub fn glGetProgramiv(program: GLuint, pname: GLenum, params: *mut GLint);
pub fn glUseProgram(program: GLuint);
glCreateProgram: unsafe fn() -> GLuint,
glDeleteProgram: unsafe fn(prog: GLuint),
glAttachShader: unsafe fn(prog: GLuint, shader: GLuint),
glDetachShader: unsafe fn(prog: GLuint, shader: GLuint),
glLinkProgram: unsafe fn(prog: GLuint),
glGetProgramiv: unsafe fn(program: GLuint, pname: GLenum, params: *mut GLint),
glUseProgram: unsafe fn(program: GLuint),
pub fn glGetUniformLocation(prog: GLuint, name: *const GLchar) -> GLint;
pub fn glGetAttribLocation(prog: GLuint, name: *const GLchar) -> GLint;
pub fn glUniform1i(location: GLint, v0: GLint);
#[allow(dead_code)]
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,
ty: GLenum,
normalized: GLboolean,
stride: GLsizei,
pointer: *const u8,
);
glGetUniformLocation: unsafe fn(prog: GLuint, name: *const GLchar) -> GLint,
glGetAttribLocation: unsafe fn(prog: GLuint, name: *const GLchar) -> GLint,
glUniform1i: unsafe fn(location: GLint, v0: GLint),
glUniform1f: unsafe fn(location: GLint, v0: GLfloat),
glUniform4f: unsafe fn(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat, v3: GLfloat),
glVertexAttribPointer: unsafe fn(
index: GLuint,
size: GLint,
ty: GLenum,
normalized: GLboolean,
stride: GLsizei,
pointer: *const u8,
),
pub fn glActiveTexture(texture: GLuint);
glActiveTexture: unsafe fn(texture: GLuint),
pub fn glEnableVertexAttribArray(idx: GLuint);
pub fn glDisableVertexAttribArray(idx: GLuint);
pub fn glDrawArrays(mode: GLenum, first: GLint, count: GLsizei);
glEnableVertexAttribArray: unsafe fn(idx: GLuint),
glDisableVertexAttribArray: unsafe fn(idx: GLuint),
glDrawArrays: unsafe fn(mode: GLenum, first: GLint, count: GLsizei),
}
}

View file

@ -2,11 +2,10 @@ use {
crate::{
format::Format,
gfx_apis::gl::{
egl::{context::EglContext, image::EglImage, PROCS},
egl::{context::EglContext, image::EglImage},
ext::GL_OES_EGL_IMAGE_EXTERNAL,
gl::sys::{
glBindTexture, glDeleteTextures, glGenTextures, glPixelStorei, glTexImage2D,
glTexParameteri, GLint, GLuint, GL_CLAMP_TO_EDGE, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GLint, GLuint, GL_CLAMP_TO_EDGE, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_TEXTURE_WRAP_T, GL_UNPACK_ROW_LENGTH_EXT,
},
sys::{GLeglImageOES, GLenum, GL_TEXTURE_EXTERNAL_OES},
@ -41,15 +40,18 @@ impl GlTexture {
if !ctx.ext.contains(GL_OES_EGL_IMAGE_EXTERNAL) {
return Err(RenderError::ExternalUnsupported);
}
let gles = ctx.dpy.gles;
let target = image_target(img.external_only);
let tex = ctx.with_current(|| unsafe {
let mut tex = 0;
glGenTextures(1, &mut tex);
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);
(gles.glGenTextures)(1, &mut tex);
(gles.glBindTexture)(target, tex);
(gles.glTexParameteri)(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
(gles.glTexParameteri)(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
ctx.dpy
.procs
.glEGLImageTargetTexture2DOES(target, GLeglImageOES(img.img.0));
(gles.glBindTexture)(target, 0);
Ok(tex)
})?;
Ok(GlTexture {
@ -74,14 +76,15 @@ impl GlTexture {
if (stride * height) as usize > data.len() {
return Err(RenderError::SmallImageBuffer);
}
let gles = ctx.dpy.gles;
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(
(gles.glGenTextures)(1, &mut tex);
(gles.glBindTexture)(GL_TEXTURE_2D, tex);
(gles.glTexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
(gles.glTexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
(gles.glPixelStorei)(GL_UNPACK_ROW_LENGTH_EXT, stride / format.bpp as GLint);
(gles.glTexImage2D)(
GL_TEXTURE_2D,
0,
format.gl_format,
@ -92,8 +95,8 @@ impl GlTexture {
format.gl_type as _,
data.as_ptr() as _,
);
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
glBindTexture(GL_TEXTURE_2D, 0);
(gles.glPixelStorei)(GL_UNPACK_ROW_LENGTH_EXT, 0);
(gles.glBindTexture)(GL_TEXTURE_2D, 0);
Ok(tex)
})?;
Ok(GlTexture {
@ -111,7 +114,7 @@ impl GlTexture {
impl Drop for GlTexture {
fn drop(&mut self) {
let _ = self.ctx.with_current(|| unsafe {
glDeleteTextures(1, &self.tex);
(self.ctx.dpy.gles.glDeleteTextures)(1, &self.tex);
Ok(())
});
}

View file

@ -5,14 +5,11 @@ use {
gfx_apis::gl::{
gl::{
frame_buffer::GlFrameBuffer,
sys::{
glBindFramebuffer, glClear, glClearColor, glViewport, GL_COLOR_BUFFER_BIT,
GL_FRAMEBUFFER,
},
sys::{GL_COLOR_BUFFER_BIT, GL_FRAMEBUFFER},
},
renderer::context::GlRenderContext,
run_ops,
sys::{glBlendFunc, glFlush, glReadnPixels, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
sys::{GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
},
theme::Color,
},
@ -46,12 +43,13 @@ impl Framebuffer {
format: &Format,
shm: &[Cell<u8>],
) {
let gles = self.ctx.ctx.dpy.gles;
let y = self.gl.height - y - height;
let _ = self.ctx.ctx.with_current(|| {
unsafe {
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
glViewport(0, 0, self.gl.width, self.gl.height);
glReadnPixels(
(gles.glBindFramebuffer)(GL_FRAMEBUFFER, self.gl.fbo);
(gles.glViewport)(0, 0, self.gl.width, self.gl.height);
(gles.glReadnPixels)(
x,
y,
width,
@ -67,19 +65,20 @@ impl Framebuffer {
}
pub fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) {
let gles = self.ctx.ctx.dpy.gles;
let _ = self.ctx.ctx.with_current(|| {
unsafe {
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
glViewport(0, 0, self.gl.width, self.gl.height);
(gles.glBindFramebuffer)(GL_FRAMEBUFFER, self.gl.fbo);
(gles.glViewport)(0, 0, self.gl.width, self.gl.height);
if let Some(c) = clear {
glClearColor(c.r, c.g, c.b, c.a);
glClear(GL_COLOR_BUFFER_BIT);
(gles.glClearColor)(c.r, c.g, c.b, c.a);
(gles.glClear)(GL_COLOR_BUFFER_BIT);
}
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
(gles.glBlendFunc)(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
run_ops(self, &ops);
unsafe {
glFlush();
(gles.glFlush)();
}
Ok(())
});