render: true ultrawide through the native renderer

This commit is contained in:
mchughalex 2026-07-20 00:36:16 +01:00
parent 035d3e22a0
commit 32eb60337a
12 changed files with 299 additions and 746 deletions

View file

@ -62,9 +62,9 @@ Create a `dlc` folder either beside the executable, inside the installed game fo
or in the user data folder. Place the DLC package files in that or in the user data folder. Place the DLC package files in that
folder and start the game. folder and start the game.
## True 21:9 Ultrawide ## True Ultrawide
The builds include an experimental true ultrawide aspect ratio mode at 21:9. You may notice occasional visual bugs or graphical glitches, especially around shadows. Performance is somewhat reduced. The builds include an experimental true ultrawide mode: the native renderer draws the world at your display's full aspect ratio (21:9 and wider) with a matching wider field of view, while the HUD and menus stay centered and undistorted. Enable it via the Aspect Ratio setting or `skate3_ultrawide = true`. It requires the native renderer; with the emulated renderer the game presents in standard 16:9. Rendering more of the scene costs proportionally more GPU time.
## Controls ## Controls
@ -210,8 +210,7 @@ SKATE3_MNK=1 ./scripts/run-linux.sh
Fullscreen is on by default. Pass `--no-fullscreen` to start windowed. Fullscreen is on by default. Pass `--no-fullscreen` to start windowed.
On Windows, ultrawide displays are detected automatically in fullscreen. For an On Windows, ultrawide displays are detected automatically in fullscreen. For an
ultrawide window, pass matching `--window_width` and `--window_height` values; ultrawide window, pass matching `--window_width` and `--window_height` values;
the renderer keeps the guest frontbuffer at a stable 16:9 size while applying the native renderer then draws true widescreen frames at that aspect.
ultrawide presentation and Hor+ correction without stretching.
To run the Linux development executable directly: To run the Linux development executable directly:

View file

@ -16,18 +16,13 @@ mnk_mode = false
mnk_capture_mouse = false mnk_capture_mouse = false
fullscreen = true fullscreen = true
# Automatically derive an ultrawide host aspect from the fullscreen monitor on # Ultrawide (native renderer): true widescreen rendering at the host display
# Windows, or from an explicit window_width/window_height pair. Leave # aspect, derived from the fullscreen monitor on Windows or from an explicit
# video_mode_width and video_mode_height at defaults for this path. # window_width/window_height pair. The emulated renderer presents 16:9
# pillarboxed. skate3_ultrawide_target_aspect (default 0 = derive at boot)
# pins the aspect explicitly.
skate3_ultrawide = false skate3_ultrawide = false
skate3_field_of_view = 60.0 skate3_field_of_view = 60.0
skate3_ultrawide_base_height = 720
skate3_ultrawide_hor_plus = true
skate3_ultrawide_hor_plus_scale = 0.0
# Risky diagnostics for narrowing texture/visibility pop-in. Enable one at a
# time when testing.
skate3_ultrawide_force_main_visibility_flags = true
skate3_ultrawide_ignore_streamer_texture_invalidations = false
# window_width = 3440 # window_width = 3440
# window_height = 1440 # window_height = 1440
vsync = false vsync = false

View file

@ -48,13 +48,17 @@ float4 ps_main(VSOut i) : SV_Target {
// taps covers reduction ratios up to ~4x (4K -> 1152 is 3.33x); narrower // taps covers reduction ratios up to ~4x (4K -> 1152 is 3.33x); narrower
// footprints undersampled the scale and the aliased detail crawled as the // footprints undersampled the scale and the aliased detail crawled as the
// scene animated: the whole blurred backdrop shimmered, worst around // scene animated: the whole blurred backdrop shimmered, worst around
// high-contrast edges. // high-contrast edges. This pass reads the second constant register as the
// source UV rect (xy = scale, zw = offset): the photo grab center-crops the
// 16:9 band out of a wide output; (1,1,0,0) = full frame.
float4 ps_down(VSOut i) : SV_Target { float4 ps_down(VSOut i) : SV_Target {
float4 rect = tint;
float2 uv = i.uv * rect.xy + rect.zw;
float3 c = 0.0; float3 c = 0.0;
[unroll] for (int y = 0; y < 4; ++y) { [unroll] for (int y = 0; y < 4; ++y) {
[unroll] for (int x = 0; x < 4; ++x) { [unroll] for (int x = 0; x < 4; ++x) {
float2 off = float2(float(x) - 1.5, float(y) - 1.5) * dir.xy; float2 off = float2(float(x) - 1.5, float(y) - 1.5) * dir.xy;
c += src.SampleLevel(smp_clamp, i.uv + off, 0).rgb; c += src.SampleLevel(smp_clamp, uv + off, 0).rgb;
} }
} }
return float4(c / 16.0, 1.0); return float4(c / 16.0, 1.0);

View file

@ -7,7 +7,10 @@ cbuffer C : register(b0) {
float4 m[10]; // m[0..3] proj rows, m[4..7] world rows, m[8] color, float4 m[10]; // m[0..3] proj rows, m[4..7] world rows, m[8] color,
// m[9].x = apply D3D9 half-pixel (2D ortho draws only), // m[9].x = apply D3D9 half-pixel (2D ortho draws only),
// m[9].y = sharp-magnification amount (0 = plain bilinear), // m[9].y = sharp-magnification amount (0 = plain bilinear),
// m[9].zw = unused (the D3D9 half-pixel shift is derived // m[9].z = clip-space X extent of the 2D band (0 = full
// target; < 1 when a wide output centers the 16:9 stream
// in a pillarboxed band, see the emit_draw column-0 scale),
// m[9].w = unused (the D3D9 half-pixel shift is derived
// in the VS from the draw's own ortho scale) // in the VS from the draw's own ortho scale)
}; };
Texture2D<float4> tex : register(t0); Texture2D<float4> tex : register(t0);
@ -55,8 +58,11 @@ VSOut vs_main(float4 p : POSITION, float2 uv : TEXCOORD0, float4 color : COLOR0)
float2 gpx = float2(abs(m[0].x), abs(m[1].y)); // one guest px in NDC float2 gpx = float2(abs(m[0].x), abs(m[1].y)); // one guest px in NDC
float2 ndc = o.pos.xy / o.pos.w; float2 ndc = o.pos.xy / o.pos.w;
float2 eps = 0.75 * gpx; float2 eps = 0.75 * gpx;
if (ndc.x <= 1.0 && ndc.x > 1.0 - eps.x) ndc.x = 1.0; // The horizontal boundary is the 2D band edge: +-1 normally, +-m[9].z
if (ndc.x >= -1.0 && ndc.x < -1.0 + eps.x) ndc.x = -1.0; // when a wide output pillarboxes the 16:9 stream.
float edge_x = m[9].z > 0.0 ? m[9].z : 1.0;
if (ndc.x <= edge_x && ndc.x > edge_x - eps.x) ndc.x = edge_x;
if (ndc.x >= -edge_x && ndc.x < -edge_x + eps.x) ndc.x = -edge_x;
if (ndc.y <= 1.0 && ndc.y > 1.0 - eps.y) ndc.y = 1.0; if (ndc.y <= 1.0 && ndc.y > 1.0 - eps.y) ndc.y = 1.0;
if (ndc.y >= -1.0 && ndc.y < -1.0 + eps.y) ndc.y = -1.0; if (ndc.y >= -1.0 && ndc.y < -1.0 + eps.y) ndc.y = -1.0;
o.pos.xy = ndc * o.pos.w; o.pos.xy = ndc * o.pos.w;

View file

@ -16309,9 +16309,9 @@ static const uint32_t k_blur_ps_blit[] = {
0x00000003, 0x0000001d, 0x000100fd, 0x00010038, 0x00000003, 0x0000001d, 0x000100fd, 0x00010038,
}; };
// blur.hlsl : ps_down (4300 bytes) // blur.hlsl : ps_down (4448 bytes)
static const uint32_t k_blur_ps_down[] = { static const uint32_t k_blur_ps_down[] = {
0x07230203, 0x00010300, 0x000e0000, 0x000000ba, 0x00000000, 0x00020011, 0x00000001, 0x0003000e, 0x07230203, 0x00010300, 0x000e0000, 0x000000c1, 0x00000000, 0x00020011, 0x00000001, 0x0003000e,
0x00000000, 0x00000001, 0x0007000f, 0x00000004, 0x00000001, 0x645f7370, 0x006e776f, 0x00000002, 0x00000000, 0x00000001, 0x0007000f, 0x00000004, 0x00000001, 0x645f7370, 0x006e776f, 0x00000002,
0x00000003, 0x00030010, 0x00000001, 0x00000007, 0x00030003, 0x00000005, 0x00000258, 0x00040005, 0x00000003, 0x00030010, 0x00000001, 0x00000007, 0x00030003, 0x00000005, 0x00000258, 0x00040005,
0x00000004, 0x65707974, 0x0000432e, 0x00040006, 0x00000004, 0x00000000, 0x00726964, 0x00050006, 0x00000004, 0x65707974, 0x0000432e, 0x00040006, 0x00000004, 0x00000000, 0x00726964, 0x00050006,
@ -16327,125 +16327,129 @@ static const uint32_t k_blur_ps_down[] = {
0x00040047, 0x00000007, 0x00000021, 0x00000000, 0x00040047, 0x00000009, 0x00000022, 0x00000000, 0x00040047, 0x00000007, 0x00000021, 0x00000000, 0x00040047, 0x00000009, 0x00000022, 0x00000000,
0x00040047, 0x00000009, 0x00000021, 0x00000005, 0x00050048, 0x00000004, 0x00000000, 0x00000023, 0x00040047, 0x00000009, 0x00000021, 0x00000005, 0x00050048, 0x00000004, 0x00000000, 0x00000023,
0x00000000, 0x00050048, 0x00000004, 0x00000001, 0x00000023, 0x00000010, 0x00030047, 0x00000004, 0x00000000, 0x00050048, 0x00000004, 0x00000001, 0x00000023, 0x00000010, 0x00030047, 0x00000004,
0x00000002, 0x00030016, 0x0000000b, 0x00000020, 0x0004002b, 0x0000000b, 0x0000000c, 0x00000000, 0x00000002, 0x00040015, 0x0000000b, 0x00000020, 0x00000001, 0x0004002b, 0x0000000b, 0x0000000c,
0x00040017, 0x0000000d, 0x0000000b, 0x00000003, 0x00040015, 0x0000000e, 0x00000020, 0x00000001, 0x00000001, 0x00030016, 0x0000000d, 0x00000020, 0x0004002b, 0x0000000d, 0x0000000e, 0x00000000,
0x0004002b, 0x0000000e, 0x0000000f, 0x00000000, 0x0004002b, 0x0000000b, 0x00000010, 0x3fc00000, 0x00040017, 0x0000000f, 0x0000000d, 0x00000003, 0x0004002b, 0x0000000b, 0x00000010, 0x00000000,
0x0004002b, 0x0000000b, 0x00000011, 0x3f800000, 0x00040017, 0x00000012, 0x0000000b, 0x00000004, 0x0004002b, 0x0000000d, 0x00000011, 0x3fc00000, 0x0004002b, 0x0000000d, 0x00000012, 0x3f800000,
0x0004001e, 0x00000004, 0x00000012, 0x00000012, 0x00040020, 0x00000013, 0x00000002, 0x00000004, 0x00040017, 0x00000013, 0x0000000d, 0x00000004, 0x0004001e, 0x00000004, 0x00000013, 0x00000013,
0x00090019, 0x00000006, 0x0000000b, 0x00000001, 0x00000002, 0x00000000, 0x00000000, 0x00000001, 0x00040020, 0x00000014, 0x00000002, 0x00000004, 0x00090019, 0x00000006, 0x0000000d, 0x00000001,
0x00000000, 0x00040020, 0x00000014, 0x00000000, 0x00000006, 0x0002001a, 0x00000008, 0x00040020, 0x00000002, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00040020, 0x00000015, 0x00000000,
0x00000015, 0x00000000, 0x00000008, 0x00040017, 0x00000016, 0x0000000b, 0x00000002, 0x00040020, 0x00000006, 0x0002001a, 0x00000008, 0x00040020, 0x00000016, 0x00000000, 0x00000008, 0x00040017,
0x00000017, 0x00000001, 0x00000016, 0x00040020, 0x00000018, 0x00000003, 0x00000012, 0x00020013, 0x00000017, 0x0000000d, 0x00000002, 0x00040020, 0x00000018, 0x00000001, 0x00000017, 0x00040020,
0x00000019, 0x00030021, 0x0000001a, 0x00000019, 0x00040020, 0x0000001b, 0x00000002, 0x00000012, 0x00000019, 0x00000003, 0x00000013, 0x00020013, 0x0000001a, 0x00030021, 0x0000001b, 0x0000001a,
0x0003001b, 0x0000000a, 0x00000006, 0x0004003b, 0x00000013, 0x00000005, 0x00000002, 0x0004003b, 0x00040020, 0x0000001c, 0x00000002, 0x00000013, 0x0003001b, 0x0000000a, 0x00000006, 0x0004003b,
0x00000014, 0x00000007, 0x00000000, 0x0004003b, 0x00000015, 0x00000009, 0x00000000, 0x0004003b, 0x00000014, 0x00000005, 0x00000002, 0x0004003b, 0x00000015, 0x00000007, 0x00000000, 0x0004003b,
0x00000017, 0x00000002, 0x00000001, 0x0004003b, 0x00000018, 0x00000003, 0x00000003, 0x0004002b, 0x00000016, 0x00000009, 0x00000000, 0x0004003b, 0x00000018, 0x00000002, 0x00000001, 0x0004003b,
0x0000000b, 0x0000001c, 0xbfc00000, 0x0005002c, 0x00000016, 0x0000001d, 0x0000001c, 0x0000001c, 0x00000019, 0x00000003, 0x00000003, 0x0004002b, 0x0000000d, 0x0000001d, 0xbfc00000, 0x0005002c,
0x0004002b, 0x0000000b, 0x0000001e, 0xbf000000, 0x0005002c, 0x00000016, 0x0000001f, 0x0000001e, 0x00000017, 0x0000001e, 0x0000001d, 0x0000001d, 0x0004002b, 0x0000000d, 0x0000001f, 0xbf000000,
0x0000001c, 0x0004002b, 0x0000000b, 0x00000020, 0x3f000000, 0x0005002c, 0x00000016, 0x00000021, 0x0005002c, 0x00000017, 0x00000020, 0x0000001f, 0x0000001d, 0x0004002b, 0x0000000d, 0x00000021,
0x00000020, 0x0000001c, 0x0005002c, 0x00000016, 0x00000022, 0x00000010, 0x0000001c, 0x0005002c, 0x3f000000, 0x0005002c, 0x00000017, 0x00000022, 0x00000021, 0x0000001d, 0x0005002c, 0x00000017,
0x00000016, 0x00000023, 0x0000001c, 0x0000001e, 0x0005002c, 0x00000016, 0x00000024, 0x0000001e, 0x00000023, 0x00000011, 0x0000001d, 0x0005002c, 0x00000017, 0x00000024, 0x0000001d, 0x0000001f,
0x0000001e, 0x0005002c, 0x00000016, 0x00000025, 0x00000020, 0x0000001e, 0x0005002c, 0x00000016, 0x0005002c, 0x00000017, 0x00000025, 0x0000001f, 0x0000001f, 0x0005002c, 0x00000017, 0x00000026,
0x00000026, 0x00000010, 0x0000001e, 0x0005002c, 0x00000016, 0x00000027, 0x0000001c, 0x00000020, 0x00000021, 0x0000001f, 0x0005002c, 0x00000017, 0x00000027, 0x00000011, 0x0000001f, 0x0005002c,
0x0005002c, 0x00000016, 0x00000028, 0x0000001e, 0x00000020, 0x0005002c, 0x00000016, 0x00000029, 0x00000017, 0x00000028, 0x0000001d, 0x00000021, 0x0005002c, 0x00000017, 0x00000029, 0x0000001f,
0x00000020, 0x00000020, 0x0005002c, 0x00000016, 0x0000002a, 0x00000010, 0x00000020, 0x0005002c, 0x00000021, 0x0005002c, 0x00000017, 0x0000002a, 0x00000021, 0x00000021, 0x0005002c, 0x00000017,
0x00000016, 0x0000002b, 0x0000001c, 0x00000010, 0x0005002c, 0x00000016, 0x0000002c, 0x0000001e, 0x0000002b, 0x00000011, 0x00000021, 0x0005002c, 0x00000017, 0x0000002c, 0x0000001d, 0x00000011,
0x00000010, 0x0005002c, 0x00000016, 0x0000002d, 0x00000020, 0x00000010, 0x0005002c, 0x00000016, 0x0005002c, 0x00000017, 0x0000002d, 0x0000001f, 0x00000011, 0x0005002c, 0x00000017, 0x0000002e,
0x0000002e, 0x00000010, 0x00000010, 0x0004002b, 0x0000000b, 0x0000002f, 0x3d800000, 0x0006002c, 0x00000021, 0x00000011, 0x0005002c, 0x00000017, 0x0000002f, 0x00000011, 0x00000011, 0x0004002b,
0x0000000d, 0x00000030, 0x0000002f, 0x0000002f, 0x0000002f, 0x00050036, 0x00000019, 0x00000001, 0x0000000d, 0x00000030, 0x3d800000, 0x0006002c, 0x0000000f, 0x00000031, 0x00000030, 0x00000030,
0x00000000, 0x0000001a, 0x000200f8, 0x00000031, 0x0004003d, 0x00000016, 0x00000032, 0x00000002, 0x00000030, 0x00050036, 0x0000001a, 0x00000001, 0x00000000, 0x0000001b, 0x000200f8, 0x00000032,
0x00050041, 0x0000001b, 0x00000033, 0x00000005, 0x0000000f, 0x0004003d, 0x00000012, 0x00000034, 0x0004003d, 0x00000017, 0x00000033, 0x00000002, 0x00050041, 0x0000001c, 0x00000034, 0x00000005,
0x00000033, 0x0007004f, 0x00000016, 0x00000035, 0x00000034, 0x00000034, 0x00000000, 0x00000001, 0x0000000c, 0x0004003d, 0x00000013, 0x00000035, 0x00000034, 0x0007004f, 0x00000017, 0x00000036,
0x00050085, 0x00000016, 0x00000036, 0x0000001d, 0x00000035, 0x0004003d, 0x00000006, 0x00000037, 0x00000035, 0x00000035, 0x00000000, 0x00000001, 0x00050085, 0x00000017, 0x00000037, 0x00000033,
0x00000007, 0x0004003d, 0x00000008, 0x00000038, 0x00000009, 0x00050081, 0x00000016, 0x00000039, 0x00000036, 0x0007004f, 0x00000017, 0x00000038, 0x00000035, 0x00000035, 0x00000002, 0x00000003,
0x00000032, 0x00000036, 0x00050056, 0x0000000a, 0x0000003a, 0x00000037, 0x00000038, 0x00070058, 0x00050081, 0x00000017, 0x00000039, 0x00000037, 0x00000038, 0x00050041, 0x0000001c, 0x0000003a,
0x00000012, 0x0000003b, 0x0000003a, 0x00000039, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x00000005, 0x00000010, 0x0004003d, 0x00000013, 0x0000003b, 0x0000003a, 0x0007004f, 0x00000017,
0x0000003c, 0x0000003b, 0x0000003b, 0x00000000, 0x00000001, 0x00000002, 0x00050085, 0x00000016, 0x0000003c, 0x0000003b, 0x0000003b, 0x00000000, 0x00000001, 0x00050085, 0x00000017, 0x0000003d,
0x0000003d, 0x0000001f, 0x00000035, 0x0004003d, 0x00000006, 0x0000003e, 0x00000007, 0x0004003d, 0x0000001e, 0x0000003c, 0x0004003d, 0x00000006, 0x0000003e, 0x00000007, 0x0004003d, 0x00000008,
0x00000008, 0x0000003f, 0x00000009, 0x00050081, 0x00000016, 0x00000040, 0x00000032, 0x0000003d, 0x0000003f, 0x00000009, 0x00050081, 0x00000017, 0x00000040, 0x00000039, 0x0000003d, 0x00050056,
0x00050056, 0x0000000a, 0x00000041, 0x0000003e, 0x0000003f, 0x00070058, 0x00000012, 0x00000042, 0x0000000a, 0x00000041, 0x0000003e, 0x0000003f, 0x00070058, 0x00000013, 0x00000042, 0x00000041,
0x00000041, 0x00000040, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x00000043, 0x00000042, 0x00000040, 0x00000002, 0x0000000e, 0x0008004f, 0x0000000f, 0x00000043, 0x00000042, 0x00000042,
0x00000042, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000d, 0x00000044, 0x0000003c, 0x00000000, 0x00000001, 0x00000002, 0x00050085, 0x00000017, 0x00000044, 0x00000020, 0x0000003c,
0x00000043, 0x00050085, 0x00000016, 0x00000045, 0x00000021, 0x00000035, 0x0004003d, 0x00000006, 0x0004003d, 0x00000006, 0x00000045, 0x00000007, 0x0004003d, 0x00000008, 0x00000046, 0x00000009,
0x00000046, 0x00000007, 0x0004003d, 0x00000008, 0x00000047, 0x00000009, 0x00050081, 0x00000016, 0x00050081, 0x00000017, 0x00000047, 0x00000039, 0x00000044, 0x00050056, 0x0000000a, 0x00000048,
0x00000048, 0x00000032, 0x00000045, 0x00050056, 0x0000000a, 0x00000049, 0x00000046, 0x00000047, 0x00000045, 0x00000046, 0x00070058, 0x00000013, 0x00000049, 0x00000048, 0x00000047, 0x00000002,
0x00070058, 0x00000012, 0x0000004a, 0x00000049, 0x00000048, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000e, 0x0008004f, 0x0000000f, 0x0000004a, 0x00000049, 0x00000049, 0x00000000, 0x00000001,
0x0000000d, 0x0000004b, 0x0000004a, 0x0000004a, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x00000002, 0x00050081, 0x0000000f, 0x0000004b, 0x00000043, 0x0000004a, 0x00050085, 0x00000017,
0x0000000d, 0x0000004c, 0x00000044, 0x0000004b, 0x00050085, 0x00000016, 0x0000004d, 0x00000022, 0x0000004c, 0x00000022, 0x0000003c, 0x0004003d, 0x00000006, 0x0000004d, 0x00000007, 0x0004003d,
0x00000035, 0x0004003d, 0x00000006, 0x0000004e, 0x00000007, 0x0004003d, 0x00000008, 0x0000004f, 0x00000008, 0x0000004e, 0x00000009, 0x00050081, 0x00000017, 0x0000004f, 0x00000039, 0x0000004c,
0x00000009, 0x00050081, 0x00000016, 0x00000050, 0x00000032, 0x0000004d, 0x00050056, 0x0000000a, 0x00050056, 0x0000000a, 0x00000050, 0x0000004d, 0x0000004e, 0x00070058, 0x00000013, 0x00000051,
0x00000051, 0x0000004e, 0x0000004f, 0x00070058, 0x00000012, 0x00000052, 0x00000051, 0x00000050, 0x00000050, 0x0000004f, 0x00000002, 0x0000000e, 0x0008004f, 0x0000000f, 0x00000052, 0x00000051,
0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x00000053, 0x00000052, 0x00000052, 0x00000000, 0x00000051, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000f, 0x00000053, 0x0000004b,
0x00000001, 0x00000002, 0x00050081, 0x0000000d, 0x00000054, 0x0000004c, 0x00000053, 0x00050085, 0x00000052, 0x00050085, 0x00000017, 0x00000054, 0x00000023, 0x0000003c, 0x0004003d, 0x00000006,
0x00000016, 0x00000055, 0x00000023, 0x00000035, 0x0004003d, 0x00000006, 0x00000056, 0x00000007, 0x00000055, 0x00000007, 0x0004003d, 0x00000008, 0x00000056, 0x00000009, 0x00050081, 0x00000017,
0x0004003d, 0x00000008, 0x00000057, 0x00000009, 0x00050081, 0x00000016, 0x00000058, 0x00000032, 0x00000057, 0x00000039, 0x00000054, 0x00050056, 0x0000000a, 0x00000058, 0x00000055, 0x00000056,
0x00000055, 0x00050056, 0x0000000a, 0x00000059, 0x00000056, 0x00000057, 0x00070058, 0x00000012, 0x00070058, 0x00000013, 0x00000059, 0x00000058, 0x00000057, 0x00000002, 0x0000000e, 0x0008004f,
0x0000005a, 0x00000059, 0x00000058, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x0000005b, 0x0000000f, 0x0000005a, 0x00000059, 0x00000059, 0x00000000, 0x00000001, 0x00000002, 0x00050081,
0x0000005a, 0x0000005a, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000d, 0x0000005c, 0x0000000f, 0x0000005b, 0x00000053, 0x0000005a, 0x00050085, 0x00000017, 0x0000005c, 0x00000024,
0x00000054, 0x0000005b, 0x00050085, 0x00000016, 0x0000005d, 0x00000024, 0x00000035, 0x0004003d, 0x0000003c, 0x0004003d, 0x00000006, 0x0000005d, 0x00000007, 0x0004003d, 0x00000008, 0x0000005e,
0x00000006, 0x0000005e, 0x00000007, 0x0004003d, 0x00000008, 0x0000005f, 0x00000009, 0x00050081, 0x00000009, 0x00050081, 0x00000017, 0x0000005f, 0x00000039, 0x0000005c, 0x00050056, 0x0000000a,
0x00000016, 0x00000060, 0x00000032, 0x0000005d, 0x00050056, 0x0000000a, 0x00000061, 0x0000005e, 0x00000060, 0x0000005d, 0x0000005e, 0x00070058, 0x00000013, 0x00000061, 0x00000060, 0x0000005f,
0x0000005f, 0x00070058, 0x00000012, 0x00000062, 0x00000061, 0x00000060, 0x00000002, 0x0000000c, 0x00000002, 0x0000000e, 0x0008004f, 0x0000000f, 0x00000062, 0x00000061, 0x00000061, 0x00000000,
0x0008004f, 0x0000000d, 0x00000063, 0x00000062, 0x00000062, 0x00000000, 0x00000001, 0x00000002, 0x00000001, 0x00000002, 0x00050081, 0x0000000f, 0x00000063, 0x0000005b, 0x00000062, 0x00050085,
0x00050081, 0x0000000d, 0x00000064, 0x0000005c, 0x00000063, 0x00050085, 0x00000016, 0x00000065, 0x00000017, 0x00000064, 0x00000025, 0x0000003c, 0x0004003d, 0x00000006, 0x00000065, 0x00000007,
0x00000025, 0x00000035, 0x0004003d, 0x00000006, 0x00000066, 0x00000007, 0x0004003d, 0x00000008, 0x0004003d, 0x00000008, 0x00000066, 0x00000009, 0x00050081, 0x00000017, 0x00000067, 0x00000039,
0x00000067, 0x00000009, 0x00050081, 0x00000016, 0x00000068, 0x00000032, 0x00000065, 0x00050056, 0x00000064, 0x00050056, 0x0000000a, 0x00000068, 0x00000065, 0x00000066, 0x00070058, 0x00000013,
0x0000000a, 0x00000069, 0x00000066, 0x00000067, 0x00070058, 0x00000012, 0x0000006a, 0x00000069, 0x00000069, 0x00000068, 0x00000067, 0x00000002, 0x0000000e, 0x0008004f, 0x0000000f, 0x0000006a,
0x00000068, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x0000006b, 0x0000006a, 0x0000006a, 0x00000069, 0x00000069, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000f, 0x0000006b,
0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000d, 0x0000006c, 0x00000064, 0x0000006b, 0x00000063, 0x0000006a, 0x00050085, 0x00000017, 0x0000006c, 0x00000026, 0x0000003c, 0x0004003d,
0x00050085, 0x00000016, 0x0000006d, 0x00000026, 0x00000035, 0x0004003d, 0x00000006, 0x0000006e, 0x00000006, 0x0000006d, 0x00000007, 0x0004003d, 0x00000008, 0x0000006e, 0x00000009, 0x00050081,
0x00000007, 0x0004003d, 0x00000008, 0x0000006f, 0x00000009, 0x00050081, 0x00000016, 0x00000070, 0x00000017, 0x0000006f, 0x00000039, 0x0000006c, 0x00050056, 0x0000000a, 0x00000070, 0x0000006d,
0x00000032, 0x0000006d, 0x00050056, 0x0000000a, 0x00000071, 0x0000006e, 0x0000006f, 0x00070058, 0x0000006e, 0x00070058, 0x00000013, 0x00000071, 0x00000070, 0x0000006f, 0x00000002, 0x0000000e,
0x00000012, 0x00000072, 0x00000071, 0x00000070, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x0008004f, 0x0000000f, 0x00000072, 0x00000071, 0x00000071, 0x00000000, 0x00000001, 0x00000002,
0x00000073, 0x00000072, 0x00000072, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000d, 0x00050081, 0x0000000f, 0x00000073, 0x0000006b, 0x00000072, 0x00050085, 0x00000017, 0x00000074,
0x00000074, 0x0000006c, 0x00000073, 0x00050085, 0x00000016, 0x00000075, 0x00000027, 0x00000035, 0x00000027, 0x0000003c, 0x0004003d, 0x00000006, 0x00000075, 0x00000007, 0x0004003d, 0x00000008,
0x0004003d, 0x00000006, 0x00000076, 0x00000007, 0x0004003d, 0x00000008, 0x00000077, 0x00000009, 0x00000076, 0x00000009, 0x00050081, 0x00000017, 0x00000077, 0x00000039, 0x00000074, 0x00050056,
0x00050081, 0x00000016, 0x00000078, 0x00000032, 0x00000075, 0x00050056, 0x0000000a, 0x00000079, 0x0000000a, 0x00000078, 0x00000075, 0x00000076, 0x00070058, 0x00000013, 0x00000079, 0x00000078,
0x00000076, 0x00000077, 0x00070058, 0x00000012, 0x0000007a, 0x00000079, 0x00000078, 0x00000002, 0x00000077, 0x00000002, 0x0000000e, 0x0008004f, 0x0000000f, 0x0000007a, 0x00000079, 0x00000079,
0x0000000c, 0x0008004f, 0x0000000d, 0x0000007b, 0x0000007a, 0x0000007a, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000f, 0x0000007b, 0x00000073, 0x0000007a,
0x00000002, 0x00050081, 0x0000000d, 0x0000007c, 0x00000074, 0x0000007b, 0x00050085, 0x00000016, 0x00050085, 0x00000017, 0x0000007c, 0x00000028, 0x0000003c, 0x0004003d, 0x00000006, 0x0000007d,
0x0000007d, 0x00000028, 0x00000035, 0x0004003d, 0x00000006, 0x0000007e, 0x00000007, 0x0004003d, 0x00000007, 0x0004003d, 0x00000008, 0x0000007e, 0x00000009, 0x00050081, 0x00000017, 0x0000007f,
0x00000008, 0x0000007f, 0x00000009, 0x00050081, 0x00000016, 0x00000080, 0x00000032, 0x0000007d, 0x00000039, 0x0000007c, 0x00050056, 0x0000000a, 0x00000080, 0x0000007d, 0x0000007e, 0x00070058,
0x00050056, 0x0000000a, 0x00000081, 0x0000007e, 0x0000007f, 0x00070058, 0x00000012, 0x00000082, 0x00000013, 0x00000081, 0x00000080, 0x0000007f, 0x00000002, 0x0000000e, 0x0008004f, 0x0000000f,
0x00000081, 0x00000080, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x00000083, 0x00000082, 0x00000082, 0x00000081, 0x00000081, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000f,
0x00000082, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000d, 0x00000084, 0x0000007c, 0x00000083, 0x0000007b, 0x00000082, 0x00050085, 0x00000017, 0x00000084, 0x00000029, 0x0000003c,
0x00000083, 0x00050085, 0x00000016, 0x00000085, 0x00000029, 0x00000035, 0x0004003d, 0x00000006, 0x0004003d, 0x00000006, 0x00000085, 0x00000007, 0x0004003d, 0x00000008, 0x00000086, 0x00000009,
0x00000086, 0x00000007, 0x0004003d, 0x00000008, 0x00000087, 0x00000009, 0x00050081, 0x00000016, 0x00050081, 0x00000017, 0x00000087, 0x00000039, 0x00000084, 0x00050056, 0x0000000a, 0x00000088,
0x00000088, 0x00000032, 0x00000085, 0x00050056, 0x0000000a, 0x00000089, 0x00000086, 0x00000087, 0x00000085, 0x00000086, 0x00070058, 0x00000013, 0x00000089, 0x00000088, 0x00000087, 0x00000002,
0x00070058, 0x00000012, 0x0000008a, 0x00000089, 0x00000088, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000e, 0x0008004f, 0x0000000f, 0x0000008a, 0x00000089, 0x00000089, 0x00000000, 0x00000001,
0x0000000d, 0x0000008b, 0x0000008a, 0x0000008a, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x00000002, 0x00050081, 0x0000000f, 0x0000008b, 0x00000083, 0x0000008a, 0x00050085, 0x00000017,
0x0000000d, 0x0000008c, 0x00000084, 0x0000008b, 0x00050085, 0x00000016, 0x0000008d, 0x0000002a, 0x0000008c, 0x0000002a, 0x0000003c, 0x0004003d, 0x00000006, 0x0000008d, 0x00000007, 0x0004003d,
0x00000035, 0x0004003d, 0x00000006, 0x0000008e, 0x00000007, 0x0004003d, 0x00000008, 0x0000008f, 0x00000008, 0x0000008e, 0x00000009, 0x00050081, 0x00000017, 0x0000008f, 0x00000039, 0x0000008c,
0x00000009, 0x00050081, 0x00000016, 0x00000090, 0x00000032, 0x0000008d, 0x00050056, 0x0000000a, 0x00050056, 0x0000000a, 0x00000090, 0x0000008d, 0x0000008e, 0x00070058, 0x00000013, 0x00000091,
0x00000091, 0x0000008e, 0x0000008f, 0x00070058, 0x00000012, 0x00000092, 0x00000091, 0x00000090, 0x00000090, 0x0000008f, 0x00000002, 0x0000000e, 0x0008004f, 0x0000000f, 0x00000092, 0x00000091,
0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x00000093, 0x00000092, 0x00000092, 0x00000000, 0x00000091, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000f, 0x00000093, 0x0000008b,
0x00000001, 0x00000002, 0x00050081, 0x0000000d, 0x00000094, 0x0000008c, 0x00000093, 0x00050085, 0x00000092, 0x00050085, 0x00000017, 0x00000094, 0x0000002b, 0x0000003c, 0x0004003d, 0x00000006,
0x00000016, 0x00000095, 0x0000002b, 0x00000035, 0x0004003d, 0x00000006, 0x00000096, 0x00000007, 0x00000095, 0x00000007, 0x0004003d, 0x00000008, 0x00000096, 0x00000009, 0x00050081, 0x00000017,
0x0004003d, 0x00000008, 0x00000097, 0x00000009, 0x00050081, 0x00000016, 0x00000098, 0x00000032, 0x00000097, 0x00000039, 0x00000094, 0x00050056, 0x0000000a, 0x00000098, 0x00000095, 0x00000096,
0x00000095, 0x00050056, 0x0000000a, 0x00000099, 0x00000096, 0x00000097, 0x00070058, 0x00000012, 0x00070058, 0x00000013, 0x00000099, 0x00000098, 0x00000097, 0x00000002, 0x0000000e, 0x0008004f,
0x0000009a, 0x00000099, 0x00000098, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x0000009b, 0x0000000f, 0x0000009a, 0x00000099, 0x00000099, 0x00000000, 0x00000001, 0x00000002, 0x00050081,
0x0000009a, 0x0000009a, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000d, 0x0000009c, 0x0000000f, 0x0000009b, 0x00000093, 0x0000009a, 0x00050085, 0x00000017, 0x0000009c, 0x0000002c,
0x00000094, 0x0000009b, 0x00050085, 0x00000016, 0x0000009d, 0x0000002c, 0x00000035, 0x0004003d, 0x0000003c, 0x0004003d, 0x00000006, 0x0000009d, 0x00000007, 0x0004003d, 0x00000008, 0x0000009e,
0x00000006, 0x0000009e, 0x00000007, 0x0004003d, 0x00000008, 0x0000009f, 0x00000009, 0x00050081, 0x00000009, 0x00050081, 0x00000017, 0x0000009f, 0x00000039, 0x0000009c, 0x00050056, 0x0000000a,
0x00000016, 0x000000a0, 0x00000032, 0x0000009d, 0x00050056, 0x0000000a, 0x000000a1, 0x0000009e, 0x000000a0, 0x0000009d, 0x0000009e, 0x00070058, 0x00000013, 0x000000a1, 0x000000a0, 0x0000009f,
0x0000009f, 0x00070058, 0x00000012, 0x000000a2, 0x000000a1, 0x000000a0, 0x00000002, 0x0000000c, 0x00000002, 0x0000000e, 0x0008004f, 0x0000000f, 0x000000a2, 0x000000a1, 0x000000a1, 0x00000000,
0x0008004f, 0x0000000d, 0x000000a3, 0x000000a2, 0x000000a2, 0x00000000, 0x00000001, 0x00000002, 0x00000001, 0x00000002, 0x00050081, 0x0000000f, 0x000000a3, 0x0000009b, 0x000000a2, 0x00050085,
0x00050081, 0x0000000d, 0x000000a4, 0x0000009c, 0x000000a3, 0x00050085, 0x00000016, 0x000000a5, 0x00000017, 0x000000a4, 0x0000002d, 0x0000003c, 0x0004003d, 0x00000006, 0x000000a5, 0x00000007,
0x0000002d, 0x00000035, 0x0004003d, 0x00000006, 0x000000a6, 0x00000007, 0x0004003d, 0x00000008, 0x0004003d, 0x00000008, 0x000000a6, 0x00000009, 0x00050081, 0x00000017, 0x000000a7, 0x00000039,
0x000000a7, 0x00000009, 0x00050081, 0x00000016, 0x000000a8, 0x00000032, 0x000000a5, 0x00050056, 0x000000a4, 0x00050056, 0x0000000a, 0x000000a8, 0x000000a5, 0x000000a6, 0x00070058, 0x00000013,
0x0000000a, 0x000000a9, 0x000000a6, 0x000000a7, 0x00070058, 0x00000012, 0x000000aa, 0x000000a9, 0x000000a9, 0x000000a8, 0x000000a7, 0x00000002, 0x0000000e, 0x0008004f, 0x0000000f, 0x000000aa,
0x000000a8, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x000000ab, 0x000000aa, 0x000000aa, 0x000000a9, 0x000000a9, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000f, 0x000000ab,
0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000d, 0x000000ac, 0x000000a4, 0x000000ab, 0x000000a3, 0x000000aa, 0x00050085, 0x00000017, 0x000000ac, 0x0000002e, 0x0000003c, 0x0004003d,
0x00050085, 0x00000016, 0x000000ad, 0x0000002e, 0x00000035, 0x0004003d, 0x00000006, 0x000000ae, 0x00000006, 0x000000ad, 0x00000007, 0x0004003d, 0x00000008, 0x000000ae, 0x00000009, 0x00050081,
0x00000007, 0x0004003d, 0x00000008, 0x000000af, 0x00000009, 0x00050081, 0x00000016, 0x000000b0, 0x00000017, 0x000000af, 0x00000039, 0x000000ac, 0x00050056, 0x0000000a, 0x000000b0, 0x000000ad,
0x00000032, 0x000000ad, 0x00050056, 0x0000000a, 0x000000b1, 0x000000ae, 0x000000af, 0x00070058, 0x000000ae, 0x00070058, 0x00000013, 0x000000b1, 0x000000b0, 0x000000af, 0x00000002, 0x0000000e,
0x00000012, 0x000000b2, 0x000000b1, 0x000000b0, 0x00000002, 0x0000000c, 0x0008004f, 0x0000000d, 0x0008004f, 0x0000000f, 0x000000b2, 0x000000b1, 0x000000b1, 0x00000000, 0x00000001, 0x00000002,
0x000000b3, 0x000000b2, 0x000000b2, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000d, 0x00050081, 0x0000000f, 0x000000b3, 0x000000ab, 0x000000b2, 0x00050085, 0x00000017, 0x000000b4,
0x000000b4, 0x000000ac, 0x000000b3, 0x00050085, 0x0000000d, 0x000000b5, 0x000000b4, 0x00000030, 0x0000002f, 0x0000003c, 0x0004003d, 0x00000006, 0x000000b5, 0x00000007, 0x0004003d, 0x00000008,
0x00050051, 0x0000000b, 0x000000b6, 0x000000b5, 0x00000000, 0x00050051, 0x0000000b, 0x000000b7, 0x000000b6, 0x00000009, 0x00050081, 0x00000017, 0x000000b7, 0x00000039, 0x000000b4, 0x00050056,
0x000000b5, 0x00000001, 0x00050051, 0x0000000b, 0x000000b8, 0x000000b5, 0x00000002, 0x00070050, 0x0000000a, 0x000000b8, 0x000000b5, 0x000000b6, 0x00070058, 0x00000013, 0x000000b9, 0x000000b8,
0x00000012, 0x000000b9, 0x000000b6, 0x000000b7, 0x000000b8, 0x00000011, 0x0003003e, 0x00000003, 0x000000b7, 0x00000002, 0x0000000e, 0x0008004f, 0x0000000f, 0x000000ba, 0x000000b9, 0x000000b9,
0x000000b9, 0x000100fd, 0x00010038, 0x00000000, 0x00000001, 0x00000002, 0x00050081, 0x0000000f, 0x000000bb, 0x000000b3, 0x000000ba,
0x00050085, 0x0000000f, 0x000000bc, 0x000000bb, 0x00000031, 0x00050051, 0x0000000d, 0x000000bd,
0x000000bc, 0x00000000, 0x00050051, 0x0000000d, 0x000000be, 0x000000bc, 0x00000001, 0x00050051,
0x0000000d, 0x000000bf, 0x000000bc, 0x00000002, 0x00070050, 0x00000013, 0x000000c0, 0x000000bd,
0x000000be, 0x000000bf, 0x00000012, 0x0003003e, 0x00000003, 0x000000c0, 0x000100fd, 0x00010038,
}; };
// blur.hlsl : ps_menu_gauss (2284 bytes) // blur.hlsl : ps_menu_gauss (2284 bytes)
@ -16728,9 +16732,9 @@ static const uint32_t k_outline_ps_main[] = {
0x00000011, 0x0003003e, 0x00000004, 0x000000ff, 0x000100fd, 0x00010038, 0x00000011, 0x0003003e, 0x00000004, 0x000000ff, 0x000100fd, 0x00010038,
}; };
// overlay2d.hlsl : vs_main (3496 bytes) // overlay2d.hlsl : vs_main (3600 bytes)
static const uint32_t k_overlay2d_vs_main[] = { static const uint32_t k_overlay2d_vs_main[] = {
0x07230203, 0x00010300, 0x000e0000, 0x00000094, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x07230203, 0x00010300, 0x000e0000, 0x00000099, 0x00000000, 0x00020011, 0x00000001, 0x0006000b,
0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001,
0x000b000f, 0x00000000, 0x00000002, 0x6d5f7376, 0x006e6961, 0x00000003, 0x00000004, 0x00000005, 0x000b000f, 0x00000000, 0x00000002, 0x6d5f7376, 0x006e6961, 0x00000003, 0x00000004, 0x00000005,
0x00000006, 0x00000007, 0x00000008, 0x00030003, 0x00000005, 0x00000258, 0x00040005, 0x00000009, 0x00000006, 0x00000007, 0x00000008, 0x00030003, 0x00000005, 0x00000258, 0x00040005, 0x00000009,
@ -16799,47 +16803,50 @@ static const uint32_t k_overlay2d_vs_main[] = {
0x00000023, 0x0000005c, 0x00000050, 0x00000057, 0x0007004f, 0x00000023, 0x0000005d, 0x0000005b, 0x00000023, 0x0000005c, 0x00000050, 0x00000057, 0x0007004f, 0x00000023, 0x0000005d, 0x0000005b,
0x0000005b, 0x00000000, 0x00000001, 0x00050050, 0x00000023, 0x0000005e, 0x00000047, 0x00000047, 0x0000005b, 0x00000000, 0x00000001, 0x00050050, 0x00000023, 0x0000005e, 0x00000047, 0x00000047,
0x00050088, 0x00000023, 0x0000005f, 0x0000005d, 0x0000005e, 0x0005008e, 0x00000023, 0x00000060, 0x00050088, 0x00000023, 0x0000005f, 0x0000005d, 0x0000005e, 0x0005008e, 0x00000023, 0x00000060,
0x0000005c, 0x0000001a, 0x00050051, 0x00000016, 0x00000061, 0x0000005f, 0x00000000, 0x000500bc, 0x0000005c, 0x0000001a, 0x00070041, 0x0000002a, 0x00000061, 0x0000000a, 0x0000000d, 0x00000015,
0x0000001c, 0x00000062, 0x00000061, 0x0000001b, 0x000300f7, 0x00000063, 0x00000000, 0x000400fa, 0x00000013, 0x0004003d, 0x00000016, 0x00000062, 0x00000061, 0x000500ba, 0x0000001c, 0x00000063,
0x00000062, 0x00000064, 0x00000063, 0x000200f8, 0x00000064, 0x00050051, 0x00000016, 0x00000065, 0x00000062, 0x00000017, 0x000600a9, 0x00000016, 0x00000064, 0x00000063, 0x00000062, 0x0000001b,
0x00000060, 0x00000000, 0x00050083, 0x00000016, 0x00000066, 0x0000001b, 0x00000065, 0x000500ba, 0x00050051, 0x00000016, 0x00000065, 0x0000005f, 0x00000000, 0x000500bc, 0x0000001c, 0x00000066,
0x0000001c, 0x00000067, 0x00000061, 0x00000066, 0x000200f9, 0x00000063, 0x000200f8, 0x00000063, 0x00000065, 0x00000064, 0x000300f7, 0x00000067, 0x00000000, 0x000400fa, 0x00000066, 0x00000068,
0x000700f5, 0x0000001c, 0x00000068, 0x0000001d, 0x0000004d, 0x00000067, 0x00000064, 0x000300f7, 0x00000067, 0x000200f8, 0x00000068, 0x00050051, 0x00000016, 0x00000069, 0x00000060, 0x00000000,
0x00000069, 0x00000000, 0x000400fa, 0x00000068, 0x0000006a, 0x00000069, 0x000200f8, 0x0000006a, 0x00050083, 0x00000016, 0x0000006a, 0x00000064, 0x00000069, 0x000500ba, 0x0000001c, 0x0000006b,
0x00060052, 0x00000023, 0x0000006b, 0x0000001b, 0x0000005f, 0x00000000, 0x000200f9, 0x00000069, 0x00000065, 0x0000006a, 0x000200f9, 0x00000067, 0x000200f8, 0x00000067, 0x000700f5, 0x0000001c,
0x000200f8, 0x00000069, 0x000700f5, 0x00000023, 0x0000006c, 0x0000005f, 0x00000063, 0x0000006b, 0x0000006c, 0x0000001d, 0x0000004d, 0x0000006b, 0x00000068, 0x000300f7, 0x0000006d, 0x00000000,
0x0000006a, 0x00050051, 0x00000016, 0x0000006d, 0x0000006c, 0x00000000, 0x000500be, 0x0000001c, 0x000400fa, 0x0000006c, 0x0000006e, 0x0000006d, 0x000200f8, 0x0000006e, 0x00060052, 0x00000023,
0x0000006e, 0x0000006d, 0x0000001e, 0x000300f7, 0x0000006f, 0x00000000, 0x000400fa, 0x0000006e, 0x0000006f, 0x00000064, 0x0000005f, 0x00000000, 0x000200f9, 0x0000006d, 0x000200f8, 0x0000006d,
0x00000070, 0x0000006f, 0x000200f8, 0x00000070, 0x00050051, 0x00000016, 0x00000071, 0x00000060, 0x000700f5, 0x00000023, 0x00000070, 0x0000005f, 0x00000067, 0x0000006f, 0x0000006e, 0x00050051,
0x00000000, 0x00050081, 0x00000016, 0x00000072, 0x0000001e, 0x00000071, 0x000500b8, 0x0000001c, 0x00000016, 0x00000071, 0x00000070, 0x00000000, 0x0004007f, 0x00000016, 0x00000072, 0x00000064,
0x00000073, 0x0000006d, 0x00000072, 0x000200f9, 0x0000006f, 0x000200f8, 0x0000006f, 0x000700f5, 0x000500be, 0x0000001c, 0x00000073, 0x00000071, 0x00000072, 0x000300f7, 0x00000074, 0x00000000,
0x0000001c, 0x00000074, 0x0000001d, 0x00000069, 0x00000073, 0x00000070, 0x000300f7, 0x00000075, 0x000400fa, 0x00000073, 0x00000075, 0x00000074, 0x000200f8, 0x00000075, 0x00050051, 0x00000016,
0x00000000, 0x000400fa, 0x00000074, 0x00000076, 0x00000075, 0x000200f8, 0x00000076, 0x00060052, 0x00000076, 0x00000060, 0x00000000, 0x00050083, 0x00000016, 0x00000077, 0x00000076, 0x00000064,
0x00000023, 0x00000077, 0x0000001e, 0x0000006c, 0x00000000, 0x000200f9, 0x00000075, 0x000200f8, 0x000500b8, 0x0000001c, 0x00000078, 0x00000071, 0x00000077, 0x000200f9, 0x00000074, 0x000200f8,
0x00000075, 0x000700f5, 0x00000023, 0x00000078, 0x0000006c, 0x0000006f, 0x00000077, 0x00000076, 0x00000074, 0x000700f5, 0x0000001c, 0x00000079, 0x0000001d, 0x0000006d, 0x00000078, 0x00000075,
0x00050051, 0x00000016, 0x00000079, 0x00000078, 0x00000001, 0x000500bc, 0x0000001c, 0x0000007a, 0x000300f7, 0x0000007a, 0x00000000, 0x000400fa, 0x00000079, 0x0000007b, 0x0000007a, 0x000200f8,
0x00000079, 0x0000001b, 0x000300f7, 0x0000007b, 0x00000000, 0x000400fa, 0x0000007a, 0x0000007c, 0x0000007b, 0x00060052, 0x00000023, 0x0000007c, 0x00000072, 0x00000070, 0x00000000, 0x000200f9,
0x0000007b, 0x000200f8, 0x0000007c, 0x00050051, 0x00000016, 0x0000007d, 0x00000060, 0x00000001, 0x0000007a, 0x000200f8, 0x0000007a, 0x000700f5, 0x00000023, 0x0000007d, 0x00000070, 0x00000074,
0x00050083, 0x00000016, 0x0000007e, 0x0000001b, 0x0000007d, 0x000500ba, 0x0000001c, 0x0000007f, 0x0000007c, 0x0000007b, 0x00050051, 0x00000016, 0x0000007e, 0x0000007d, 0x00000001, 0x000500bc,
0x00000079, 0x0000007e, 0x000200f9, 0x0000007b, 0x000200f8, 0x0000007b, 0x000700f5, 0x0000001c, 0x0000001c, 0x0000007f, 0x0000007e, 0x0000001b, 0x000300f7, 0x00000080, 0x00000000, 0x000400fa,
0x00000080, 0x0000001d, 0x00000075, 0x0000007f, 0x0000007c, 0x000300f7, 0x00000081, 0x00000000, 0x0000007f, 0x00000081, 0x00000080, 0x000200f8, 0x00000081, 0x00050051, 0x00000016, 0x00000082,
0x000400fa, 0x00000080, 0x00000082, 0x00000081, 0x000200f8, 0x00000082, 0x00060052, 0x00000023, 0x00000060, 0x00000001, 0x00050083, 0x00000016, 0x00000083, 0x0000001b, 0x00000082, 0x000500ba,
0x00000083, 0x0000001b, 0x00000078, 0x00000001, 0x000200f9, 0x00000081, 0x000200f8, 0x00000081, 0x0000001c, 0x00000084, 0x0000007e, 0x00000083, 0x000200f9, 0x00000080, 0x000200f8, 0x00000080,
0x000700f5, 0x00000023, 0x00000084, 0x00000078, 0x0000007b, 0x00000083, 0x00000082, 0x00050051, 0x000700f5, 0x0000001c, 0x00000085, 0x0000001d, 0x0000007a, 0x00000084, 0x00000081, 0x000300f7,
0x00000016, 0x00000085, 0x00000084, 0x00000001, 0x000500be, 0x0000001c, 0x00000086, 0x00000085, 0x00000086, 0x00000000, 0x000400fa, 0x00000085, 0x00000087, 0x00000086, 0x000200f8, 0x00000087,
0x0000001e, 0x000300f7, 0x00000087, 0x00000000, 0x000400fa, 0x00000086, 0x00000088, 0x00000087, 0x00060052, 0x00000023, 0x00000088, 0x0000001b, 0x0000007d, 0x00000001, 0x000200f9, 0x00000086,
0x000200f8, 0x00000088, 0x00050051, 0x00000016, 0x00000089, 0x00000060, 0x00000001, 0x00050081, 0x000200f8, 0x00000086, 0x000700f5, 0x00000023, 0x00000089, 0x0000007d, 0x00000080, 0x00000088,
0x00000016, 0x0000008a, 0x0000001e, 0x00000089, 0x000500b8, 0x0000001c, 0x0000008b, 0x00000085, 0x00000087, 0x00050051, 0x00000016, 0x0000008a, 0x00000089, 0x00000001, 0x000500be, 0x0000001c,
0x0000008a, 0x000200f9, 0x00000087, 0x000200f8, 0x00000087, 0x000700f5, 0x0000001c, 0x0000008c, 0x0000008b, 0x0000008a, 0x0000001e, 0x000300f7, 0x0000008c, 0x00000000, 0x000400fa, 0x0000008b,
0x0000001d, 0x00000081, 0x0000008b, 0x00000088, 0x000300f7, 0x0000008d, 0x00000000, 0x000400fa, 0x0000008d, 0x0000008c, 0x000200f8, 0x0000008d, 0x00050051, 0x00000016, 0x0000008e, 0x00000060,
0x0000008c, 0x0000008e, 0x0000008d, 0x000200f8, 0x0000008e, 0x00060052, 0x00000023, 0x0000008f, 0x00000001, 0x00050081, 0x00000016, 0x0000008f, 0x0000001e, 0x0000008e, 0x000500b8, 0x0000001c,
0x0000001e, 0x00000084, 0x00000001, 0x000200f9, 0x0000008d, 0x000200f8, 0x0000008d, 0x000700f5, 0x00000090, 0x0000008a, 0x0000008f, 0x000200f9, 0x0000008c, 0x000200f8, 0x0000008c, 0x000700f5,
0x00000023, 0x00000090, 0x00000084, 0x00000087, 0x0000008f, 0x0000008e, 0x0005008e, 0x00000023, 0x0000001c, 0x00000091, 0x0000001d, 0x00000086, 0x00000090, 0x0000008d, 0x000300f7, 0x00000092,
0x00000091, 0x00000090, 0x00000047, 0x0009004f, 0x00000020, 0x00000092, 0x0000005b, 0x00000091, 0x00000000, 0x000400fa, 0x00000091, 0x00000093, 0x00000092, 0x000200f8, 0x00000093, 0x00060052,
0x00000004, 0x00000005, 0x00000002, 0x00000003, 0x000200f9, 0x0000004c, 0x000200f8, 0x0000004c, 0x00000023, 0x00000094, 0x0000001e, 0x00000089, 0x00000001, 0x000200f9, 0x00000092, 0x000200f8,
0x000700f5, 0x00000020, 0x00000093, 0x00000048, 0x0000002b, 0x00000092, 0x0000008d, 0x0003003e, 0x00000092, 0x000700f5, 0x00000023, 0x00000095, 0x00000089, 0x0000008c, 0x00000094, 0x00000093,
0x00000006, 0x00000093, 0x0003003e, 0x00000007, 0x0000002d, 0x0003003e, 0x00000008, 0x0000002e, 0x0005008e, 0x00000023, 0x00000096, 0x00000095, 0x00000047, 0x0009004f, 0x00000020, 0x00000097,
0x000100fd, 0x00010038, 0x0000005b, 0x00000096, 0x00000004, 0x00000005, 0x00000002, 0x00000003, 0x000200f9, 0x0000004c,
0x000200f8, 0x0000004c, 0x000700f5, 0x00000020, 0x00000098, 0x00000048, 0x0000002b, 0x00000097,
0x00000092, 0x0003003e, 0x00000006, 0x00000098, 0x0003003e, 0x00000007, 0x0000002d, 0x0003003e,
0x00000008, 0x0000002e, 0x000100fd, 0x00010038,
}; };
// overlay2d.hlsl : ps_main (5168 bytes) // overlay2d.hlsl : ps_main (5168 bytes)

View file

@ -49,7 +49,7 @@
#include <rex/filesystem/devices/host_path_device.h> #include <rex/filesystem/devices/host_path_device.h>
#include <rex/filesystem/vfs.h> #include <rex/filesystem/vfs.h>
#include <rex/graphics/flags.h> #include <rex/graphics/flags.h>
#include <rex/graphics/ultrawide_debug.h> #include <rex/graphics/native_guest_renderer.h>
#include <rex/input/input_system.h> #include <rex/input/input_system.h>
#include <rex/kernel/xam/module.h> #include <rex/kernel/xam/module.h>
#include <rex/logging.h> #include <rex/logging.h>
@ -66,7 +66,6 @@
#include <rex/ui/keybinds.h> #include <rex/ui/keybinds.h>
#include <rex/ui/window.h> #include <rex/ui/window.h>
#include <rex/ui/overlay/simple_settings_overlay.h> #include <rex/ui/overlay/simple_settings_overlay.h>
#include <rex/ui/overlay/ultrawide_targets_overlay.h>
#include <imgui.h> #include <imgui.h>
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
@ -93,44 +92,17 @@ REXCVAR_DEFINE_STRING(skate3_dlc_root, "", "Skate 3",
REXCVAR_DEFINE_BOOL(skate3_auto_install_dlc, true, "Skate 3", REXCVAR_DEFINE_BOOL(skate3_auto_install_dlc, true, "Skate 3",
"Install DLC package files found in configured DLC folders"); "Install DLC package files found in configured DLC folders");
REXCVAR_DEFINE_BOOL(skate3_ultrawide, false, "Skate 3", REXCVAR_DEFINE_BOOL(skate3_ultrawide, false, "Skate 3",
"Automatically derive an ultrawide guest video mode from the host display"); "Ultrawide display support: the native renderer draws true widescreen "
"frames at the host display aspect (requires the native renderer; the "
"emulated fallback presents 16:9 pillarboxed)")
.lifecycle(rex::cvar::Lifecycle::kRequiresRestart);
REXCVAR_DEFINE_DOUBLE(skate3_field_of_view, 60.0, "Skate 3", REXCVAR_DEFINE_DOUBLE(skate3_field_of_view, 60.0, "Skate 3",
"Gameplay camera field of view in degrees") "Gameplay camera field of view in degrees")
.range(40.0, 120.0); .range(40.0, 120.0);
REXCVAR_DEFINE_INT32(skate3_ultrawide_base_height, 720, "Skate 3",
"Guest video mode height used when deriving ultrawide modes")
.range(480, 2160)
.lifecycle(rex::cvar::Lifecycle::kRequiresRestart);
REXCVAR_DEFINE_BOOL(skate3_ultrawide_hor_plus, true, "Skate 3",
"Apply Hor+ clip-space correction for ultrawide video modes");
REXCVAR_DEFINE_DOUBLE(skate3_ultrawide_hor_plus_scale, 0.0, "Skate 3",
"Manual Hor+ X scale override (0 = derive from host aspect)")
.range(0.0, 4.0)
.lifecycle(rex::cvar::Lifecycle::kRequiresRestart);
REXCVAR_DEFINE_BOOL(skate3_ultrawide_disable_ndc_correction, false, "Skate 3",
"Diagnostic: disable the GPU NDC Hor+ correction while preserving guest-side "
"ultrawide diagnostics");
REXCVAR_DEFINE_BOOL(skate3_ultrawide_trace_draws, false, "Skate 3",
"Diagnostic: collect live draw fingerprints for the F7 ultrawide overlay");
REXCVAR_DEFINE_BOOL(skate3_ultrawide_object_stage_trace_to_disk, false, "Skate 3",
"Diagnostic: write object render-stage transition summaries to disk");
REXCVAR_DEFINE_BOOL(skate3_ultrawide_object_stage_trace_continuous, false, "Skate 3",
"Diagnostic: continuously trace object render-stage summaries");
REXCVAR_DEFINE_INT32(skate3_ultrawide_object_stage_trace_frames_remaining, 0, "Skate 3",
"Diagnostic: trace this many object render-stage frames")
.range(0, 1000000);
REXCVAR_DEFINE_INT32(skate3_ultrawide_object_stage_marker, 0, "Skate 3",
"Diagnostic: mark the next object-stage frame (1 visible, 2 invisible)")
.range(0, 2);
REXCVAR_DEFINE_INT32(skate3_ultrawide_object_stage_missing_limit, 256, "Skate 3",
"Diagnostic: maximum missing-main objects to log per object-stage frame")
.range(0, 4096);
REXCVAR_DEFINE_BOOL(skate3_ultrawide_force_main_visibility_flags, false, "Skate 3",
"Force main render object visibility flags while Hor+ ultrawide is active");
REXCVAR_DEFINE_BOOL(skate3_ultrawide_widen_game_frustum, true, "Skate 3", REXCVAR_DEFINE_BOOL(skate3_ultrawide_widen_game_frustum, true, "Skate 3",
"Widen the game-side main-world cull frustum to match the ultrawide view"); "Widen the game-side main-world cull frustum to match the ultrawide view");
REXCVAR_DEFINE_DOUBLE(skate3_ultrawide_target_aspect, 0.0, "Skate 3", REXCVAR_DEFINE_DOUBLE(skate3_ultrawide_target_aspect, 0.0, "Skate 3",
"Derived host display aspect for ultrawide presentation (0 = disabled)") "Ultrawide display aspect (0 = derive from the host display at boot)")
.range(0.0, 8.0); .range(0.0, 8.0);
namespace { namespace {
@ -290,40 +262,42 @@ std::optional<DisplaySize> ResolveUltrawideTargetDisplaySize() {
} }
void ApplyUltrawideVideoDefaults() { void ApplyUltrawideVideoDefaults() {
if (!REXCVAR_GET(skate3_ultrawide) || if (!REXCVAR_GET(skate3_ultrawide)) {
rex::cvar::HasNonDefaultValue("skate3_ultrawide_target_aspect")) {
return; return;
} }
const std::optional<DisplaySize> target_size = ResolveUltrawideTargetDisplaySize(); // Explicitly configured aspect wins; otherwise derive it from the
if (!target_size || target_size->width <= 0 || target_size->height <= 0) { // fullscreen monitor (or a configured window size) once at boot.
return; double target_aspect = rex::cvar::HasNonDefaultValue("skate3_ultrawide_target_aspect")
} ? REXCVAR_GET(skate3_ultrawide_target_aspect)
: 0.0;
const double target_aspect =
static_cast<double>(target_size->width) / static_cast<double>(target_size->height);
if (target_aspect <= kSixteenNineAspect + kUltrawideAspectEpsilon) { if (target_aspect <= kSixteenNineAspect + kUltrawideAspectEpsilon) {
return; const std::optional<DisplaySize> target_size = ResolveUltrawideTargetDisplaySize();
if (!target_size || target_size->width <= 0 || target_size->height <= 0) {
return;
}
target_aspect =
static_cast<double>(target_size->width) / static_cast<double>(target_size->height);
if (target_aspect <= kSixteenNineAspect + kUltrawideAspectEpsilon) {
return;
}
rex::cvar::SetFlagByName("skate3_ultrawide_target_aspect", std::to_string(target_aspect));
} }
rex::cvar::SetFlagByName("skate3_ultrawide_target_aspect", std::to_string(target_aspect)); // The native renderer draws true wide frames at this aspect (wide guest
// output + Hor+ projection + centered 2D band). Emulated fallback frames
// keep the 16:9 guest output and present pillarboxed via the letterbox
// default below.
rex::graphics::SetNativeGuestOutputWideAspect(
std::clamp(target_aspect, kSixteenNineAspect, 8.0));
if (!rex::cvar::HasNonDefaultValue("present_letterbox")) { if (!rex::cvar::HasNonDefaultValue("present_letterbox")) {
rex::cvar::SetFlagByName("present_letterbox", "true"); rex::cvar::SetFlagByName("present_letterbox", "true");
} }
} }
void DisableActiveUltrawideDiagnostics() { void DisableActiveDebugDiagnostics() {
constexpr std::string_view kFalseFlags[] = { constexpr std::string_view kFalseFlags[] = {
"skate3_ultrawide_trace_draws",
"skate3_ultrawide_object_stage_trace_to_disk",
"skate3_ultrawide_object_stage_trace_continuous",
"skate3_ultrawide_force_main_visibility_flags",
"skate3_ultrawide_texture_trace_bind_keys",
"skate3_ultrawide_texture_trace_scaled_resolve",
"skate3_ultrawide_ignore_streamer_texture_invalidations",
"skate3_ultrawide_screen_callback_tracking",
"skate3_ultrawide_fake_occlusion_queries",
"perf_draw_fingerprints", "perf_draw_fingerprints",
"perf_keep_heavyweight_draw_diagnostics", "perf_keep_heavyweight_draw_diagnostics",
"trace_gpu_stream", "trace_gpu_stream",
@ -333,9 +307,6 @@ void DisableActiveUltrawideDiagnostics() {
} }
constexpr std::string_view kZeroFlags[] = { constexpr std::string_view kZeroFlags[] = {
"skate3_ultrawide_texture_trace_remaining",
"skate3_ultrawide_object_stage_trace_frames_remaining",
"skate3_ultrawide_object_stage_marker",
"vulkan_debug_log_frame_summaries_remaining", "vulkan_debug_log_frame_summaries_remaining",
"vulkan_debug_log_resolve_decisions_remaining", "vulkan_debug_log_resolve_decisions_remaining",
"vulkan_debug_log_team_profile_background_candidates_remaining", "vulkan_debug_log_team_profile_background_candidates_remaining",
@ -346,8 +317,6 @@ void DisableActiveUltrawideDiagnostics() {
for (std::string_view flag : kZeroFlags) { for (std::string_view flag : kZeroFlags) {
rex::cvar::SetFlagByName(std::string(flag), "0"); rex::cvar::SetFlagByName(std::string(flag), "0");
} }
rex::cvar::SetFlagByName("skate3_ultrawide_fake_occlusion_sample_count", "1000");
} }
std::filesystem::path DefaultDocumentsUserRoot() { std::filesystem::path DefaultDocumentsUserRoot() {
@ -558,11 +527,7 @@ void Skate3BaseApp::OnConfigurePaths(rex::PathConfig& paths) {
LoadAndNormalizeSimpleSettings(user_settings_path_, config_path_); LoadAndNormalizeSimpleSettings(user_settings_path_, config_path_);
Skate3InitializeFieldOfViewOverride(); Skate3InitializeFieldOfViewOverride();
ApplyUltrawideVideoDefaults(); ApplyUltrawideVideoDefaults();
if (!rex::graphics::ultrawide_debug::LoadTargets(paths.cache_root / DisableActiveDebugDiagnostics();
"skate3_ultrawide_targets.toml")) {
rex::graphics::ultrawide_debug::LoadBuiltInSkate3Classifier();
}
DisableActiveUltrawideDiagnostics();
} }
void Skate3BaseApp::OnConfigureFonts(ImFontAtlas* atlas) { void Skate3BaseApp::OnConfigureFonts(ImFontAtlas* atlas) {
@ -745,15 +710,6 @@ void Skate3BaseApp::OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) {
"Toggle native/emulated renderer", [] { "Toggle native/emulated renderer", [] {
skate3::native_scene::ToggleSceneEnabled(); skate3::native_scene::ToggleSceneEnabled();
}); });
rex::ui::RegisterBind("bind_skate3_ultrawide_targets", "F7",
"Skate 3 ultrawide targets", [this] {
// Developer tuning dialog; rides the same opt-in as
// the F4 cvar browser.
if (rex::cvar::Query<bool>(
"advanced_settings_overlay_enabled")) {
ToggleUltrawideTargets();
}
});
rex::ui::RegisterBind("bind_skate3_save_draw_fingerprints", "F8", rex::ui::RegisterBind("bind_skate3_save_draw_fingerprints", "F8",
"Save draw fingerprint log", [this] { "Save draw fingerprint log", [this] {
SaveDrawFingerprintLog(); SaveDrawFingerprintLog();
@ -856,7 +812,6 @@ void Skate3BaseApp::OnPostSetup() {
void Skate3BaseApp::OnShutdown() { void Skate3BaseApp::OnShutdown() {
rex::ui::UnregisterBind("bind_skate3_menu"); rex::ui::UnregisterBind("bind_skate3_menu");
rex::ui::UnregisterBind("bind_skate3_menu_alt"); rex::ui::UnregisterBind("bind_skate3_menu_alt");
rex::ui::UnregisterBind("bind_skate3_ultrawide_targets");
rex::ui::UnregisterBind("bind_skate3_save_draw_fingerprints"); rex::ui::UnregisterBind("bind_skate3_save_draw_fingerprints");
rex::ui::UnregisterBind("bind_skate3_log_debug_marker"); rex::ui::UnregisterBind("bind_skate3_log_debug_marker");
rex::ui::UnregisterBind("bind_skate3_log_user_marker"); rex::ui::UnregisterBind("bind_skate3_log_user_marker");
@ -864,7 +819,6 @@ void Skate3BaseApp::OnShutdown() {
ApplyGameplayCursorMode(); ApplyGameplayCursorMode();
skate3::native_scene::SetSettingsMenuBlur(false); skate3::native_scene::SetSettingsMenuBlur(false);
simple_settings_dialog_.reset(); simple_settings_dialog_.reset();
ultrawide_targets_dialog_.reset();
native_debug_dialog_.reset(); native_debug_dialog_.reset();
render_mode_indicator_.reset(); render_mode_indicator_.reset();
} }
@ -969,24 +923,6 @@ void Skate3BaseApp::ToggleSimpleSettings() {
simple_settings_dialog_->Show(); simple_settings_dialog_->Show();
} }
void Skate3BaseApp::ToggleUltrawideTargets() {
if (ultrawide_targets_dialog_) {
if (ultrawide_targets_dialog_->visible()) {
ultrawide_targets_dialog_->Hide();
} else {
ApplySettingsCursorMode();
ultrawide_targets_dialog_->Show();
}
return;
}
const auto export_path = cache_root() / "skate3_ultrawide_targets.toml";
ultrawide_targets_dialog_ = std::make_unique<rex::ui::UltrawideTargetsDialog>(
imgui_drawer(), export_path, [this]() { ApplyGameplayCursorMode(); });
ApplySettingsCursorMode();
ultrawide_targets_dialog_->Show();
}
void Skate3BaseApp::ToggleNativeDebug() { void Skate3BaseApp::ToggleNativeDebug() {
if (!native_debug_dialog_) { if (!native_debug_dialog_) {
native_debug_dialog_ = std::make_unique<skate3::NativeDebugDialog>(imgui_drawer()); native_debug_dialog_ = std::make_unique<skate3::NativeDebugDialog>(imgui_drawer());
@ -1126,7 +1062,7 @@ void Skate3BaseApp::LogUserMarker() {
void Skate3BaseApp::LogDebugMarker() { void Skate3BaseApp::LogDebugMarker() {
const uint32_t marker = debug_marker_count_.fetch_add(1, std::memory_order_relaxed) + 1; const uint32_t marker = debug_marker_count_.fetch_add(1, std::memory_order_relaxed) + 1;
DisableActiveUltrawideDiagnostics(); DisableActiveDebugDiagnostics();
REXLOG_WARN("USER DEBUG MARKER #{}: F9 pressed; active diagnostics disabled", marker); REXLOG_WARN("USER DEBUG MARKER #{}: F9 pressed; active diagnostics disabled", marker);
} }

View file

@ -12,7 +12,6 @@
#include <rex/rex_app.h> #include <rex/rex_app.h>
#include <rex/ui/overlay/simple_settings_overlay.h> #include <rex/ui/overlay/simple_settings_overlay.h>
#include <rex/ui/overlay/ultrawide_targets_overlay.h>
#include "skate3_native_debug_dialog.h" #include "skate3_native_debug_dialog.h"
@ -40,7 +39,6 @@ class Skate3BaseApp : public rex::ReXApp {
void InstallBigDeviceAliases(); void InstallBigDeviceAliases();
void InstallDlcPackages(); void InstallDlcPackages();
void ToggleSimpleSettings(); void ToggleSimpleSettings();
void ToggleUltrawideTargets();
void ToggleNativeDebug(); void ToggleNativeDebug();
void ApplySettingsCursorMode(); void ApplySettingsCursorMode();
void ApplyGameplayCursorMode(); void ApplyGameplayCursorMode();
@ -60,7 +58,6 @@ class Skate3BaseApp : public rex::ReXApp {
std::filesystem::path user_settings_path_; std::filesystem::path user_settings_path_;
std::filesystem::path profiles_path_; std::filesystem::path profiles_path_;
std::unique_ptr<rex::ui::SimpleSettingsDialog> simple_settings_dialog_; std::unique_ptr<rex::ui::SimpleSettingsDialog> simple_settings_dialog_;
std::unique_ptr<rex::ui::UltrawideTargetsDialog> ultrawide_targets_dialog_;
std::unique_ptr<skate3::NativeDebugDialog> native_debug_dialog_; std::unique_ptr<skate3::NativeDebugDialog> native_debug_dialog_;
std::unique_ptr<skate3::RenderModeIndicator> render_mode_indicator_; std::unique_ptr<skate3::RenderModeIndicator> render_mode_indicator_;
bool recipe_overlay_installed_ = false; bool recipe_overlay_installed_ = false;

View file

@ -13,7 +13,7 @@
#include <vector> #include <vector>
#include <rex/cvar.h> #include <rex/cvar.h>
#include <rex/graphics/ultrawide_debug.h> #include <rex/kernel/guest_presence.h>
#include <rex/input/input.h> #include <rex/input/input.h>
#include <rex/input/input_system.h> #include <rex/input/input_system.h>
#include <rex/kernel/xam/input_injection.h> #include <rex/kernel/xam/input_injection.h>
@ -356,7 +356,7 @@ void StartGameplayInputWorkerIfNeeded() {
} }
g_input_worker = std::thread([tokens, settle_ms] { g_input_worker = std::thread([tokens, settle_ms] {
// Wait for the gameplay presence context (0x8001 == 1). // Wait for the gameplay presence context (0x8001 == 1).
while (rex::graphics::ultrawide_debug::Skate3GameplayContextValue() != 1) { while (rex::kernel::guest_presence::GameplayContextValue() != 1) {
if (!InterruptibleSleepMs(100)) { if (!InterruptibleSleepMs(100)) {
return; return;
} }

View file

@ -33,7 +33,7 @@
#include <rex/cvar.h> #include <rex/cvar.h>
#include <rex/graphics/native_guest_renderer.h> #include <rex/graphics/native_guest_renderer.h>
#include <rex/graphics/ultrawide_debug.h> #include <rex/kernel/guest_presence.h>
#include <rex/logging.h> #include <rex/logging.h>
#include "native/skate3_native_diag.h" #include "native/skate3_native_diag.h"
@ -9853,7 +9853,7 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
// behind a live menu). The editor's _nis shader heartbeat separates the // behind a live menu). The editor's _nis shader heartbeat separates the
// two: editor draws stamp it every frame, portrait passes use the // two: editor draws stamp it every frame, portrait passes use the
// _default compiles and never do. // _default compiles and never do.
if (rex::graphics::ultrawide_debug::Skate3GameplayContextValue() == 0 && if (rex::kernel::guest_presence::GameplayContextValue() == 0 &&
!scene.items.empty() && scene.items.size() <= 48 && !scene.items.empty() && scene.items.size() <= 48 &&
!CasEditorActive(base)) { !CasEditorActive(base)) {
bool all_char = true; bool all_char = true;

View file

@ -33,7 +33,7 @@
#include <rex/cvar.h> #include <rex/cvar.h>
#include <rex/graphics/native_guest_renderer.h> #include <rex/graphics/native_guest_renderer.h>
#include <rex/graphics/ultrawide_debug.h> #include <rex/kernel/guest_presence.h>
#include <rex/logging.h> #include <rex/logging.h>
#include "native/skate3_native_diag.h" #include "native/skate3_native_diag.h"
@ -4609,7 +4609,7 @@ bool YieldForMenus(const NativeGuestOutputRenderContext& context) {
static bool s_in_loading = false; static bool s_in_loading = false;
static bool s_seen_gameplay = false; static bool s_seen_gameplay = false;
static bool s_pause_native = false; static bool s_pause_native = false;
const bool in_menus = rex::graphics::ultrawide_debug::Skate3GameplayContextValue() == 0; const bool in_menus = rex::kernel::guest_presence::GameplayContextValue() == 0;
// Render-thread mirror for the 2D texture resolver: menu screens shorten // Render-thread mirror for the 2D texture resolver: menu screens shorten
// the content-liveness recheck cadence (see resolve_2d_texture) so // the content-liveness recheck cadence (see resolve_2d_texture) so
// in-place rewrites of UI textures (the one-shot skater-portrait resolves) // in-place rewrites of UI textures (the one-shot skater-portrait resolves)
@ -9945,6 +9945,17 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
} }
} }
// Hor+ ultrawide: the 2D stream and the guest screenshot raster are
// authored for the 16:9 frontbuffer. On a wide output the 2D replay
// scales clip-space X by this factor (centering ortho HUD/menu/FMV draws
// in a pillarboxed 16:9 band and narrowing perspective SimpleDraw markers
// to match the widened scene projection - one operation covers both), and
// the photo grab center-crops the same band.
const float out_aspect2d =
float(context.guest_output_width) / float(context.guest_output_height);
const float wide_2d_scale =
out_aspect2d > (16.0f / 9.0f) * 1.01f ? (16.0f / 9.0f) / out_aspect2d : 1.0f;
// ---- Native photo grab (photo_grab_native) ---- // ---- Native photo grab (photo_grab_native) ----
// Consume: CPU-tile the newest fence-completed readback into the guest // Consume: CPU-tile the newest fence-completed readback into the guest
// screenshot target. Produce: downsample this frame's finished output // screenshot target. Produce: downsample this frame's finished output
@ -10055,10 +10066,17 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
cmd->SetScissor(grab_sc); cmd->SetScissor(grab_sc);
cmd->SetPrimitiveTopology(nrhi::PrimitiveTopology::kTriangleList); cmd->SetPrimitiveTopology(nrhi::PrimitiveTopology::kTriangleList);
cmd->SetPipeline(g_r.pso_blur_down); cmd->SetPipeline(g_r.pso_blur_down);
const float grab_consts[4] = {1.0f / float(context.guest_output_width), // Source UV rect (second register): the centered 16:9 band on a
// wide output; the guest screenshot raster is 16:9.
const float grab_consts[8] = {1.0f / float(context.guest_output_width),
1.0f / float(context.guest_output_height), 1.0f / float(context.guest_output_height),
0.0f, 0.0f}; 0.0f,
cmd->SetRootConstants(0, 4, grab_consts, 0); 0.0f,
wide_2d_scale,
1.0f,
(1.0f - wide_2d_scale) * 0.5f,
0.0f};
cmd->SetRootConstants(0, 8, grab_consts, 0);
cmd->SetTexture(1, g_r.output_srv_slot); cmd->SetTexture(1, g_r.output_srv_slot);
cmd->Draw(3, 0); cmd->Draw(3, 0);
// blur_tex[0] -> the readback buffer; restore steady states. // blur_tex[0] -> the readback buffer; restore steady states.
@ -10144,9 +10162,17 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
cmd->SetViewport(blur_vp); cmd->SetViewport(blur_vp);
cmd->SetScissor(blur_sc); cmd->SetScissor(blur_sc);
cmd->SetPipeline(g_r.pso_blur_down); cmd->SetPipeline(g_r.pso_blur_down);
const float d_consts[4] = {1.0f / float(context.guest_output_width), // Full-frame source rect: the blur squeezes the whole wide frame into
1.0f / float(context.guest_output_height), 0.0f, 0.0f}; // the 1152x640 blur space and the final stretch-back undoes it.
cmd->SetRootConstants(0, 4, d_consts, 0); const float d_consts[8] = {1.0f / float(context.guest_output_width),
1.0f / float(context.guest_output_height),
0.0f,
0.0f,
1.0f,
1.0f,
0.0f,
0.0f};
cmd->SetRootConstants(0, 8, d_consts, 0);
cmd->SetTexture(1, g_r.output_srv_slot); cmd->SetTexture(1, g_r.output_srv_slot);
cmd->Draw(3, 0); cmd->Draw(3, 0);
// H: blur_tex[0] -> blur_tex[1]. // H: blur_tex[0] -> blur_tex[1].
@ -10242,6 +10268,15 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
} }
float constants[40]; float constants[40];
std::memcpy(constants, d.consts, sizeof(d.consts)); std::memcpy(constants, d.consts, sizeof(d.consts));
// Wide output: scale the staged projection's clip.x row (the VS
// computes clip.x = dot(wp, c0)) so the 16:9-authored stream lands
// centered (see wide_2d_scale).
if (wide_2d_scale != 1.0f) {
constants[0] *= wide_2d_scale;
constants[1] *= wide_2d_scale;
constants[2] *= wide_2d_scale;
constants[3] *= wide_2d_scale;
}
// 2D ortho draws have no translation row in the projection (c3 == // 2D ortho draws have no translation row in the projection (c3 ==
// (0,0,0,1)); perspective view-proj rows do. Half-pixel applies to // (0,0,0,1)); perspective view-proj rows do. Half-pixel applies to
// the former only. // the former only.
@ -10252,12 +10287,14 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
// (see the cvar; the shader gates on actual fetch magnification). // (see the cvar; the shader gates on actual fetch magnification).
constants[37] = float(std::clamp( constants[37] = float(std::clamp(
REXCVAR_GET(skate3_native_render_scene_2d_sharp), 0.0, 2.0)); REXCVAR_GET(skate3_native_render_scene_2d_sharp), 0.0, 2.0));
// m[9].zw: unused. The D3D9 half-pixel shift is derived in the VS // m[9].z: clip-space X extent of the 2D band, the edge-snap
// from the draw's own ortho scale (+0.5 GUEST pixel down-right, // boundary in the VS (0 = full target). m[9].w: unused. The D3D9
// matching the emulated path's half_pixel_offset reversal); the // half-pixel shift is derived in the VS from the draw's own ortho
// old up-left OUTPUT-pixel nudge staged here left a see-through // scale (+0.5 GUEST pixel down-right, matching the emulated path's
// sliver along the bottom/right of edge-to-edge loading quads. // half_pixel_offset reversal); the old up-left OUTPUT-pixel nudge
constants[38] = 0.0f; // staged here left a see-through sliver along the bottom/right of
// edge-to-edge loading quads.
constants[38] = wide_2d_scale != 1.0f ? wide_2d_scale : 0.0f;
constants[39] = 0.0f; constants[39] = 0.0f;
cmd->SetRootConstants(0, 40, constants, 0); cmd->SetRootConstants(0, 40, constants, 0);
cmd->SetTexture(1, srv_view); cmd->SetTexture(1, srv_view);

View file

@ -32,7 +32,6 @@
#include <rex/cvar.h> #include <rex/cvar.h>
#include <rex/graphics/native_guest_renderer.h> #include <rex/graphics/native_guest_renderer.h>
#include <rex/graphics/ultrawide_debug.h>
#include <rex/logging.h> #include <rex/logging.h>
#include "native/skate3_native_diag.h" #include "native/skate3_native_diag.h"

View file

@ -2,25 +2,23 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <atomic>
#include <cmath> #include <cmath>
#include <cstdlib>
#include <cstdint> #include <cstdint>
#include <filesystem>
#include <fstream>
#include <unordered_map>
#include <string>
#include <string_view>
#include <mutex>
#include <rex/cvar.h> #include <rex/cvar.h>
#include <rex/graphics/ultrawide_debug.h> #include <rex/graphics/native_guest_renderer.h>
#include <rex/logging.h>
// Guest-side ultrawide support: the native renderer draws true widescreen
// frames (wide guest output + Hor+ projection), but the game's own CPU
// culling still tests against its 16:9 view frustum and would drop side
// content before it ever reaches the renderer. The frustum patch scope below
// is injected into the recompiled cull routine (see
// cmake/ApplySkate3CodegenPatches.cmake) and widens the cull planes in guest
// memory to match the wide view.
inline bool Skate3UltrawideHasExpandedTargetAspect() { inline bool Skate3UltrawideHasExpandedTargetAspect() {
if (!rex::cvar::Query<bool>("skate3_ultrawide") || if (!rex::cvar::Query<bool>("skate3_ultrawide") ||
!rex::cvar::Query<bool>("skate3_ultrawide_hor_plus") || !rex::graphics::IsNativeGuestOutputActive()) {
!rex::graphics::ultrawide_debug::IsSkate3GameplayUltrawideActive()) {
return false; return false;
} }
@ -28,165 +26,16 @@ inline bool Skate3UltrawideHasExpandedTargetAspect() {
(16.0 / 9.0) + 0.01; (16.0 / 9.0) + 0.01;
} }
inline float Skate3UltrawideFloatFromU32(uint32_t value) {
union {
uint32_t u;
float f;
} bits{value};
return bits.f;
}
inline uint32_t Skate3UltrawideU32FromFloat(float value) {
union {
float f;
uint32_t u;
} bits{value};
return bits.u;
}
inline double Skate3UltrawideMaybeOverrideGameplayFrustumAspect(uint32_t site_id,
double native_aspect) {
if (!Skate3UltrawideHasExpandedTargetAspect() ||
!rex::cvar::Query<bool>("skate3_ultrawide_force_main_visibility_flags") ||
!std::isfinite(native_aspect) || native_aspect <= 0.0) {
return native_aspect;
}
const double forced_aspect = std::clamp(
rex::cvar::Query<double>("skate3_ultrawide_target_aspect"), 16.0 / 9.0, 8.0);
if (forced_aspect <= native_aspect + 0.001) {
return native_aspect;
}
const uint32_t native_milli = uint32_t(std::clamp(native_aspect * 1000.0, 0.0, 100000.0));
const uint32_t forced_milli = uint32_t(std::clamp(forced_aspect * 1000.0, 0.0, 100000.0));
rex::graphics::ultrawide_debug::RecordScreenCallback(
rex::graphics::ultrawide_debug::ScreenCallbackKind::kWidth, site_id, native_milli);
rex::graphics::ultrawide_debug::RecordScreenCallbackResult(
rex::graphics::ultrawide_debug::ScreenCallbackKind::kWidth, site_id, native_milli,
forced_milli);
return forced_aspect;
}
inline void Skate3UltrawideMaybeExpandMainCullRange(PPCContext& ctx, u8* base,
uint32_t min_addr,
uint32_t max_addr) {
if (!Skate3UltrawideHasExpandedTargetAspect()) {
return;
}
const double target_aspect = std::clamp(
rex::cvar::Query<double>("skate3_ultrawide_target_aspect"), 16.0 / 9.0, 8.0);
const float scale = float(target_aspect / (16.0 / 9.0));
if (scale <= 1.0f) {
return;
}
const float native_min = Skate3UltrawideFloatFromU32(REX_LOAD_U32(min_addr));
const float native_max = Skate3UltrawideFloatFromU32(REX_LOAD_U32(max_addr));
if (!std::isfinite(native_min) || !std::isfinite(native_max) ||
native_max <= native_min) {
return;
}
const float center = (native_min + native_max) * 0.5f;
const float half_width = (native_max - native_min) * 0.5f * scale;
const float widened_min = center - half_width;
const float widened_max = center + half_width;
if (!std::isfinite(widened_min) || !std::isfinite(widened_max)) {
return;
}
REX_STORE_U32(min_addr, Skate3UltrawideU32FromFloat(widened_min));
REX_STORE_U32(max_addr, Skate3UltrawideU32FromFloat(widened_max));
}
inline uint32_t Skate3UltrawideRecordScreenHeight(uint32_t site_id, uint32_t native_height) {
rex::graphics::ultrawide_debug::RecordScreenCallback(
rex::graphics::ultrawide_debug::ScreenCallbackKind::kHeight, site_id, native_height);
return native_height;
}
inline uint32_t Skate3UltrawideMaybeOverrideScreenFlag(
rex::graphics::ultrawide_debug::ScreenCallbackKind kind, uint32_t site_id,
uint32_t native_value) {
const bool selected =
rex::graphics::ultrawide_debug::RecordScreenCallback(kind, site_id, native_value);
return selected ? 1 : native_value;
}
inline uint32_t Skate3UltrawideMaybeForceMainVisibilityFlag(uint32_t site_id,
uint32_t native_value) {
rex::graphics::ultrawide_debug::RecordScreenCallback(
rex::graphics::ultrawide_debug::ScreenCallbackKind::kScreenFlag, site_id, native_value);
if (!Skate3UltrawideHasExpandedTargetAspect() ||
!rex::cvar::Query<bool>("skate3_ultrawide_force_main_visibility_flags")) {
return native_value;
}
rex::graphics::ultrawide_debug::RecordScreenCallbackResult(
rex::graphics::ultrawide_debug::ScreenCallbackKind::kScreenFlag, site_id, native_value, 1);
return 1;
}
inline uint32_t Skate3UltrawideMaybeForceHighestLodState(uint32_t site_id, uint32_t object,
uint32_t native_state) {
if (!Skate3UltrawideHasExpandedTargetAspect() ||
!rex::cvar::Query<bool>("skate3_ultrawide_force_main_visibility_flags") ||
native_state == 0) {
return native_state;
}
return 0;
}
inline thread_local bool g_skate3_ultrawide_force_main_cull_classifier = false;
struct Skate3UltrawideMainCullClassifierScope {
explicit Skate3UltrawideMainCullClassifierScope(bool enabled)
: previous(g_skate3_ultrawide_force_main_cull_classifier) {
g_skate3_ultrawide_force_main_cull_classifier =
previous || (enabled && Skate3UltrawideHasExpandedTargetAspect());
}
~Skate3UltrawideMainCullClassifierScope() {
g_skate3_ultrawide_force_main_cull_classifier = previous;
}
bool previous;
};
inline uint32_t Skate3UltrawideMaybeForceMainCullClassifierHalfword(uint32_t native_value) {
if (!g_skate3_ultrawide_force_main_cull_classifier ||
!rex::cvar::Query<bool>("skate3_ultrawide_force_main_visibility_flags")) {
return native_value;
}
return 1;
}
inline bool Skate3UltrawideShouldForceWorldMainCullDescriptor(u8* base, uint32_t descriptor) {
if (!Skate3UltrawideHasExpandedTargetAspect() ||
!rex::cvar::Query<bool>("skate3_ultrawide_force_main_visibility_flags") ||
descriptor < 512) {
return false;
}
constexpr uint32_t kWorldVtable = 0x8230B278;
const uint32_t object = descriptor - 512;
if (REX_LOAD_U32(object) != kWorldVtable) {
return false;
}
const uint32_t output_flags = REX_LOAD_U32(descriptor + 12);
return output_flags != 0 && output_flags == REX_LOAD_U32(object + 496);
}
inline bool Skate3UltrawideShouldWidenGameCullFrustum(u8* base, uint32_t cull_block) { inline bool Skate3UltrawideShouldWidenGameCullFrustum(u8* base, uint32_t cull_block) {
if (!Skate3UltrawideHasExpandedTargetAspect() || // Every cull block reaching the vectorized cull job gets its left/right
!rex::cvar::Query<bool>("skate3_ultrawide_widen_game_frustum") || !cull_block) { // planes widened: DoFrustumCulling reads them unconditionally, including
return false; // blocks with no extra cull volumes (the word at +5260); gating on that
} // count left 16:9 culling holes at the frame edges in the areas whose
// blocks carry none. Over-inclusion is safe (a few extra submitted
return REX_LOAD_U32(cull_block + 5260) != 0; // meshes); the plane sanity checks below still veto implausible data.
(void)base;
return cull_block != 0 && Skate3UltrawideHasExpandedTargetAspect() &&
rex::cvar::Query<bool>("skate3_ultrawide_widen_game_frustum");
} }
struct Skate3UltrawideGameFrustumPatchScope { struct Skate3UltrawideGameFrustumPatchScope {
@ -336,279 +185,3 @@ struct Skate3UltrawideGameFrustumPatchScope {
float side_scale = 1.0f; float side_scale = 1.0f;
bool active = false; bool active = false;
}; };
inline std::filesystem::path Skate3UltrawideCacheLogPath(const char* filename);
enum Skate3UltrawideObjectStageBits : uint32_t {
kSkate3ObjectStageActive = 1u << 0,
kSkate3ObjectStagePrep = 1u << 1,
kSkate3ObjectStageList = 1u << 2,
kSkate3ObjectStageMain = 1u << 3,
};
struct Skate3UltrawideObjectStageRecord {
uint32_t bits = 0;
uint32_t vtable = 0;
uint32_t target = 0;
uint32_t first_site = 0;
uint32_t last_site = 0;
uint32_t aux0 = 0;
uint32_t aux1 = 0;
};
inline uint64_t& Skate3UltrawideObjectStageFrameId() {
static uint64_t frame = 0;
return frame;
}
inline uint32_t& Skate3UltrawideObjectStageRenderer() {
static uint32_t renderer = 0;
return renderer;
}
inline std::unordered_map<uint32_t, Skate3UltrawideObjectStageRecord>&
Skate3UltrawideObjectStageRecords() {
static std::unordered_map<uint32_t, Skate3UltrawideObjectStageRecord> records;
return records;
}
inline std::mutex& Skate3UltrawideObjectStageMutex() {
static std::mutex mutex;
return mutex;
}
inline std::ofstream& Skate3UltrawideObjectStageLogFile() {
static std::ofstream log_file;
if (!log_file.is_open()) {
std::filesystem::path log_path =
Skate3UltrawideCacheLogPath("skate3_ultrawide_object_stage_trace.log");
std::error_code ec;
if (log_path.has_parent_path()) {
std::filesystem::create_directories(log_path.parent_path(), ec);
}
log_file.open(log_path, std::ios::out | std::ios::trunc);
if (log_file.is_open()) {
log_file << "seq,frame,kind,marker,renderer,object,bits,site,vtable,target,aux0,aux1,"
"active,prep,list,main,missing_main,total\n";
}
}
return log_file;
}
inline bool Skate3UltrawideObjectStageTraceEnabled() {
return rex::cvar::Query<bool>("skate3_ultrawide_object_stage_trace_continuous") ||
rex::cvar::Query<int32_t>("skate3_ultrawide_object_stage_trace_frames_remaining") > 0 ||
rex::cvar::Query<int32_t>("skate3_ultrawide_object_stage_marker") != 0;
}
inline void Skate3UltrawideWriteObjectStageLog(
uint64_t frame, const char* kind, uint32_t marker, uint32_t renderer, uint32_t object,
uint32_t bits, uint32_t site, uint32_t vtable, uint32_t target, uint32_t aux0,
uint32_t aux1, uint32_t active_count, uint32_t prep_count, uint32_t list_count,
uint32_t main_count, uint32_t missing_main_count, uint32_t total_count) {
if (!rex::cvar::Query<bool>("skate3_ultrawide_object_stage_trace_to_disk")) {
return;
}
static std::atomic<uint64_t> sequence{0};
std::ofstream& log_file = Skate3UltrawideObjectStageLogFile();
if (!log_file.is_open()) {
return;
}
log_file << std::dec << sequence.fetch_add(1, std::memory_order_relaxed) << ',' << frame
<< ',' << kind << ',' << marker << ",0x" << std::hex << renderer << ",0x"
<< object << ",0x" << bits << ",0x" << site << ",0x" << vtable << ",0x"
<< target << ",0x" << aux0 << ",0x" << aux1 << ',' << std::dec << active_count
<< ',' << prep_count << ',' << list_count << ',' << main_count << ','
<< missing_main_count << ',' << total_count << '\n';
log_file.flush();
}
inline void Skate3UltrawideFinalizeObjectStageFrameLocked(const char* reason) {
auto& records = Skate3UltrawideObjectStageRecords();
if (records.empty()) {
return;
}
const uint32_t marker =
static_cast<uint32_t>(rex::cvar::Query<int32_t>("skate3_ultrawide_object_stage_marker"));
const bool enabled = Skate3UltrawideObjectStageTraceEnabled();
uint32_t remaining =
static_cast<uint32_t>(std::max(0, rex::cvar::Query<int32_t>(
"skate3_ultrawide_object_stage_trace_frames_remaining")));
if (!enabled) {
records.clear();
return;
}
uint32_t active_count = 0;
uint32_t prep_count = 0;
uint32_t list_count = 0;
uint32_t main_count = 0;
uint32_t missing_main_count = 0;
for (const auto& [object, record] : records) {
active_count += (record.bits & kSkate3ObjectStageActive) ? 1 : 0;
prep_count += (record.bits & kSkate3ObjectStagePrep) ? 1 : 0;
list_count += (record.bits & kSkate3ObjectStageList) ? 1 : 0;
main_count += (record.bits & kSkate3ObjectStageMain) ? 1 : 0;
if ((record.bits & (kSkate3ObjectStagePrep | kSkate3ObjectStageList)) &&
!(record.bits & kSkate3ObjectStageMain)) {
++missing_main_count;
}
}
const uint64_t frame = Skate3UltrawideObjectStageFrameId();
const uint32_t renderer = Skate3UltrawideObjectStageRenderer();
Skate3UltrawideWriteObjectStageLog(frame, reason, marker, renderer, 0, 0, 0, 0, 0, 0, 0,
active_count, prep_count, list_count, main_count,
missing_main_count, static_cast<uint32_t>(records.size()));
uint32_t emitted_missing = 0;
const uint32_t missing_limit = static_cast<uint32_t>(std::clamp(
rex::cvar::Query<int32_t>("skate3_ultrawide_object_stage_missing_limit"), 0, 4096));
for (const auto& [object, record] : records) {
if (!((record.bits & (kSkate3ObjectStagePrep | kSkate3ObjectStageList)) &&
!(record.bits & kSkate3ObjectStageMain))) {
continue;
}
if (emitted_missing++ >= missing_limit) {
break;
}
Skate3UltrawideWriteObjectStageLog(frame, "missing-main", marker, renderer, object,
record.bits, record.last_site, record.vtable,
record.target, record.aux0, record.aux1, active_count,
prep_count, list_count, main_count, missing_main_count,
static_cast<uint32_t>(records.size()));
}
if (remaining > 0) {
rex::cvar::SetFlagByName("skate3_ultrawide_object_stage_trace_frames_remaining",
std::to_string(remaining - 1));
}
if (marker != 0) {
rex::cvar::SetFlagByName("skate3_ultrawide_object_stage_marker", "0");
}
records.clear();
}
inline void Skate3UltrawideBeginObjectStageFrame(uint32_t site_id, uint32_t renderer) {
if (!Skate3UltrawideHasExpandedTargetAspect()) {
return;
}
if (renderer < 0x10000) {
return;
}
std::lock_guard lock(Skate3UltrawideObjectStageMutex());
Skate3UltrawideFinalizeObjectStageFrameLocked("frame");
++Skate3UltrawideObjectStageFrameId();
Skate3UltrawideObjectStageRenderer() = renderer;
if (Skate3UltrawideObjectStageTraceEnabled()) {
Skate3UltrawideWriteObjectStageLog(Skate3UltrawideObjectStageFrameId(), "begin", 0,
renderer, 0, 0, site_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
inline uint32_t Skate3UltrawideObjectStageBitForAction(std::string_view action) {
if (action == "render-active-v68") {
return kSkate3ObjectStageActive;
}
if (action == "render-prep-v48") {
return kSkate3ObjectStagePrep;
}
if (action == "render-list-v24") {
return kSkate3ObjectStageList;
}
if (action == "render-main-v52") {
return kSkate3ObjectStageMain;
}
return 0;
}
inline void Skate3UltrawideRecordObjectStage(const char* action, uint32_t site_id,
uint32_t object, uint32_t vtable,
uint32_t target, uint32_t aux0,
uint32_t aux1, uint32_t renderer) {
const uint32_t bit = Skate3UltrawideObjectStageBitForAction(action ? action : "");
if (!bit || !object || !Skate3UltrawideHasExpandedTargetAspect()) {
return;
}
std::lock_guard lock(Skate3UltrawideObjectStageMutex());
auto& record = Skate3UltrawideObjectStageRecords()[object];
if (!record.bits) {
record.first_site = site_id;
record.vtable = vtable;
record.target = target;
}
record.bits |= bit;
record.last_site = site_id;
record.aux0 = aux0;
record.aux1 = aux1;
if (vtable) {
record.vtable = vtable;
}
if (target) {
record.target = target;
}
if (renderer >= 0x10000) {
Skate3UltrawideObjectStageRenderer() = renderer;
}
}
inline uint32_t Skate3UltrawideMaybeForceMainObjectActive(uint32_t site_id,
uint32_t native_value) {
rex::graphics::ultrawide_debug::RecordScreenCallback(
rex::graphics::ultrawide_debug::ScreenCallbackKind::kScreenFlag, site_id, native_value);
if (!Skate3UltrawideHasExpandedTargetAspect() ||
!rex::cvar::Query<bool>("skate3_ultrawide_force_main_visibility_flags")) {
return native_value;
}
rex::graphics::ultrawide_debug::RecordScreenCallbackResult(
rex::graphics::ultrawide_debug::ScreenCallbackKind::kScreenFlag, site_id, native_value, 1);
return 1;
}
inline uint32_t Skate3UltrawideMaybeForceWorldPartVisible(uint32_t site_id,
uint32_t native_value,
uint32_t sibling_value) {
rex::graphics::ultrawide_debug::RecordScreenCallback(
rex::graphics::ultrawide_debug::ScreenCallbackKind::kScreenFlag, site_id, native_value);
if (native_value != 0 || sibling_value == 0 || !Skate3UltrawideHasExpandedTargetAspect() ||
!rex::cvar::Query<bool>("skate3_ultrawide_force_main_visibility_flags")) {
return native_value;
}
rex::graphics::ultrawide_debug::RecordScreenCallbackResult(
rex::graphics::ultrawide_debug::ScreenCallbackKind::kScreenFlag, site_id, native_value, 1);
return 1;
}
inline std::filesystem::path Skate3UltrawideCacheLogPath(const char* filename) {
#if defined(_WIN32)
char* appdata_raw = nullptr;
size_t appdata_length = 0;
if (_dupenv_s(&appdata_raw, &appdata_length, "APPDATA") == 0 && appdata_raw &&
appdata_length > 0) {
std::filesystem::path appdata_path(appdata_raw);
std::free(appdata_raw);
return appdata_path / "skate3" / "cache" / filename;
}
std::free(appdata_raw);
#else
if (const char* appdata = std::getenv("APPDATA")) {
return std::filesystem::path(appdata) / "skate3" / "cache" / filename;
}
#endif
return filename;
}
inline void Skate3UltrawideTraceRenderVirtual(const char* action, uint32_t site_id,
uint32_t object_ptr, uint32_t vtable_ptr,
uint32_t target_ptr, uint32_t aux0 = 0,
uint32_t aux1 = 0, uint32_t renderer = 0) {
Skate3UltrawideRecordObjectStage(action, site_id, object_ptr, vtable_ptr, target_ptr, aux0,
aux1, renderer);
}