Skip to content

Mullion v0.4

Pre-release
Pre-release

Choose a tag to compare

@dttdrv dttdrv released this 25 Oct 16:56

Mullion v0.4 is mostly about getting things right. A new test suite written from Microsoft's specifications found a lot, and the fixes ship here, along with M1 and M2 support, shader model 6.7, D3D11On12 and a round of Direct3D 12 speedups. Built from main at 7bcdcb44, 57 commits since v0.3.

Note: Mullion now runs on every Apple silicon Mac, M1 and later. CrossOver users no longer have to rename folders inside CrossOver.app: ./install.sh --crossover <bottle> sets a bottle up once, and CrossOver updates keep it. The manual way still works; see Installing.

Games

  • Forza Horizon 5: pipelines that blend with a second output the shader never writes now build, and 8x MSAA pipelines on a GPU without 8x are refused before their shaders compile, which was the slow part (#34).
  • Unity 6 games: start on Direct3D 12 instead of dropping to Direct3D 11. The adapter reports its memory as shared system memory too (#49), the tight alignment query answers instead of failing (#50), and the HUD shows the real feature level (#51).

New

  • M1 and M2 (Apple7 and Apple8 GPUs) are supported. What differs on them is taken from what the GPU reports: format capabilities per GPU, 32-bit float filtering, and at most 4x MSAA below Apple10.
  • Shader model 6.7 on Direct3D 12: QuadAny, QuadAll and helper lanes in wave operations. Advanced texture operations and writable MSAA textures don't work yet, so a shader that needs them is refused when its pipeline is created.
  • D3D11On12: D3D11On12CreateDevice returns a device on the Direct3D 12 queue, with wrapped resources and fences shared by both APIs (#37).
  • Stream output from ExecuteIndirect.
  • Every call Mullion refuses now says why in the log, and a log path that can't be written is reported.
  • The Direct3D 11 immediate context answers ID3D11VideoContext.
  • ./install.sh --crossover <bottle> installs Mullion for one CrossOver bottle.

Fixes

Shaders

  • Ops with two destinations (imul, umul, udiv, uaddc, usubb), swapc and sincos no longer read the wrong component past y.
  • Calls nested deeper than 32 levels no longer run.
  • resinfo takes the reciprocal of sizes only, answers zeros for a mip out of range, and reports 0 mips for a null MSAA view.
  • sample_c and gather4_c compare zero references correctly over denormal texels.
  • Half-precision wave sums no longer count helper lanes.

Direct3D 12

  • Root signatures over 64 DWORDs, and root ranges past their limits, are refused.
  • ResolveQueryData checks its arguments instead of crashing.
  • Waits on a fence finish when the device is removed, and releasing a fence wakes its waiters.
  • A render target format Metal can't render to is an absent slot, as on Windows, instead of failing the pipeline.
  • Resource creation follows the specification: CPU-visible textures need a power-of-two element size, volume textures with CPU access have one mip, zero-width buffers are refused, buffers on a custom heap without CPU access can't be mapped, advertised 1D depth formats can be created, and legal BC writes are accepted.
  • D24 depth converts correctly in copies, and depth clears and readback round within the specification's tolerance.
  • Depth views give the right components.
  • ALPHA_FACTOR and INV_ALPHA_FACTOR reach the alpha channel.
  • Stream output's scratch is cleared on every execution, an ExecuteIndirect with a zero count resets the state it would have set, and stencil-only clears have a pipeline of their own.
  • Sampler feedback encodes no longer lose regions to a race between the clear and the record.
  • 64-bit texture atomic exchanges are fenced.

Direct3D 11 and 10

  • Direct3D 10.1 takes all 32 vertex buffer slots, not 16.
  • Copies within one resource that overlap read the source as it was before the copy.
  • State objects keep their lifetimes and validation: d3d10_state and d3d11_raster_state no longer crash.
  • Resource creation refuses bind flags a usage forbids, and checks dimensions against the limits.
  • Partial constant buffer updates, dynamic initial data, structured buffer copies and GenerateMips give the right values.
  • Clears convert to the format correctly: packed channels in order, half floats rounded toward zero, RGB10A2 integers clamped.
  • UAV counters stay resident, CSInvocations counts Dispatch and DispatchIndirect, and queries on deferred contexts begin when they should.
  • Geometry shader pipeline statistics are counted on the GPU.
  • BC copies snap to whole 4x4 blocks.
  • A failed Map leaves the pitches as they were (#58).

Blending and multisampling

  • Float blending keeps NaNs and signed zeros through zero weights, on both APIs.
  • Lines with MultisampleEnable are drawn as Direct3D's 1.4 pixel wide quads.
  • A pixel shader that writes memory runs once per pixel under MSAA, not once per sample.
  • Centroid inputs pick the right sample under a partial sample mask, and the center sample pattern works.
  • Huge triangles no longer show seams where Metal splits them.

DXGI

  • A swap chain resized with a list of queues presents through those queues, in order.
  • Gamma control works only in fullscreen, as on Windows, and outputs and factories check their arguments.
  • The window's pixel format follows the swap chain's colour space.

Performance

All Direct3D 12, by @aaf2tbz:

  • A UAV barrier keeps a render pass open when its draws used no UAVs (#53).
  • The residency set is committed once per command buffer instead of once per resource (#54).
  • A compute pass whose dispatches all wait on each other runs on a serial encoder (#55).
  • A colour clear and a depth clear of the same size share one pass (#56).
  • Textures the CPU never touches start out private, so Metal can compress them (#57).
  • sin and cos use Metal's fast versions within pi, where their error is bounded (#52).

Development

  • A test suite of Direct3D 10, 11, 12 and DXGI, written from Microsoft's specifications. It runs on the Apple7, Apple8, Apple9 and native GPU families of one Mac, and every fix carries a fault patch the suite must catch.
  • tests/run.py --jobs runs tests side by side, and runs each one that failed beside others again alone. A full run of all four families takes about 50 minutes instead of 3 hours.
  • tests/perf, a probe of 117 small scenes for measuring Direct3D 12 changes (#48).
  • The 32-bit build compiles again, and the suite runs in a native arm64 Wine (#36).

Installing

You need a Mac with Apple silicon, macOS 15 or later, and an x86_64 Wine. Mullion runs 64-bit games.

In CrossOver, run ./install.sh --crossover <bottle>. It leaves CrossOver.app as it is and gives the bottle its own CrossOver root with Mullion as its DXMT. Run it again after a CrossOver update that adds files. To undo it, put back the bottle's cxbottle.conf.before-mullion.

If you'd rather not run a script: rename CrossOver.app/Contents/SharedSupport/CrossOver/lib/dxmt to dxmt-original, put the unpacked mullion-v0.4 folder in its place, rename it to dxmt, and set the bottle to DXMT. A CrossOver update brings back its own DXMT this way.

Either way, on the first game launch macOS asks about winemetal.so. Allow it in System Settings, Privacy & Security, and start the game again.

For any other Wine, ./install.sh <wine> [prefix ...] works as before.

Known issues

  • Direct3D 11 video decoding and processing are still missing: the video context's methods answer E_NOTIMPL.

Thanks

A big thank you to @aaf2tbz, who did D3D11On12, the Unity fixes, all of the performance work above and the probe behind it, the 32-bit build, the native arm64 test runs, the video context and the profile fixes. Thanks also to @partprogramming09, whose M1 and M2 work in v0.3 and testing on an M1 Pro made the support in this release possible.

If something breaks, please let me know.

Full Changelog: v0.3...v0.4