From bd0b752337474668722c3fb3fe031199c19fde12 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Thu, 29 Nov 2018 16:55:36 -0800 Subject: [PATCH] Add RenderQuality API (#555) View::setRenderQuality gives the ability to control the rendering quality of a given view. In particular this allows the app to lower the quality of the HDR color buffer by using R11G11B10F instead of RGB(A)16F. --- .../filament-android/src/main/cpp/View.cpp | 26 ++++++--- .../com/google/android/filament/View.java | 30 ++++++++++- filament/include/filament/View.h | 54 ++++++++++++++++--- filament/src/Renderer.cpp | 23 +++++++- filament/src/View.cpp | 8 +++ filament/src/details/Renderer.h | 13 +---- filament/src/details/View.h | 10 ++++ 7 files changed, 136 insertions(+), 28 deletions(-) diff --git a/android/filament-android/src/main/cpp/View.cpp b/android/filament-android/src/main/cpp/View.cpp index a9485a9376..e8c375e4b3 100644 --- a/android/filament-android/src/main/cpp/View.cpp +++ b/android/filament-android/src/main/cpp/View.cpp @@ -119,7 +119,7 @@ extern "C" JNIEXPORT jint JNICALL Java_com_google_android_filament_View_nGetAntiAliasing(JNIEnv*, jclass, jlong nativeView) { View* view = (View*) nativeView; - return (jint)view->getAntiAliasing(); + return (jint) view->getAntiAliasing(); } extern "C" JNIEXPORT void JNICALL @@ -134,21 +134,31 @@ Java_com_google_android_filament_View_nSetDynamicResolutionOptions(JNIEnv*, options.targetFrameTimeMilli = targetFrameTimeMilli; options.headRoomRatio = headRoomRatio; options.scaleRate = scaleRate; - options.minScale = math::float2{ minScale }; - options.maxScale = math::float2{ maxScale }; - options.history = (uint8_t)history; - return view->setDynamicResolutionOptions(options); + options.minScale = math::float2{minScale}; + options.maxScale = math::float2{maxScale}; + options.history = (uint8_t) history; + view->setDynamicResolutionOptions(options); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_View_nSetRenderQuality(JNIEnv*, jclass, + jlong nativeView, jint hdrColorBufferQuality) { + View* view = (View*) nativeView; + View::RenderQuality renderQuality; + renderQuality.hdrColorBuffer = View::QualityLevel(hdrColorBufferQuality); + view->setRenderQuality(renderQuality); } extern "C" JNIEXPORT void JNICALL -Java_com_google_android_filament_View_nSetDynamicLightingOptions(JNIEnv *env, +Java_com_google_android_filament_View_nSetDynamicLightingOptions(JNIEnv*, jclass, jlong nativeView, jfloat zLightNear, jfloat zLightFar) { View* view = (View*) nativeView; view->setDynamicLightingOptions(zLightNear, zLightFar); } extern "C" JNIEXPORT void JNICALL -Java_com_google_android_filament_View_nSetDepthPrepass(JNIEnv *env, +Java_com_google_android_filament_View_nSetDepthPrepass(JNIEnv*, jclass, jlong nativeView, jint value) { View* view = (View*) nativeView; view->setDepthPrepass(View::DepthPrepass(value)); @@ -165,5 +175,5 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_google_android_filament_View_nIsPostProcessingEnabled(JNIEnv*, jclass, jlong nativeView) { View* view = (View*) nativeView; - return view->isPostProcessingEnabled(); + return static_cast(view->isPostProcessingEnabled()); } 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 0c8ce489ce..a597282e53 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 @@ -30,6 +30,7 @@ public class View { private Camera mCamera; private Viewport mViewport = new Viewport(0, 0, 0, 0); private DynamicResolutionOptions mDynamicResolution; + private RenderQuality mRenderQuality; private DepthPrepass mDepthPrepass = DepthPrepass.DEFAULT; public static class DynamicResolutionOptions { @@ -41,7 +42,18 @@ public class View { public float minScale = 0.5f; public float maxScale = 1.0f; public int history = 9; - }; + } + + public enum QualityLevel { + LOW, + MEDIUM, + HIGH, + ULTRA + } + + public static class RenderQuality { + public QualityLevel hdrColorBuffer = QualityLevel.HIGH; + } public enum AntiAliasing { NONE, @@ -169,13 +181,26 @@ public class View { return mDynamicResolution; } + public void setRenderQuality(@NonNull RenderQuality renderQuality) { + mRenderQuality = renderQuality; + nSetRenderQuality(getNativeObject(), renderQuality.hdrColorBuffer.ordinal()); + } + + @NonNull + public RenderQuality getRenderQuality() { + if (mRenderQuality == null) { + mRenderQuality = new RenderQuality(); + } + return mRenderQuality; + } + @NonNull public DepthPrepass getDepthPrepass() { return mDepthPrepass; } public void setDepthPrepass(@NonNull DepthPrepass depthPrepass) { - mDepthPrepass = mDepthPrepass; + mDepthPrepass = depthPrepass; nSetDepthPrepass(getNativeObject(), depthPrepass.value); } @@ -228,6 +253,7 @@ public class View { boolean enabled, boolean homogeneousScaling, float targetFrameTimeMilli, float headRoomRatio, float scaleRate, float minScale, float maxScale, int history); + private static native void nSetRenderQuality(long nativeView, int hdrColorBufferQuality); private static native void nSetDynamicLightingOptions(long nativeView, float zLightNear, float zLightFar); private static native void nSetDepthPrepass(long nativeView, int value); private static native void nSetPostProcessingEnabled(long nativeView, boolean enabled); diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index 7491fe0b18..5c9f85097f 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -110,12 +110,41 @@ public: float scaleRate = 0.125f; //!< rate at which the scale will change float targetFrameTimeMilli = 1000.0f / 60.0f; //!< desired frame time, or budget. float headRoomRatio = 0.0f; //!< additional headroom for the GPU - float reserved[5] = { 0.0f }; //!< reserved fields, must be zero uint8_t history = 9; //!< history size bool enabled = false; //!< enable or disable dynamic resolution bool homogeneousScaling = false; //!< set to true to force homogeneous scaling }; + enum class QualityLevel : int8_t { + LOW, + MEDIUM, + HIGH, + ULTRA + }; + + /** + * Structure used to set the quality of the rendering of a View. This structure + * offers separate quality settings for different parts of the rendering pipeline: + * + * hdrColorBuffer: sets the quality of the HDR color buffer. A quality of HIGH or ULTRA means + * using an RGB16F or RGBA16F color buffer. This means colors in the LDR + * range (0..1) have a 10 bit precision. A quality of LOW or MEDIUM means + * using an R11G11B10F opaque color buffer or an RGBA16F transparent color + * buffer. With R11G11B10F colors in the LDR range have a precision of either + * 6 bits (red and green channels) or 5 bits (blue channel). + */ + struct RenderQuality { + QualityLevel hdrColorBuffer = QualityLevel::HIGH; //!< quality of the color buffer + }; + + /** + * List of available post-processing anti-aliasing techniques. + */ + enum AntiAliasing : uint8_t { + NONE = 0, + FXAA = 1 + }; + enum class DepthPrepass : int8_t { DEFAULT = -1, DISABLED, @@ -178,6 +207,10 @@ public: */ Scene* getScene() noexcept; + /** + * Returns the Scene currently associated with this View. + * @return A pointer to the Scene associated to this View. nullptr if no Scene is set. + */ Scene const* getScene() const noexcept { return const_cast(this)->getScene(); } @@ -326,11 +359,6 @@ public: */ uint8_t getSampleCount() const noexcept; - enum AntiAliasing : uint8_t { - NONE = 0, - FXAA = 1 - }; - /** * Enables or disables anti-aliasing in the post-processing stage. Enabled by default. * MSAA can be enabled in addition, see setSampleCount(). @@ -361,6 +389,20 @@ public: */ DynamicResolutionOptions getDynamicResolutionOptions() const noexcept; + /** + * Sets the rendering quality for this view. Refer to RenderQuality for more + * information about the different settings available. + * + * @param renderQuality The render quality to use on this view + */ + void setRenderQuality(RenderQuality const& renderQuality) noexcept; + + /** + * Returns the render quality used by this view. + * @return value set by setRenderQuality(). + */ + RenderQuality getRenderQuality() const noexcept; + /** * Sets options relative to dynamic lighting for this view. * diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index 72b9029cc9..eb6189d60b 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -95,6 +95,27 @@ void FRenderer::terminate(FEngine& engine) { } } +driver::TextureFormat FRenderer::getHdrFormat(const View& view) const noexcept { + const bool translucent = mSwapChain->isTransparent(); + if (translucent) return driver::TextureFormat::RGBA16F; + + switch (view.getRenderQuality().hdrColorBuffer) { + case View::QualityLevel::LOW: + case View::QualityLevel::MEDIUM: + return driver::TextureFormat::R11F_G11F_B10F; + case View::QualityLevel::HIGH: + case View::QualityLevel::ULTRA: + return !mIsRGB16FSupported ? driver::TextureFormat::RGBA16F + : driver::TextureFormat::RGB16F; + } +} + +driver::TextureFormat FRenderer::getLdrFormat() const noexcept { + const bool translucent = mSwapChain->isTransparent(); + return (translucent || !mIsRGB8Supported) ? driver::TextureFormat::RGBA8 + : driver::TextureFormat::RGB8; +} + void FRenderer::render(FView const* view) { SYSTRACE_CALL(); @@ -177,7 +198,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { */ const uint8_t useMSAA = view.getSampleCount(); - const TextureFormat hdrFormat = getHdrFormat(); + const TextureFormat hdrFormat = getHdrFormat(view); const TextureFormat ldrFormat = getLdrFormat(); RenderTargetPool::Target const* colorTarget = nullptr; diff --git a/filament/src/View.cpp b/filament/src/View.cpp index 1346d921cc..cd91469bc1 100644 --- a/filament/src/View.cpp +++ b/filament/src/View.cpp @@ -847,6 +847,14 @@ View::DynamicResolutionOptions View::getDynamicResolutionOptions() const noexcep return upcast(this)->getDynamicResolutionOptions(); } +void View::setRenderQuality(const RenderQuality& renderQuality) noexcept { + upcast(this)->setRenderQuality(renderQuality); +} + +View::RenderQuality View::getRenderQuality() const noexcept { + return upcast(this)->getRenderQuality(); +} + void View::setPostProcessingEnabled(bool enabled) noexcept { upcast(this)->setPostProcessingEnabled(enabled); } diff --git a/filament/src/details/Renderer.h b/filament/src/details/Renderer.h index 7a36c5fcae..49d1c0394c 100644 --- a/filament/src/details/Renderer.h +++ b/filament/src/details/Renderer.h @@ -120,17 +120,8 @@ private: return mCommandsHighWatermark * sizeof(RenderPass::Command); } - driver::TextureFormat getHdrFormat() const noexcept { - const bool translucent = mSwapChain->isTransparent(); - return (translucent || !mIsRGB16FSupported) ? driver::TextureFormat::RGBA16F - : driver::TextureFormat::RGB16F; - } - - driver::TextureFormat getLdrFormat() const noexcept { - const bool translucent = mSwapChain->isTransparent(); - return (translucent || !mIsRGB8Supported) ? driver::TextureFormat::RGBA8 - : driver::TextureFormat::RGB8; - } + driver::TextureFormat getHdrFormat(const View& view) const noexcept; + driver::TextureFormat getLdrFormat() const noexcept; // keep a reference to our engine FEngine& mEngine; diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 73d20d9fbc..8bfdd258fa 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -180,6 +180,14 @@ public: return mDynamicResolution; } + void setRenderQuality(RenderQuality const& renderQuality) noexcept { + mRenderQuality = renderQuality; + } + + RenderQuality getRenderQuality() const noexcept { + return mRenderQuality; + } + void setDynamicLightingOptions(float zLightNear, float zLightFar) noexcept; void setPostProcessingEnabled(bool enabled) noexcept { @@ -279,6 +287,8 @@ private: float mDynamicWorkloadScale = 1.0f; bool mIsDynamicResolutionSupported = false; + RenderQuality mRenderQuality; + mutable UniformBuffer mPerViewUb; mutable SamplerBuffer mPerViewSb;