-
Notifications
You must be signed in to change notification settings - Fork 480
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
Texture and texture creator #667
Comments
I'll take a look into in a few hours, but in the meantime you can try getting help from the #rust, #rust-beginners and #rust-gamedev IRC channels on mozilla's IRC, I'm sure they will be willing to help!
…On Jun 2, 2017, 16:19, at 16:19, Adrien FAURE ***@***.***> wrote:
Hello, First of all sorry for the newbee question.
I have some trouble to understand how I can manage the Texture and the
Texture creator.
I am stuck with the lifetime of the texture. So for the moment I do
something like the code bellow to get a texture, but I have to do it at
each iteration of my game loop. I have the feeling that is not the way
it have to be used.
```rust
/// Example of how I create a texture
let map_loader =
sdl2::rwops::RWops::from_file(Path::new("assets/Overworld.png"),
"r").unwrap();
let surface: Surface = map_loader.load_png().unwrap();
let texture =
self.creator.create_texture_from_surface(&surface).unwrap();
```
So basically I wanted to have a structure that own some information
(such as the texture for example) the `GameScene`:
```rust
pub struct GameScene<'a> {
creator: sdl2::render::TextureCreator<sdl2::video::WindowContext>,
/// I would create a texture once and store it.
texture: sdl2::render::Texture<'a>,
/** Other objects **/
}
```
So here it is, the code bellow does not compile because the creator
outlives the texture.
I have no clue of how to do such a things, I did some attempts:
```rust
struct TextureHolder<'a> {
creator: &'a sdl2::render::TextureCreator<sdl2::video::WindowContext>,
texture: sdl2::render::Texture<'a>
}
pub struct GameScene<'a> {
creator: sdl2::render::TextureCreator<sdl2::video::WindowContext>,
texture: TextureHolder<'a>
}
```
The code above would allows me to have a texture and its creator
bounded to the same lifetime
But when I am creating a GameScene with the following code
```rust
let creator = canvas.texture_creator();
let textureHolder = TextureHolder {
creator: &creator,
texture: creator.create_texture_from_surface(&surface).unwrap()
};
GameScene{
/// I have to find someone to own my creator.
creator: creator,
grid: grid,
map: map,
/// So this
textureHolder : textureHolder
}
```
I've got the error :
```
error: `creator` does not live long enough
--> src\scene.rs:95:23
|
95 | creator: &creator,
| ^^^^^^^ does not live long enough
...
105 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on
the body at 62:81...
```
I understand that the texture is bound to the creator, but I have no
clue how to achieve this. I hope someone could point me to the right
direction.
By the time I'll read some documentations about the lifetime :) .
I'm sorry for the inconvenience,
Thank you very much.
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
#667
|
Hello, I will go on IRC tomorrow, and I will keep this thread up to date. |
Hi, so I went on IRC to ask my question. I wonder what is the recommended way to obtain/store a texture before rendering it ? And what is the cost of creating a new texture: with Thank you. By the way, very interesting stackoverflow thread, thank you; |
We have several examples using |
Hi thank you for your answer, but still I am not convinced of the resource manager. For me the API works well as long as the code stays in one file. But I try to split my code into submodules, Thanks for the help, I think I will try a higher level library such as piston. I saw that they also use the this sdl2 binding. |
I have had similar issues and my recommendation is for your main to handle the lifetimes of the dependencies that are meant to last your whole program. What I mean by this is, create the texture creator (and renderer) in your main and pass a reference of the texture creator(do not move the creator, only a reference is needed!) onto your game struct. This way we guarantee that the texture creator outlives any texture that is created within your game (your game goes out of scope before the texture creator) which solves all the lifetime issues you are having. I hope this helps. I do this for both texture creator the TtfContext as they both need to outlast textures or fonts respectively. I hope this helps (: |
I wonder if it would be possible to remove the need to have an explicit lifetime on the Texture struct, though. That would make the whole lifetime management a lot easier. |
I would love to find a solution that simplifies the lifetime management of textures. I am unsure how it coule be done given the constraints of sdl2 while keeping the code safe. Safety for me means |
The other immediate solution would be to wrap a reference to Renderer/ TextureCreator on every texture, and destroy the Renderer only when all the textures are dropped as well, but the overhead would be non-negligible, plus you may not want to allocate on the heap unnecessarily . Since Window cannot be destroyed before renderer as well, that would mean that a memory leak would potentially lead to a forever-opened window as well, and I'm not sure that's what we want... I feel like the current way it is implemented is the "Rust" way of doing it, but if you don't agree with that, the SDL2_sys bindings are open and you can totally create your own wrapper that manages Textures differently! |
The issue with the explicit lifetime on Texture is that as soon as you have some complex structure that needs to access the Texture, you start propagating explicit lifetimes all over your code. You can see an example at my repo here: https://github.com/tanis2000/minigame-rust Those structs just need to be able to access the Texture while rendering so that I am carrying around a reference to the Texture of the sprite batch item that I computed. This is still manageable, but then I started adding my own implementation of an entity-component-system on top of that and components that carry around an image, like a sprite, now need to reference their texture as well. So I have to propagate the explicit lifetime over there, too. And the main object that is instantiating the TextureCreator is having issues as I need to keep a reference to TextureCreator somewhere but also pass it over to my texture manager (sort of a resource manager for textures). I know there must be a solution but things have started getting tricky. It's not really a rust-sdl2 issue per se; it's more like an issue with the need to refactor lifetimes as you build more systems into your own engine. That's why I started wondering if there could be a solution to avoid the explicit lifetime on the Texture itself, but I understand it's probably not possible because Rust is actually forcing you to behave the way you should. |
What we could do is add a feature that would totally remove the lifetimes by removing the fact that Texture are destroyed on Drop. We could let them live indefinitely or manually (via a This alternative is a little bit unsafe and requires more end-user control, but it will get rid of the lifetime and be easier to manage in things such as ECS as well. I'm going to try something with that in mind soon, and if you don't mind @tanis2000 I'd like you to test that upcoming feature to tell me how it sounds. If that goes well, it's going to be in the v0.31. |
Sure thing! I'm up to test it out and see how it fits. |
Unless I misunderstood your question, I'm seeing your proposal as "Texture holding a Rc". Correct me if I'm wrong. The problem I have with Texture holding an Rc of Canvas is that Canvas cannot be dropped unless all Textures have been dropped as well. Since the Canvas can't be dropped, that means that potentially the Window that is linked to the Canvas can't be dropped. The thing is that Window's drop is literally "stop displaying this Window" from the Operating System perspective, meaning that if you have a memory leak with a Texture, you would have your window left opened until that memory leak goes away... Which is at worst at the program's completion. The program's completion doesn't sound too bad in a single game, but if your application is made of multiple parts and multiple windows, you don't want to see one of the window still opened with no interaction possible whatsoever (you wouldn't even be able to close it since your event loop for this Window would not be active anymore). I agree that having memory leaks is something programmer-related, but it's trickier to debug than lifetimes. The tricky part is that memory leaks are 100% safe and can happen a lot of the time, especially when dealing with That's why I would prefer something slightly unsafe (but you don't even have to use it, you can let Canvas' Drop drop all the textures without worries) if someone needs fine tuning, than something safe but potentially doing something that the programmer doesn't want at all. |
I don't know how possible this is, and I wish I had the time to test it out, but in my head I had envisioned the possibility of having the rust version of the sdl2 renderer mimic the c version of sdl2 a little closer, and how that might help. By this I mean, in the c version of sdl2, we have this renderer that owns the textures, and it only is in charge of mananging them. The reason why the textures cannot outlive ther renderer, is because the renderer will destroy them all when the renderer is destroyed. I wonder how possible and beneficial it would be to do such a thing within the rust version. If we mimic'd this in the rust version, I envision we would have some shared data map that is owned (through some internall unsafe code) by the This would solve the lifetime issues because now the TextureCreator doesn't care if the texture identifier outlives the Renderer. If the texture identifier outlives the Renderer, well too bad, no one can render it anyway and the real SDL_Texture was destroyed already. If the Renderer is passed an incorrect identifier, then we return an error, since all of those methods already return I am unsure how doable this is, but I think by "enforcing" the C behavior in the Rust wrapper, we might be able to pull something that feels more idiomatic and ergonomic. Some kinks that would need to be worked out is how would this affect current methods on the I am unsure if this added anything to the discussion since it seems you all already have an idea, I just wanted to share a thought I had but have not had the time to implement yet. |
@Cobrand actually I mean that the Canvas should own a map of Rc<SDL_Texture> so that it can lend the texture to whatever function is in need of a reference through a clone(). It might make things less "unsafe", but then again I'm no expert with Rc so I might be completely off with this. While I like @nrxus proposal, it would actually make it a little more difficult the management of textures for those not using the SDL2 rendering stuff. As an example, I am just using SDL2 to manage the window and the textures, while all the rendering is done with my own renderer that is using OpenGL ES 2 with no SDL2 involved at that stage except for retrieving the handle to the actual texture. On the other hand, just like you envisioned the SDL2 renderer being able to pull out the SDL_Texture and use it, if such a mechanic would be directly available from within the Renderer, that would be fine as well. I'd just skip the rendering part and use the Renderer as a texture storage of sorts. |
This crate stills aims to have minimum impact on performance while being the closest to the source, and in the source the Renderer doesn't own the Textures, it's merely linked. If the Renderer dies, all of the Textures die automatically, and that's it. A HashMap is still pa performance overhead; having to implement that in the default sdl2 crate means that everyone that don't want to use a HashMap won't be able to do it with sdl2 only, they'd have to use sdl2-sys instead. Having a |
It depends how you view "owning". From my perspective, if the Renderer is in charge of creating and destroying the textures, I would view it as owning the Textures. I agree with the performance overhead, though. Hashmaps would be a hit that we might not want people to incur as the default. |
Fixed by #683, feel free to re-open if that's not enough. |
That's super! I'm going to switch my master to use this feature as tests worked fine |
Hello, First of all I am sorry for the newbee question.
I have some trouble to understand how I can manage the Texture and the Texture creator.
I am stuck with the lifetime of the texture. So for the moment I do something like the code bellow to get a texture, but I have to do it at each iteration of my game loop. I have the feeling that is not the way it have to be used.
So basically I wanted to have a structure that own some information (such as the texture for example) the
GameScene
:So here it is, the code bellow does not compile because the creator outlives the texture.
I have no clue of how to do such a things, I did some attempts:
The code above would allows me to have a texture and its creator bounded to the same lifetime
But when I am creating a GameScene with the following code
I've got the error :
I understand that the texture is bound to the creator, but I have no clue how to achieve this. I hope someone could point me to the right direction.
By the time I'll read some documentations about the lifetime :) .
I'm sorry for the inconvenience,
Thank you very much.
The text was updated successfully, but these errors were encountered: