Skip to content

macOS support + cross-platform asset pipeline#3187

Merged
xen2 merged 60 commits into
stride3d:masterfrom
xen2:feature/xplat-assetcompiler
May 24, 2026
Merged

macOS support + cross-platform asset pipeline#3187
xen2 merged 60 commits into
stride3d:masterfrom
xen2:feature/xplat-assetcompiler

Conversation

@xen2
Copy link
Copy Markdown
Member

@xen2 xen2 commented May 24, 2026

PR Details

Stride's asset compiler ran Windows-only because of native deps (FreeImage,
FreeType-based MSDF, DirectXTex, Bullet, VHACD, PVRTT) and a handful of
path/loader assumptions. This branch makes a full Linux + macOS asset build +
test pipeline.

Native dependency rework (cross-platform wrappers + CI builds)

All of those deps build are easy to reproduce (simple github CI workflows)

  • DirectXTexstride_directxtex C wrapper, cross-platform build workflow.
  • MSDF fontstride_msdfgen library replacing in-process FreeType.
  • ImageSharp replaces FreeImage in StandardImageHelper + TextureConverter.
  • ASTC: new astcenc 5.3.0 backend + LDR formats; PVRTT removed (ASTC covers
    mobile compression).
  • Bullet / V-HACD v4: cross-platform build workflows, drops osx-x64, adds
    osx-arm64.
  • MoltenVK 1.4.1 on macOS for Vulkan.
  • FFmpeg 7.1.1 + Stride.Video 7.x API migration + VideoBackend abstraction;
    new VideoSmokeTest covering load/seek with HW/SW decode-path gold pairs.
  • Native lib loading: SONAME glob on Linux/macOS, Unix apphost handling,
    StrideNativeLib RID-aware copy.

Build / SDK

  • Tests collapsed into one multi-TFM csproj per project
    It was Windows/Android/iOS triplet before. This will make tests and sln much easier to maintain.
  • Stride.Local.props atomic bootstrap (race fix) + StridePlatforms
    defaulted from host OS.

CI

  • Linux: now build on Linux instead of Windows
  • macOS: full test CI, building on macOS
  • Vulkan validation layers enforced, vulkan/macos gold baseline bumped.
  • tools/CompareGold can get build artifacts from forks.

Related Issue

Closes #1169
Closes #1061
Closes #335
Closes #1390
Closes #3021
Closes #2596
Closes #2922
Closes #2496
Closes #2305
Closes #360
Closes #2001

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My change requires a change to the documentation.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have built and run the editor to try this change out.

xen2 added 14 commits May 24, 2026 11:07
Replaces System.Drawing.Bitmap with ImageSharp's Image<Rgba32> in the
SpriteFont compiler so Stride.Assets no longer pulls a Windows-only
runtime dependency.

- SpriteFont/Compiler/: migrate Bitmap/PixelAccessor/Color/Rectangle to
  Image<Rgba32>/Rgba32 and ImageSharp.Rectangle, drop the PixelAccessor
  lock helper (ImageSharp doesn't need it).
- Stride.csproj: drop the unused System.Drawing.Common PackageReference
  (only iOS/UWP partials used it, and the reference was gated to net10.0
  so it was never pulled for those TFMs anyway).
- Directory.Packages.props: deduplicate SixLabors.ImageSharp (3.1.5 +
  3.1.12 -> 3.1.12, fewer CVEs) and Microsoft.Direct3D.WARP.
JPEG-XR / Windows Media Photo isn't supported by ImageSharp and has no
production callers in Stride. Removes the enum value, the Save method
stubs (which all threw NotImplementedException anyway), the WIC case,
and the Wmp branches in tests.
…harp

Desktop now loads/saves images via SixLabors.ImageSharp instead of FreeImage:
Stride.csproj loses its native FreeImage dependency.

- Save methods (Gif/Tiff/Bmp/Jpg/Png) move to the shared partial and use
  ImageSharp. Replaces the per-platform stubs (iOS/Android all threw
  NotImplementedException, Android had ad-hoc Bitmap.Compress for Png/Jpg).
- Desktop LoadFromMemory uses ImageSharp's Bgra32 path; no FreeImage preload.
- iOS/Android LoadFromMemory kept native (UIImage/BitmapFactory) for
  hardware-accelerated decode.
- Drop StandardImageHelper.UWP.cs and WICHelper.cs (UWP target was
  intentionally omitted in the SDK; both files were dead code).
Replace the FreeImage-backed FITexLib with a managed ImageSharpTexLib for
common bitmap I/O and pixel-space operations (rescale, flip, R/B swap,
gamma, sub-image swap). Operates on Image<Bgra32>; supports B8G8R8A8 /
R8G8B8A8 and their SRgb/Typeless variants. Rescale-filter mapping:
Bilinear -> Triangle, BSpline -> Spline; others 1:1. Gamma matches
FreeImage's out = 255 * (in/255)^(1/gamma).

With no remaining consumers, fully remove the Stride.FreeImage project,
the deps/FreeImage native bundle, and the Stride.csproj reference left
over from the StandardImageHelper migration. Drop libfreeimage-dev from
the Linux CI job and the FreeImage-era "BMP save not supported on Linux"
test skips (ImageSharp is cross-platform). Refresh THIRD PARTY.md.
Workflow .github/workflows/dep-dxtwrapper.yml builds DxtWrapper.{dll,so,dylib}
per RID with DirectXTex static-linked. RIDs: win-x64, win-arm64, linux-x64,
osx-arm64. Non-Windows jobs also check out DirectX-Headers and DirectXMath.

Wrapper API reshaped (Option A): hides DirectX::ScratchImage behind an opaque
DxtImageSet handle. Each op reads input images/metadata, allocates a fresh
output set. Removes the dxtCreateScratchImage / dxtInitialize* family that C#
never needed.

Adds dxtLoadHDR/dxtSaveHDR, dxtScaleMipsAlphaForCoverage, dxtBytesPerBlock,
dxtCalculateMipLevels[3D]. WIC entry guarded by _WIN32.

C# side (DxtNetWrapper.cs, DxtTexLib.cs) will be updated in a follow-up commit
once the workflow has produced the new binaries to verify the native API.
Rewrites DxtNetWrapper.cs around an opaque DxtImageSet handle (replaces
the ScratchImage class + the dxtCreate/Initialize* family that callers
never used). DllImports now target stride_directxtex.{dll,so,dylib}.

Adds: DDS_FLAGS_PERMISSIVE etc., TGA_FLAGS, BC7 quality knobs, HDR I/O,
ScaleMipsAlphaForCoverage, BytesPerBlock, CalculateMipLevels helpers.

DxtTexLib.cs updated to the transaction-style API (each op consumes
input arrays + metadata, returns a fresh DxtImageSet). Adds .hdr to
the loadable extension list. Disposes prior set before replacing.

Stride.TextureConverter.csproj: glob now also picks up .dylib for
macOS native runtimes.

Binaries in deps/TextureWrappers/Release/{rid}/ replaced with workflow
output (DirectXTex may2026, DirectX-Headers v1.619.1, DirectXMath
may2026). Adds osx-arm64; drops stale Debug/ and old DxtWrapper.* names.
TextureTool's static ctor still PreloadLibrary'd "DxtWrapper" — eager
load failed with DllNotFoundException before any P/Invoke could fire.
Renamed to "stride_directxtex" to match the actual lib filename.

Added a non-skipped Fact in DxtTexLibTest: load+convert+save round-trip
on an existing fixture. Exercises native lib loading, P/Invoke
marshalling, struct layout, and the DDS encode path end-to-end — caught
the preload-name regression above.
Imaging-library migrations change output bytes:
- TextureConvertCommand 3->4: ImageSharp vs FreeImage resamplers.
- OfflineRasterizedFontCommand 1->2: System.Drawing -> ImageSharp in
  glyph rasterization / cropping / packing.
- SignedDistanceFieldFontCommand 0->1: same migration in SDF importer.
stride_msdfgen.{dll,so,dylib} per RID (win-x64, win-arm64, linux-x64,
osx-arm64), static-linking msdfgen-core + msdfgen-ext + private FreeType.
Minimal C ABI for SDF glyph generation, writes RGBA8 directly.

Layout mirrors dxtwrapper. Workflow installs FreeType static to a staging
prefix, then sets FREETYPE_LIBRARY / FREETYPE_INCLUDE_DIRS for the wrapper
CMake (FindFreetype's HINT search is unreliable from msdfgen on Windows).
Replace per-glyph Process.Start("msdfgen.exe") + tmp-bmp roundtrip with
direct P/Invoke into stride_msdfgen. Same output, no subprocess per glyph,
no system msdfgen needed on Linux/macOS PATH.

- SignedDistanceFieldFontImporter: hold msdfgen context + font handle
  across Import(); LoadSDFBitmap writes RGBA in-process.
- Stride.Assets.csproj: bundle via StrideNativeLib, drop <Content msdfgen.exe>.
- deps/msdfgen: replace msdfgen.exe + build/checkout scripts with the
  multi-RID artifact from dep-msdfgen.yml.
- THIRD PARTY.md: add msdfgen attribution.
Bundles astcenc.dll/.so/.dylib (win-x64/linux-x64/osx-arm64) and adds an
AstcTexLib backend wrapping the ARM astcenc API. New ASTC LDR PixelFormats
(4x4..12x12, UNorm + SRgb) with Vulkan mapping; ComputePitch derives block
size from the format. DetermineOutputFormat emits ASTC_6x6_UNorm[_SRgb]
for Android/iOS at Level_10_0+ (replaces ETC2_*).
ASTC superseded ETC2 on Android/iOS for compressed sprite output, leaving
PVRTT (the ETC2/PVRTC encoder) with no callers. Drops:
- deps/PVRTT/ (~10 binaries + headers + license)
- Stride.TextureConverter.TexLibraries.PvrttTexLib + its C# wrapper layer
- Stride.TextureConverter.Tests.PvrttTexLibTest
- PVRTexLib preload in TextureTool

ETC* / EAC* PixelFormat entries stay in the enum for backward compatibility
with already-built content. There is just no encoder for them anymore.

DetermineOutputFormat Level_9_x branch (pre-Vulkan GLES 2.0 era) now falls
back to uncompressed R8G8B8A8 instead of ETC1; the path is effectively dead
for a Vulkan-targeted engine.
@xen2 xen2 force-pushed the feature/xplat-assetcompiler branch from 55e15eb to 369e5ab Compare May 24, 2026 02:09
@xen2 xen2 changed the title crossplat-assetcompiler: make the asset pipeline cross-platform macOS support + cross-platform asset pipeline May 24, 2026
@xen2
Copy link
Copy Markdown
Member Author

xen2 commented May 24, 2026

/ci e2e

@stride-chatops
Copy link
Copy Markdown

stride-chatops Bot commented May 24, 2026

@stride-chatops
Copy link
Copy Markdown

xen2 added 11 commits May 24, 2026 14:39
Each test project now builds for Windows + Android + iOS from one .csproj
via the new MultiPlatform Tests SDK. Stride.Engine.Tests's surviving
.Windows/.Android/.iOS triplet collapses into one .csproj;
.Windows.sdpkg renamed to .sdpkg.

bin\ normalized to <Platform>-<Api>\<Config>\ matching obj\.
…stream

Adds a per-tool forks list (persisted to <ciCacheDir>/forks.json) and fans the
runs query out across stride3d/stride + each fork in parallel. Each run row
shows a repo chip so the artifact source is unambiguous; the artifact/download
endpoints take a repo param so they hit the same fork the user picked.
Build jobs move from windows-2025 to ubuntu-24.04. Game build installs
libvulkan1+xvfb and registers the Lavapipe ICD so CompilerApp has a
Vulkan device for asset compilation.
@xen2 xen2 force-pushed the feature/xplat-assetcompiler branch from 369e5ab to bed24d6 Compare May 24, 2026 05:40
@xen2
Copy link
Copy Markdown
Member Author

xen2 commented May 24, 2026

/ci e2e

@stride-chatops
Copy link
Copy Markdown

stride-chatops Bot commented May 24, 2026

@stride-chatops
Copy link
Copy Markdown

1 similar comment
@stride-chatops
Copy link
Copy Markdown

@xen2 xen2 force-pushed the feature/xplat-assetcompiler branch from bed24d6 to de8fc6a Compare May 24, 2026 05:59
xen2 added 2 commits May 24, 2026 15:13
…dummy)

Add WriteNullable/ReadNullable/SerializeNullable<T> in SerializerExtensions
for reference-type nullables (value types already via NullableSerializer).
Wire SoundSerializer through them (bump to Version 5)
@xen2
Copy link
Copy Markdown
Member Author

xen2 commented May 24, 2026

/ci e2e

@stride-chatops
Copy link
Copy Markdown

stride-chatops Bot commented May 24, 2026

@stride-chatops
Copy link
Copy Markdown

@xen2 xen2 merged commit 6301e28 into stride3d:master May 24, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment