Choosing Per‑Platform Texture Compression in MonoGame’s Content Pipeline
Learn how to configure per‑platform texture compression (BC7 on Windows, ASTC on Android) in MonoGame's MGCB pipeline, verify the output, and understand the build‑time trade‑offs.
13 Sept 2026, 08:30 UTC

The Compression Dilemma
When you ship a MonoGame title to Windows, Android, and iOS you quickly hit a texture‑format wall. DirectX prefers BC7, OpenGL ES/Vulkan likes ASTC or ETC2, and older iOS devices only understand PVRTC. Shipping a single .xnb that works everywhere forces you to pick the lowest common denominator — usually uncompressed RGBA — which blows up memory and bandwidth on mobile.
The MonoGame Content Pipeline (MGCB) solves this by letting you choose a compression format per target platform at build time. The decision is baked into the .xnb files, so the runtime simply loads the already‑compressed texture. The catch: you must rebuild the content for each platform and you cannot swap formats at runtime.
How MGCB Handles Platform‑Specific Compression
The pipeline stores processor parameters in the .mgcb project. For each texture you can override the TextureFormat property per platform (WindowsDX, DesktopGL, Android, iOS, etc.). The MGCB Editor (since 3.8.1) surfaces these overrides in a per‑platform property grid, so you rarely need to hand‑edit XML.
- WindowsDX / DesktopGL – BC1‑BC7 (DirectX) or S3TC/BPTC (OpenGL).
- Android – ETC1, ETC2, ASTC (via KTX2).
- iOS – PVRTC (legacy) or ASTC (modern).
When you run dotnet publish -r <rid> the MSBuild target MonoGameContentReference invokes mgcb with the appropriate /platform: switch, producing a platform‑specific Content/ folder full of .xnb files.
Worked Example: BC7 for Windows, ASTC for Android
Assume a new DesktopGL project called MyGame with a texture Content/Textures/ui.png.
- Create the project and open the editor (run in the project root, no elevated rights needed):
The editor launches and showsdotnet new mgdesktopgl -o MyGame cd MyGame dotnet mgcb-editor Content/Content.mgcbui.pngunder theTexturesnode. - Set platform overrides: select
ui.png, open the Processor Parameters pane, expand Platform Overrides. Add two entries:- Platform:
WindowsDX→TextureFormat = BC7 - Platform:
Android→TextureFormat = ASTC
.mgcbfile. - Platform:
- Publish for each runtime identifier (requires the Android SDK and a Windows SDK for the respective RIDs):
dotnet publish -f net8.0 -r win-x64 -c Release # output: bin/Release/net8.0/win-x64/publish/Content/Textures/ui.xnb dotnet publish -f net8.0 -r android-arm64 -c Release # output: bin/Release/net8.0/android-arm64/publish/Content/Textures/ui.xnb - Verify the compression – open each .xnb with a hex viewer (e.g.,
xxdon Linux/macOS or a GUI hex editor on Windows). The Windows .xnb should start with the DDS magic44 44 53 20followed by a BC7 FourCC (42 43 37 20). The Android .xnb should contain a KTX2 header (AB 4B 54 58 20 32 30 0A) and an ASTC block identifier.
At runtime ContentManager.Load<Texture2D>("Textures/ui") loads the correct variant automatically because the platform‑specific Content folder is bundled with the app.
Trade‑offs and Limitations
- Build‑time lock‑in – you cannot switch from BC7 to ASTC without a full content rebuild. If you need to support a new GPU family, you must add another platform override and republish.
- Artifact size – each platform gets its own .xnb set, increasing CI storage and publish time.
- Legacy SpriteFont processor on Linux still falls back to
System.Drawing(requireslibgdiplus), unrelated to textures but worth noting if you hit build failures. - FBX version ceiling – AssimpNet tops out at FBX 2020; newer assets may need conversion before import.
If you need runtime format selection (e.g., user‑chooses quality), you must ship multiple .xnb copies and pick the appropriate ContentManager root via platform detection.
Verifying the Result in CI
Add a quick verification step to your pipeline:
# After dotnet publish for win-x64
xxd -l 16 bin/Release/net8.0/win-x64/publish/Content/Textures/ui.xnb | grep -q "44 44 53 20" && echo "Windows BC7 OK"
# After dotnet publish for android-arm64
xxd -l 16 bin/Release/net8.0/android-arm64/publish/Content/Textures/ui.xnb | grep -q "AB 4B 54 58" && echo "Android ASTC OK"
These checks run in the same agent that performed the publish, require only read access to the output directory, and fail fast if the wrong compressor was used.
Closing Action
Start by adding a single platform override for your most memory‑constrained target (usually Android). Run the two publish commands above, verify the headers, and then expand the override list for each additional platform. Keep the source .png and the .mgcb file under version control so you can always rebuild when MonoGame 4.x introduces a new XNB version.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.