From 1b36f82c1e6658f21300cf1d5dda614b15f97b29 Mon Sep 17 00:00:00 2001
From: Mathias Agopian
Date: Fri, 10 Apr 2020 15:54:14 -0700
Subject: [PATCH] API BREAKAGE: this change aims to fix multi-view support
(#2376)
* API BREAKAGE: this change aims to fix multi-view support
What has changed:
- View doesn't have a notion of clear color anymore
- View doesn't have a notion of discard flags anymore
- The clear color and color-buffer discard/clear flags are moved to Renderer
- Skybox can now be set to a constant color
- View have a blend-mode
What does is all mean:
"Clearing" (i.e.) setting its background is now handled by Skybox, by
setting a constant color to the Skybox. This should take care of
drawing views side by side.
When a view needs to be drawn on top of another, it's BlendMode needs to
be set to TRANSLUCENT and of course and, generally, it wither won't have
a skybox, or will have one that sets some translucent pixels.
As an optimization, a View with BlendMode::OPAQUE will have its
background cleared with the color specified in Renderer.
If the SwapChain already has some content, it's now possible to set
the Renderer to not discard the content, together with TRANSLUCENT views,
it's possible to draw on top of that content.
It is NOT possible to share depth/stencil buffers between views.
Fixes: #2369, #2372, #2364
* Address reviewers comments.
Note: WebGL is still broken with this PR
---
.../src/main/cpp/Renderer.cpp | 10 ++
.../filament-android/src/main/cpp/SkyBox.cpp | 16 +++
.../filament-android/src/main/cpp/View.cpp | 36 ++-----
.../com/google/android/filament/Renderer.java | 51 +++++++++
.../com/google/android/filament/Skybox.java | 51 +++++++++
.../com/google/android/filament/View.java | 102 ++++++++----------
.../android/filament/hellocam/MainActivity.kt | 2 +-
.../filament/hellotriangle/MainActivity.kt | 5 +-
.../android/filament/ibl/MainActivity.kt | 5 -
.../android/filament/litcube/MainActivity.kt | 5 +-
.../filament/material_builder/MainActivity.kt | 5 -
.../filament/multiview/MainActivity.kt | 28 ++---
.../filament/streamtest/MainActivity.kt | 2 +-
.../filament/textureview/MainActivity.kt | 5 +-
.../android/filament/textured/MainActivity.kt | 5 -
.../transparentrendering/MainActivity.kt | 8 +-
filament/include/filament/Renderer.h | 31 ++++++
filament/include/filament/Scene.h | 2 +-
filament/include/filament/Skybox.h | 14 +++
filament/include/filament/View.h | 52 +++------
filament/src/Renderer.cpp | 100 +++++++++--------
filament/src/Scene.cpp | 8 +-
filament/src/Skybox.cpp | 37 +++++--
filament/src/View.cpp | 40 ++-----
filament/src/details/Renderer.h | 7 ++
filament/src/details/Scene.h | 5 +-
filament/src/details/Skybox.h | 8 +-
filament/src/details/View.h | 45 ++------
filament/src/fg/FrameGraphHandle.h | 3 +-
.../src/fg/fg/RenderTargetResourceEntry.cpp | 4 +-
filament/src/materials/skybox.mat | 21 +++-
filament/test/filament_rendering_test.cpp | 11 +-
.../hello-triangle/FilamentView.mm | 2 +-
.../transparent-rendering/FilamentView.mm | 2 +-
libs/filamentapp/src/FilamentApp.cpp | 11 +-
samples/animation.cpp | 6 +-
samples/depthtesting.cpp | 7 +-
samples/frame_generator.cpp | 20 ++--
samples/gltf_viewer.cpp | 6 +-
samples/heightfield.cpp | 6 +-
samples/hellotriangle.cpp | 6 +-
samples/point_sprites.cpp | 7 +-
samples/shadowtest.cpp | 6 +-
samples/strobecolor.cpp | 11 +-
samples/texturedquad.cpp | 7 +-
samples/viewtest.cpp | 6 +-
web/filament-js/jsbindings.cpp | 1 -
47 files changed, 495 insertions(+), 333 deletions(-)
diff --git a/android/filament-android/src/main/cpp/Renderer.cpp b/android/filament-android/src/main/cpp/Renderer.cpp
index 405fddaf1c..b140b50a5d 100644
--- a/android/filament-android/src/main/cpp/Renderer.cpp
+++ b/android/filament-android/src/main/cpp/Renderer.cpp
@@ -163,3 +163,13 @@ Java_com_google_android_filament_Renderer_nSetFrameRateOptions(JNIEnv*, jclass,
.history = (uint8_t)history,
.interval = (uint8_t)interval });
}
+
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_android_filament_Renderer_nSetClearOptions(JNIEnv *, jclass ,
+ jlong nativeRenderer, jfloat r, jfloat g, jfloat b, jfloat a,
+ jboolean clear, jboolean discard) {
+ Renderer *renderer = (Renderer *) nativeRenderer;
+ renderer->setClearOptions({ .clearColor = {r, g, b, a},
+ .clear = (bool) clear,
+ .discard = (bool) discard});
+}
diff --git a/android/filament-android/src/main/cpp/SkyBox.cpp b/android/filament-android/src/main/cpp/SkyBox.cpp
index 6b31d27a32..7fbd81ce32 100644
--- a/android/filament-android/src/main/cpp/SkyBox.cpp
+++ b/android/filament-android/src/main/cpp/SkyBox.cpp
@@ -18,6 +18,8 @@
#include
+#include
- *
- * This method discards the content of all the buffers in the render target. See
- * {@link #setRenderTarget(RenderTarget, EnumSet)} if you need more precise control.
- *
*
* @param target render target associated with view, or null for the swap chain
*/
public void setRenderTarget(@Nullable RenderTarget target) {
- setRenderTarget(target, TargetBufferFlags.ALL);
- }
-
- /**
- * Specifies an offscreen render target to render into.
- *
- *
- * By default, the view's associated render target is null, which corresponds to the
- * SwapChain associated with the engine.
- *
- *
- * @param target render target associated with view, or null for the swap chain
- * @param flags buffers that need to be discarded before rendering.
- */
- public void setRenderTarget(@Nullable RenderTarget target,
- @NonNull EnumSet flags) {
mRenderTarget = target;
- nSetRenderTarget(getNativeObject(), target != null ? target.getNativeObject() : 0,
- TargetBufferFlags.flags(flags));
+ nSetRenderTarget(getNativeObject(), target != null ? target.getNativeObject() : 0);
}
/**
@@ -954,6 +923,7 @@ public class View {
* Sets bloom options.
*
* @param options Options for bloom.
+ * @see #getBloomOptions
*/
public void setBloomOptions(@NonNull BloomOptions options) {
mBloomOptions = options;
@@ -963,10 +933,25 @@ public class View {
options.threshold, options.enabled);
}
+ /**
+ * Gets the bloom options
+ * @see #setBloomOptions
+ *
+ * @return bloom options currently set.
+ */
+ @NonNull
+ public BloomOptions getBloomOptions() {
+ if (mBloomOptions == null) {
+ mBloomOptions = new BloomOptions();
+ }
+ return mBloomOptions;
+ }
+
/**
* Sets fog options.
*
* @param options Options for fog.
+ * @see #getFogOptions
*/
public void setFogOptions(@NonNull FogOptions options) {
mFogOptions = options;
@@ -978,18 +963,20 @@ public class View {
}
/**
- * Gets the bloom options
+ * Gets the fog options
*
- * @return bloom options currently set.
+ * @return fog options currently set.
+ * @see #setFogOptions
*/
@NonNull
- public BloomOptions getBloomOptions() {
- if (mBloomOptions == null) {
- mBloomOptions = new BloomOptions();
+ public FogOptions getFogOptions() {
+ if (mFogOptions == null) {
+ mFogOptions = new FogOptions();
}
- return mBloomOptions;
+ return mFogOptions;
}
+
public long getNativeObject() {
if (mNativeObject == 0) {
throw new IllegalStateException("Calling method on destroyed View");
@@ -1005,12 +992,9 @@ public class View {
private static native void nSetScene(long nativeView, long nativeScene);
private static native void nSetCamera(long nativeView, long nativeCamera);
private static native void nSetViewport(long nativeView, int left, int bottom, int width, int height);
- private static native void nSetClearColor(long nativeView, float r, float g, float b, float a);
- private static native void nGetClearColor(long nativeView, float[] out);
- private static native void nSetClearTargets(long nativeView, boolean color, boolean depth, boolean stencil);
private static native void nSetVisibleLayers(long nativeView, int select, int value);
private static native void nSetShadowsEnabled(long nativeView, boolean enabled);
- private static native void nSetRenderTarget(long nativeView, long nativeRenderTarget, int flags);
+ private static native void nSetRenderTarget(long nativeView, long nativeRenderTarget);
private static native void nSetSampleCount(long nativeView, int count);
private static native int nGetSampleCount(long nativeView);
private static native void nSetAntiAliasing(long nativeView, int type);
@@ -1031,5 +1015,5 @@ public class View {
private static native void nSetAmbientOcclusionOptions(long nativeView, float radius, float bias, float power, float resolution, float intensity, int quality);
private static native void nSetBloomOptions(long nativeView, long dirtNativeObject, float dirtStrength, float strength, int resolution, float anamorphism, int levels, int blendMode, boolean threshold, boolean enabled);
private static native void nSetFogOptions(long nativeView, float distance, float maximumOpacity, float height, float heightFalloff, float v, float v1, float v2, float density, float inScatteringStart, float inScatteringSize, boolean fogColorFromIbl, boolean enabled);
-
+ private static native void nSetBlendMode(long nativeView, int blendMode);
}
diff --git a/android/samples/sample-hello-camera/src/main/java/com/google/android/filament/hellocam/MainActivity.kt b/android/samples/sample-hello-camera/src/main/java/com/google/android/filament/hellocam/MainActivity.kt
index e36130d9b4..9cdc483313 100644
--- a/android/samples/sample-hello-camera/src/main/java/com/google/android/filament/hellocam/MainActivity.kt
+++ b/android/samples/sample-hello-camera/src/main/java/com/google/android/filament/hellocam/MainActivity.kt
@@ -113,7 +113,7 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
}
private fun setupView() {
- view.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
+ scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
view.camera = camera
view.scene = scene
}
diff --git a/android/samples/sample-hello-triangle/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt b/android/samples/sample-hello-triangle/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt
index 4365c6c605..637671fc03 100644
--- a/android/samples/sample-hello-triangle/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt
+++ b/android/samples/sample-hello-triangle/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt
@@ -117,10 +117,7 @@ class MainActivity : Activity() {
}
private fun setupView() {
- // Clear the background to middle-grey
- // Setting up a clear color is useful for debugging but usually
- // unnecessary when using a skybox
- view.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
+ scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
// view.isPostProcessingEnabled = false
diff --git a/android/samples/sample-image-based-lighting/src/main/java/com/google/android/filament/ibl/MainActivity.kt b/android/samples/sample-image-based-lighting/src/main/java/com/google/android/filament/ibl/MainActivity.kt
index ba475b4a86..ff47f85df5 100644
--- a/android/samples/sample-image-based-lighting/src/main/java/com/google/android/filament/ibl/MainActivity.kt
+++ b/android/samples/sample-image-based-lighting/src/main/java/com/google/android/filament/ibl/MainActivity.kt
@@ -117,11 +117,6 @@ class MainActivity : Activity() {
}
private fun setupView() {
- // Clear the background to middle-grey
- // Setting up a clear color is useful for debugging but usually
- // unnecessary when using a skybox
- view.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
-
view.ambientOcclusion = View.AmbientOcclusion.SSAO
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
diff --git a/android/samples/sample-lit-cube/src/main/java/com/google/android/filament/litcube/MainActivity.kt b/android/samples/sample-lit-cube/src/main/java/com/google/android/filament/litcube/MainActivity.kt
index bb7952c84a..80d4664f86 100644
--- a/android/samples/sample-lit-cube/src/main/java/com/google/android/filament/litcube/MainActivity.kt
+++ b/android/samples/sample-lit-cube/src/main/java/com/google/android/filament/litcube/MainActivity.kt
@@ -118,10 +118,7 @@ class MainActivity : Activity() {
}
private fun setupView() {
- // Clear the background to middle-grey
- // Setting up a clear color is useful for debugging but usually
- // unnecessary when using a skybox
- view.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
+ scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
// view.isPostProcessingEnabled = false
diff --git a/android/samples/sample-material-builder/src/main/java/com/google/android/filament/material_builder/MainActivity.kt b/android/samples/sample-material-builder/src/main/java/com/google/android/filament/material_builder/MainActivity.kt
index bb53f2953e..aeaed65353 100644
--- a/android/samples/sample-material-builder/src/main/java/com/google/android/filament/material_builder/MainActivity.kt
+++ b/android/samples/sample-material-builder/src/main/java/com/google/android/filament/material_builder/MainActivity.kt
@@ -116,11 +116,6 @@ class MainActivity : Activity() {
}
private fun setupView() {
- // Clear the background to middle-grey
- // Setting up a clear color is useful for debugging but usually
- // unnecessary when using a skybox
- view.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
-
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
// view.isPostProcessingEnabled = false
diff --git a/android/samples/sample-multi-view/src/main/java/com/google/android/filament/multiview/MainActivity.kt b/android/samples/sample-multi-view/src/main/java/com/google/android/filament/multiview/MainActivity.kt
index a7fd2d678a..a970b08065 100644
--- a/android/samples/sample-multi-view/src/main/java/com/google/android/filament/multiview/MainActivity.kt
+++ b/android/samples/sample-multi-view/src/main/java/com/google/android/filament/multiview/MainActivity.kt
@@ -65,6 +65,8 @@ class MainActivity : Activity() {
private lateinit var view1: View
private lateinit var view2: View
private lateinit var view3: View
+ // We need skybox to set the background color
+ private lateinit var skybox: Skybox
// Should be pretty obvious :)
private lateinit var camera: Camera
@@ -123,24 +125,13 @@ class MainActivity : Activity() {
view2.setName("view2");
view3.setName("view3");
+ skybox = Skybox.Builder().build(engine);
+ scene.skybox = skybox
+
camera = engine.createCamera()
}
private fun setupViews() {
- // To use multi-view properly with mobile GPUs, we need to make sure to tell
- // Filament to not discard buffers after the first view we render
- view1.setRenderTarget(null, View.TargetBufferFlags.NONE)
- view2.setRenderTarget(null, View.TargetBufferFlags.NONE)
- view3.setRenderTarget(null, View.TargetBufferFlags.NONE)
-
- // Clears are not restricted by the scissor so we want to disable clear targets
- // except for the first view we render
- view1.setClearTargets(false, false, false)
- view2.setClearTargets(false, false, false)
- view3.setClearTargets(false, false, false)
-
- view0.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
-
view0.camera = camera
view1.camera = camera
view2.camera = camera
@@ -382,6 +373,7 @@ class MainActivity : Activity() {
engine.destroyView(view1)
engine.destroyView(view2)
engine.destroyView(view3)
+ engine.destroySkybox(skybox)
engine.destroyScene(scene)
engine.destroyCamera(camera)
@@ -406,10 +398,18 @@ class MainActivity : Activity() {
// If beginFrame() returns false you should skip the frame
// This means you are sending frames too quickly to the GPU
if (renderer.beginFrame(swapChain!!, frameTimeNanos)) {
+ skybox.setColor(0.035f, 0.035f, 0.035f, 1.0f);
renderer.render(view0)
+
+ skybox.setColor(1.0f, 0.0f, 0.0f, 1.0f);
renderer.render(view1)
+
+ skybox.setColor(0.0f, 1.0f, 0.0f, 1.0f);
renderer.render(view2)
+
+ skybox.setColor(0.0f, 0.0f, 1.0f, 1.0f);
renderer.render(view3)
+
renderer.endFrame()
}
}
diff --git a/android/samples/sample-stream-test/src/main/java/com/google/android/filament/streamtest/MainActivity.kt b/android/samples/sample-stream-test/src/main/java/com/google/android/filament/streamtest/MainActivity.kt
index 7fdd05f45e..33545b7fb7 100644
--- a/android/samples/sample-stream-test/src/main/java/com/google/android/filament/streamtest/MainActivity.kt
+++ b/android/samples/sample-stream-test/src/main/java/com/google/android/filament/streamtest/MainActivity.kt
@@ -125,7 +125,7 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
}
private fun setupView() {
- view.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
+ scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
view.camera = camera
view.scene = scene
}
diff --git a/android/samples/sample-texture-view/src/main/java/com/google/android/filament/textureview/MainActivity.kt b/android/samples/sample-texture-view/src/main/java/com/google/android/filament/textureview/MainActivity.kt
index 435b134530..55db366043 100644
--- a/android/samples/sample-texture-view/src/main/java/com/google/android/filament/textureview/MainActivity.kt
+++ b/android/samples/sample-texture-view/src/main/java/com/google/android/filament/textureview/MainActivity.kt
@@ -117,10 +117,7 @@ class MainActivity : Activity() {
}
private fun setupView() {
- // Clear the background to middle-grey
- // Setting up a clear color is useful for debugging but usually
- // unnecessary when using a skybox
- view.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
+ scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
// view.isPostProcessingEnabled = false
diff --git a/android/samples/sample-textured-object/src/main/java/com/google/android/filament/textured/MainActivity.kt b/android/samples/sample-textured-object/src/main/java/com/google/android/filament/textured/MainActivity.kt
index 1dcca6a75b..5cd67e350f 100644
--- a/android/samples/sample-textured-object/src/main/java/com/google/android/filament/textured/MainActivity.kt
+++ b/android/samples/sample-textured-object/src/main/java/com/google/android/filament/textured/MainActivity.kt
@@ -121,11 +121,6 @@ class MainActivity : Activity() {
}
private fun setupView() {
- // Clear the background to middle-grey
- // Setting up a clear color is useful for debugging but usually
- // unnecessary when using a skybox
- view.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
-
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
// view.isPostProcessingEnabled = false
diff --git a/android/samples/sample-transparent-view/src/main/java/com/google/android/filament/transparentrendering/MainActivity.kt b/android/samples/sample-transparent-view/src/main/java/com/google/android/filament/transparentrendering/MainActivity.kt
index 8ff038ae13..8ab5da530d 100644
--- a/android/samples/sample-transparent-view/src/main/java/com/google/android/filament/transparentrendering/MainActivity.kt
+++ b/android/samples/sample-transparent-view/src/main/java/com/google/android/filament/transparentrendering/MainActivity.kt
@@ -137,12 +137,14 @@ class MainActivity : Activity() {
scene = engine.createScene()
view = engine.createView()
camera = engine.createCamera()
+
+ // clear the swapchain with transparent pixels
+ val options = renderer.clearOptions
+ options.clear = true
+ renderer.clearOptions = options
}
private fun setupView() {
- // Make sure to clear to a fully transparent color
- view.setClearColor(0.0f, 0.0f, 0.0f, 0.0f)
-
// Tell the view which camera we want to use
view.camera = camera
diff --git a/filament/include/filament/Renderer.h b/filament/include/filament/Renderer.h
index fd405d4ef6..7a6d2bee1e 100644
--- a/filament/include/filament/Renderer.h
+++ b/filament/include/filament/Renderer.h
@@ -69,6 +69,10 @@ class PixelBufferDescriptor;
class UTILS_PUBLIC Renderer : public FilamentAPI {
public:
+ /**
+ * Use DisplayInfo to set important Display properties. This is used to achieve correct
+ * frame pacing and dynamic resolution scaling.
+ */
struct DisplayInfo {
// refresh-rate of the display in Hz. set to 0 for offscreen or turn off frame-pacing.
float refreshRate = 60.0f;
@@ -109,6 +113,25 @@ public:
uint8_t interval = 1; //!< desired frame interval in unit of 1.0 / DisplayInfo::refreshRate
};
+ /**
+ * ClearOptions are used at the beginning of a frame to clear or retain the SwapChain content.
+ */
+ struct ClearOptions {
+ /** Color to use to clear the SwapChain */
+ math::float4 clearColor = {};
+ /**
+ * Whether the SwapChain should be cleared using the clearColor. Use this if translucent
+ * View will be drawn, for instance.
+ */
+ bool clear = false;
+ /**
+ * Whether the SwapChain content should be discarded. clear implies discard. Set this
+ * to false (along with clear to false as well) if the SwapChain already has content that
+ * needs to be preserved
+ */
+ bool discard = true;
+ };
+
/**
* Information about the display this Renderer is associated to. This information is needed
* to accurately compute dynamic-resolution scaling and for frame-pacing.
@@ -124,6 +147,14 @@ public:
*/
void setFrameRateOptions(FrameRateOptions const& options) noexcept;
+ /**
+ * Set ClearOptions which are used at the beginning of a frame to clear or retain the
+ * SwapChain content.
+ *
+ * @param options
+ */
+ void setClearOptions(const ClearOptions& options);
+
/**
* Get the Engine that created this Renderer.
*
diff --git a/filament/include/filament/Scene.h b/filament/include/filament/Scene.h
index 6dca2229fc..2ce7d0bce8 100644
--- a/filament/include/filament/Scene.h
+++ b/filament/include/filament/Scene.h
@@ -72,7 +72,7 @@ public:
*
* @param skybox The Skybox to use to fill untouched pixels, or nullptr to unset the Skybox.
*/
- void setSkybox(Skybox const* skybox) noexcept;
+ void setSkybox(Skybox* skybox) noexcept;
/**
* Set the IndirectLight to use when rendering the Scene.
diff --git a/filament/include/filament/Skybox.h b/filament/include/filament/Skybox.h
index d453e6779a..6081f8f2d3 100644
--- a/filament/include/filament/Skybox.h
+++ b/filament/include/filament/Skybox.h
@@ -24,6 +24,7 @@
#include
#include
+#include