Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SurfaceTexture bindings #267

Merged
merged 37 commits into from
Jun 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
66e3ed7
adds surface_texture support
lattice0 Apr 23, 2022
d39cb7e
changes
lattice0 Apr 23, 2022
1c6a647
update_tex_image
lattice0 Apr 23, 2022
49a6b27
clippy
lattice0 Apr 23, 2022
83878d3
clippy fixed
lattice0 Apr 23, 2022
0431a32
no sync
lattice0 Apr 23, 2022
cef7247
Update ndk/src/surface_texture.rs
lattice0 May 18, 2022
2bd0001
Merge branch 'master' into master
lattice0 May 18, 2022
84a4a83
fix media
lattice0 May 18, 2022
ff2d807
posix
lattice0 May 18, 2022
0f7f56a
fixes
lattice0 May 18, 2022
57d61ae
pub
lattice0 May 18, 2022
830b682
debug
lattice0 May 18, 2022
82a7626
surface texture enhancements
lattice0 May 22, 2022
cce23e7
merge import
lattice0 May 22, 2022
8c12f72
fmt
lattice0 May 22, 2022
438c8fd
api guards
lattice0 May 22, 2022
05ebfd0
unused import fix
lattice0 May 22, 2022
32151c2
texture
lattice0 May 25, 2022
cb36cbe
fix
lattice0 May 25, 2022
1e6fd42
Update ndk/src/surface_texture.rs
lattice0 May 27, 2022
8bd28a6
Update ndk/src/surface_texture.rs
lattice0 May 27, 2022
8beef62
Update ndk/src/surface_texture.rs
lattice0 May 27, 2022
02d8165
Update ndk/src/surface_texture.rs
lattice0 May 27, 2022
2944324
Update ndk/src/surface_texture.rs
lattice0 May 27, 2022
421ac3f
Update ndk/src/surface_texture.rs
lattice0 May 27, 2022
4742ff5
mods
lattice0 May 27, 2022
39a5a59
adds
lattice0 May 27, 2022
52e2141
format
lattice0 May 28, 2022
cac2ead
Apply suggestions from code review
MarijnS95 May 28, 2022
88ba5e0
Update ndk/src/surface_texture.rs
lattice0 May 28, 2022
ec5700f
better docs
lattice0 May 28, 2022
4dd0762
docs
lattice0 May 28, 2022
d8d2bce
Doc cleanup
MarijnS95 Jun 8, 2022
20a95c2
Merge remote-tracking branch 'upstream/master' into lattice0/master
MarijnS95 Jun 8, 2022
fc0c399
Add changelog entry
MarijnS95 Jun 8, 2022
4908cac
More doc links
MarijnS95 Jun 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ndk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- native_window: Add `format()` getter and `set_buffers_geometry()` setter. (#276)
- native_activity: Add `set_window_format()` setter. (#277)
- native_activity: Add `set_window_flags()` to change window behavior. (#278)
- Add `SurfaceTexture` bindings. (#267)

# 0.6.0 (2022-01-05)

Expand Down
2 changes: 2 additions & 0 deletions ndk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ pub mod looper;
pub mod media;
pub mod native_activity;
pub mod native_window;
pub mod posix;
pub mod surface_texture;
pub mod trace;
10 changes: 10 additions & 0 deletions ndk/src/posix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use thiserror::Error;

#[derive(Debug, Error)]
pub struct PosixError(pub i32);

impl std::fmt::Display for PosixError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Posix Error: {}", self.0)
}
}
172 changes: 172 additions & 0 deletions ndk/src/surface_texture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//! Bindings for [`ASurfaceTexture`]
//!
//! See <https://source.android.com/devices/graphics/arch-st> for an architectural overview of
//! [`SurfaceTexture`] internals.
//!
//! [`ASurfaceTexture`]: https://developer.android.com/ndk/reference/group/surface-texture
#![cfg(feature = "api-level-28")]

use super::posix::PosixError;
use crate::native_window::NativeWindow;
use jni_sys::{jobject, JNIEnv};
use std::{convert::TryInto, ptr::NonNull, time::Duration};

/// An opaque type to manage [`android.graphics.SurfaceTexture`] from native code
///
/// [`android.graphics.SurfaceTexture`]: https://developer.android.com/reference/android/graphics/SurfaceTexture
#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SurfaceTexture {
ptr: NonNull<ffi::ASurfaceTexture>,
}

unsafe impl Send for SurfaceTexture {}

impl Drop for SurfaceTexture {
fn drop(&mut self) {
unsafe { ffi::ASurfaceTexture_release(self.ptr.as_ptr()) }
}
}

impl SurfaceTexture {
/// Assumes ownership of `ptr`
///
/// # Safety
/// `ptr` must be a valid pointer to an Android [`ffi::ASurfaceTexture`].
pub unsafe fn from_ptr(ptr: NonNull<ffi::ASurfaceTexture>) -> Self {
Self { ptr }
}

/// Get a reference to the native [`SurfaceTexture`] from the corresponding Java object.
///
/// # Safety
///
/// This function should be called with a healthy JVM pointer and with a non-null
/// [`android.graphics.SurfaceTexture`], which must be kept alive on the Java/Kotlin side.
///
/// The caller must keep a reference to the Java [`android.graphics.SurfaceTexture`] during the
/// lifetime of the returned [`SurfaceTexture`]. Failing to do so could result in the
/// [`SurfaceTexture`] to stop functioning properly once the Java object gets finalized.
/// However, this will not result in program termination.
///
/// [`android.graphics.SurfaceTexture`]: https://developer.android.com/reference/android/graphics/SurfaceTexture
pub unsafe fn from_surface_texture(env: *mut JNIEnv, surface_texture: jobject) -> Option<Self> {
let a_surface_texture_ptr = ffi::ASurfaceTexture_fromSurfaceTexture(env, surface_texture);
let s = NonNull::new(a_surface_texture_ptr)?;
Some(SurfaceTexture::from_ptr(s))
}

/// Returns a pointer to the native [`ffi::ASurfaceTexture`].
pub fn ptr(&self) -> NonNull<ffi::ASurfaceTexture> {
self.ptr
}

/// Returns a reference to a [`NativeWindow`] (i.e. the Producer) for this [`SurfaceTexture`].
///
/// This is equivalent to Java's:
/// ```java
/// Surface sur = new Surface(surfaceTexture);
lattice0 marked this conversation as resolved.
Show resolved Hide resolved
/// ```
pub fn acquire_native_window(&self) -> Option<NativeWindow> {
let native_window = unsafe { ffi::ASurfaceTexture_acquireANativeWindow(self.ptr.as_ptr()) };
let n = NonNull::new(native_window)?;
Some(unsafe { NativeWindow::from_ptr(n) })
}

/// Attach the [`SurfaceTexture`] to the OpenGL ES context that is current on the calling
/// thread.
///
/// A new OpenGL ES texture object is created and populated with the [`SurfaceTexture`] image
/// frame that was current at the time of the last call to
/// [`detach_from_gl_context()`][Self::detach_from_gl_context()]. This new texture is bound to
/// the `GL_TEXTURE_EXTERNAL_OES` texture target.
///
/// This can be used to access the [`SurfaceTexture`] image contents from multiple OpenGL ES
/// contexts. Note, however, that the image contents are only accessible from one OpenGL ES
/// context at a time.
pub fn attach_to_gl_context(&self, tex_name: u32) -> Result<(), PosixError> {
let r = unsafe { ffi::ASurfaceTexture_attachToGLContext(self.ptr.as_ptr(), tex_name) };
if r == 0 {
Ok(())
} else {
Err(PosixError(r))
}
}

/// Detach the [`SurfaceTexture`] from the OpenGL ES context that owns the OpenGL ES texture
/// object.
///
/// This call must be made with the OpenGL ES context current on the calling thread. The OpenGL
/// ES texture object will be deleted as a result of this call. After calling this method all
/// calls to [`update_tex_image()`][Self::update_tex_image()] will fail until a successful call
/// to [`attach_to_gl_context()`][Self::attach_to_gl_context()] is made.
///
/// This can be used to access the [`SurfaceTexture`] image contents from multiple OpenGL ES
/// contexts. Note, however, that the image contents are only accessible from one OpenGL ES
/// context at a time.
pub fn detach_from_gl_context(&self) -> Result<(), PosixError> {
let r = unsafe { ffi::ASurfaceTexture_detachFromGLContext(self.ptr.as_ptr()) };
if r == 0 {
Ok(())
} else {
Err(PosixError(r))
}
}

/// Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set
/// by the most recent call to [`update_tex_image()`][Self::update_tex_image()].
///
/// This transform matrix maps 2D homogeneous texture coordinates of the form `(s, t, 0, 1)`
/// with `s` and `t` in the inclusive range `[0, 1]` to the texture coordinate that should be
/// used to sample that location from the texture. Sampling the texture outside of the range of
/// this transform is undefined.
///
/// The matrix is stored in column-major order so that it may be passed directly to OpenGL ES
/// via the [`glLoadMatrixf()`] or [`glUniformMatrix4fv()`] functions.
///
/// [`glLoadMatrixf()`]: https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glLoadMatrix.xml
/// [`gluniformmatrix4fv()`]: https://www.khronos.org/registry/OpenGL-Refpages/es3.1/html/glUniform.xhtml
pub fn transform_matrix(&self) -> [f32; 16] {
let mut r = [0f32; 16];
unsafe { ffi::ASurfaceTexture_getTransformMatrix(self.ptr.as_ptr(), r.as_mut_ptr()) };
r
}

/// Retrieve the timestamp associated with the texture image set by the most recent call to
/// [`update_tex_image()`][Self::update_tex_image()].
///
/// This timestamp is in nanoseconds, and is normally monotonically increasing. The timestamp
/// should be unaffected by time-of-day adjustments, and for a camera should be strictly
/// monotonic but for a [`MediaPlayer`] may be reset when the position is set. The specific
/// meaning and zero point of the timestamp depends on the source providing images to the
/// [`SurfaceTexture`]. Unless otherwise specified by the image source, timestamps cannot
/// generally be compared across [`SurfaceTexture`] instances, or across multiple program
/// invocations. It is mostly useful for determining time offsets between subsequent frames.
///
/// For EGL/Vulkan producers, this timestamp is the desired present time set with the
/// [`EGL_ANDROID_presentation_time`] or [`VK_GOOGLE_display_timing`] extensions.
///
/// [`MediaPlayer`]: https://developer.android.com/reference/android/media/MediaPlayer
/// [`EGL_ANDROID_presentation_time`]: https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_presentation_time.txt
/// [`VK_GOOGLE_display_timing`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_display_timing.html
pub fn timestamp(&self) -> Duration {
Duration::from_nanos(
unsafe { ffi::ASurfaceTexture_getTimestamp(self.ptr.as_ptr()) }
.try_into()
.unwrap(),
)
}

/// Update the texture image to the most recent frame from the image stream.
lattice0 marked this conversation as resolved.
Show resolved Hide resolved
///
/// This may only be called while the OpenGL ES context that owns the texture is current on the
/// calling thread. It will implicitly bind its texture to the `GL_TEXTURE_EXTERNAL_OES`
/// texture target.
pub fn update_tex_image(&self) -> Result<(), PosixError> {
let r = unsafe { ffi::ASurfaceTexture_updateTexImage(self.ptr.as_ptr()) };
if r == 0 {
Ok(())
} else {
Err(PosixError(r))
}
}
lattice0 marked this conversation as resolved.
Show resolved Hide resolved
}
lattice0 marked this conversation as resolved.
Show resolved Hide resolved