Add support for SGSR 1.0
SGSR stands for Snapdragon Game Super Resolution. It is an efficient upscaler for mobile. Split the upscaling passes into multiple methods in PostProcessManager. Also, add a way to preserve the alpha channel in the FXAA pass.
This commit is contained in:
committed by
Mathias Agopian
parent
5b3343fcc2
commit
48a2c6483b
@@ -1420,10 +1420,10 @@ public class View {
|
||||
/**
|
||||
* Upscaling quality
|
||||
* LOW: bilinear filtered blit. Fastest, poor quality
|
||||
* MEDIUM: AMD FidelityFX FSR1 w/ mobile optimizations
|
||||
* MEDIUM: Qualcomm Snapdragon Game Super Resolution (SGSR) 1.0
|
||||
* HIGH: AMD FidelityFX FSR1 w/ mobile optimizations
|
||||
* ULTRA: AMD FidelityFX FSR1
|
||||
* FSR1 require a well anti-aliased (MSAA or TAA), noise free scene.
|
||||
* FSR1 and SGSR require a well anti-aliased (MSAA or TAA), noise free scene. Avoid FXAA and dithering.
|
||||
*
|
||||
* The default upscaling quality is set to LOW.
|
||||
*/
|
||||
|
||||
@@ -252,6 +252,7 @@ set(MATERIAL_SRCS
|
||||
src/materials/fsr/fsr_easu_mobile.mat
|
||||
src/materials/fsr/fsr_easu_mobileF.mat
|
||||
src/materials/fsr/fsr_rcas.mat
|
||||
src/materials/sgsr/sgsr1.mat
|
||||
src/materials/resolveDepth.mat
|
||||
src/materials/separableGaussianBlur.mat
|
||||
src/materials/skybox.mat
|
||||
@@ -504,6 +505,12 @@ add_custom_command(
|
||||
APPEND
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${MATERIAL_DIR}/sgsr1.filamat"
|
||||
DEPENDS src/materials/sgsr/sgsr1_shader_mobile.fs
|
||||
APPEND
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${MATERIAL_DIR}/separableGaussianBlur.filamat"
|
||||
DEPENDS src/materials/separableGaussianBlur.vs
|
||||
|
||||
@@ -86,10 +86,10 @@ struct DynamicResolutionOptions {
|
||||
/**
|
||||
* Upscaling quality
|
||||
* LOW: bilinear filtered blit. Fastest, poor quality
|
||||
* MEDIUM: AMD FidelityFX FSR1 w/ mobile optimizations
|
||||
* MEDIUM: Qualcomm Snapdragon Game Super Resolution (SGSR) 1.0
|
||||
* HIGH: AMD FidelityFX FSR1 w/ mobile optimizations
|
||||
* ULTRA: AMD FidelityFX FSR1
|
||||
* FSR1 require a well anti-aliased (MSAA or TAA), noise free scene.
|
||||
* FSR1 and SGSR require a well anti-aliased (MSAA or TAA), noise free scene. Avoid FXAA and dithering.
|
||||
*
|
||||
* The default upscaling quality is set to LOW.
|
||||
*/
|
||||
|
||||
@@ -311,6 +311,7 @@ static const PostProcessManager::StaticMaterialInfo sMaterialList[] = {
|
||||
{ "fsr_easu_mobile", MATERIAL(FSR_EASU_MOBILE) },
|
||||
{ "fsr_easu_mobileF", MATERIAL(FSR_EASU_MOBILEF) },
|
||||
{ "fsr_rcas", MATERIAL(FSR_RCAS) },
|
||||
{ "sgsr1", MATERIAL(SGSR1) },
|
||||
{ "debugShadowCascades", MATERIAL(DEBUGSHADOWCASCADES) },
|
||||
{ "resolveDepth", MATERIAL(RESOLVEDEPTH) },
|
||||
{ "shadowmap", MATERIAL(SHADOWMAP) },
|
||||
@@ -2328,7 +2329,7 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver,
|
||||
mi->setParameter("vignette", vignetteParameters);
|
||||
mi->setParameter("vignetteColor", vignetteOptions.color);
|
||||
mi->setParameter("dithering", colorGradingConfig.dithering);
|
||||
mi->setParameter("fxaa", colorGradingConfig.fxaa);
|
||||
mi->setParameter("outputLuminance", colorGradingConfig.outputLuminance);
|
||||
mi->setParameter("temporalNoise", temporalNoise);
|
||||
mi->commit(driver);
|
||||
|
||||
@@ -2544,7 +2545,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
|
||||
mi->setParameter("bloom", bloomParameters);
|
||||
mi->setParameter("vignette", vignetteParameters);
|
||||
mi->setParameter("vignetteColor", vignetteOptions.color);
|
||||
mi->setParameter("fxaa", colorGradingConfig.fxaa);
|
||||
mi->setParameter("outputLuminance", colorGradingConfig.outputLuminance);
|
||||
mi->setParameter("temporalNoise", temporalNoise);
|
||||
mi->setParameter("viewport", float4{
|
||||
float(vp.left) / input.width,
|
||||
@@ -2562,7 +2563,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
|
||||
|
||||
FrameGraphId<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,
|
||||
FrameGraphId<FrameGraphTexture> const input, filament::Viewport const& vp,
|
||||
TextureFormat const outFormat, bool const translucent) noexcept {
|
||||
TextureFormat const outFormat, bool const preserveAlphaChannel) noexcept {
|
||||
|
||||
struct PostProcessFXAA {
|
||||
FrameGraphId<FrameGraphTexture> input;
|
||||
@@ -2587,7 +2588,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,
|
||||
|
||||
auto const& material = getPostProcessMaterial("fxaa");
|
||||
|
||||
PostProcessVariant const variant = translucent ?
|
||||
PostProcessVariant const variant = preserveAlphaChannel ?
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
FMaterialInstance* const mi =
|
||||
@@ -2920,20 +2921,171 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
|
||||
}
|
||||
|
||||
FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool translucent,
|
||||
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> const input,
|
||||
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
|
||||
SamplerMagFilter filter) noexcept {
|
||||
|
||||
bool sourceHasLuminance, DynamicResolutionOptions dsrOptions,
|
||||
FrameGraphId<FrameGraphTexture> const input, filament::Viewport const& vp,
|
||||
FrameGraphTexture::Descriptor const& outDesc, SamplerMagFilter filter) noexcept {
|
||||
// The code below cannot handle sub-resources
|
||||
assert_invariant(fg.getSubResourceDescriptor(input).layer == 0);
|
||||
assert_invariant(fg.getSubResourceDescriptor(input).level == 0);
|
||||
|
||||
const bool lowQualityFallback = translucent && dsrOptions.quality != QualityLevel::LOW;
|
||||
const bool lowQualityFallback = translucent;
|
||||
if (lowQualityFallback) {
|
||||
// FidelityFX-FSR doesn't support the alpha channel currently
|
||||
// FidelityFX-FSR nor SGSR support the source alpha channel currently
|
||||
dsrOptions.quality = QualityLevel::LOW;
|
||||
}
|
||||
|
||||
if (dsrOptions.quality == QualityLevel::LOW) {
|
||||
return upscaleBilinear(fg, translucent, dsrOptions, input, vp, outDesc, filter);
|
||||
}
|
||||
if (dsrOptions.quality == QualityLevel::MEDIUM) {
|
||||
return upscaleSGSR1(fg, sourceHasLuminance, dsrOptions, input, vp, outDesc);
|
||||
}
|
||||
return upscaleFSR1(fg, dsrOptions, input, vp, outDesc);
|
||||
}
|
||||
|
||||
FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph& fg, bool translucent,
|
||||
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> const input,
|
||||
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
|
||||
SamplerMagFilter filter) noexcept {
|
||||
|
||||
struct QuadBlitData {
|
||||
FrameGraphId<FrameGraphTexture> input;
|
||||
FrameGraphId<FrameGraphTexture> output;
|
||||
};
|
||||
|
||||
auto const& ppQuadBlit = fg.addPass<QuadBlitData>(dsrOptions.enabled ? "upscaling" : "compositing",
|
||||
[&](FrameGraph::Builder& builder, auto& data) {
|
||||
data.input = builder.sample(input);
|
||||
data.output = builder.createTexture("upscaled output", outDesc);
|
||||
data.output = builder.write(data.output, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
|
||||
builder.declareRenderPass(builder.getName(data.output), {
|
||||
.attachments = { .color = { data.output } },
|
||||
.clearFlags = TargetBufferFlags::DEPTH });
|
||||
},
|
||||
[this, vp, translucent, filter](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
|
||||
// helper to enable blending
|
||||
auto enableTranslucentBlending = [](PipelineState& pipeline) {
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA;
|
||||
pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
|
||||
};
|
||||
|
||||
auto color = resources.getTexture(data.input);
|
||||
auto const& inputDesc = resources.getDescriptor(data.input);
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// set uniforms
|
||||
|
||||
auto& material = getPostProcessMaterial("blitLow");
|
||||
FMaterialInstance* const mi =
|
||||
PostProcessMaterial::getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("color", color, {
|
||||
.filterMag = filter
|
||||
});
|
||||
|
||||
mi->setParameter("levelOfDetail", 0.0f);
|
||||
|
||||
mi->setParameter("viewport", float4{
|
||||
float(vp.left) / inputDesc.width,
|
||||
float(vp.bottom) / inputDesc.height,
|
||||
float(vp.width) / inputDesc.width,
|
||||
float(vp.height) / inputDesc.height
|
||||
});
|
||||
mi->commit(driver);
|
||||
mi->use(driver);
|
||||
|
||||
auto out = resources.getRenderPassInfo();
|
||||
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine));
|
||||
if (translucent) {
|
||||
enableTranslucentBlending(pipeline);
|
||||
}
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
});
|
||||
|
||||
auto output = ppQuadBlit->output;
|
||||
|
||||
// if we had to take the low quality fallback, we still do the "sharpen pass"
|
||||
if (dsrOptions.sharpness > 0.0f) {
|
||||
output = rcas(fg, dsrOptions.sharpness, output, outDesc, translucent);
|
||||
}
|
||||
|
||||
// we rely on automatic culling of unused render passes
|
||||
return output;
|
||||
}
|
||||
|
||||
FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg, bool sourceHasLuminance,
|
||||
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> const input,
|
||||
filament::Viewport const&, FrameGraphTexture::Descriptor const& outDesc) noexcept {
|
||||
|
||||
struct QuadBlitData {
|
||||
FrameGraphId<FrameGraphTexture> input;
|
||||
FrameGraphId<FrameGraphTexture> output;
|
||||
};
|
||||
|
||||
auto const& ppQuadBlit = fg.addPass<QuadBlitData>(dsrOptions.enabled ? "upscaling" : "compositing",
|
||||
[&](FrameGraph::Builder& builder, auto& data) {
|
||||
data.input = builder.sample(input);
|
||||
data.output = builder.createTexture("upscaled output", outDesc);
|
||||
data.output = builder.write(data.output, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
|
||||
builder.declareRenderPass(builder.getName(data.output), {
|
||||
.attachments = { .color = { data.output } },
|
||||
.clearFlags = TargetBufferFlags::DEPTH });
|
||||
},
|
||||
[this, sourceHasLuminance](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
|
||||
auto color = resources.getTexture(data.input);
|
||||
auto const& inputDesc = resources.getDescriptor(data.input);
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// set uniforms
|
||||
|
||||
auto const& material = getPostProcessMaterial("sgsr1");
|
||||
|
||||
PostProcessVariant const variant = sourceHasLuminance ?
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
FMaterialInstance* const mi =
|
||||
PostProcessMaterial::getMaterialInstance(mEngine, material, variant);
|
||||
|
||||
mi->setParameter("color", color, {
|
||||
// The SGSR documentation doesn't clarify if LINEAR or NEAREST should be used. The
|
||||
// sample code uses NEAREST, but that doesn't seem right, since it would mean the
|
||||
// LERP mode would not be a LERP, and the non-edges would be sampled as NEAREST.
|
||||
.filterMag = SamplerMagFilter::LINEAR
|
||||
});
|
||||
|
||||
mi->setParameter("viewport", float4{
|
||||
1.0f / inputDesc.width,
|
||||
1.0f / inputDesc.height,
|
||||
float(inputDesc.width),
|
||||
float(inputDesc.height),
|
||||
});
|
||||
|
||||
mi->commit(driver);
|
||||
mi->use(driver);
|
||||
|
||||
auto out = resources.getRenderPassInfo();
|
||||
commitAndRenderFullScreenQuad(driver, out, mi, variant);
|
||||
|
||||
});
|
||||
|
||||
auto output = ppQuadBlit->output;
|
||||
|
||||
// we rely on automatic culling of unused render passes
|
||||
return output;
|
||||
}
|
||||
|
||||
FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
||||
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> const input,
|
||||
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc) noexcept {
|
||||
|
||||
const bool twoPassesEASU = mWorkaroundSplitEasu &&
|
||||
(dsrOptions.quality == QualityLevel::MEDIUM
|
||||
|| dsrOptions.quality == QualityLevel::HIGH);
|
||||
@@ -2964,7 +3116,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
|
||||
.attachments = { .color = { data.output }, .depth = { data.depth }},
|
||||
.clearFlags = TargetBufferFlags::DEPTH });
|
||||
},
|
||||
[this, twoPassesEASU, dsrOptions, vp, translucent, filter](FrameGraphResources const& resources,
|
||||
[this, twoPassesEASU, dsrOptions, vp](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
|
||||
@@ -2989,14 +3141,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
|
||||
float2{ inputDesc.width, inputDesc.height });
|
||||
};
|
||||
|
||||
// helper to enable blending
|
||||
auto enableTranslucentBlending = [](PipelineState& pipeline) {
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA;
|
||||
pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
|
||||
};
|
||||
|
||||
auto color = resources.getTexture(data.input);
|
||||
auto const& inputDesc = resources.getDescriptor(data.input);
|
||||
auto const& outputDesc = resources.getDescriptor(data.output);
|
||||
@@ -3023,29 +3167,21 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
|
||||
}
|
||||
|
||||
{ // just a scope to not leak local variables
|
||||
const std::string_view blitterNames[4] = {
|
||||
"blitLow", "fsr_easu_mobile", "fsr_easu_mobile", "fsr_easu" };
|
||||
unsigned const index = std::min(3u, unsigned(dsrOptions.quality));
|
||||
const std::string_view blitterNames[2] = { "fsr_easu_mobile", "fsr_easu" };
|
||||
unsigned const index = std::min(1u, unsigned(dsrOptions.quality) - 2);
|
||||
easuMaterial = &getPostProcessMaterial(blitterNames[index]);
|
||||
FMaterialInstance* const mi =
|
||||
PostProcessMaterial::getMaterialInstance(mEngine, *easuMaterial);
|
||||
if (dsrOptions.quality != QualityLevel::LOW) {
|
||||
setEasuUniforms(mi, inputDesc, outputDesc);
|
||||
}
|
||||
|
||||
setEasuUniforms(mi, inputDesc, outputDesc);
|
||||
|
||||
mi->setParameter("color", color, {
|
||||
.filterMag = (dsrOptions.quality == QualityLevel::LOW) ?
|
||||
filter : SamplerMagFilter::LINEAR
|
||||
.filterMag = SamplerMagFilter::LINEAR
|
||||
});
|
||||
|
||||
if (blitterNames[index] != "blitLow") {
|
||||
mi->setParameter("resolution",
|
||||
float4{outputDesc.width, outputDesc.height, 1.0f / outputDesc.width,
|
||||
1.0f / outputDesc.height});
|
||||
}
|
||||
|
||||
if (blitterNames[index] == "blitLow") {
|
||||
mi->setParameter("levelOfDetail", 0.0f);
|
||||
}
|
||||
mi->setParameter("resolution",
|
||||
float4{outputDesc.width, outputDesc.height, 1.0f / outputDesc.width,
|
||||
1.0f / outputDesc.height});
|
||||
|
||||
mi->setParameter("viewport", float4{
|
||||
float(vp.left) / inputDesc.width,
|
||||
@@ -3066,29 +3202,19 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
|
||||
auto pipeline0 = getPipelineState(splitEasuMaterial->getMaterial(mEngine));
|
||||
auto pipeline1 = getPipelineState(easuMaterial->getMaterial(mEngine));
|
||||
pipeline1.rasterState.depthFunc = SamplerCompareFunc::NE;
|
||||
if (translucent) {
|
||||
enableTranslucentBlending(pipeline0);
|
||||
enableTranslucentBlending(pipeline1);
|
||||
}
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
driver.draw(pipeline0, mFullScreenQuadRph, 0, 3, 1);
|
||||
driver.draw(pipeline1, mFullScreenQuadRph, 0, 3, 1);
|
||||
driver.endRenderPass();
|
||||
} else {
|
||||
auto pipeline = getPipelineState(easuMaterial->getMaterial(mEngine));
|
||||
if (translucent) {
|
||||
enableTranslucentBlending(pipeline);
|
||||
}
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
}
|
||||
});
|
||||
|
||||
auto output = ppQuadBlit->output;
|
||||
|
||||
// if we had to take the low quality fallback, we still do the "sharpen pass"
|
||||
if (dsrOptions.sharpness > 0.0f &&
|
||||
(dsrOptions.quality != QualityLevel::LOW || lowQualityFallback)) {
|
||||
output = rcas(fg, dsrOptions.sharpness, output, outDesc, translucent);
|
||||
if (dsrOptions.sharpness > 0.0f) {
|
||||
output = rcas(fg, dsrOptions.sharpness, output, outDesc, false);
|
||||
}
|
||||
|
||||
// we rely on automatic culling of unused render passes
|
||||
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
bool asSubpass{};
|
||||
bool customResolve{};
|
||||
bool translucent{};
|
||||
bool fxaa{};
|
||||
bool outputLuminance{}; // Whether to output luminance in the alpha channel. Ignored by the TRANSLUCENT variant.
|
||||
bool dithering{};
|
||||
backend::TextureFormat ldrFormat{};
|
||||
};
|
||||
@@ -227,7 +227,7 @@ public:
|
||||
// Anti-aliasing
|
||||
FrameGraphId<FrameGraphTexture> fxaa(FrameGraph& fg,
|
||||
FrameGraphId<FrameGraphTexture> input, Viewport const& vp,
|
||||
backend::TextureFormat outFormat, bool translucent) noexcept;
|
||||
backend::TextureFormat outFormat, bool preserveAlphaChannel) noexcept;
|
||||
|
||||
// Temporal Anti-aliasing
|
||||
void TaaJitterCamera(
|
||||
@@ -251,12 +251,25 @@ public:
|
||||
|
||||
// high quality upscaler
|
||||
// - when translucent, reverts to LINEAR
|
||||
// - doens't handle sub-resouces
|
||||
// - doesn't handle sub-resouces
|
||||
FrameGraphId<FrameGraphTexture> upscale(FrameGraph& fg, bool translucent,
|
||||
bool sourceHasLuminance, DynamicResolutionOptions dsrOptions,
|
||||
FrameGraphId<FrameGraphTexture> input, Viewport const& vp,
|
||||
FrameGraphTexture::Descriptor const& outDesc, backend::SamplerMagFilter filter) noexcept;
|
||||
|
||||
FrameGraphId<FrameGraphTexture> upscaleBilinear(FrameGraph& fg, bool translucent,
|
||||
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> input,
|
||||
Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
|
||||
backend::SamplerMagFilter filter) noexcept;
|
||||
|
||||
FrameGraphId<FrameGraphTexture> upscaleFSR1(FrameGraph& fg,
|
||||
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> input,
|
||||
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc) noexcept;
|
||||
|
||||
FrameGraphId<FrameGraphTexture> upscaleSGSR1(FrameGraph& fg, bool sourceHasLuminance,
|
||||
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> input,
|
||||
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc) noexcept;
|
||||
|
||||
FrameGraphId<FrameGraphTexture> rcas(
|
||||
FrameGraph& fg,
|
||||
float sharpness,
|
||||
|
||||
@@ -681,6 +681,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
hasColorGrading &&
|
||||
!bloomOptions.enabled && !dofOptions.enabled && !taaOptions.enabled;
|
||||
|
||||
// whether we're scaled at all
|
||||
bool scaled = any(notEqual(scale, float2(1.0f)));
|
||||
|
||||
// asSubpass is disabled with TAA (although it's supported) because performance was degraded
|
||||
// on qualcomm hardware -- we might need a backend dependent toggle at some point
|
||||
const PostProcessManager::ColorGradingConfig colorGradingConfig{
|
||||
@@ -695,18 +698,15 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
hasColorGrading &&
|
||||
!engine.debug.renderer.disable_subpasses,
|
||||
.translucent = needsAlphaChannel,
|
||||
.fxaa = hasFXAA,
|
||||
.outputLuminance = hasFXAA || scaled, // ignored by translucent variants (false)
|
||||
.dithering = hasDithering,
|
||||
.ldrFormat = (hasColorGrading && hasFXAA) ?
|
||||
.ldrFormat = (hasColorGrading && (hasFXAA || scaled)) ?
|
||||
TextureFormat::RGBA8 : getLdrFormat(needsAlphaChannel)
|
||||
};
|
||||
|
||||
// by construction (msaaSampleCount) both asSubpass and customResolve can't be true
|
||||
assert_invariant(colorGradingConfig.asSubpass + colorGradingConfig.customResolve < 2);
|
||||
|
||||
// whether we're scaled at all
|
||||
bool scaled = any(notEqual(scale, float2(1.0f)));
|
||||
|
||||
// vp is the user defined viewport within the View
|
||||
filament::Viewport const& vp = view.getViewport();
|
||||
|
||||
@@ -1351,8 +1351,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
}
|
||||
|
||||
if (hasFXAA) {
|
||||
input = ppm.fxaa(fg, input, xvp, colorGradingConfig.ldrFormat,
|
||||
!hasColorGrading || needsAlphaChannel);
|
||||
bool const preserveAlphaChannel = needsAlphaChannel ||
|
||||
(hasColorGrading && colorGradingConfig.outputLuminance);
|
||||
input = ppm.fxaa(fg, input, xvp, colorGradingConfig.ldrFormat, preserveAlphaChannel);
|
||||
// the padded buffer is resolved now
|
||||
xvp.left = xvp.bottom = 0;
|
||||
svp = xvp;
|
||||
@@ -1360,9 +1361,11 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
if (scaled) {
|
||||
mightNeedFinalBlit = false;
|
||||
auto viewport = DEBUG_DYNAMIC_SCALING ? xvp : vp;
|
||||
input = ppm.upscale(fg, needsAlphaChannel, dsrOptions, input, xvp, {
|
||||
.width = viewport.width, .height = viewport.height,
|
||||
.format = colorGradingConfig.ldrFormat }, SamplerMagFilter::LINEAR);
|
||||
bool const sourceHasLuminance = !needsAlphaChannel &&
|
||||
(hasColorGrading && colorGradingConfig.outputLuminance);
|
||||
input = ppm.upscale(fg, needsAlphaChannel, sourceHasLuminance, dsrOptions, input, xvp, {
|
||||
.width = viewport.width, .height = viewport.height,
|
||||
.format = colorGradingConfig.ldrFormat }, SamplerMagFilter::LINEAR);
|
||||
xvp.left = xvp.bottom = 0;
|
||||
svp = xvp;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ material {
|
||||
},
|
||||
{
|
||||
type : int,
|
||||
name : fxaa
|
||||
name : outputLuminance
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
@@ -166,10 +166,10 @@ void postProcess(inout PostProcessInputs postProcess) {
|
||||
color = dither(color, materialParams.temporalNoise);
|
||||
}
|
||||
|
||||
// kill alpha computations when opaque / fxaa luminance
|
||||
// kill alpha computations when opaque / luminance
|
||||
#if POST_PROCESS_OPAQUE
|
||||
color.a = 1.0;
|
||||
if (materialParams.fxaa > 0) {
|
||||
if (materialParams.outputLuminance > 0) {
|
||||
color.a = luminance(color.rgb);
|
||||
}
|
||||
#endif
|
||||
|
||||
29
filament/src/materials/sgsr/LICENSE.txt
Normal file
29
filament/src/materials/sgsr/LICENSE.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
80
filament/src/materials/sgsr/sgsr1.mat
Normal file
80
filament/src/materials/sgsr/sgsr1.mat
Normal file
@@ -0,0 +1,80 @@
|
||||
material {
|
||||
name : sgsr1,
|
||||
parameters : [
|
||||
{
|
||||
type : sampler2d,
|
||||
name : color,
|
||||
precision: medium
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : viewport,
|
||||
precision: high
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
vertex
|
||||
],
|
||||
depthWrite : false,
|
||||
depthCulling : false,
|
||||
domain: postprocess
|
||||
}
|
||||
|
||||
vertex {
|
||||
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
|
||||
postProcess.normalizedUV = uvToRenderTargetUV(postProcess.normalizedUV);
|
||||
postProcess.vertex.xy = postProcess.normalizedUV;
|
||||
}
|
||||
}
|
||||
|
||||
fragment {
|
||||
|
||||
void dummy(){}
|
||||
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
#if defined(FILAMENT_HAS_FEATURE_TEXTURE_GATHER)
|
||||
#define gather textureGather
|
||||
#else
|
||||
vec4 gather(const mediump sampler2D color, highp vec2 p, const int comp) {
|
||||
highp ivec2 i = ivec2(p * materialParams.viewport.zw - 0.5);
|
||||
vec4 d;
|
||||
d[0] = texelFetchOffset(color, i, 0, ivec2(0, 1))[comp];
|
||||
d[1] = texelFetchOffset(color, i, 0, ivec2(1, 1))[comp];
|
||||
d[2] = texelFetchOffset(color, i, 0, ivec2(1, 0))[comp];
|
||||
d[3] = texelFetchOffset(color, i, 0, ivec2(0, 0))[comp];
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Operation modes:
|
||||
* RGBA -> 1
|
||||
* RGBY -> 3
|
||||
* LERP -> 4
|
||||
*/
|
||||
|
||||
// SGSR cannot support translucency;
|
||||
// So we hijack the POST_PROCESS variant to select whether a luminance channel is present
|
||||
#if POST_PROCESS_OPAQUE
|
||||
# define OperationMode 1
|
||||
#else
|
||||
# define OperationMode 3
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If set, will use edge direction to improve visual quality
|
||||
* Expect a minimal cost increase
|
||||
*/
|
||||
#define UseEdgeDirection
|
||||
#define EdgeThreshold 8.0 / 255.0
|
||||
#define EdgeSharpness 2.0
|
||||
|
||||
#include "sgsr1_shader_mobile.fs"
|
||||
|
||||
void postProcess(inout PostProcessInputs postProcess) {
|
||||
highp vec4 vp[1] = vec4[1]( materialParams.viewport );
|
||||
postProcess.color = sgsr(materialParams_color, variable_vertex.xy, vp);
|
||||
}
|
||||
}
|
||||
132
filament/src/materials/sgsr/sgsr1_shader_mobile.fs
Normal file
132
filament/src/materials/sgsr/sgsr1_shader_mobile.fs
Normal file
@@ -0,0 +1,132 @@
|
||||
//============================================================================================================
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
//============================================================================================================
|
||||
|
||||
////////////////////////
|
||||
// USER CONFIGURATION //
|
||||
////////////////////////
|
||||
|
||||
float fastLanczos2(float x)
|
||||
{
|
||||
float wA = x-4.0;
|
||||
float wB = x*wA-wA;
|
||||
wA *= wA;
|
||||
return wB*wA;
|
||||
}
|
||||
|
||||
#if defined(UseEdgeDirection)
|
||||
vec2 weightY(float dx, float dy, float c, vec3 data)
|
||||
#else
|
||||
vec2 weightY(float dx, float dy, float c, float data)
|
||||
#endif
|
||||
{
|
||||
#if defined(UseEdgeDirection)
|
||||
float std = data.x;
|
||||
vec2 dir = data.yz;
|
||||
|
||||
float edgeDis = ((dx*dir.y)+(dy*dir.x));
|
||||
float x = (((dx*dx)+(dy*dy))+((edgeDis*edgeDis)*((clamp(((c*c)*std),0.0,1.0)*0.7)+-1.0)));
|
||||
#else
|
||||
float std = data;
|
||||
float x = ((dx*dx)+(dy*dy))* 0.55 + clamp(abs(c)*std, 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
float w = fastLanczos2(x);
|
||||
return vec2(w, w * c);
|
||||
}
|
||||
|
||||
vec2 edgeDirection(vec4 left, vec4 right)
|
||||
{
|
||||
vec2 dir;
|
||||
float RxLz = (right.x + (-left.z));
|
||||
float RwLy = (right.w + (-left.y));
|
||||
vec2 delta;
|
||||
delta.x = (RxLz + RwLy);
|
||||
delta.y = (RxLz + (-RwLy));
|
||||
float lengthInv = inversesqrt((delta.x * delta.x+ 3.075740e-05) + (delta.y * delta.y));
|
||||
dir.x = (delta.x * lengthInv);
|
||||
dir.y = (delta.y * lengthInv);
|
||||
return dir;
|
||||
}
|
||||
|
||||
vec4 sgsr(mediump sampler2D ps0, highp vec2 in_TEXCOORD0, highp vec4 ViewportInfo[1])
|
||||
{
|
||||
vec4 color;
|
||||
if(OperationMode == 1)
|
||||
color.xyz = textureLod(ps0,in_TEXCOORD0.xy,0.0).xyz;
|
||||
else
|
||||
color.xyzw = textureLod(ps0,in_TEXCOORD0.xy,0.0).xyzw;
|
||||
|
||||
#if OperationMode != 4
|
||||
if (OperationMode!=4)
|
||||
{
|
||||
highp vec2 imgCoord = ((in_TEXCOORD0.xy*ViewportInfo[0].zw)+vec2(-0.5,0.5));
|
||||
highp vec2 imgCoordPixel = floor(imgCoord);
|
||||
highp vec2 coord = (imgCoordPixel*ViewportInfo[0].xy);
|
||||
vec2 pl = (imgCoord+(-imgCoordPixel));
|
||||
vec4 left = gather(ps0,coord, OperationMode);
|
||||
|
||||
float edgeVote = abs(left.z - left.y) + abs(color[OperationMode] - left.y) + abs(color[OperationMode] - left.z) ;
|
||||
if(edgeVote > EdgeThreshold)
|
||||
{
|
||||
coord.x += ViewportInfo[0].x;
|
||||
|
||||
vec4 right = gather(ps0,coord + vec2(ViewportInfo[0].x, 0.0), OperationMode);
|
||||
vec4 upDown;
|
||||
upDown.xy = gather(ps0,coord + vec2(0.0, -ViewportInfo[0].y),OperationMode).wz;
|
||||
upDown.zw = gather(ps0,coord+ vec2(0.0, ViewportInfo[0].y), OperationMode).yx;
|
||||
|
||||
float mean = (left.y+left.z+right.x+right.w)*0.25;
|
||||
left = left - vec4(mean);
|
||||
right = right - vec4(mean);
|
||||
upDown = upDown - vec4(mean);
|
||||
color.w = color[OperationMode] - mean;
|
||||
|
||||
float sum = (((((abs(left.x)+abs(left.y))+abs(left.z))+abs(left.w)) +
|
||||
(((abs(right.x)+abs(right.y))+abs(right.z))+abs(right.w))) +
|
||||
(((abs(upDown.x)+abs(upDown.y))+abs(upDown.z))+abs(upDown.w)));
|
||||
|
||||
#if defined(UseEdgeDirection)
|
||||
float sumMean = 1.014185e+01 / sum;
|
||||
float std = (sumMean * sumMean);
|
||||
vec3 data = vec3(std, edgeDirection(left, right));
|
||||
#else
|
||||
// taken from sgsr sample
|
||||
float data = 2.181818 / sum;
|
||||
#endif
|
||||
|
||||
vec2 aWY = weightY(pl.x, pl.y+1.0, upDown.x,data);
|
||||
aWY += weightY(pl.x-1.0, pl.y+1.0, upDown.y,data);
|
||||
aWY += weightY(pl.x-1.0, pl.y-2.0, upDown.z,data);
|
||||
aWY += weightY(pl.x, pl.y-2.0, upDown.w,data);
|
||||
aWY += weightY(pl.x+1.0, pl.y-1.0, left.x,data);
|
||||
aWY += weightY(pl.x, pl.y-1.0, left.y,data);
|
||||
aWY += weightY(pl.x, pl.y, left.z,data);
|
||||
aWY += weightY(pl.x+1.0, pl.y, left.w,data);
|
||||
aWY += weightY(pl.x-1.0, pl.y-1.0, right.x,data);
|
||||
aWY += weightY(pl.x-2.0, pl.y-1.0, right.y,data);
|
||||
aWY += weightY(pl.x-2.0, pl.y, right.z,data);
|
||||
aWY += weightY(pl.x-1.0, pl.y, right.w,data);
|
||||
|
||||
float finalY = aWY.y/aWY.x;
|
||||
float maxY = max(max(left.y,left.z),max(right.x,right.w));
|
||||
float minY = min(min(left.y,left.z),min(right.x,right.w));
|
||||
float deltaY = clamp(EdgeSharpness*finalY, minY, maxY) -color.w;
|
||||
|
||||
//smooth high contrast input
|
||||
deltaY = clamp(deltaY, -23.0 / 255.0, 23.0 / 255.0);
|
||||
|
||||
color.x = clamp(color.x+deltaY, 0.0, 1.0);
|
||||
color.y = clamp(color.y+deltaY, 0.0, 1.0);
|
||||
color.z = clamp(color.z+deltaY, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
color.w = 1.0; //assume alpha channel is not used
|
||||
return color;
|
||||
}
|
||||
Reference in New Issue
Block a user