render: compile the showcase gates out of the standard shader variants
This commit is contained in:
parent
137d97c190
commit
7fa9585285
8 changed files with 13520 additions and 32 deletions
|
|
@ -364,8 +364,17 @@ float4 ps_tonemap(VSOut i) : SV_Target {
|
|||
// 256 + the layer mask left/right of the split at sh_v2.w (output
|
||||
// pixels), 0 = off. Post layers reveal per pixel by their mask bits:
|
||||
// AO 16, volumetrics 64, bloom 128 (SSR gates in its own composite).
|
||||
// Compiled in only for the SHOWCASE=1 variant; the default build folds
|
||||
// the mask to off and every gate below dead-strips.
|
||||
#ifndef SHOWCASE
|
||||
#define SHOWCASE 0
|
||||
#endif
|
||||
#if SHOWCASE
|
||||
float scv = i.pos.x < sh_v2.w ? sh_v2.y : sh_v2.z;
|
||||
int sc_mask = scv < 255.5 ? -1 : (int)(scv + 0.5) - 256;
|
||||
#else
|
||||
const int sc_mask = -1;
|
||||
#endif
|
||||
float ao = ao_plane.SampleLevel(smp_linear, i.uv, 0);
|
||||
if (sc_mask >= 0 && (sc_mask & 16) == 0) {
|
||||
ao = 1.0;
|
||||
|
|
@ -446,6 +455,7 @@ float4 ps_tonemap(VSOut i) : SV_Target {
|
|||
// overpass) saturated to a solid black void.
|
||||
float3 outc =
|
||||
ToneMapScene((x + haze) * (1.0 - 0.55 * saturate(shaft)) + bloom);
|
||||
#if SHOWCASE
|
||||
// Showcase divider: a soft white line at the split while a wipe is in
|
||||
// flight (the two sides show different stages).
|
||||
if (sh_v2.w > 0.5 && abs(sh_v2.y - sh_v2.z) > 0.5) {
|
||||
|
|
@ -454,5 +464,6 @@ float4 ps_tonemap(VSOut i) : SV_Target {
|
|||
outc = lerp(outc, float3(1.0, 1.0, 1.0),
|
||||
saturate(1.0 - d / half_w) * 0.85);
|
||||
}
|
||||
#endif
|
||||
return float4(outc, 1.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,9 +157,20 @@ VSOut vs_main(float3 p : POSITION, float2 uv : TEXCOORD0, float2 uv2 : TEXCOORD1
|
|||
// content belongs to the normal frame and stays hidden until the bit
|
||||
// reveals (the sequencer folds their bits into every step when the layer
|
||||
// is not part of the run). Returns -1 when the showcase is off.
|
||||
// The showcase code compiles in only for the SHOWCASE=1 shader variants,
|
||||
// which the pipeline family swaps in for the duration of a run. The default
|
||||
// build folds the mask to the off value, so every showcase branch
|
||||
// dead-strips and the program matches the pre-showcase compile exactly.
|
||||
#ifndef SHOWCASE
|
||||
#define SHOWCASE 0
|
||||
#endif
|
||||
int ShowcaseMask(float px_x) {
|
||||
#if SHOWCASE
|
||||
float v = px_x < sh_v2.w ? sh_v2.y : sh_v2.z;
|
||||
return v < 255.5 ? -1 : (int)(v + 0.5) - 256;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
// True when the given layer bit is revealed on this pixel's side of the
|
||||
// split (or the showcase is off entirely).
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -54,9 +54,18 @@ float3 SplineOut(float3 c) {
|
|||
// Showcase blackout gate: the spline pass draws outside the scene shaders,
|
||||
// so ps_main's blackout stage (scene.hlsl, mask bit 1024) cannot cover it;
|
||||
// without this the neon lines leak over the black recording bookends.
|
||||
// Compiled in only for the SHOWCASE=1 variant swapped in during a run; the
|
||||
// default build folds to visible and the gate dead-strips.
|
||||
#ifndef SHOWCASE
|
||||
#define SHOWCASE 0
|
||||
#endif
|
||||
bool SplineVisible(float px_x) {
|
||||
#if SHOWCASE
|
||||
int bits = (int)(intensity.w + 0.5);
|
||||
return ((px_x < intensity.z ? 1 : 2) & bits) != 0;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
float4 ps_default(VSOut i) : SV_Target {
|
||||
if (!SplineVisible(i.pos.x)) {
|
||||
|
|
|
|||
|
|
@ -285,11 +285,17 @@ float4 ps_march(VSOut i) : SV_Target {
|
|||
}
|
||||
|
||||
float4 ps_composite(VSOut i) : SV_Target {
|
||||
#ifndef SHOWCASE
|
||||
#define SHOWCASE 0
|
||||
#endif
|
||||
#if SHOWCASE
|
||||
// Showcase gate: alpha 0 leaves the scene plane untouched on a side
|
||||
// whose build-up stage has not revealed reflections yet.
|
||||
// whose build-up stage has not revealed reflections yet. Compiled in
|
||||
// only for the SHOWCASE=1 variant swapped in during a run.
|
||||
if ((i.pos.x < p2.x ? p2.y : p2.z) < 0.5f) {
|
||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
#endif
|
||||
float4 g = tex1c.SampleLevel(smp_point, i.uv, 0);
|
||||
float wrefl = abs(g.a);
|
||||
float dbg = p0.w;
|
||||
|
|
|
|||
|
|
@ -2656,15 +2656,31 @@ bool EnsureScenePsoFamily(const NativeGuestOutputRenderContext& context) {
|
|||
}
|
||||
|
||||
// HDR=1 switches the pixel shader's output encode to pre-tonemap linear
|
||||
// (see scene.hlsl ToneOut/PassGamma).
|
||||
const nrhi::ShaderMacro hdr_defs[] = {{"HDR", "1"}, {nullptr, nullptr}};
|
||||
// (see scene.hlsl ToneOut/PassGamma); SHOWCASE=1 compiles the build-up
|
||||
// split/mask gates in (swapped in only while a run is live). The variant
|
||||
// string is the canonical ";"-joined macro signature the offline SPIR-V
|
||||
// matrix uses.
|
||||
nrhi::ShaderMacro ps_defs[3];
|
||||
uint32_t ps_def_count = 0;
|
||||
if (g_r.hdr_active) {
|
||||
ps_defs[ps_def_count++] = {"HDR", "1"};
|
||||
}
|
||||
if (g_r.showcase_shaders) {
|
||||
ps_defs[ps_def_count++] = {"SHOWCASE", "1"};
|
||||
}
|
||||
ps_defs[ps_def_count] = {nullptr, nullptr};
|
||||
char ps_variant[24];
|
||||
std::snprintf(ps_variant, sizeof(ps_variant), "%s%s%s",
|
||||
g_r.hdr_active ? "HDR=1" : "",
|
||||
g_r.hdr_active && g_r.showcase_shaders ? ";" : "",
|
||||
g_r.showcase_shaders ? "SHOWCASE=1" : "");
|
||||
nrhi::Shader* vs = device->CreateShader(
|
||||
MakeShaderDesc(nrhi::ShaderStage::kVertex, "scene.hlsl", kShaderSource,
|
||||
"vs_main", nullptr, ""));
|
||||
nrhi::Shader* ps = device->CreateShader(
|
||||
MakeShaderDesc(nrhi::ShaderStage::kPixel, "scene.hlsl", kShaderSource,
|
||||
"ps_main", g_r.hdr_active ? hdr_defs : nullptr,
|
||||
g_r.hdr_active ? "HDR=1" : ""));
|
||||
"ps_main", ps_def_count != 0 ? ps_defs : nullptr,
|
||||
ps_variant));
|
||||
if (vs == nullptr || ps == nullptr) {
|
||||
REXLOG_ERROR("native-scene: shader compile failed");
|
||||
g_r.failed = true;
|
||||
|
|
@ -2995,18 +3011,34 @@ bool EnsureSplinePsos(const NativeGuestOutputRenderContext& context) {
|
|||
*p = nullptr;
|
||||
}
|
||||
}
|
||||
const nrhi::ShaderMacro hdr_defs[] = {{"HDR", "1"}, {nullptr, nullptr}};
|
||||
const nrhi::ShaderMacro* sp_defs = g_r.hdr_active ? hdr_defs : nullptr;
|
||||
const char* sp_variant = g_r.hdr_active ? "HDR=1" : "";
|
||||
// SHOWCASE=1 compiles the blackout gate in (see spline.hlsl
|
||||
// SplineVisible); like the scene family, the variant follows the
|
||||
// showcase swap so normal sessions carry no gate at all.
|
||||
nrhi::ShaderMacro sp_defs[3];
|
||||
uint32_t sp_def_count = 0;
|
||||
if (g_r.hdr_active) {
|
||||
sp_defs[sp_def_count++] = {"HDR", "1"};
|
||||
}
|
||||
if (g_r.showcase_shaders) {
|
||||
sp_defs[sp_def_count++] = {"SHOWCASE", "1"};
|
||||
}
|
||||
sp_defs[sp_def_count] = {nullptr, nullptr};
|
||||
char sp_variant[24];
|
||||
std::snprintf(sp_variant, sizeof(sp_variant), "%s%s%s",
|
||||
g_r.hdr_active ? "HDR=1" : "",
|
||||
g_r.hdr_active && g_r.showcase_shaders ? ";" : "",
|
||||
g_r.showcase_shaders ? "SHOWCASE=1" : "");
|
||||
nrhi::Shader* svs = device->CreateShader(
|
||||
MakeShaderDesc(nrhi::ShaderStage::kVertex, "spline.hlsl",
|
||||
kShaderSplineSource, "vs_main", nullptr, ""));
|
||||
nrhi::Shader* spd = device->CreateShader(
|
||||
MakeShaderDesc(nrhi::ShaderStage::kPixel, "spline.hlsl",
|
||||
kShaderSplineSource, "ps_default", sp_defs, sp_variant));
|
||||
kShaderSplineSource, "ps_default",
|
||||
sp_def_count != 0 ? sp_defs : nullptr, sp_variant));
|
||||
nrhi::Shader* spk = device->CreateShader(
|
||||
MakeShaderDesc(nrhi::ShaderStage::kPixel, "spline.hlsl",
|
||||
kShaderSplineSource, "ps_darken", sp_defs, sp_variant));
|
||||
kShaderSplineSource, "ps_darken",
|
||||
sp_def_count != 0 ? sp_defs : nullptr, sp_variant));
|
||||
if (svs == nullptr || spd == nullptr || spk == nullptr) {
|
||||
REXLOG_ERROR("native-scene: spline shader compile failed");
|
||||
g_r.failed = true;
|
||||
|
|
@ -3981,7 +4013,8 @@ bool EnsurePipeline(const NativeGuestOutputRenderContext& context) {
|
|||
if (!g_r.pso || g_r.rtv_format != context.guest_output->format() ||
|
||||
g_r.hdr_active != hdr_want ||
|
||||
(hdr_want && g_r.hdr_scene_format != hdr_fmt_want) ||
|
||||
g_r.msaa != msaa_want) {
|
||||
g_r.msaa != msaa_want ||
|
||||
g_r.showcase_shaders != g_r.showcase_shaders_want) {
|
||||
if (g_r.msaa != msaa_want && g_r.pfx_ready) {
|
||||
// The photo-postfx depth-pack pass is compiled against the depth
|
||||
// buffer's sample count (PFX_MSAA variant); retire the chain's PSOs
|
||||
|
|
@ -3997,14 +4030,24 @@ bool EnsurePipeline(const NativeGuestOutputRenderContext& context) {
|
|||
g_r.hdr_active = hdr_want;
|
||||
g_r.hdr_scene_format = hdr_fmt_want;
|
||||
g_r.msaa = msaa_want;
|
||||
g_r.showcase_shaders = g_r.showcase_shaders_want;
|
||||
if (!EnsureScenePsoFamily(context) || !EnsureResolvePso(context) ||
|
||||
!EnsureBlurPsos(context) || !EnsureOutlineEdgePso(context) ||
|
||||
!Ensure2dPso(context) || !EnsureSplinePsos(context) ||
|
||||
!EnsureShadowPsos(context)) {
|
||||
if (g_r.showcase_shaders) {
|
||||
// A showcase-variant build failure must not pin the sticky failure
|
||||
// latch: drop the swap request so the F5 retry rebuilds the
|
||||
// standard shaders.
|
||||
g_r.showcase_shaders_want = false;
|
||||
g_r.showcase_shaders = false;
|
||||
REXCVAR_SET(skate3_native_render_scene_showcase, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
REXLOG_INFO("native-scene: pipelines created (MSAA x{}, {})", g_r.msaa,
|
||||
g_r.hdr_active ? "HDR" : "classic");
|
||||
REXLOG_INFO("native-scene: pipelines created (MSAA x{}, {}{})", g_r.msaa,
|
||||
g_r.hdr_active ? "HDR" : "classic",
|
||||
g_r.showcase_shaders ? ", showcase variants" : "");
|
||||
g_r.rtv_format = context.guest_output->format();
|
||||
}
|
||||
|
||||
|
|
@ -6946,6 +6989,18 @@ static void TickShowcase(uint32_t output_width, bool hdr_on) {
|
|||
const bool want = REXCVAR_GET(skate3_native_render_scene_showcase);
|
||||
if (!s.active) {
|
||||
if (!want) {
|
||||
// No run pending: release the showcase shader swap (the next
|
||||
// EnsurePipeline rebuild returns the family to the standard
|
||||
// variants with the showcase code compiled out).
|
||||
g_r.showcase_shaders_want = false;
|
||||
return;
|
||||
}
|
||||
// The run's shaders carry the split/mask gates only in their
|
||||
// SHOWCASE=1 variants: request the swap and hold the start until the
|
||||
// next EnsurePipeline rebuild has them live (rows stay zero, so the
|
||||
// waiting frames render normally).
|
||||
g_r.showcase_shaders_want = true;
|
||||
if (!g_r.showcase_shaders) {
|
||||
return;
|
||||
}
|
||||
// Layer availability: the material looks need nothing; the shadow and
|
||||
|
|
@ -7082,6 +7137,7 @@ static void TickShowcase(uint32_t output_width, bool hdr_on) {
|
|||
}
|
||||
if (!want) {
|
||||
s.active = false;
|
||||
g_r.showcase_shaders_want = false;
|
||||
REXLOG_INFO("native-scene: showcase cancelled");
|
||||
return;
|
||||
}
|
||||
|
|
@ -7104,6 +7160,7 @@ static void TickShowcase(uint32_t output_width, bool hdr_on) {
|
|||
}
|
||||
if (idx >= int(s.steps.size())) {
|
||||
s.active = false;
|
||||
g_r.showcase_shaders_want = false;
|
||||
REXCVAR_SET(skate3_native_render_scene_showcase, false);
|
||||
REXLOG_INFO("native-scene: showcase finished");
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -636,6 +636,17 @@ struct RendererState {
|
|||
nrhi::Pipeline* pso_bloom_up = nullptr; // additive ONE/ONE tent upsample
|
||||
nrhi::Pipeline* pso_tonemap = nullptr;
|
||||
nrhi::Format hdr_pso_out_format = nrhi::Format::kUnknown;
|
||||
// Showcase shader swap: while a build-up run is live the pipeline family
|
||||
// rebuilds with the SHOWCASE=1 shader variants (the split/mask gates
|
||||
// compiled in); every other session runs shaders with the showcase code
|
||||
// compiled out entirely, so normal rendering carries none of it. _want is
|
||||
// set by TickShowcase (a run needs the variants BEFORE its first frame),
|
||||
// applied by the EnsurePipeline rebuild block; the per-pass built flags
|
||||
// let the lazily-built tonemap/SSR pipelines follow the swap.
|
||||
bool showcase_shaders_want = false;
|
||||
bool showcase_shaders = false;
|
||||
bool hdr_showcase = false;
|
||||
bool ssr_showcase = false;
|
||||
// 1x float scene plane: the MSAA resolve destination (or the scene target
|
||||
// itself when MSAA is off); the AO composite, bloom extract and tonemap
|
||||
// all consume/write it.
|
||||
|
|
|
|||
|
|
@ -460,7 +460,8 @@ bool EnsureSsrPipeline(const NativeGuestOutputRenderContext& context) {
|
|||
return false;
|
||||
}
|
||||
if (g_r.pso_ssr_march != nullptr && g_r.ssr_msaa == g_r.msaa &&
|
||||
g_r.ssr_scene_fmt == g_r.hdr_scene_format) {
|
||||
g_r.ssr_scene_fmt == g_r.hdr_scene_format &&
|
||||
g_r.ssr_showcase == g_r.showcase_shaders) {
|
||||
return true;
|
||||
}
|
||||
nrhi::Device* device = context.device;
|
||||
|
|
@ -519,9 +520,13 @@ bool EnsureSsrPipeline(const NativeGuestOutputRenderContext& context) {
|
|||
nrhi::Shader* ps_march = device->CreateShader(
|
||||
MakeShaderDesc(nrhi::ShaderStage::kPixel, "ssr.hlsl", kSsrShaderSource,
|
||||
"ps_march", nullptr, ""));
|
||||
nrhi::Shader* ps_comp = device->CreateShader(
|
||||
MakeShaderDesc(nrhi::ShaderStage::kPixel, "ssr.hlsl", kSsrShaderSource,
|
||||
"ps_composite", nullptr, ""));
|
||||
// The composite follows the showcase shader swap (its SHOWCASE=1 variant
|
||||
// carries the per-side reveal gate).
|
||||
const nrhi::ShaderMacro sc_defs[] = {{"SHOWCASE", "1"}, {nullptr, nullptr}};
|
||||
nrhi::Shader* ps_comp = device->CreateShader(MakeShaderDesc(
|
||||
nrhi::ShaderStage::kPixel, "ssr.hlsl", kSsrShaderSource, "ps_composite",
|
||||
g_r.showcase_shaders ? sc_defs : nullptr,
|
||||
g_r.showcase_shaders ? "SHOWCASE=1" : ""));
|
||||
const bool shaders_ok = scene_vs != nullptr && ps_gbuf != nullptr &&
|
||||
vs != nullptr && ps_lin != nullptr &&
|
||||
ps_march != nullptr && ps_comp != nullptr;
|
||||
|
|
@ -591,6 +596,7 @@ bool EnsureSsrPipeline(const NativeGuestOutputRenderContext& context) {
|
|||
}
|
||||
g_r.ssr_msaa = g_r.msaa;
|
||||
g_r.ssr_scene_fmt = g_r.hdr_scene_format;
|
||||
g_r.ssr_showcase = g_r.showcase_shaders;
|
||||
REXLOG_INFO("native-scene: ssr pipeline created (MSAA x{})", g_r.msaa);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1315,7 +1321,8 @@ bool EnsureHdrPipeline(const NativeGuestOutputRenderContext& context) {
|
|||
return false;
|
||||
}
|
||||
if (g_r.pso_tonemap != nullptr &&
|
||||
g_r.hdr_pso_out_format == context.guest_output->format()) {
|
||||
g_r.hdr_pso_out_format == context.guest_output->format() &&
|
||||
g_r.hdr_showcase == g_r.showcase_shaders) {
|
||||
return true;
|
||||
}
|
||||
nrhi::Device* device = context.device;
|
||||
|
|
@ -1384,9 +1391,13 @@ bool EnsureHdrPipeline(const NativeGuestOutputRenderContext& context) {
|
|||
nrhi::Shader* ps_up = device->CreateShader(
|
||||
MakeShaderDesc(nrhi::ShaderStage::kPixel, "hdr.hlsl", kHdrShaderSource,
|
||||
"ps_bloom_up", nullptr, ""));
|
||||
nrhi::Shader* ps_tone = device->CreateShader(
|
||||
MakeShaderDesc(nrhi::ShaderStage::kPixel, "hdr.hlsl", kHdrShaderSource,
|
||||
"ps_tonemap", nullptr, ""));
|
||||
// The tonemap follows the showcase shader swap (its SHOWCASE=1 variant
|
||||
// carries the post-layer gates and the split divider).
|
||||
const nrhi::ShaderMacro sc_defs[] = {{"SHOWCASE", "1"}, {nullptr, nullptr}};
|
||||
nrhi::Shader* ps_tone = device->CreateShader(MakeShaderDesc(
|
||||
nrhi::ShaderStage::kPixel, "hdr.hlsl", kHdrShaderSource, "ps_tonemap",
|
||||
g_r.showcase_shaders ? sc_defs : nullptr,
|
||||
g_r.showcase_shaders ? "SHOWCASE=1" : ""));
|
||||
const bool shaders_ok = vs != nullptr && ps_first != nullptr &&
|
||||
ps_down != nullptr && ps_up != nullptr &&
|
||||
ps_tone != nullptr;
|
||||
|
|
@ -1428,6 +1439,7 @@ bool EnsureHdrPipeline(const NativeGuestOutputRenderContext& context) {
|
|||
return fail("pso");
|
||||
}
|
||||
g_r.hdr_pso_out_format = context.guest_output->format();
|
||||
g_r.hdr_showcase = g_r.showcase_shaders;
|
||||
REXLOG_INFO("native-scene: HDR post pipeline created");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue