From 8866e2829f5f9e8379088c5b37e6fff4fe6c2355 Mon Sep 17 00:00:00 2001 From: Pixelflinger Date: Sat, 7 Mar 2020 23:40:47 -0800 Subject: [PATCH] Add a quality option to dynamic-scaling It controls the quality of the upsampling filter. This can help a lot if heavy scaling is needed to maintain performance, it also helps if MSAA is not enabled. There are 3 quality levels, low, medium and high. 1, 4 and 9 bilinear taps are used for each level respectively. The high quality setting employs a tent filter. --- .../filament-android/src/main/cpp/View.cpp | 11 +++-- .../com/google/android/filament/View.java | 13 ++++- filament/CMakeLists.txt | 4 +- filament/include/filament/View.h | 3 ++ filament/src/PostProcessManager.cpp | 32 +++++++++---- filament/src/PostProcessManager.h | 8 ++-- filament/src/Renderer.cpp | 9 ++-- filament/src/materials/blitHigh.mat | 47 +++++++++++++++++++ .../src/materials/{blit.mat => blitLow.mat} | 8 +++- filament/src/materials/blitMedium.mat | 42 +++++++++++++++++ 10 files changed, 149 insertions(+), 28 deletions(-) create mode 100644 filament/src/materials/blitHigh.mat rename filament/src/materials/{blit.mat => blitLow.mat} (72%) create mode 100644 filament/src/materials/blitMedium.mat diff --git a/android/filament-android/src/main/cpp/View.cpp b/android/filament-android/src/main/cpp/View.cpp index 622366686f..223e8d79a8 100644 --- a/android/filament-android/src/main/cpp/View.cpp +++ b/android/filament-android/src/main/cpp/View.cpp @@ -162,17 +162,18 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_View_nSetDynamicResolutionOptions(JNIEnv*, jclass, jlong nativeView, jboolean enabled, jboolean homogeneousScaling, jfloat targetFrameTimeMilli, jfloat headRoomRatio, jfloat scaleRate, - jfloat minScale, jfloat maxScale, jint history) { - View* view = (View*) nativeView; + jfloat minScale, jfloat maxScale, jint history, jint quality) { + View* view = (View*)nativeView; View::DynamicResolutionOptions options; options.enabled = enabled; options.homogeneousScaling = homogeneousScaling; options.targetFrameTimeMilli = targetFrameTimeMilli; options.headRoomRatio = headRoomRatio; options.scaleRate = scaleRate; - options.minScale = filament::math::float2{minScale}; - options.maxScale = filament::math::float2{maxScale}; - options.history = (uint8_t) history; + options.minScale = filament::math::float2{ minScale }; + options.maxScale = filament::math::float2{ maxScale }; + options.history = (uint8_t)history; + options.quality = (View::QualityLevel)quality; view->setDynamicResolutionOptions(options); } diff --git a/android/filament-android/src/main/java/com/google/android/filament/View.java b/android/filament-android/src/main/java/com/google/android/filament/View.java index 14a625b015..2a02d73b4a 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/View.java +++ b/android/filament-android/src/main/java/com/google/android/filament/View.java @@ -133,6 +133,14 @@ public class View { * History size. higher values, tend to filter more (clamped to 30). */ public int history = 9; + + /** + * Upscaling quality. LOW: 1 bilinear taps, MEDIUM: 4 bilinear taps, HIGH: 9 bilinear taps. + * If minScale needs to be very low, it might help to use MEDIUM or HIGH here. + * The default upsacling quality is set to LOW. + */ + @NonNull + public QualityLevel quality = QualityLevel.LOW; } /** @@ -652,7 +660,8 @@ public class View { options.scaleRate, options.minScale, options.maxScale, - options.history); + options.history, + options.quality.ordinal()); } /** @@ -878,7 +887,7 @@ public class View { private static native void nSetDynamicResolutionOptions(long nativeView, boolean enabled, boolean homogeneousScaling, float targetFrameTimeMilli, float headRoomRatio, float scaleRate, - float minScale, float maxScale, int history); + float minScale, float maxScale, int history, int quality); private static native void nSetRenderQuality(long nativeView, int hdrColorBufferQuality); private static native void nSetDynamicLightingOptions(long nativeView, float zLightNear, float zLightFar); private static native void nSetPostProcessingEnabled(long nativeView, boolean enabled); diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index f0277c1a1a..57d107bc44 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -141,7 +141,9 @@ set(PRIVATE_HDRS set(MATERIAL_SRCS src/materials/defaultMaterial.mat - src/materials/blit.mat + src/materials/blitLow.mat + src/materials/blitMedium.mat + src/materials/blitHigh.mat src/materials/bloomDownsample.mat src/materials/bloomUpsample.mat src/materials/bilateralBlur.mat diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index 503ba5ea20..15dfd8f552 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -94,6 +94,8 @@ public: * history: History size. higher values, tend to filter more (clamped to 30) * minScale: the minimum scale in X and Y this View should use * maxScale: the maximum scale in X and Y this View should use + * quality: upscaling quality. + * LOW: 1 bilinear tap, Medium: 4 bilinear taps, High: 9 bilinear taps (tent) * * \note * Dynamic resolution is only supported on platforms where the time to render @@ -120,6 +122,7 @@ public: uint8_t history = 9; //!< history size bool enabled = false; //!< enable or disable dynamic resolution bool homogeneousScaling = false; //!< set to true to force homogeneous scaling + QualityLevel quality = QualityLevel::LOW; //!< Upscaling quality }; /** diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index b881267813..2274dbb176 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -52,7 +52,7 @@ PostProcessManager::PostProcessMaterial::PostProcessMaterial(FEngine& engine, mMaterial = upcast(Material::Builder().package(data, size).build(engine)); mMaterialInstance = mMaterial->getDefaultInstance(); // TODO: After all materials using this class have been converted to the post-process material - // domain, load both OPAQUE and TRANSPARENt variants here. + // domain, load both OPAQUE and TRANSPARENT variants here. mProgram = mMaterial->getProgram(0); } @@ -113,7 +113,9 @@ void PostProcessManager::init() noexcept { mSeparableGaussianBlur = PostProcessMaterial(mEngine, MATERIALS_SEPARABLEGAUSSIANBLUR_DATA, MATERIALS_SEPARABLEGAUSSIANBLUR_SIZE); mBloomDownsample = PostProcessMaterial(mEngine, MATERIALS_BLOOMDOWNSAMPLE_DATA, MATERIALS_BLOOMDOWNSAMPLE_SIZE); mBloomUpsample = PostProcessMaterial(mEngine, MATERIALS_BLOOMUPSAMPLE_DATA, MATERIALS_BLOOMUPSAMPLE_SIZE); - mBlit = PostProcessMaterial(mEngine, MATERIALS_BLIT_DATA, MATERIALS_BLIT_SIZE); + mBlit[0] = PostProcessMaterial(mEngine, MATERIALS_BLITLOW_DATA, MATERIALS_BLITLOW_SIZE); + mBlit[1] = PostProcessMaterial(mEngine, MATERIALS_BLITMEDIUM_DATA, MATERIALS_BLITMEDIUM_SIZE); + mBlit[2] = PostProcessMaterial(mEngine, MATERIALS_BLITHIGH_DATA, MATERIALS_BLITHIGH_SIZE); mTonemapping = PostProcessMaterial(mEngine, MATERIALS_TONEMAPPING_DATA, MATERIALS_TONEMAPPING_SIZE); mFxaa = PostProcessMaterial(mEngine, MATERIALS_FXAA_DATA, MATERIALS_FXAA_SIZE); @@ -150,7 +152,9 @@ void PostProcessManager::terminate(DriverApi& driver) noexcept { mSeparableGaussianBlur.terminate(engine); mBloomDownsample.terminate(engine); mBloomUpsample.terminate(engine); - mBlit.terminate(engine); + mBlit[0].terminate(engine); + mBlit[1].terminate(engine); + mBlit[2].terminate(engine); mTonemapping.terminate(engine); mFxaa.terminate(engine); } @@ -364,7 +368,8 @@ FrameGraphId PostProcessManager::opaqueBlit(FrameGraph& fg, return ppBlit.getData().output; } -FrameGraphId PostProcessManager::blendBlit(FrameGraph& fg, +FrameGraphId PostProcessManager::blendBlit( + FrameGraph& fg, bool translucent, View::QualityLevel quality, FrameGraphId input, FrameGraphTexture::Descriptor outDesc) noexcept { @@ -389,20 +394,27 @@ FrameGraphId PostProcessManager::blendBlit(FrameGraph& fg, auto color = resources.getTexture(data.input); auto out = resources.get(data.drt); + auto const& desc = resources.getDescriptor(data.input); - FMaterialInstance* const mi = mBlit.getMaterialInstance(); + unsigned index = std::min(2u, (unsigned)quality); + PostProcessMaterial& material = mBlit[index]; + FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("color", color, { .filterMag = SamplerMagFilter::LINEAR, .filterMin = SamplerMinFilter::LINEAR }); + mi->setParameter("resolution", + float4{ desc.width, desc.height, 1.0f / desc.width, 1.0f / desc.height }); mi->commit(driver); mi->use(driver); - PipelineState pipeline(mBlit.getPipelineState()); - 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; + PipelineState pipeline(material.getPipelineState()); + if (translucent) { + 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; + } driver.beginRenderPass(out.target, out.params); driver.draw(pipeline, fullScreenRenderPrimitive); driver.endRenderPass(); diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index 9419b76c76..4dcb826b41 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -56,9 +56,9 @@ public: FrameGraphId opaqueBlit(FrameGraph& fg, FrameGraphId input, FrameGraphTexture::Descriptor outDesc) noexcept; - FrameGraphId blendBlit(FrameGraph& fg, - FrameGraphId input, - FrameGraphTexture::Descriptor outDesc) noexcept; + FrameGraphId blendBlit( + FrameGraph& fg, bool translucent, View::QualityLevel quality, + FrameGraphId input, FrameGraphTexture::Descriptor outDesc) noexcept; FrameGraphId resolve(FrameGraph& fg, const char* outputBufferName, FrameGraphId input) noexcept; @@ -132,7 +132,7 @@ private: PostProcessMaterial mSeparableGaussianBlur; PostProcessMaterial mBloomDownsample; PostProcessMaterial mBloomUpsample; - PostProcessMaterial mBlit; + PostProcessMaterial mBlit[3]; PostProcessMaterial mTonemapping; PostProcessMaterial mFxaa; diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index efd47ad14b..5f8631241d 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -199,6 +199,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { bool fxaa = view.getAntiAliasing() == View::AntiAliasing::FXAA; uint8_t msaa = view.getSampleCount(); float2 scale = view.updateScale(mFrameInfoManager.getLastFrameTime()); + const View::QualityLevel upscalingQuality = view.getDynamicResolutionOptions().quality; if (!hasPostProcess) { // dynamic scaling and FXAA are part of the post-process phase and can't happen if // it's disabled. @@ -392,10 +393,10 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { input = ppm.fxaa(fg, input, ldrFormat, !toneMapping || translucent); } if (scaled) { - if (UTILS_LIKELY(!blending)) { + if (UTILS_LIKELY(!blending && upscalingQuality == View::QualityLevel::LOW)) { input = ppm.opaqueBlit(fg, input, { .format = ldrFormat }); } else { - input = ppm.blendBlit(fg, input, { .format = ldrFormat }); + input = ppm.blendBlit(fg, true, upscalingQuality, input, { .format = ldrFormat }); } } } @@ -412,10 +413,10 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { const bool outputIsInput = fg.equal(input, colorPassOutput); if ((outputIsInput && viewRenderTarget == mRenderTarget && msaa > 1) || (!outputIsInput && blending)) { - if (UTILS_LIKELY(!blending)) { + if (UTILS_LIKELY(!blending && upscalingQuality == View::QualityLevel::LOW)) { input = ppm.opaqueBlit(fg, input, { .format = ldrFormat }); } else { - input = ppm.blendBlit(fg, input, { .format = ldrFormat }); + input = ppm.blendBlit(fg, true, upscalingQuality, input, { .format = ldrFormat }); } } diff --git a/filament/src/materials/blitHigh.mat b/filament/src/materials/blitHigh.mat new file mode 100644 index 0000000000..9608548911 --- /dev/null +++ b/filament/src/materials/blitHigh.mat @@ -0,0 +1,47 @@ +material { + name : blit, + parameters : [ + { + type : sampler2d, + name : color, + precision: medium + }, + { + type : float4, + name : resolution, + precision: high + } + ], + variables : [ + vertex + ], + depthWrite : false, + depthCulling : false, + domain: postprocess +} + +vertex { + void postProcessVertex(inout PostProcessVertexInputs postProcess) { + postProcess.vertex.xy = postProcess.normalizedUV; + } +} + +fragment { + void postProcess(inout PostProcessInputs postProcess) { + highp vec2 uv = variable_vertex.xy; // interpolated to pixel center + highp float du = materialParams.resolution.z; + highp float dv = materialParams.resolution.w; + vec4 c0, c1; + c0 = textureLod(materialParams_color, uv + vec2(-du, -dv), 0.0); + c0 += textureLod(materialParams_color, uv + vec2( du, -dv), 0.0); + c0 += textureLod(materialParams_color, uv + vec2( du, dv), 0.0); + c0 += textureLod(materialParams_color, uv + vec2(-du, dv), 0.0); + c0 += 4.0 * textureLod(materialParams_color, uv, 0.0); + c1 = textureLod(materialParams_color, uv + vec2(-du, 0.0), 0.0); + c1 += textureLod(materialParams_color, uv + vec2( 0.0, -dv), 0.0); + c1 += textureLod(materialParams_color, uv + vec2( du, 0.0), 0.0); + c1 += textureLod(materialParams_color, uv + vec2( 0.0, dv), 0.0); + postProcess.color = (c0 + 2.0 * c1) * (1.0 / 16.0); + } +} + diff --git a/filament/src/materials/blit.mat b/filament/src/materials/blitLow.mat similarity index 72% rename from filament/src/materials/blit.mat rename to filament/src/materials/blitLow.mat index 05a3d45965..075a987517 100644 --- a/filament/src/materials/blit.mat +++ b/filament/src/materials/blitLow.mat @@ -5,6 +5,11 @@ material { type : sampler2d, name : color, precision: medium + }, + { + type : float4, + name : resolution, + precision: high } ], variables : [ @@ -23,8 +28,7 @@ vertex { fragment { void postProcess(inout PostProcessInputs postProcess) { - highp vec2 uv = variable_vertex.xy; // interpolated to pixel center - postProcess.color = textureLod(materialParams_color, uv, 0.0); + postProcess.color = textureLod(materialParams_color, variable_vertex.xy, 0.0); } } diff --git a/filament/src/materials/blitMedium.mat b/filament/src/materials/blitMedium.mat new file mode 100644 index 0000000000..f904fa91f0 --- /dev/null +++ b/filament/src/materials/blitMedium.mat @@ -0,0 +1,42 @@ +material { + name : blit, + parameters : [ + { + type : sampler2d, + name : color, + precision: medium + }, + { + type : float4, + name : resolution, + precision: high + } + ], + variables : [ + vertex + ], + depthWrite : false, + depthCulling : false, + domain: postprocess +} + +vertex { + void postProcessVertex(inout PostProcessVertexInputs postProcess) { + postProcess.vertex.xy = postProcess.normalizedUV; + } +} + +fragment { + void postProcess(inout PostProcessInputs postProcess) { + highp vec2 uv = variable_vertex.xy; // interpolated to pixel center + highp float du = 0.5 * materialParams.resolution.z; + highp float dv = 0.5 * materialParams.resolution.w; + vec4 c; + c = textureLod(materialParams_color, uv + vec2(-du, -dv), 0.0); + c += textureLod(materialParams_color, uv + vec2( du, -dv), 0.0); + c += textureLod(materialParams_color, uv + vec2( du, dv), 0.0); + c += textureLod(materialParams_color, uv + vec2(-du, dv), 0.0); + postProcess.color = c * 0.25; + } +} +