Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Paid Bounty] Upgrade MonoGame to use BasisUniversal for cross platfo…
…rm Texture Compression (MonoGame#8456) To briefly restate the paid bounty, MonoGame's texture compression tooling does not work on ARM based CPUs (like the recent Apple M) chips. The goal of the bounty was to restore functionality on ARM based CPUs. The actual implementation detail of the bounty was to swap out old texture compression tools (like PVRTexLibNET and NVTT) with a new command-line utility called [Basis Universal](https://github.com/BinomialLLC/basis_universal). This PR completes the cross-platform goal of the bounty, and introduces some implementation _beyond_ what was originally documented in the paid bounty. Here is a quick tldr of what is in the PR, and more details below. - Content Pipeline Context - ETC2 Support - ATSTC Support - Dotnet tool references to `mgcb-basisu` and `mgcb-crunch` - Nuget library references `ktxLoader` and `bcnEncoder` - Removal of PVRTex and NVTT To begin, I ripped out the PVRTex and NVTT libraries. Immediately, the following classes (and in some cases, their sub-classes) had compile errors, - `DxtBitmapContent`, - `AtcBitmapContent`, - `Etc1BitmapContent`, - `PvrtcBitmapContent` From those 4 base types, _several_ `SurfaceFormat` types were no longer compressible. However, at this point, I find it helpful to remember that not all `SurfaceFormat` values were actually selectable by users. In the Content Builder, the users select a `TextureProcessorOutputFormat` value which _hints_ which `SurfaceFormat` to use, but doesn't strictly enforce it. For example, the user may select `TextureProcessorOutputFormat.DxtCompressed`, but exactly which DXT `SurfaceFormat` is selected is left to the Content Builder code (specifically, the `GraphicsUtil.CompressDxt` function) There are a cascade of `SurfaceFormat`s that broke, and unfortunately, _Basis Universal_ doesn't actually cover all of the formats. _BasisU_'s format list is [here](https://github.com/BinomialLLC/basis_universal/blob/ad9386a4a1cf2a248f7bbd45f543a7448db15267/transcoder/basisu_transcoder.h#L49). To cover the formats that weren't supported directly by _BasisU_, this PR also includes the external command line utility, [Crunch](https://github.com/MonoGame/MonoGame.Tool.Crunch), as well as a nuget library for [BcnEncoder](https://github.com/Nominom/BCnEncoder.NET). Here is a table of all the formats that broke after I removed the old texture compression tools, if they're still supported, and if so, what tool is doing the compression. | Format | Still Supported | Tool | Note | | - | - | - | - | | DXT1 | yes | BcnEncoder | | | DXT1a | yes | BcnEncoder | | | DXT3 | yes | Crunch | BcnEncoder produces bad results for textures with alpha for dxt3 only | | DXT5 | yes | BcnEncoder | | | RgbaAtcExplicitAlpha | yes | BcnEncoder | | | RgbaAtcInterpolatedAlpha | yes | BcnEncoder | | | RgbaAtcInterpolatedAlpha | yes | BcnEncoder | | | RgbEtc1 | yes | Crunch | | | ETC2 | yes | Crunch | this PR adds support for ETC2 compression, which previously was not available | | ASTC_4x4_Rgba | yes | BasisU | this PR adds support for ASTC compression, as well as the SurfaceFormat value | | RgbPvrtc4Bpp | yes | BasisU | | | RgbaPvrtc4Bpp | yes | BasisU | | | RgbPvrtc2Bpp | no | - | | | RgbaPvrtc2Bpp | no | - | | Alarm bells may be going off in your brain for the lack of `RgbPvrtc2Bpp` and `RgbaPvrtc2Bpp` support. However, the correlated subtypes of `PvrtcBitmapContent` for those 2Bpp variants, `PvrtcRgb2BitmapContent`, and `PvrtcRgba2BitmapContent` had _no_ usages in the codebase. The `TextureProcessorOutputFormat.PvrCompressed` option would always lead users to the _4Bpp_ variant. This PR marks the 2Bpp variants with the `[Obsolete]` tag but does not delete them. _BasisU_ does not support the 2Bpp variant, but since the types were never used, I felt it was okay to deprecate them. It turns out that _BasisU_ is actually only used for a _relatively_ small subset of the formats. The _BcnEncoder_ library is handling several formats. The library is much faster an transcoding the textures because it is running within the same dotnet process and does not need to generate any intermediate files. The _BcnEncoder_ library is a nuget package, and comes with a few dependencies. Comparatively, the _Crunch_ and _BasisU_ tools are invoking separate processes on the machine to handle the compression, and those processes require data to be passed via file, which requires the Content Builder to do file reads&writes. In both cases, I'm using another library, _KtxLoader_, to read the compressed byte arrays. The file requirement is the reason for the newly added `ContextScopeFactory` in this PR. The current architecture is set up so that the compression is triggered from within a `BitmapContent`'s public API, but since those types are originally XNA types, I cannot change their public API to include any contextual information about where to generate the intermediate files. Instead of modifying the public API, I've introduce a new concept into the Content Builder, called a _Context Scope_. Essentially, every time some content is being processed, it creates a `static`-ally available view of the contextual information, which is used to infer the directory where intermediate files should be created/destroyed. As noted in the table above, this PR adds support for `ETC2`. I've deprecated the `TextureProcessorOutputFormat.Etc1Compressed` option, and added a more generalized `TextureProcessorOutputFormat.EtcCompressed` option. This new option will use ETC2 compression if the source texture is found to have non opaque alpha values. Otherwise, ETC1 is still used. Also, this PR adds support for ASTC. To support this, I created a brand new entry in the `TextureProcessorOutputFormat` enum, and the `SurfaceFormat` enum. Basis Universal was packaged into a custom [monogame tool](https://github.com/MonoGame/MonoGame.Tool.BasisUniversal), and published to [nuget](https://www.nuget.org/packages/mgcb-crunch). The original paid bounty issue can be found here, MonoGame#8419 And I had my draft PR against my personal fork of MonoGame. A fair amount of development discussion took place on that thread, so feel free to review it. cdhanna#1 Known Issues - MultiThreaded context issue? - I need to do a bit digging into the `ContextScopeFactory` and make sure it works in a possibly multi-threaded scenario. I was testing it via Unit Tests. - How do the users get access to the dotnet tools `mgcb-crunch` and `mgcb-basisu`? - For development, there is a local `.config/dotnet-tools.json` file which makes the tools available to use during Unit Tests. But its unclear to me how these tools get resolved in an actual production use case. I think there is a plan amongst the maintainers of MonoGame, but I don't fully understand it (yet). ---- I've enjoyed working on this, and I've learned _a lot_. Thanks to all those who have helped out and answered my questions :) Co-authored-by: Chris Hanna <[email protected]>
- Loading branch information