Screenshots and profiling

Discuss things related to game programming and programming languages
Post Reply
User avatar
celes
Posts: 28
Joined: Sun Feb 15, 2026 8:09 pm
Location: The offices at Carrot Corp
Pronouns: she/they

Screenshots and profiling

Post by celes »

As a part of the preparations for setting up the Steam page, I thought it'd be cool to have a better, more automated way to capture screenshots from the game. So I created this fancy new ScreenshotManager thing that can extract pixels from the game's framebuffer and save them as PNG files.

Here you have it in all its glory, and as a bonus you get to see some unsafe C# in action! I gotta say, SDL makes this stuff easy and hard at the same time: Easy because the documentation is amazing and everything has examples. Hard, because there were a couple nasty surprises to figure out, especially figuring out when asking OpenGL for "RGBA" pixels you have to tell SDL to save in ABGR, plus the mandatory OpenGL vertical flip, of course :blobcatnodfast:
image.png
image.png (77.08 KiB) Viewed 485 times
But then, I tried it, and the thing froze my game... not by much, only a split second, but enough for me to be annoyed. Because I want this thing running in the background taking screenshots while I play, and I don't wanna get a hiccup every few seconds when playing!

At first glance, it seemed the culprit was that glGetTexImage. Everyone will tell you that transferring pixel data from the GPU to the CPU is super slow and will block everything, stall rendering, and probably will make you late for dinner too. Because suddenly we're all hardware people and everyone knows "pci express is super slow", or something.

Anyway, after a quick detour into Pixel Buffer Objects, which apparently can speed this up, but not as much as one would hope, I had an epiphany: What if I actually profile this?

Well, turns out 100% of the time is taken by that SavePNG function in SDL_Image and the actual data transfer from the GPU to CPU is negligible... Why does SavePNG take so long (about 250ms)? Don't know don't care, but now we have a solution. We run it in a separate thread and let the magic of parallelism do the rest. Since we have the pixel data in an array that nobody else knows about (something something *ownership*), we can do all the SDL stuff on the side while the game continues running.
image.png
image.png (54.09 KiB) Viewed 485 times
I'll also take the opportunity to appreciate how easy it was to do all this "low level" manipulation mostly-safely (no formal proof for you :pensivepumpkin:) and quite idiomatically. Especially spawning that thread which took almost no effort!

Remember kids: Always profile first :blobfoxthinksmart:

*EDIT*: Oops! And there was a tiny memory leak in there. I forgor to destroy the SDL surface. Guess I'm not used to cleaning up after myself ^^' Serves me right for boasting about how (un)safe this stuff was.
 

POSTREACT(ions) SUMMARY

User avatar
Sugui
Posts: 8
Joined: Tue Feb 17, 2026 12:50 pm
Location: Europe
Pronouns: she/her

Re: Screenshots and profiling

Post by Sugui »

Interesting post! Doing the saving in a separate thread makes the most sense, i/o operations, especially writing to a file, can be very slow. I guess you could still be single threaded by using coroutines, writing chunks of the file bit by bit, and keeping the file handle open until you finish. But your approach seems more practical than using coroutines in this case.

Also, why is everything of the code "unsafe". Is it because you are creating arrays in C# and passing them to C as pointers?

I remembering you saying in the Discord server I think, that you game was single threaded, guess that's not exactly true anymore :blobcatgiggle:
no formal proof for you
Just where it hurts :akko_nope:
 

POSTREACT(ions) SUMMARY

User avatar
celes
Posts: 28
Joined: Sun Feb 15, 2026 8:09 pm
Location: The offices at Carrot Corp
Pronouns: she/they

Re: Screenshots and profiling

Post by celes »

In this case, I haven't profiled that far so I don't know for sure, but it's probably not disk I/O, because the OS usually caches things heavily. For small files, the blocking part of "writing to a file" is a lot more like a copy to ram than anything to do with hard drive latency. So basically the OS is doing the same thread trick I'm doing for me.

I'd need to profile, but if I had to take a guess it's probably the code compressing the pixels into PNG, I guess it takes some time to do that for a 1920x1080 image.
Sugui wrote:Just where it hurts :akko_nope:
ehehehe :blobcatgiggle:
 

POSTREACT(ions) SUMMARY

Carrot (1)
Sugui
Post Reply