I just chose Rust to get into programming, the road is a quite a bit harder but I wanted to start with a language that I think has the most promise.
I have started to dabble with the rust-sdl2 crate and I am stuck on a specific issue and struggling to understand the documentation.
I'm trying to render pixels to the screen at a decent frame rate so I started playing using sdl2::render::Canvas::draw_point and sdl2::render::Canvas::set_draw_color but it's dreadfully slow.
I did a bit of research and it seems that the fastest way to do it is to use a texture and then copy the texture to the renderer. Unfornately, I can only find examples on how to load textures from files and I can't figure out how to actually write to a raw texture.
I would really appreciate some help, I guess the fact that I'm a beginner at both Rust and SDL doesn't help but it's the only way I found to get myself some motivation.
Sometimes, the best place to look for procedural information is the original library’s documentation: There’s a C example on the SDL_CreateTexture page; the basic approach seems to be:
Thanks @2e71828 that was my first idea (well second, after looking at the crate documentation) but it's a bit obscure to a noob like me, I haven't touched C in close to 30 years.
I'm trying to figure out how to write to the texture itself, it created it as follow.
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem.window("rust-sdl2", 320, 240)
.position_centered()
.build()
.unwrap();
let mut canvas : Canvas<Window> = window.into_canvas()
.present_vsync()
.accelerated()
.build()
.unwrap();
let creator = canvas.texture_creator();
let mut texture = creator.create_texture_static(PixelFormatEnum::RGBA8888, 640, 480).unwrap();
But from there, I don't know how to write data to the texture.
Thanks a lot for that, the thing I don't understand now is how to write into that texture structure, how to I actually write the ARGB definition of each pixel into that texture?
My understanding is that @fernando wants (for performance reasons) to write to an offscreen buffer, and then blit that in one shot to the screen. I don’t know if this way is actually faster than drawing to the framebuffer directly, but it’s at least plausible.
Yes, that's exactly it, I tried doing it this way first but it's super slow
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem.window("rust-sdl2 keftals", screen_size[0], screen_size[1])
.position_centered()
// .fullscreen()
.build()
.unwrap();
let mut canvas : Canvas<Window> = window.into_canvas()
.present_vsync()
.accelerated()
.build()
.unwrap();
Then a loop doing something like
for y in 0..599 {
for x in 0..1023 {
// some computation happening to rrr, gee, bee
canvas.set_draw_color(Color::RGB(rrr, gee, bee));
canvas.draw_point(Point::new(x as i32, y as i32)).unwrap();
}
}
With a canvas.clear() and canvas.present() at the beginning and end of each frame.
This is extremely slow, on my laptop each frame takes over 90ms to render.
That’s often a last resort, as you have to give up SDL’s drawing routines. It might not be too bad for you, though, since you’re calculating every pixel in order anyway.
As far as I can see, that is 612k heap allocations per frame (introduced by Point::new()), so I think it's of course slow. Maybe storing them in an array would make it faster?
It looks like Point::new() is just a stack allocation, and never touches the heap— it probably gets inlined by the compiler.
The slow part is draw_point itself: when it’s writing directly to the framebuffer, it has to store that value on the video card. The interconnect between main and video memory is relatively slow and optimized more for bulk transfers than random access.
Mm.. I was under the impression that any of those operations would be relatively fast, as long as you don't call canvas.present(), where, at that point, everything is sent to the framebuffer?