我目前正在将一个用C++编写的OpenGL应用程序移植到Rust上,遇到了一个设计问题,这个问题可能会有其他的影响,因为我对Rust很陌生。
目前我使用的是glutin
和gl_generator
的组合。在bindings模块中生成全局函数会生成以下API:
gl::load_with(|symbol| context.get_proc_address(symbol));
// anywhere else since it's global
gl::CreateProgram();
字符集
这与我在C++中用于访问全局方法的 Package 类的范例几乎相同:
// ...
FShader::~FShader() {
if (Handle != 0) {
glDeleteProgram(Handle);
}
}
auto FShader::bind() const -> void { glUseProgram(Handle); }
// ...
型
在阅读了更多的帖子之后,我注意到一些人建议使用结构生成器,并使用对象而不是全局方法。
let gl = Rc::new(gl::Gl::load_with(|symbol| context.get_proc_address(symbol)));
// ...
pub struct Shader {
gl: Rc<gl::Gl>,
handle: u32,
}
impl Drop for Shader {
fn drop(&mut self) {
unsafe {
self.gl.DeleteProgram(self.handle);
}
}
}
impl Shader {
pub fn new(gl: Rc<gl::Gl>) -> Result<Shader, ()> {
let handle = unsafe { gl.CreateProgram() };
// ...
Ok(Shader { gl, handle })
}
}
型
这种方法无疑更加冗长,因为所有的 Package 类都必须存储一个指向gl::Gl
对象的引用,以便能够释放资源。Drop::drop
的签名似乎是为什么在对象之间共享引用是必要的原因。这样做还有其他好处吗?使用Rc
是最好的方法还是使用常规引用更合理?
1条答案
按热度按时间rm5edbpk1#
使用常规引用在性能方面可能会更好,因为
Rc
s具有引用计数的开销。但是,如果要使用引用,则必须处理大量的生存期注解,这可能会使代码更加冗长。此外,你还必须保持
gl::GL
对象的活动,只要你使用OpenGL(我认为这是程序的整个生命周期)。