scene: native pause menu + render-mode corner indicator
This commit is contained in:
parent
b4d2e59b70
commit
302ba69241
7 changed files with 190 additions and 20 deletions
|
|
@ -11,6 +11,12 @@
|
||||||
// stretch back, reproducing both the kernel and the lattice.
|
// stretch back, reproducing both the kernel and the lattice.
|
||||||
cbuffer C : register(b0) {
|
cbuffer C : register(b0) {
|
||||||
float4 dir; // xy = blur axis, z = kernel scale (the game's PS c0.x, 8)
|
float4 dir; // xy = blur axis, z = kernel scale (the game's PS c0.x, 8)
|
||||||
|
float4 tint; // rgb = the game's PS c1 of the blur pass: the menu fade
|
||||||
|
// modulate. Both blur ucodes end in `mul oC0, r0, c1`, so it
|
||||||
|
// applies PER PASS (squared overall). Gameplay popups stage
|
||||||
|
// (1,1,1), why the original port had no multiply, the
|
||||||
|
// pause menu stages ~(0.35,0.33,0.32) = the darkened
|
||||||
|
// backdrop (measured in a live pause-menu capture).
|
||||||
};
|
};
|
||||||
Texture2D<float4> src : register(t0);
|
Texture2D<float4> src : register(t0);
|
||||||
SamplerState smp_clamp : register(s1);
|
SamplerState smp_clamp : register(s1);
|
||||||
|
|
@ -35,7 +41,7 @@ float4 ps_main(VSOut i) : SV_Target {
|
||||||
c += src.SampleLevel(smp_clamp, i.uv + step * k, 0).rgb * w[k];
|
c += src.SampleLevel(smp_clamp, i.uv + step * k, 0).rgb * w[k];
|
||||||
c += src.SampleLevel(smp_clamp, i.uv - step * k, 0).rgb * w[k];
|
c += src.SampleLevel(smp_clamp, i.uv - step * k, 0).rgb * w[k];
|
||||||
}
|
}
|
||||||
return float4(c, 1.0);
|
return float4(c * tint.rgb, 1.0);
|
||||||
}
|
}
|
||||||
// Prefiltered downsample of the (higher-res) native output into the game's
|
// Prefiltered downsample of the (higher-res) native output into the game's
|
||||||
// 1152x640 blur space (dir.xy = source texel size). A 4x4 grid of bilinear
|
// 1152x640 blur space (dir.xy = source texel size). A 4x4 grid of bilinear
|
||||||
|
|
|
||||||
|
|
@ -702,7 +702,10 @@ std::optional<rex::PathConfig> Skate3BaseApp::OnFinalizePaths(
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skate3BaseApp::OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) {
|
void Skate3BaseApp::OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) {
|
||||||
(void)drawer;
|
// Always-on native/emulated corner readout (top right; cvar
|
||||||
|
// skate3_native_render_mode_indicator hides it live). Input-transparent,
|
||||||
|
// so it never affects cursor or focus handling.
|
||||||
|
render_mode_indicator_ = std::make_unique<skate3::RenderModeIndicator>(drawer);
|
||||||
rex::ui::RegisterBind("bind_skate3_menu", "Escape", "Skate 3 settings", [this] {
|
rex::ui::RegisterBind("bind_skate3_menu", "Escape", "Skate 3 settings", [this] {
|
||||||
ToggleSimpleSettings();
|
ToggleSimpleSettings();
|
||||||
});
|
});
|
||||||
|
|
@ -802,6 +805,7 @@ void Skate3BaseApp::OnShutdown() {
|
||||||
simple_settings_dialog_.reset();
|
simple_settings_dialog_.reset();
|
||||||
ultrawide_targets_dialog_.reset();
|
ultrawide_targets_dialog_.reset();
|
||||||
native_debug_dialog_.reset();
|
native_debug_dialog_.reset();
|
||||||
|
render_mode_indicator_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skate3BaseApp::ToggleSimpleSettings() {
|
void Skate3BaseApp::ToggleSimpleSettings() {
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ class Skate3BaseApp : public rex::ReXApp {
|
||||||
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<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_;
|
||||||
bool recipe_overlay_installed_ = false;
|
bool recipe_overlay_installed_ = false;
|
||||||
bool big_device_aliases_installed_ = false;
|
bool big_device_aliases_installed_ = false;
|
||||||
std::atomic<uint32_t> debug_marker_count_{0};
|
std::atomic<uint32_t> debug_marker_count_{0};
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,16 @@
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
#include <rex/cvar.h>
|
#include <rex/cvar.h>
|
||||||
|
#include <rex/graphics/native_guest_renderer.h>
|
||||||
|
|
||||||
#include "skate3_native_scene.h"
|
#include "skate3_native_scene.h"
|
||||||
|
|
||||||
|
REXCVAR_DEFINE_BOOL(skate3_native_render_mode_indicator, true, "Skate 3",
|
||||||
|
"Small top-right corner readout of which renderer produced the "
|
||||||
|
"last presented frame: NATIVE (native scene renderer) or "
|
||||||
|
"EMULATED (Xenos GPU emulation: menus/loading yields, F5 off).")
|
||||||
|
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
||||||
|
|
||||||
// Hook-layer master (boot-time), shown read-only.
|
// Hook-layer master (boot-time), shown read-only.
|
||||||
REXCVAR_DECLARE(bool, skate3_native_render);
|
REXCVAR_DECLARE(bool, skate3_native_render);
|
||||||
// Hot-reload feature gates (skate3_native_scene.cpp).
|
// Hot-reload feature gates (skate3_native_scene.cpp).
|
||||||
|
|
@ -400,4 +407,23 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderModeIndicator::OnDraw(ImGuiIO& io) {
|
||||||
|
if (!REXCVAR_GET(skate3_native_render_mode_indicator)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const bool native = rex::graphics::IsNativeGuestOutputActive();
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x - 10.0f, 10.0f), ImGuiCond_Always,
|
||||||
|
ImVec2(1.0f, 0.0f));
|
||||||
|
ImGui::SetNextWindowBgAlpha(0.35f);
|
||||||
|
ImGui::Begin("##render_mode_indicator", nullptr,
|
||||||
|
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs |
|
||||||
|
ImGuiWindowFlags_AlwaysAutoResize |
|
||||||
|
ImGuiWindowFlags_NoSavedSettings |
|
||||||
|
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav);
|
||||||
|
ImGui::TextColored(native ? ImVec4(0.35f, 1.0f, 0.45f, 1.0f)
|
||||||
|
: ImVec4(1.0f, 0.65f, 0.25f, 1.0f),
|
||||||
|
"%s", native ? "NATIVE" : "EMULATED");
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace skate3
|
} // namespace skate3
|
||||||
|
|
|
||||||
|
|
@ -24,4 +24,18 @@ class NativeDebugDialog final : public rex::ui::ImGuiDialog {
|
||||||
bool visible_ = false;
|
bool visible_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Tiny always-on top-right corner readout of which renderer produced the
|
||||||
|
// last presented frame: NATIVE (native scene renderer) or EMULATED (Xenos
|
||||||
|
// GPU emulation; menus/loading yields, F5 off). Input-transparent, no
|
||||||
|
// continuous repaint (updates ride the guest frame paints); hidden via
|
||||||
|
// skate3_native_render_mode_indicator (hot).
|
||||||
|
class RenderModeIndicator final : public rex::ui::ImGuiDialog {
|
||||||
|
public:
|
||||||
|
explicit RenderModeIndicator(rex::ui::ImGuiDrawer* drawer) : ImGuiDialog(drawer) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool WantsContinuousRepaint() const override { return false; }
|
||||||
|
void OnDraw(ImGuiIO& io) override;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace skate3
|
} // namespace skate3
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,16 @@ REXCVAR_DEFINE_BOOL(skate3_native_render_scene_photo_yield, true, "Skate 3",
|
||||||
"is fine. Detected by polling the FrontEndManager NIS push-state "
|
"is fine. Detected by polling the FrontEndManager NIS push-state "
|
||||||
"stack (plus the PhotoReplayController heartbeat as a backup).")
|
"stack (plus the PhotoReplayController heartbeat as a backup).")
|
||||||
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
||||||
|
REXCVAR_DEFINE_BOOL(skate3_native_render_scene_pause_native, true, "Skate 3",
|
||||||
|
"Keep the NATIVE renderer active through the in-game pause menu "
|
||||||
|
"instead of yielding to the emulated output. Pause is told apart "
|
||||||
|
"from loading screens / the boot frontend by the world still "
|
||||||
|
"submitting perspective scenes while the presence context reads 0 "
|
||||||
|
"(loads and the frontend stop publishing within ~300 ms, which "
|
||||||
|
"falls back to the yield path and its cache clears). Native pause "
|
||||||
|
"also skips the pause-entry cache clears, so unpausing costs "
|
||||||
|
"nothing.")
|
||||||
|
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
||||||
REXCVAR_DEFINE_BOOL(skate3_native_render_snapshot_all_draws, false, "Skate 3",
|
REXCVAR_DEFINE_BOOL(skate3_native_render_snapshot_all_draws, false, "Skate 3",
|
||||||
"Record the draw stream on every recorded frame instead of 2 of every "
|
"Record the draw stream on every recorded frame instead of 2 of every "
|
||||||
"60 (large .draws.bin; for targeted investigations)")
|
"60 (large .draws.bin; for targeted investigations)")
|
||||||
|
|
@ -488,6 +498,12 @@ std::mutex g_scene_mutex;
|
||||||
// vectors) every frame.
|
// vectors) every frame.
|
||||||
std::shared_ptr<const FrameScene> g_scene;
|
std::shared_ptr<const FrameScene> g_scene;
|
||||||
uint64_t g_generation = 0;
|
uint64_t g_generation = 0;
|
||||||
|
// Steady-clock stamp of the last scene publish (BuildFrameScene only
|
||||||
|
// publishes when a perspective view submitted this frame). YieldForMenus
|
||||||
|
// uses its freshness to tell the in-game pause menu (the world keeps
|
||||||
|
// resubmitting behind the menu) apart from loading screens and the boot
|
||||||
|
// frontend (publishes stop), for skate3_native_render_scene_pause_native.
|
||||||
|
std::atomic<int64_t> g_last_publish_ns{-1};
|
||||||
// Debug-dialog cache flushes: consumed at the top of RenderScene so texture/
|
// Debug-dialog cache flushes: consumed at the top of RenderScene so texture/
|
||||||
// mesh-affecting toggles (mip chains, 565 fixes, ...) take effect immediately
|
// mesh-affecting toggles (mip chains, 565 fixes, ...) take effect immediately
|
||||||
// instead of only for newly streamed content.
|
// instead of only for newly streamed content.
|
||||||
|
|
@ -666,6 +682,15 @@ bool g_sky_sun_have = false;
|
||||||
// popup is actually up, so this can never stick on.
|
// popup is actually up, so this can never stick on.
|
||||||
float g_ui_blur = 8.0f;
|
float g_ui_blur = 8.0f;
|
||||||
bool g_ui_blur_seen = false;
|
bool g_ui_blur_seen = false;
|
||||||
|
// Blur modulate color (the blur passes' PS c1): both blur ucodes end in
|
||||||
|
// `mul oC0, r0, c1`: the game's menu fade. Gameplay popups stage (1,1,1)
|
||||||
|
// (why the exact port originally had no multiply); the pause menu stages
|
||||||
|
// ~(0.35,0.33,0.32), squared across the H+V passes = the darkened pause
|
||||||
|
// backdrop. Read live on the blur_hBlurPS draw, accepted only when the
|
||||||
|
// bank's c0 kernel row reads exactly (8,8); a stale mid-stage bank fails
|
||||||
|
// that gate (the staleness class that pulsed the blur radius when c0.x was
|
||||||
|
// fed live, see g_ui_blur above).
|
||||||
|
float g_ui_blur_color[3] = {1.0f, 1.0f, 1.0f};
|
||||||
// Hold the blur across publishes that carry no blur draw: the game does not
|
// Hold the blur across publishes that carry no blur draw: the game does not
|
||||||
// issue the pass chain on every swap while the popup is up, and publishing
|
// issue the pass chain on every swap while the popup is up, and publishing
|
||||||
// the raw per-swap flag alternated blur on/off: a visible brightness
|
// the raw per-swap flag alternated blur on/off: a visible brightness
|
||||||
|
|
@ -4031,6 +4056,23 @@ void OnDrawDone(uint8_t* base, uint32_t func, uint32_t r4, uint32_t r5, uint32_t
|
||||||
// pulsed the blur radius; the popup backdrop shimmered.
|
// pulsed the blur radius; the popup backdrop shimmered.
|
||||||
g_ui_blur = 8.0f;
|
g_ui_blur = 8.0f;
|
||||||
g_ui_blur_seen = true;
|
g_ui_blur_seen = true;
|
||||||
|
// Fade modulate (PS c1, see g_ui_blur_color): genuinely dynamic (the
|
||||||
|
// pause fade ramps in over a few frames), so it must be read live,
|
||||||
|
// gated on the c0 kernel row reading exactly its known (8,8) staging,
|
||||||
|
// which a stale mid-update bank fails. NaN also fails the comparisons.
|
||||||
|
const uint32_t ps_bank = g_ps_bank.load(std::memory_order_relaxed);
|
||||||
|
if (ps_bank != 0) {
|
||||||
|
const float k0 = LoadGuestF32(base, ps_bank + 0);
|
||||||
|
const float k1 = LoadGuestF32(base, ps_bank + 4);
|
||||||
|
float c1[3];
|
||||||
|
for (int a = 0; a < 3; ++a) {
|
||||||
|
c1[a] = LoadGuestF32(base, ps_bank + 16 + a * 4);
|
||||||
|
}
|
||||||
|
if (k0 == 8.0f && k1 == 8.0f && c1[0] >= 0.0f && c1[0] <= 1.0f &&
|
||||||
|
c1[1] >= 0.0f && c1[1] <= 1.0f && c1[2] >= 0.0f && c1[2] <= 1.0f) {
|
||||||
|
std::memcpy(g_ui_blur_color, c1, sizeof(g_ui_blur_color));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Selected-object outline capture (see g_frame_selected): the sky draw
|
// Selected-object outline capture (see g_frame_selected): the sky draw
|
||||||
|
|
@ -7678,6 +7720,7 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
|
||||||
}
|
}
|
||||||
const bool blur_active = g_ui_blur_seen || g_ui_blur_hold > 0;
|
const bool blur_active = g_ui_blur_seen || g_ui_blur_hold > 0;
|
||||||
scene.ui_blur = blur_active ? g_ui_blur : 0.0f;
|
scene.ui_blur = blur_active ? g_ui_blur : 0.0f;
|
||||||
|
std::memcpy(scene.ui_blur_color, g_ui_blur_color, sizeof(scene.ui_blur_color));
|
||||||
if (g_ui_blur_seen) {
|
if (g_ui_blur_seen) {
|
||||||
g_ui_blur_hold = 2;
|
g_ui_blur_hold = 2;
|
||||||
} else if (g_ui_blur_hold > 0) {
|
} else if (g_ui_blur_hold > 0) {
|
||||||
|
|
@ -7686,9 +7729,17 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
|
||||||
{
|
{
|
||||||
static bool s_blur_was_active = false;
|
static bool s_blur_was_active = false;
|
||||||
if (blur_active != s_blur_was_active) {
|
if (blur_active != s_blur_was_active) {
|
||||||
REXLOG_INFO("native-scene: popup background blur {} (kernel scale {:.1f})",
|
REXLOG_INFO(
|
||||||
blur_active ? "ON" : "off", g_ui_blur);
|
"native-scene: popup background blur {} (kernel scale {:.1f}, fade "
|
||||||
|
"{:.2f}/{:.2f}/{:.2f})",
|
||||||
|
blur_active ? "ON" : "off", g_ui_blur, g_ui_blur_color[0],
|
||||||
|
g_ui_blur_color[1], g_ui_blur_color[2]);
|
||||||
s_blur_was_active = blur_active;
|
s_blur_was_active = blur_active;
|
||||||
|
if (!blur_active) {
|
||||||
|
// Don't carry one popup's fade into the next popup's first frame
|
||||||
|
// if its own c1 read misses the coherence gate.
|
||||||
|
g_ui_blur_color[0] = g_ui_blur_color[1] = g_ui_blur_color[2] = 1.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_ui_blur_seen = false;
|
g_ui_blur_seen = false;
|
||||||
|
|
@ -7884,6 +7935,10 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
|
||||||
.count()));
|
.count()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_last_publish_ns.store(std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||||
|
std::chrono::steady_clock::now().time_since_epoch())
|
||||||
|
.count(),
|
||||||
|
std::memory_order_relaxed);
|
||||||
std::lock_guard<std::mutex> lock(g_scene_mutex);
|
std::lock_guard<std::mutex> lock(g_scene_mutex);
|
||||||
scene.generation = ++g_generation;
|
scene.generation = ++g_generation;
|
||||||
g_scene = std::make_shared<const FrameScene>(std::move(scene));
|
g_scene = std::make_shared<const FrameScene>(std::move(scene));
|
||||||
|
|
@ -12897,13 +12952,56 @@ void PrewarmCommit(const NativeGuestOutputRenderContext& context,
|
||||||
// output. Handles the cache clears on entry and the takeover re-arm +
|
// output. Handles the cache clears on entry and the takeover re-arm +
|
||||||
// loading-screen pipeline build / prewarm commit while yielded.
|
// loading-screen pipeline build / prewarm commit while yielded.
|
||||||
bool YieldForMenus(const NativeGuestOutputRenderContext& context) {
|
bool YieldForMenus(const NativeGuestOutputRenderContext& context) {
|
||||||
static bool s_in_menus = false;
|
static bool s_yielding = false;
|
||||||
|
static bool s_seen_gameplay = false;
|
||||||
|
static bool s_pause_native = false;
|
||||||
const bool in_menus = rex::graphics::ultrawide_debug::Skate3GameplayContextValue() == 0;
|
const bool in_menus = rex::graphics::ultrawide_debug::Skate3GameplayContextValue() == 0;
|
||||||
if (in_menus != s_in_menus) {
|
if (!in_menus) {
|
||||||
s_in_menus = in_menus;
|
s_seen_gameplay = true;
|
||||||
if (in_menus) {
|
}
|
||||||
|
// In-game pause menu: the presence context reads 0, but the world keeps
|
||||||
|
// resubmitting perspective scenes behind the menu (loading screens and the
|
||||||
|
// boot frontend stop publishing): stay native there so the pause backdrop
|
||||||
|
// renders natively and the caches survive the pause. The 2D pause UI rides
|
||||||
|
// the same captured-APT overlay replay as the gameplay HUD. If publishes
|
||||||
|
// go stale (a load was picked from the pause menu, or the game stops
|
||||||
|
// redrawing the world), this degrades to the yield path below within
|
||||||
|
// ~300 ms, cache clears and all.
|
||||||
|
bool pause_native = false;
|
||||||
|
if (in_menus && s_seen_gameplay &&
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_pause_native)) {
|
||||||
|
const int64_t last_ns = g_last_publish_ns.load(std::memory_order_relaxed);
|
||||||
|
const int64_t now_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||||
|
std::chrono::steady_clock::now().time_since_epoch())
|
||||||
|
.count();
|
||||||
|
pause_native = last_ns >= 0 && now_ns - last_ns < 300'000'000;
|
||||||
|
}
|
||||||
|
if (pause_native != s_pause_native) {
|
||||||
|
s_pause_native = pause_native;
|
||||||
|
if (pause_native) {
|
||||||
REXLOG_INFO(
|
REXLOG_INFO(
|
||||||
"native-scene: menus/pause/loading - yielding to emulated output "
|
"native-scene: pause menu over live world - staying NATIVE "
|
||||||
|
"(2d stats at entry: draws_2d={} other={} dropped={})",
|
||||||
|
g_draws_2d.load(std::memory_order_relaxed),
|
||||||
|
g_draws_2d_other.load(std::memory_order_relaxed),
|
||||||
|
g_draws_2d_dropped.load(std::memory_order_relaxed));
|
||||||
|
} else {
|
||||||
|
REXLOG_INFO(
|
||||||
|
"native-scene: leaving native pause ({}; 2d stats at exit: "
|
||||||
|
"draws_2d={} other={} dropped={})",
|
||||||
|
in_menus ? "scene publishes went stale - loading/frontend"
|
||||||
|
: "gameplay resumed",
|
||||||
|
g_draws_2d.load(std::memory_order_relaxed),
|
||||||
|
g_draws_2d_other.load(std::memory_order_relaxed),
|
||||||
|
g_draws_2d_dropped.load(std::memory_order_relaxed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const bool yield = in_menus && !pause_native;
|
||||||
|
if (yield != s_yielding) {
|
||||||
|
s_yielding = yield;
|
||||||
|
if (yield) {
|
||||||
|
REXLOG_INFO(
|
||||||
|
"native-scene: menus/loading - yielding to emulated output "
|
||||||
"(presence context)");
|
"(presence context)");
|
||||||
// Arena addresses are reused across map loads: let the next load's
|
// Arena addresses are reused across map loads: let the next load's
|
||||||
// registrations re-queue meshes (and re-stage textures) at reused
|
// registrations re-queue meshes (and re-stage textures) at reused
|
||||||
|
|
@ -12927,7 +13025,7 @@ bool YieldForMenus(const NativeGuestOutputRenderContext& context) {
|
||||||
g_prewarm_dropped.load(std::memory_order_relaxed), queued);
|
g_prewarm_dropped.load(std::memory_order_relaxed), queued);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (in_menus) {
|
if (yield) {
|
||||||
// Re-arm the takeover gate for the next stretch of gameplay (map
|
// Re-arm the takeover gate for the next stretch of gameplay (map
|
||||||
// load, unpause).
|
// load, unpause).
|
||||||
g_warmup_armed.store(true, std::memory_order_relaxed);
|
g_warmup_armed.store(true, std::memory_order_relaxed);
|
||||||
|
|
@ -13509,11 +13607,13 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
|
||||||
if (!SceneEnabled() || context.backend != NativeGuestOutputBackend::kD3D12) {
|
if (!SceneEnabled() || context.backend != NativeGuestOutputBackend::kD3D12) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// While the game reports menus / pause / loading (presence context 0x8001
|
// While the game reports menus / loading (presence context 0x8001 == 0),
|
||||||
// == 0), yield to the emulated output: the native scene neither renders
|
// yield to the emulated output, EXCEPT the in-game pause menu (world
|
||||||
// the 2D UI (the pause menu was invisible) nor the menu's world backdrop
|
// still publishing perspective scenes), which stays native when
|
||||||
// materials (everything drew untextured white). The emulated frame is
|
// skate3_native_render_scene_pause_native is on: the pause UI rides the
|
||||||
// complete and correct there; native rendering resumes on unpause.
|
// same captured-APT 2D replay as the gameplay HUD, and the backdrop is the
|
||||||
|
// ordinary native world. Loading screens and the boot frontend still
|
||||||
|
// render emulated (complete and correct there).
|
||||||
if (YieldForMenus(context)) {
|
if (YieldForMenus(context)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -15389,8 +15489,15 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
|
||||||
flush();
|
flush();
|
||||||
list.D3DOMSetRenderTargets(1, &blur_rtv1, FALSE, nullptr);
|
list.D3DOMSetRenderTargets(1, &blur_rtv1, FALSE, nullptr);
|
||||||
list.D3DSetPipelineState(g_r.pso_blur);
|
list.D3DSetPipelineState(g_r.pso_blur);
|
||||||
const float h_consts[4] = {1.0f, 0.0f, scene.ui_blur, 0.0f};
|
const float h_consts[8] = {1.0f,
|
||||||
list.D3DSetGraphicsRoot32BitConstants(0, 4, h_consts, 0);
|
0.0f,
|
||||||
|
scene.ui_blur,
|
||||||
|
0.0f,
|
||||||
|
scene.ui_blur_color[0],
|
||||||
|
scene.ui_blur_color[1],
|
||||||
|
scene.ui_blur_color[2],
|
||||||
|
1.0f};
|
||||||
|
list.D3DSetGraphicsRoot32BitConstants(0, 8, h_consts, 0);
|
||||||
srv_table(g_r.blur_srv[0]);
|
srv_table(g_r.blur_srv[0]);
|
||||||
list.D3DDrawInstanced(3, 1, 0, 0);
|
list.D3DDrawInstanced(3, 1, 0, 0);
|
||||||
// V: blur_tex[1] -> blur_tex[0].
|
// V: blur_tex[1] -> blur_tex[0].
|
||||||
|
|
@ -15398,8 +15505,15 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
|
||||||
to_rt(g_r.blur_tex[0]);
|
to_rt(g_r.blur_tex[0]);
|
||||||
flush();
|
flush();
|
||||||
list.D3DOMSetRenderTargets(1, &blur_rtv0, FALSE, nullptr);
|
list.D3DOMSetRenderTargets(1, &blur_rtv0, FALSE, nullptr);
|
||||||
const float v_consts[4] = {0.0f, 1.0f, scene.ui_blur, 0.0f};
|
const float v_consts[8] = {0.0f,
|
||||||
list.D3DSetGraphicsRoot32BitConstants(0, 4, v_consts, 0);
|
1.0f,
|
||||||
|
scene.ui_blur,
|
||||||
|
0.0f,
|
||||||
|
scene.ui_blur_color[0],
|
||||||
|
scene.ui_blur_color[1],
|
||||||
|
scene.ui_blur_color[2],
|
||||||
|
1.0f};
|
||||||
|
list.D3DSetGraphicsRoot32BitConstants(0, 8, v_consts, 0);
|
||||||
srv_table(g_r.blur_srv[1]);
|
srv_table(g_r.blur_srv[1]);
|
||||||
list.D3DDrawInstanced(3, 1, 0, 0);
|
list.D3DDrawInstanced(3, 1, 0, 0);
|
||||||
// Replace: blur_tex[0] stretched over the full output (basictex).
|
// Replace: blur_tex[0] stretched over the full output (basictex).
|
||||||
|
|
|
||||||
|
|
@ -300,6 +300,11 @@ struct FrameScene {
|
||||||
// capture), detected per frame from the blur_hBlurPS draw. The native
|
// capture), detected per frame from the blur_hBlurPS draw. The native
|
||||||
// replica runs after the MSAA resolve, before the 2D overlay draws.
|
// replica runs after the MSAA resolve, before the 2D overlay draws.
|
||||||
float ui_blur = 0.0f;
|
float ui_blur = 0.0f;
|
||||||
|
// Blur modulate color (the blur passes' PS c1; both blur ucodes end in
|
||||||
|
// `mul oC0, r0, c1`, so it applies per pass): (1,1,1) under gameplay
|
||||||
|
// popups, the dark menu fade in the pause menu; its square is the
|
||||||
|
// darkened pause backdrop.
|
||||||
|
float ui_blur_color[3] = {1.0f, 1.0f, 1.0f};
|
||||||
// Selection-outline color (postfx_edgedetectstencilPS c0; the park-editor
|
// Selection-outline color (postfx_edgedetectstencilPS c0; the park-editor
|
||||||
// blue in every capture), refreshed from the guest edge-detect draw when
|
// blue in every capture), refreshed from the guest edge-detect draw when
|
||||||
// it runs. Consumed by the outline composite when any item is selected.
|
// it runs. Consumed by the outline composite when any item is selected.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue