Skip to content

Rewrite PNG parsing for minimal allocations#22297

Merged
PunkPun merged 4 commits into
OpenRA:bleedfrom
PunkPun:png
Jan 19, 2026
Merged

Rewrite PNG parsing for minimal allocations#22297
PunkPun merged 4 commits into
OpenRA:bleedfrom
PunkPun:png

Conversation

@PunkPun
Copy link
Copy Markdown
Member

@PunkPun PunkPun commented Jan 14, 2026

When launching dune2k, now the only overheads in png constructor are from the C# decompressor. The dotnet decompressor quite a bit faster than zlib

Screenshot 2026-01-14 214602

PR:
Screenshot 2026-01-14 214646

Though from a broader PngSpriteSheet parser the performance seems to have increased by about 100%.

This rewrite removes as many allocations as possible, rather more relying on the stack and allocating much less of it. One of the most problematic parts was memory churn on collecting IDAT chunks with all their image data, then delaying processing them to the end chunk. Instead now we immediatelly parse all IDAT chunks without copying and stream them into the decompressor via custom stream.

Copy link
Copy Markdown
Member

@RoosterDragon RoosterDragon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall approach looks good to me, some nitpicking

Comment thread OpenRA.Game/FileFormats/Png.cs Outdated
Comment thread OpenRA.Game/FileFormats/Png.cs Outdated
Comment thread OpenRA.Game/FileFormats/Png.cs Outdated
Comment thread OpenRA.Game/FileFormats/Png.cs
Comment thread OpenRA.Game/FileFormats/Png.cs Outdated
Comment thread OpenRA.Game/FileFormats/Png.cs Outdated
Comment thread OpenRA.Game/FileFormats/Png.cs Outdated
Comment thread OpenRA.Game/FileFormats/Png.cs Outdated
Comment thread OpenRA.Game/FileFormats/Png.cs Outdated
Comment thread OpenRA.Game/FileFormats/Png.cs
@PunkPun PunkPun marked this pull request as draft January 15, 2026 15:10
@PunkPun PunkPun marked this pull request as ready for review January 15, 2026 19:41
@PunkPun
Copy link
Copy Markdown
Member Author

PunkPun commented Jan 15, 2026

Updated


// Drain remaining Zlib footer bytes if necessary.
Span<byte> drain = stackalloc byte[16];
while (ds.Read(drain) > 0) { }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to read these final bytes instead of just ignoring them?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a contract for the stream to finish at the end of the chunk and consume the crc. I believe this wasn't called on any of D2K Png's, but lack of it was breaking some other png's

@PunkPun PunkPun merged commit ea07cb2 into OpenRA:bleed Jan 19, 2026
2 checks passed
@PunkPun PunkPun deleted the png branch January 19, 2026 13:26
@PunkPun
Copy link
Copy Markdown
Member Author

PunkPun commented Jan 19, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants