Homebrew Release: PNGShot - Capture screenshots as PNGs.

  • Thread starter Thread starter JK_
  • Start date Start date
  • Views Views 8,707
  • Replies Replies 69
  • Likes Likes 18
Maybe we should have a pinned post or blog for developers for how to optimise for the switch and best practices.

Use apple lock exit, always commit fs when creating file and closing, multithread where possible (not included same source transfer obviously), 4mb buffers for fs r/w, use boost mode during io transfers, always set file size upfront, when final size isn't known or working with limited memory (sysmod) always increase the file size in chunks of around 64k or bigger if possible, always use native fs, benchmark everything and never assume, never use ai to write code for the switch, lazy load everything (do not load all icons, metadata, configs at startup ffs), binary size is important the bigger it is the longer it takes to load and in the case of sysmod it takes up more limited memory, just like with lazy load try to multi thread exiting code to speed up exiting by 2-3x, it can sometimes pay to compress assets bundled in romfs and then inflate them at runtime as inflating GREATLY outperforms io read time, etc.etc.etc...

I can go on but you get the point.
Post automatically merged:

I thought the set size function only allowed you to make files larger for some reason? Guess I was wrong.

I actually found this out rewriting JKSV. If you know the end size of a file, creating the file with the size needed is a lot faster when writing than resizing and writing.
Setsize is just ftruncate. You can shrink, grow etc. normally you can let the os/kernel handle growing the file optimally especially as writes are buffered, but this isn't the case on the switch.
 
Maybe we should have a pinned post or blog for developers for how to optimise for the switch and best practices.

Use apple lock exit, always commit fs when creating file and closing, multithread where possible (not included same source transfer obviously), 4mb buffers for fs r/w, use boost mode during io transfers, always set file size upfront, when final size isn't known or working with limited memory (sysmod) always increase the file size in chunks of around 64k or bigger if possible, always use native fs, benchmark everything and never assume, never use ai to write code for the switch, lazy load everything (do not load all icons, metadata, configs at startup ffs), binary size is important the bigger it is the longer it takes to load and in the case of sysmod it takes up more limited memory, just like with lazy load try to multi thread exiting code to speed up exiting by 2-3x, it can sometimes pay to compress assets bundled in romfs and then inflate them at runtime as inflating GREATLY outperforms io read time, etc.etc.etc...

I can go on but you get the point.
This actually doesn't apply to a lot of homebrew (I think?). PNGShot and JKSV use the FS calls directly (JKSV through a C++ wrapper I wrote). I could be wrong, but most homebrew probably doesn't. libnx uses newlib to provide a C stdio like environment. Most people probably use fopen, fread, fwrite, etc. Using that newlib/stdio env doesn't allow that kind of control.

Setsize is just ftruncate. You can shrink, grow etc. normally you can let the os/kernel handle growing the file optimally especially as writes are buffered, but this isn't the case on the switch.
That's how we got here and why PNGShot works the way it does. I don't know why I thought the function wouldn't allow you to shrink the size? Maybe I got it mixed up with something on 3DS?
 
  • Love
Reactions: impeeza
To add to the list: if you're porting a game that has a huge amount of assets ESPECIALLY so if using gadot or any other game engine, then you will notice that loading is extremely slow. This is caused by romfs loading being slow due to opening and closing many small/large files.

A better option is to just pack all the files into a blob (still inside romfs if you wish). Then at startup, load the entire blob into memory and then load assets from that. This block can be a zip, physfs or anything similar. You can even load the entire romfs blob into memory and write some customer romfs devoptab code to handle reading files with stdio. The latter requires the least amount of changes to game engines etc.

This isn't possible if the total size of assets is something insane like 2-3gb, but most ports are not that big. And forget about supporting applet mode anyway. If the user loads the game with pallet mode, show an error and exit when the user presses A to confirm reading it.
Post automatically merged:

This actually doesn't apply to a lot of homebrew (I think?). PNGShot and JKSV use the FS calls directly (JKSV through a C++ wrapper I wrote). I could be wrong, but most homebrew probably doesn't. libnx uses newlib to provide a C stdio like environment. Most people probably use fopen, fread, fwrite, etc. Using that newlib/stdio env doesn't allow that kind of control.


That's how we got here and why PNGShot works the way it does. I don't know why I thought the function wouldn't allow you to shrink the size? Maybe I got it mixed up with something on 3DS?
Devs can still use stdio and achieve great performance. Multi threading and doing writes in large blocks of around 4mib is something that could be easily added. Along with locking exit and lazy loading. The latter I see pretty much no homebrew do. They just load everything upfront so loads times take a million years. This is why when fw 20 rolled around, most apps shit the bed and took forever to load.
 
Last edited by AllOver,
@namename11 @AllOver write speed is not an issue here. Read my post again...

- PNG DOESN'T SUPPORT WRITING RAW DATA.
Raw data is not the issue here, speed is.

Reserving 2.64MiB in RAM or even multiples of it is not an issue on lower fws (I have 40MiB free I think), but I understand if @JK_ doesn't want to implement such a niche feature.
 
Config has been implemented. There's only two keys as of now:
JSON:
{
    "AllowJPEGs": true,
    "CompressionLevel": 4
}

I implemented JKSV/fslib's way of handling the reserved file size in C for PNGShot. Previous work to add config made @masagrator's pull request unmergeable (is that even a word?) before he made it. I had to add a wrapper function for reading and in doing that had to do some other revisions. I think I fixed a macro bug I should have noticed earlier too.

A couple of more things and we should be good to go?
 
  • Love
  • Like
Reactions: lightwo and impeeza
I guess minor nitpick would be to use something like ini over json for a much smaller binary size.
 
I only mention it because it's a sysmod. Saving a few hundred kb is worth saving.
Last release was 155KB. Current build I have is 189KB. That's not just json-c either, that's the changes and things I needed to add too. All things considered, I don't think it's that bad, really.
 
  • Like
Reactions: lightwo and AllOver
Last release was 155KB. Current build I have is 189KB. That's not just json-c either, that's the changes and things I needed to add too. All things considered, I don't think it's that bad, really.
Yeah that's better than I thought it would be
 
I think the sdmc:/switch/PNGShot/[date][time].png route is simple, but the sdmc:/Nintendo/Album/PNGs/YYYY/MM/DD/YYYYMMDD_hhmmss.png route is complicated and requires many clicks.
 
  • Like
Reactions: lightwo
I think the sdmc:/switch/PNGShot/[date][time].png route is simple, but the sdmc:/Nintendo/Album/PNGs/YYYY/MM/DD/YYYYMMDD_hhmmss.png route is complicated and requires many clicks.
The next release will split every unsigned integer into its individual bits for naming. Every 1 and 0 will be its own sub-folder. It think it's even more organized and cool cause it's binary.

All unsigned integers will also be cast to 64 bits before this for maximum clicks and organization.
 
Binary is sexy
010010010010000001100001011001110111001001100101011001010010111000100000010101110110010100100000011100110110100001101111011101010110110001100100001000000110000101101100011011000010000001110101011100110110010100100000011000100110100101101110011000010111001001111001001011000010000001100010011101010111010000100000011011110110111001101100011110010010000001100010011010010110111001100001011100100111100100100000011100110111010001110010011010010110111001100111011100110010000001100011011011110110111001110110011001010111001001110100011001010110010000100000011101010111001101101001011011100110011100100000011100000111001001101111011001110111001001100001011011010111001100100000011101110111001001101001011101000111010001100101011011100010000001101001011011100010000001100001011100110111001101100101011011010110001001101100011110010010000001100001011011100110010000100000010000110010000001100011011011110111010101101110011101000010000001100001011100110010000001110010011001010110000101101100001000000110001001101001011011100110000101110010011110010010111000100000010101000110100001100001011101000010011101110011001000000110100001101111011101110010000001000111011011110110010000100000011010010110111001110100011001010110111001100100011001010110010000100000011010010111010000101110001000000100000101101110011110010010000001100010011010010110111001100001011100100111100100100000011001110110010101101110011001010111001001100001011101000110010101100100001000000111010101110011011010010110111001100111001000000110111101101110011011000110100101101110011001010010000001110111011001010110001000100000011101000110111101101111011011000111001100100000011010010111001100100000011001100110000101101011011001010010000001100010011010010110111001100001011100100111100100101110
 
  • Like
Reactions: kidkat210
010010010010000001100001011001110111001001100101011001010010111000100000010101110110010100100000011100110110100001101111011101010110110001100100001000000110000101101100011011000010000001110101011100110110010100100000011000100110100101101110011000010111001001111001001011000010000001100010011101010111010000100000011011110110111001101100011110010010000001100010011010010110111001100001011100100111100100100000011100110111010001110010011010010110111001100111011100110010000001100011011011110110111001110110011001010111001001110100011001010110010000100000011101010111001101101001011011100110011100100000011100000111001001101111011001110111001001100001011011010111001100100000011101110111001001101001011101000111010001100101011011100010000001101001011011100010000001100001011100110111001101100101011011010110001001101100011110010010000001100001011011100110010000100000010000110010000001100011011011110111010101101110011101000010000001100001011100110010000001110010011001010110000101101100001000000110001001101001011011100110000101110010011110010010111000100000010101000110100001100001011101000010011101110011001000000110100001101111011101110010000001000111011011110110010000100000011010010110111001110100011001010110111001100100011001010110010000100000011010010111010000101110001000000100000101101110011110010010000001100010011010010110111001100001011100100111100100100000011001110110010101101110011001010111001001100001011101000110010101100100001000000111010101110011011010010110111001100111001000000110111101101110011011000110100101101110011001010010000001110111011001010110001000100000011101000110111101101111011011000111001100100000011010010111001100100000011001100110000101101011011001010010000001100010011010010110111001100001011100100111100100101110
01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000001 01110011 01110011 01100101 01101101 01100010 01101100 01111001
 
  • Like
Reactions: kidkat210
What's wrong, why it saves 720 when I'm in dock...?
 

Attachments

  • Screenshot_2026-05-05-23-24-13-175_bin.mt.plus.canary.jpg
    Screenshot_2026-05-05-23-24-13-175_bin.mt.plus.canary.jpg
    156.8 KB · Views: 11
  • 20260506_001652.png
    20260506_001652.png
    996.9 KB · Views: 4

Site & Scene News

Popular threads in this forum