Commit Graph
1 Commits
Author SHA1 Message Date
Neo 53d32a761e Improve "Add raw copy dependencies for incompatible textures"
Initial PR was made by Avan for Ryubing.

This allows for Trails in the Sky 1st Chapter (and by extension Trails through Daybreak, Trails through Daybreak II, Trails Beyond the Horizon, and the future Trails in the Sky 2nd Chapter – tested via demo – to be fully playable.

Initial PR caused issues on macOS devices, specifically crashing in certain games (such as Mario Kart 8 Deluxe and the aforementioned Trails games). It was reverted on the original Ryubing project (at the time of writing this description) for causing small rendering issues on The Legend of Zelda: Breath of the Wild.

The rendering issues do not appear on macOS.

This commit improves the original PR by eliminating said macOS crash.

Trails in the Sky 1st writes its exposure/brightness value through an R32G32Float 1x1 texture and later reads the raw bits back through an R32Uint 2x1 texture mapped to the same guest memory. The two texture formats/dimensions are fully incompatible as texture views, so they end
up as separate host textures, and nothing kept their contents coherent - the reader saw stale zeroed data, making the exposure calculation (and the rendered image) too dark. (This is the initial fix for the game)

TextureGroup already had a raw-copy dependency mechanism intended to
handle this class of alias (TextureDependency, TextureGroupHandle
raw-copy plumbing), gated by CanCreateRawCopyDependency's strict same-guest-memory checks. This commit fixes three bugs that kept that mechanism from working correctly (and thus crashing Trails and other games, such as Mario Kart 8 Deluxe):

(1) TextureGroup.InitializeOverlaps() and TextureGroup.RegisterIncompatibleOverlap() only forwarded overlaps to CreateCopyDependency() when compatibility was LayoutIncompatible or better, silently excluding the fully Incompatible case the raw-copy path exists for. Widened both guards to let Incompatible overlaps through so CanCreateRawCopyDependency actually gets a chance to run.

(2) Once Incompatible overlaps were allowed through, CreateCopyDependency(TextureGroup, ...) could still fall back to a regular, non-raw textureCopy for such pairs, since ViewLayoutCompatible/CopySizeMatches only check byte size and were never meant to reason about fully incompatible pairs (e.g. a depth format aliasing a color format with the same byte size). On Vulkan running through MoltenVK on macOS, that non-raw copy path requires a pixel-format-reinterpreting texture view, and MoltenVK/Metal refuses to create any view onto a depth-format texture ("not castable"), aborting emulation. textureCopy is now forced false for Incompatible pairs, leaving raw copy (which already excludes depth/stencil formats) as the only route for that severity level.

(3) TextureGroupHandle.Inherit() copied a handle's pending DeferredCopy to the new handle when a view was recreated, but did not copy DeferredCopyRaw alongside it. A handle that inherited a pending raw copy would then execute it through the regular (non-raw) CopyTo path once acknowledged, reinterpreting the source bytes with the wrong row layout and corrupting the image - visible as vertical flickering stripes whenever a view happened to be recreated with a raw copy still pending. DeferredCopyRaw is now carried over together with DeferredCopy.

(As mentioned earlier, vertical stripes aren't present on macOS, so (3) doesn't negatively have an effect on macOS in any way).
2026-08-29 10:49:56 -05:00