首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为安卓的SurfaceTexture实现Glium的后端(用锈蚀渲染到SurfaceTexture)

如何为安卓的SurfaceTexture实现Glium的后端(用锈蚀渲染到SurfaceTexture)
EN

Stack Overflow用户
提问于 2022-05-22 01:30:55
回答 1查看 208关注 0票数 1

铁锈的胶质细胞库是一个很好的OpenGL包装器,它可以方便使用插槽。为了实现它的新后端,您必须实现https://github.com/glium/glium/blob/cacb970c8ed2e45a6f98d12bd7fcc03748b0e122/src/backend/mod.rs#L36

我想将Android的SurfaceTexture实现为Backend

看来我需要为SurfaceTexture实现一个新的后端:https://github.com/glium/glium/blob/master/src/backend/mod.rs#L36

以下是C++的SurfaceTexture https://developer.android.com/ndk/reference/group/surface-texture#summary函数

我认为Backend::make_current(&self);映射到attachToGLContext(ASurfaceTexture *st,uint32_t texName)

在调用Backend::is_current(&self) -> bool时,可以根据每个被标记为活动或不活动的SurfaceTexture进行模拟。

也许Backend::get_framebuffer_dimensions(&self) -> (u32, u32)就是在创建时定义的SurfaceTexture的大小,所以我可以使用它。我只是不知道该怎么处理Backend::swap_buffers(&self) -> Result<(), SwapBuffersError>

也许Backend::unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void可以调用一些Android来获取OpenGL函数的地址。

但是,ASurfaceTexture_updateTexImage(ASurfaceTexture *st)看起来很重要,而且是必需的,我不知道在Backend中映射到什么。另外,ASurfaceTexture_detachFromGLContext(ASurfaceTexture *st)呢?

PS:我知道还有其他方法可以呈现给android小部件,但是我需要呈现给一个颤振小部件,也是它通过SurfaceTexture的唯一方法。

EN

回答 1

Stack Overflow用户

发布于 2022-05-24 20:39:52

一段时间前,我用一种黑客式的解决方案成功地完成了这个任务,也许它仍然有效,因为glium最近并没有发生太大的变化。

但以我使用ASurfaceTexture的经验来看,其结果并不可靠,可能是因为我错误地使用了它,或者是因为安卓制造商不太重视它,我不知道。但是我没有看到任何真正的程序在使用它,所以我决定使用经过良好测试的Java来连接所有的东西。

代码语言:javascript
复制
class MyGLView extends GLSurfaceView
                implements GLSurfaceView.Renderer {
    public MyGLView(Context context) {
        super(context);
        setEGLContextClientVersion(2);
        setEGLConfigChooser(8, 8, 8, 0, 0, 0);
        setRenderer(this);
    }
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLJNILib.init();
    }
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLJNILib.resize(width, height);
    }
    public void onDrawFrame(GL10 gl) {
        GLJNILib.render();
}

com.example.myapp.GLJNILib是绑定到锈蚀本机库的JNI,在这里发生了神奇的事情。接口非常简单:

代码语言:javascript
复制
package com.example.myapplication;

public class GLJNILib {

     static {
        System.loadLibrary("myrustlib");
     }

     public static native void init();
     public static native void resize(int width, int height);
     public static native void step();
}

现在,这个锈蚀库可以通过几种方式来设计。在我的特定项目中,由于它是一个具有单一全屏视图的简单游戏,我只是创建了glium上下文并将其存储在一个全局变量中。更复杂的程序可以将Backend存储到Java对象中,但这会使生命周期复杂化,我不需要它。

代码语言:javascript
复制
struct Data {
    dsp: Rc<glium::backend::Context>,
    size: (u32, u32),
}

static mut DATA: Option<Data> = None;

但是首先,我们必须实现特性glium::backend::Backend,这碰巧是非常容易的,如果我们假设每次调用一个Rust函数时,适当的GL上下文总是当前的:

代码语言:javascript
复制
struct Backend;

extern "C" {
    fn eglGetProcAddress(procname: *const c_char) -> *const c_void;
}

unsafe impl glium::backend::Backend for Backend {
    fn swap_buffers(&self) -> Result<(), glium::SwapBuffersError> {
        Ok(())
    }
    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        let cs = CString::new(symbol).unwrap();
        let ptr = eglGetProcAddress(cs.as_ptr());
        ptr
    }
    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        let data = unsafe { &DATA.as_ref().unwrap() };
        data.size
    }
    fn is_current(&self) -> bool {
        true
    }
    unsafe fn make_current(&self) {
    }
}

现在我们可以实现JNI init函数:

代码语言:javascript
复制
use jni::{
    JNIEnv,
    objects::{JClass, JObject},
    sys::{jint}
};

#[no_mangle]
#[allow(non_snake_case)]
pub extern "system"
fn Java_com_example_myapp_GLJNILib_init(_env: JNIEnv, _class: JClass) { log_panic(|| {
    unsafe {
        DATA = None
    };

    let backend = Backend;
    let dsp = unsafe { glium::backend::Context::new(backend, false, Default::default()).unwrap() };
    // Use dsp to create additional GL objects: programs, textures, buffers...
    // and store them inside `DATA` or another global.
    unsafe {
        DATA = Some(Data {
            dsp,
            size: (256, 256), //dummy size
        });
    }
}

当视图的大小发生变化时,将更新该大小(而不是glium这么多地使用该值):

代码语言:javascript
复制
#[no_mangle]
#[allow(non_snake_case)]
pub extern "system"
fn Java_com_example_myapp_GLJNILib_resize(_env: JNIEnv, _class: JClass, width: jint, height: jint) {
    let data = unsafe { &mut DATA.as_mut().unwrap() };
    data.size = (width as u32, height as u32);
}

类似地,render函数:

代码语言:javascript
复制
#[no_mangle]
#[allow(non_snake_case)]
pub extern "system"
fn Java_com_example_myapp_GLJNILib_render(_env: JNIEnv, _class: JClass) {
    let data = unsafe { &mut DATA.as_ref().unwrap() };
    let dsp = &data.dsp;

    let mut target = glium::Frame::new(dsp.clone(), dsp.get_framebuffer_dimensions());
    
    // use dsp and target at will, such as:
    target.clear_color(0.0, 0.0, 1.0, 1.0);
    let (width, height) = target.get_dimensions();
    //...

    target.finish().unwrap();
}

注意,target.finish()仍然是必需的,尽管glium实际上并没有执行交换。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72334238

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档