Extend the RE draw-logger to dump the first few vertex POSITIONS (read
from guest memory) under each draw. The f32 position bytes are identical
between the guest buffer and the on-disc .xpr (only f16 pairs are
rearranged on load), so these values can be grep'd for in a resource file
to locate a mesh whose in-file offset is otherwise unknown.
Validated: world-space stage geometry byte-matches Stage_*.xpr at exact
offsets. (Load-time-transformed meshes like the player ship don't match,
which is itself a useful finding.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reverse-engineering aid for decoding game mesh formats against GPU ground
truth. When the `log_draws` cvar is set, each distinct draw's primitive
type, index buffer (guest base / count / format / endianness), and full
per-stream vertex declaration (fetch-constant base + stride, and every
element's format + offset) is written to xenia_re_draws.log.
- command_processor.{h,cc}: CommandProcessor::LogDrawForRE(), no-op unless
the cvar is set. De-dups by the vertex-declaration fingerprint (shader +
primitive + element formats/offsets), so animated UI that redraws the
same format into fresh buffers every frame collapses to one record --
keeping it near-free (an earlier address-keyed de-dup flooded the log and
stalled the GPU thread). Capped at 4096 distinct formats.
- pm4_command_processor_implement.h: call it from ExecutePacketType3Draw
after IssueDraw (so the vertex shader has been analyzed). Backend-agnostic
base path -- works for the Vulkan build.
Used to confirm Project Sylpheed's XBG7 mesh layout (triangle list, pos
f32x3 / normal f16x4 / uv f16x2, variable stride).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This resolves the TODO in GetColorClearShaderConstants about which 32 bit portion is in which register.
For 64bpp formats, RB_COLOR_CLEAR_LO holds the lower 32 bits of the packed clear value, and RB_COLOR_CLEAR holds the upper 32 bits.
RegisterFile zeroes the whole register file at construction, but a real
console comes up with non-zero values in several of the context
registers. If a game reads one of those before writing it, it gets 0
under emulation and the real default on hardware.
I read the reset values off a retail console (read-only) and checked
them against the AMD R6xx register reference and the r600g defaults in
Mesa, which set the same registers to the same values at context init.
Where the hardware read matches the driver default it's a genuine
power-on default, not leftover runtime state.
Left the tessellation levels out on purpose: they reset to 1.0f too, but
the backends do register + 1.0f, so seeding them here would change the
effective reset factor. That needs its own change.
Integer num_format fetches now get their scale CPU-side instead of trying to guess in the shader. This is authoritative; no cvar. Both translators now use texture_integer_scale_bits after signs/gamma and before exponent bias. This alone fixes black screens and a bunch of rendering bugs across at least several dozen titles.
This new information lives in the updated FormatInfo table, including fixed component widths.
Resolve also has two new fixes.
8_8_8_8_GAMMA EDRAM sources can now decode through the PWL curve while still in linear space, before MSAA resolve or format conversion, then re-encoded for gamma destinations. This is also now default enabled via gamma_decode_pwl_resolve and has improved blowout in at least 4 titles, with no obvious regressions thus far.
Full resolve can also now pack fixed destinations according to copy_dest_number.
Check shared memory validity before marking textures up to date and installing watches. If the backing range was invalidated, leave the texture outdated so it can be reloaded later.
Implements EVENT_WRITE_ZPD handling across shared CommandProcessor, D3D12, and Vulkan backends.
This adds a shared report lifecycle. Reports can span submissions/render passes, split into multiple segments, and asynchronously retire. Reports can also survive same-slot reuse, which is critical for titles that aggressively recycle against a small pool.
RTV/FBO use their respective host occlusion queries, whereas ROV/FSI use counter buffers instead, with shader helpers that are called from the translated PS, accumulating surviving MSAA sample coverage into active slots. Regardless of approach, results are copied to small, dedicated readbacks and fed through shared retirement.
Fast mode writes speculative values and patches in resolved results later. Strict mode waits for real results with a small retire backstop so it doesn't spin forever when a report gets weird. Fake mode's fundamentals are unchanged, it just now uses XenosZPDReport memory helpers like all the modes do.
Also adds optional sample count saturation for instances when attenuation isn't a one-for-one with real hardware, an optional alternate fast behavior that preserves cached zeroes (that can improve flare-heavy titles but might regress occlusion culling), and normalization for upscaling.
QueryBatch is still unsupported other than a fake path that's enabled when a range is set via cvar.
Based entirely off existing xbyak x86 implementation and available
tests. Still needs a lot of optimization and testing on non-Windows
platforms.
So far passes all tests and boots at least some games on Windows.
version.h is now found via CMAKE_BINARY_DIR on the include path instead
of a hardcoded "build/version.h" path. This allows out-of-tree and
multi-config builds to each generate and find their own version header
without colliding.
d37c22aa replaced skylander with the new portal HID library but
missed updating three CMakeLists.txt files. No replacement needed
since xenia-hid already links xenia-hid-portal transitively.
For 4xMSAA 32bpp, samples 2/3 add a +4 byte horizontal offset to the
EDRAM address. The old typed buffer code (Buffer<uint4>) implicitly
truncated this offset via integer division (>> 2), and the .yw swizzle
compensated by selecting odd elements within the aligned uint4 load.
After the ByteAddressBuffer conversion, Load4 uses the exact byte
address including the +4 offset, shifting the load window by one dword.
The .yw swizzle then picks samples from the wrong pixels, causing
visual artifacts like vertical streaks in Resident Evil 5.
Fix by aligning the load address down to 16 bytes and selecting the
swizzle based on whether the address was offset.
Adds async_shader_compilation cvar (default true) that forces new
pipelines to be created async from the main thread, skips draws entirely
on D3D12 and on vulkan replaces pixel shader with placeholder until the
real one is ready. Causes some visual artifacts on first load but
greatly reduces load times and stutter.
Gamma stored as R16G16B16A16_UNORM is 64bpp in host memory but
represents a single 32bpp pixel, unlike true 64bpp formats which pack
two 32bpp pixels together. Separate dest_is_gamma_unorm16 from
dest_is_64bpp to avoid incorrect coordinate transforms.
Add output paths for gamma_unorm16 destinations:
- gamma→gamma: direct passthrough (already linear in R16G16B16A16)
- k_8_8_8_8→gamma: convert gamma-encoded source to linear
- Cross-format packed EDRAM: midpoint encoding to survive UNORM16
quantization round-trip through PreSaturatedLinearToPWLGamma
Fixes red bleeding in Halo Reach, image halving in Just Cause 2,
Portal not rendering, and black rock/plant textures in Halo Reach.
The original commit (2eea146b) correctly added kXenosFormat_16_16_EDRAM
case labels and fixed the unpack clamp from -1.0 to -32.0, but
incorrectly changed the resolve pack functions from UNorm to signed EDRAM
encoding. The resolve destination is a regular texture sampled as UNorm
[0,1], not EDRAM. Using EDRAM packing double-encodes the [-32,32]
scaling, crushing all values by ~64x and caused visual issues
particularly in UE3 titles.
The bytecode submitted with the change was actually correct, but the
source had additional incorrect pieces that only manifested when shaders
were rebuilt.
Resolves TODO(Triang3l) by implementing a mathematical workaround to allow exponent 31 for extended float16 range up to +/-131008.0f as expected by the native Xbox 360 hardware, bypassing standard D3D12 f32tof16 boundaries which incorrectly clamp/inf values.
Replaces the UNorm packing functions with custom Edram functions to preserve the native [-32.0, 32.0] float range and scale mathematically instead of using saturate(). Fixes displaced water meshes in games like Mercenaries 2.