-
Notifications
You must be signed in to change notification settings - Fork 11
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
Texenvs need to stay alive until they're drawn #36
Comments
This comment was marked as off-topic.
This comment was marked as off-topic.
*edit: I've since gained more of an understanding of how textures and texenvs work, and have a different solution outlined in #41 (comment) for managing this. So please go have a look there first. Hihi. I'm having my own look into an API for textures, however there is one particular issue that's makes it slightly difficult. Like was mentioned earlier how a texture must stay alive until it is drawn, while a texture is bound it must be pinned and also cannot be unbound except by binding a different texture to the same texture unit (at least as far as I can tell). Some API designs I have considered for binding textures are as follows. (Although keeping in mind these all still suffer from the issue outlined in #41, however I imagine that will be a greater fix at a later time.
struct Texture { ... }
struct TextureBinding<'t> {
tex: &'t Texture, // Holding a reference to it will effectively pin it for the duration of the guard's lifetime right?
unit: TexUnit,
}
impl Drop for TextureBinding<'_> {
fn drop(&mut self) {
unsafe { C3D_UnbindTex(self.tex, self.unit); } // But this doesn't exist ;~;
}
}
impl Instance {
fn bind_texture<'t>(&mut self, texture: &Texture, unit: TexUnit) -> Option<TextureBinding> {
if isBound(unit) {
return None
}
unsafe { C3D_TexBind(texture, unit); }
Some(TextureBinding {
tex: texture,
unit,
})
}
} However, since there's not currently any functionality to actually unbind a texture this doesn't really work. Perhaps at initialization of the
struct Texture { ... }
struct Instance {
...
bound_textures: [Option<Pin<Box<Texture>>>; 3],
}
impl Instance {
/// Binds a texture to the given texture unit, returning the previously bound texture if there was one
fn bind_texture(&mut self, texture: Box<Texture>, unit: TexUnit) -> Option<Box<Texture>> {
unsafe { C3D_TexBind(texture, unit); }
let idx: usize = match unit { ... };
self.bound_textures[idx].replace(Pin::new(idx)).map(|p| p.get_mut())
}
}
struct Texture { ... }
struct Instance<'t> {
...
bound_textures: [Option<&'t Texture>; 3],
}
impl<'t> Instance<'t> {
fn bind_texture(&mut self, texture: &'t Texture, unit: TexUnit) {
unsafe { C3D_TexBind(texture, unit); }
let idx: usize = match unit { ... };
self.bound_textures[idx] = Some(texture)
}
} I guess this also avoids the issue of textures being dropped before the frame finishes rendering if the 3 seems like the simplest option but also the most limited, and 1 just sort of isn't possible right now without some weird hacky stuff to have a default texture maybe? So only option 2 really works and would allow textures to be modified after they have been bound (and unbound). I didn't initially love that the textures would have to boxed, but honestly it's probably not a big deal. If anybody has any thoughts or suggestions, please share them. Otherwise I might just continue experimenting on my fork (https://github.com/Bash-09/citro3d-rs) and seeing if I get anywhere. |
Yeah, I saw that a little while ago. Unfortunately, the main bit of rendering a model it doesn't touch, textures, is the bit I'm having difficulty with. I've successfully got a shape with a texture, but I find myself hopelessly lost trying to understand how the texture pipeline is supposed to work and I had to go a fair bit against my understanding of how it should work in order to get two faces with two different textures.
Please enjoy this square, which took me about 9 hours to get textured:
PXL_20231223_094143210.mp4
(Sorry for the terrible recording quality. I should have turned down my screen brightness first.)
The problem I'm having is that the texture pipeline seems to persist state across draw calls (
Instance::draw_arrays
calls, really), even when I think it shouldn't be - first, enabling textures for only the first face and resetting the TexEnv pipeline for the second did nothing, giving me a lovely yellow square (texture coordinates (0.0, 0.0) on Bowser's face) on the back; and second, using two separate textures for the two sides gave me Peach on both sides, for some reason (the Peach texture got used for both sides instead of only the second side, as if the GPU were batching the draws and preserving only the last-written texture). I worked around the issue by merging the textures into one, using it for both draw calls, and adjusting the texture coordinates to match.I suppose I can technically deal with this by merging all the textures for everything that's supposed to be drawn on one frame into one giant texture and using that for every shape that frame, but it feels like I'm misunderstanding something fundamental about how textures are supposed to work. Either that or it's a bug.
(By the way, having a safe wrapper for
draw_elements
would be pretty handy in the future for optimising the number of vertices.)My friend figured it out, and in retrospect it's sort of obvious - textures have to be alive until they're drawn, and if they're freed before the end of the frame, strange things happen. TexEnvs still don't work how I think they do, but at least I can draw more than one texture at a time now.
Originally posted by @Jhynjhiruu in #35 (comment)
The text was updated successfully, but these errors were encountered: