Merge pull request #104 from mahkoh/jorth/dynamic-egl
render: load libEGL and libGLESv2 at runtime
This commit is contained in:
commit
c99272230c
16 changed files with 341 additions and 260 deletions
|
|
@ -40,6 +40,8 @@ The following features have been implemented and should work:
|
|||
- Hardware cursors
|
||||
- Pointer constraints
|
||||
- Selecting the primary device in multi-GPU systems
|
||||
- An OpenGL backend
|
||||
- A Vulkan backend
|
||||
|
||||
### Missing Features
|
||||
|
||||
|
|
@ -56,7 +58,6 @@ automatically. It is however unavoidable that Jay depends on a number of native
|
|||
libraries:
|
||||
|
||||
* **libinput.so**: For input event processing.
|
||||
* **libEGL.so**, **libGLESv2.so**: For OpenGL rendering.
|
||||
* **libgbm.so**: For graphics buffer allocation.
|
||||
* **libxkbcommon.so**: For keymap handling.
|
||||
* **libudev.so**: For device enumeration and hotplug support.
|
||||
|
|
@ -76,6 +77,8 @@ At runtime, Jay depends on the following services being available on the system:
|
|||
Jay as an X client.)
|
||||
* **Logind**: For the metal backend. (Only required if you want to run Jay from
|
||||
a TTY.)
|
||||
* **libEGL.so**, **libGLESv2.so**: For the OpenGL backend.
|
||||
* **libvulkan.so**: For the Vulkan backend.
|
||||
|
||||
## Building and Installing
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue