diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md
index d000a526635..4a1a9c7fa7e 100644
--- a/NEW_RELEASE_NOTES.md
+++ b/NEW_RELEASE_NOTES.md
@@ -7,6 +7,3 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
-
-- matc: New option `-1` to disable generation of ESSL 1.0 code in Feature Level 0 materials
-- matc: Support optimizations for ESSL 1.0 code [⚠️ **Recompile materials**]
diff --git a/README.md b/README.md
index b0278db43f3..50bcf1ecec1 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
- implementation 'com.google.android.filament:filament-android:1.47.0'
+ implementation 'com.google.android.filament:filament-android:1.48.0'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
-pod 'Filament', '~> 1.47.0'
+pod 'Filament', '~> 1.48.0'
```
### Snapshots
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index a87c44268c7..3459c5001f8 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -7,7 +7,13 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
+## v1.48.0
+
+- matc: New option `-1` to disable generation of ESSL 1.0 code in Feature Level 0 materials
+- matc: Support optimizations for ESSL 1.0 code [⚠️ **Recompile materials**]
+
## v1.47.0
+
- engine: Support up to 4 side-by-side stereoscopic eyes, configurable at Engine creation time. See
`Engine::Config::stereoscopicEyeCount`. [⚠️ **Recompile Materials**]
diff --git a/android/filament-android/src/main/cpp/Engine.cpp b/android/filament-android/src/main/cpp/Engine.cpp
index b5fd507aa18..51499a14bc9 100644
--- a/android/filament-android/src/main/cpp/Engine.cpp
+++ b/android/filament-android/src/main/cpp/Engine.cpp
@@ -435,6 +435,13 @@ Java_com_google_android_filament_Engine_nIsAutomaticInstancingEnabled(JNIEnv*, j
return (jboolean)engine->isAutomaticInstancingEnabled();
}
+extern "C" JNIEXPORT jlong JNICALL
+Java_com_google_android_filament_Engine_nGetMaxStereoscopicEyes(JNIEnv*, jclass, jlong nativeEngine) {
+ Engine* engine = (Engine*) nativeEngine;
+ return (jlong) engine->getMaxStereoscopicEyes();
+}
+
+
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_Engine_nGetSupportedFeatureLevel(JNIEnv *, jclass,
jlong nativeEngine) {
@@ -477,7 +484,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderConfig(JNIEnv*,
jclass, jlong nativeBuilder, jlong commandBufferSizeMB, jlong perRenderPassArenaSizeMB,
jlong driverHandleArenaSizeMB, jlong minCommandBufferSizeMB, jlong perFrameCommandsSizeMB,
- jlong jobSystemThreadCount) {
+ jlong jobSystemThreadCount, jlong stereoscopicEyeCount) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
Engine::Config config = {
.commandBufferSizeMB = (uint32_t) commandBufferSizeMB,
@@ -486,6 +493,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
.minCommandBufferSizeMB = (uint32_t) minCommandBufferSizeMB,
.perFrameCommandsSizeMB = (uint32_t) perFrameCommandsSizeMB,
.jobSystemThreadCount = (uint32_t) jobSystemThreadCount,
+ .stereoscopicEyeCount = (uint8_t) stereoscopicEyeCount,
};
builder->config(&config);
}
diff --git a/android/filament-android/src/main/cpp/View.cpp b/android/filament-android/src/main/cpp/View.cpp
index fc4de145e90..e2d8efacb3a 100644
--- a/android/filament-android/src/main/cpp/View.cpp
+++ b/android/filament-android/src/main/cpp/View.cpp
@@ -480,6 +480,17 @@ Java_com_google_android_filament_View_nIsStencilBufferEnabled(JNIEnv *, jclass,
return view->isStencilBufferEnabled();
}
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_google_android_filament_View_nSetStereoscopicOptions(JNIEnv *, jclass, jlong nativeView,
+ jboolean enabled) {
+ View* view = (View*) nativeView;
+ View::StereoscopicOptions options {
+ .enabled = (bool) enabled
+ };
+ view->setStereoscopicOptions(options);
+}
+
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_View_nSetGuardBandOptions(JNIEnv *, jclass,
diff --git a/android/filament-android/src/main/java/com/google/android/filament/Engine.java b/android/filament-android/src/main/java/com/google/android/filament/Engine.java
index 26fd9e81c3a..014cc33ceec 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/Engine.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/Engine.java
@@ -111,6 +111,8 @@ public class Engine {
private long mNativeObject;
+ private Config mConfig;
+
@NonNull private final TransformManager mTransformManager;
@NonNull private final LightManager mLightManager;
@NonNull private final RenderableManager mRenderableManager;
@@ -163,6 +165,7 @@ public static class Builder {
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
private final BuilderFinalizer mFinalizer;
private final long mNativeBuilder;
+ private Config mConfig;
public Builder() {
mNativeBuilder = nCreateBuilder();
@@ -204,10 +207,11 @@ public Builder sharedContext(Object sharedContext) {
* @return A reference to this Builder for chaining calls.
*/
public Builder config(Config config) {
+ mConfig = config;
nSetBuilderConfig(mNativeBuilder, config.commandBufferSizeMB,
config.perRenderPassArenaSizeMB, config.driverHandleArenaSizeMB,
config.minCommandBufferSizeMB, config.perFrameCommandsSizeMB,
- config.jobSystemThreadCount);
+ config.jobSystemThreadCount, config.stereoscopicEyeCount);
return this;
}
@@ -235,7 +239,7 @@ public Builder featureLevel(FeatureLevel featureLevel) {
public Engine build() {
long nativeEngine = nBuilderBuild(mNativeBuilder);
if (nativeEngine == 0) throw new IllegalStateException("Couldn't create Engine");
- return new Engine(nativeEngine);
+ return new Engine(nativeEngine, mConfig);
}
private static class BuilderFinalizer {
@@ -343,14 +347,24 @@ public static class Config {
* the number of threads to use.
*/
public long jobSystemThreadCount = 0;
+
+ /**
+ * The number of eyes to render when stereoscopic rendering is enabled. Supported values are
+ * between 1 and Engine#getMaxStereoscopicEyes() (inclusive).
+ *
+ * @see View#setStereoscopicOptions
+ * @see Engine#getMaxStereoscopicEyes
+ */
+ public long stereoscopicEyeCount = 2;
}
- private Engine(long nativeEngine) {
+ private Engine(long nativeEngine, Config config) {
mNativeObject = nativeEngine;
mTransformManager = new TransformManager(nGetTransformManager(nativeEngine));
mLightManager = new LightManager(nGetLightManager(nativeEngine));
mRenderableManager = new RenderableManager(nGetRenderableManager(nativeEngine));
mEntityManager = new EntityManager(nGetEntityManager(nativeEngine));
+ mConfig = config;
}
/**
@@ -543,6 +557,37 @@ public boolean isAutomaticInstancingEnabled() {
return nIsAutomaticInstancingEnabled(getNativeObject());
}
+ /**
+ * Retrieves the configuration settings of this {@link Engine}.
+ *
+ * This method returns the configuration object that was supplied to the Engine's {@link
+ * Builder#config} method during the creation of this Engine. If the {@link Builder::config}
+ * method was not explicitly called (or called with null), this method returns the default
+ * configuration settings.
+ *
+ * @return a {@link Config} object with this Engine's configuration
+ * @see Builder#config
+ */
+ @NonNull
+ public Config getConfig() {
+ if (mConfig == null) {
+ mConfig = new Config();
+ }
+ return mConfig;
+ }
+
+ /**
+ * Returns the maximum number of stereoscopic eyes supported by Filament. The actual number of
+ * eyes rendered is set at Engine creation time with the {@link
+ * Engine#Config#stereoscopicEyeCount} setting.
+ *
+ * @return the max number of stereoscopic eyes supported
+ * @see Engine#Config#stereoscopicEyeCount
+ */
+ public long getMaxStereoscopicEyes() {
+ return nGetMaxStereoscopicEyes(getNativeObject());
+ }
+
// SwapChain
@@ -1171,6 +1216,7 @@ private static void assertDestroy(boolean success) {
private static native long nGetEntityManager(long nativeEngine);
private static native void nSetAutomaticInstancingEnabled(long nativeEngine, boolean enable);
private static native boolean nIsAutomaticInstancingEnabled(long nativeEngine);
+ private static native long nGetMaxStereoscopicEyes(long nativeEngine);
private static native int nGetSupportedFeatureLevel(long nativeEngine);
private static native int nSetActiveFeatureLevel(long nativeEngine, int ordinal);
private static native int nGetActiveFeatureLevel(long nativeEngine);
@@ -1180,7 +1226,8 @@ private static void assertDestroy(boolean success) {
private static native void nSetBuilderBackend(long nativeBuilder, long backend);
private static native void nSetBuilderConfig(long nativeBuilder, long commandBufferSizeMB,
long perRenderPassArenaSizeMB, long driverHandleArenaSizeMB,
- long minCommandBufferSizeMB, long perFrameCommandsSizeMB, long jobSystemThreadCount);
+ long minCommandBufferSizeMB, long perFrameCommandsSizeMB, long jobSystemThreadCount,
+ long stereoscopicEyeCount);
private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal);
private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext);
private static native long nBuilderBuild(long nativeBuilder);
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 91622d26c41..8dfe948023d 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
@@ -75,6 +75,7 @@ public class View {
private AmbientOcclusionOptions mAmbientOcclusionOptions;
private BloomOptions mBloomOptions;
private FogOptions mFogOptions;
+ private StereoscopicOptions mStereoscopicOptions;
private RenderTarget mRenderTarget;
private BlendMode mBlendMode;
private DepthOfFieldOptions mDepthOfFieldOptions;
@@ -1055,6 +1056,51 @@ public boolean isStencilBufferEnabled() {
return nIsStencilBufferEnabled(getNativeObject());
}
+ /**
+ * Sets the stereoscopic rendering options for this view.
+ *
+ *
+ * Currently, only one type of stereoscopic rendering is supported: side-by-side.
+ * Side-by-side stereo rendering splits the viewport into two halves: a left and right half.
+ * Eye 0 will render to the left half, while Eye 1 will render into the right half.
+ *
+ *
+ *
+ * Currently, the following features are not supported with stereoscopic rendering:
+ * - post-processing
+ * - shadowing
+ * - punctual lights
+ *
+ *
+ *
+ * Stereo rendering depends on device and platform support. To check if stereo rendering is
+ * supported, use {@link Engine#isStereoSupported()}. If stereo rendering is not supported, then
+ * the stereoscopic options have no effect.
+ *
+ *
+ * @param options The stereoscopic options to use on this view
+ * @see #getStereoscopicOptions
+ */
+ public void setStereoscopicOptions(@NonNull StereoscopicOptions options) {
+ mStereoscopicOptions = options;
+ nSetStereoscopicOptions(getNativeObject(), options.enabled);
+ }
+
+ /**
+ * Gets the stereoscopic options.
+ *
+ * @return options Stereoscopic options currently set.
+ * @see #setStereoscopicOptions
+ */
+ @NonNull
+ public StereoscopicOptions getStereoscoopicOptions() {
+ if (mStereoscopicOptions == null) {
+ mStereoscopicOptions = new StereoscopicOptions();
+ }
+ return mStereoscopicOptions;
+ }
+
+
/**
* A class containing the result of a picking query
*/
@@ -1220,6 +1266,7 @@ void clearNativeObject() {
private static native void nSetBloomOptions(long nativeView, long dirtNativeObject, float dirtStrength, float strength, int resolution, int levels, int blendMode, boolean threshold, boolean enabled, float highlight,
boolean lensFlare, boolean starburst, float chromaticAberration, int ghostCount, float ghostSpacing, float ghostThreshold, float haloThickness, float haloRadius, float haloThreshold);
private static native void nSetFogOptions(long nativeView, float distance, float maximumOpacity, float height, float heightFalloff, float cutOffDistance, float v, float v1, float v2, float density, float inScatteringStart, float inScatteringSize, boolean fogColorFromIbl, long skyColorNativeObject, boolean enabled);
+ private static native void nSetStereoscopicOptions(long nativeView, boolean enabled);
private static native void nSetBlendMode(long nativeView, int blendMode);
private static native void nSetDepthOfFieldOptions(long nativeView, float cocScale, float maxApertureDiameter, boolean enabled, int filter,
boolean nativeResolution, int foregroundRingCount, int backgroundRingCount, int fastGatherRingCount, int maxForegroundCOC, int maxBackgroundCOC);
diff --git a/android/gradle.properties b/android/gradle.properties
index 6dda5b45e97..db2639526bc 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
-VERSION_NAME=1.47.0
+VERSION_NAME=1.48.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp
index cfe4cacde61..1c49dcc0ecf 100644
--- a/filament/backend/src/opengl/OpenGLDriver.cpp
+++ b/filament/backend/src/opengl/OpenGLDriver.cpp
@@ -1969,6 +1969,13 @@ void OpenGLDriver::makeCurrent(Handle schDraw, Handle
GLSwapChain* scRead = handle_cast(schRead);
mPlatform.makeCurrent(scDraw->swapChain, scRead->swapChain);
mCurrentDrawSwapChain = scDraw;
+
+ // From the GL spec for glViewport and glScissor:
+ // When a GL context is first attached to a window, width and height are set to the
+ // dimensions of that window.
+ // So basically, our viewport/scissor can be reset to "something" here.
+ mContext.state.window.viewport = {};
+ mContext.state.window.scissor = {};
}
// ------------------------------------------------------------------------------------------------
diff --git a/filament/backend/test/BackendTest.cpp b/filament/backend/test/BackendTest.cpp
index 70261e8bf83..2cb5f75b95e 100644
--- a/filament/backend/test/BackendTest.cpp
+++ b/filament/backend/test/BackendTest.cpp
@@ -86,9 +86,9 @@ void BackendTest::executeCommands() {
}
void BackendTest::flushAndWait() {
- auto& api = getDriverApi();
- api.finish();
+ getDriverApi().finish();
executeCommands();
+ getDriver().purge();
}
Handle BackendTest::createSwapChain() {
diff --git a/filament/backend/test/test_Blit.cpp b/filament/backend/test/test_Blit.cpp
index de4f5a66b34..3144071910f 100644
--- a/filament/backend/test/test_Blit.cpp
+++ b/filament/backend/test/test_Blit.cpp
@@ -193,60 +193,6 @@ static void createFaces(DriverApi& dapi, Handle texture, int baseWidt
dapi.update3DImage(texture, level, 0, 0, 0, width, height, 6, std::move(pb));
}
-TEST_F(BackendTest, CubemapMinify) {
- auto& api = getDriverApi();
-
- Handle texture = api.createTexture(
- SamplerType::SAMPLER_CUBEMAP, 4, TextureFormat::RGBA8, 1, 256, 256, 1,
- TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
-
- createFaces(api, texture, 256, 256, 0, float3(0.5, 0, 0));
-
- const int srcLevel = 0;
- const int dstLevel = 1;
-
- const TextureCubemapFace srcFace = TextureCubemapFace::NEGATIVE_Y;
- const TextureCubemapFace dstFace = TextureCubemapFace::NEGATIVE_Y;
-
- const TargetBufferInfo srcInfo = { texture, srcLevel, +srcFace };
- const TargetBufferInfo dstInfo = { texture, dstLevel, +dstFace };
-
- Handle srcRenderTarget;
- srcRenderTarget = api.createRenderTarget( TargetBufferFlags::COLOR,
- 256 >> srcLevel, 256 >> srcLevel, 1, { srcInfo }, {}, {});
-
- Handle dstRenderTarget;
- dstRenderTarget = api.createRenderTarget( TargetBufferFlags::COLOR,
- 256 >> dstLevel, 256 >> dstLevel, 1, { dstInfo }, {}, {});
-
- api.blit(TargetBufferFlags::COLOR0, dstRenderTarget,
- {0, 0, 256 >> dstLevel, 256 >> dstLevel}, srcRenderTarget,
- {0, 0, 256 >> srcLevel, 256 >> srcLevel}, SamplerMagFilter::LINEAR);
-
- // Push through an empty frame. Note that this test does not do
- // makeCurrent / commit and is therefore similar to renderStandaloneView.
- api.beginFrame(0, 0);
- api.endFrame(0);
-
- // Grab a screenshot.
- ScreenshotParams params { 256 >> dstLevel, 256 >> dstLevel, "CubemapMinify.png" };
- api.beginFrame(0, 0);
- dumpScreenshot(api, dstRenderTarget, ¶ms);
- api.endFrame(0);
-
- // Wait for the ReadPixels result to come back.
- api.finish();
- executeCommands();
- getDriver().purge();
-
- // Cleanup.
- api.destroyTexture(texture);
- api.destroyRenderTarget(srcRenderTarget);
- api.destroyRenderTarget(dstRenderTarget);
- executeCommands();
-}
-
-
TEST_F(BackendTest, ColorMagnify) {
auto& api = getDriverApi();
@@ -263,7 +209,7 @@ TEST_F(BackendTest, ColorMagnify) {
api.makeCurrent(swapChain, swapChain);
// Create a source texture.
- Handle srcTexture = api.createTexture(
+ Handle const srcTexture = api.createTexture(
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
const bool flipY = sBackend == Backend::OPENGL;
@@ -271,7 +217,7 @@ TEST_F(BackendTest, ColorMagnify) {
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
// Create a destination texture.
- Handle dstTexture = api.createTexture(
+ Handle const dstTexture = api.createTexture(
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
@@ -338,7 +284,7 @@ TEST_F(BackendTest, ColorMinify) {
api.makeCurrent(swapChain, swapChain);
// Create a source texture.
- Handle srcTexture = api.createTexture(
+ Handle const srcTexture = api.createTexture(
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
const bool flipY = sBackend == Backend::OPENGL;
@@ -346,7 +292,7 @@ TEST_F(BackendTest, ColorMinify) {
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
// Create a destination texture.
- Handle dstTexture = api.createTexture(
+ Handle const dstTexture = api.createTexture(
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
@@ -362,29 +308,20 @@ TEST_F(BackendTest, ColorMinify) {
// Do a "minify" blit from level 1 of the source RT to the level 0 of the destination RT.
const int srcLevel = 1;
- api.blit(TargetBufferFlags::COLOR0, dstRenderTargets[0],
- {0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTargets[srcLevel],
- {0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR);
-
- // Push through an empty frame to allow the texture to upload and the blit to execute.
- api.beginFrame(0, 0);
- api.commit(swapChain);
- api.endFrame(0);
+ api.blit(TargetBufferFlags::COLOR0,
+ dstRenderTargets[0], {0, 0, kDstTexWidth, kDstTexHeight},
+ srcRenderTargets[srcLevel], {0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel},
+ SamplerMagFilter::LINEAR);
// Grab a screenshot.
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "ColorMinify.png" };
- api.beginFrame(0, 0);
dumpScreenshot(api, dstRenderTargets[0], ¶ms);
- api.commit(swapChain);
- api.endFrame(0);
// Wait for the ReadPixels result to come back.
- api.finish();
- executeCommands();
- getDriver().purge();
+ flushAndWait();
// Check if the image matches perfectly to our golden run.
- const uint32_t expected = 0x7739bef5;
+ const uint32_t expected = 0xf3d9c53f;
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
EXPECT_TRUE(params.pixelHashResult == expected);
@@ -417,8 +354,6 @@ TEST_F(BackendTest, DepthMinify) {
{
ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform);
Program prog = shaderGen.getProgram(api);
- Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
- prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
prog.uniformBlockBindings({{"params", 1}});
program = api.createProgram(std::move(prog));
}
@@ -550,85 +485,82 @@ TEST_F(BackendTest, ColorResolve) {
constexpr auto kColorTexFormat = TextureFormat::RGBA8;
constexpr int kSampleCount = 4;
- // Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
- auto swapChain = api.createSwapChainHeadless(256, 256, 0);
- api.makeCurrent(swapChain, swapChain);
-
// Create a program.
ProgramHandle program;
{
ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform);
Program prog = shaderGen.getProgram(api);
- Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
- prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
prog.uniformBlockBindings({{"params", 1}});
program = api.createProgram(std::move(prog));
}
// Create a VertexBuffer, IndexBuffer, and RenderPrimitive.
- TrianglePrimitive* triangle = new TrianglePrimitive(api);
+ TrianglePrimitive const triangle(api);
// Create 4-sample texture.
- Handle srcColorTexture = api.createTexture(
+ Handle const srcColorTexture = api.createTexture(
SamplerType::SAMPLER_2D, 1, kColorTexFormat, kSampleCount, kSrcTexWidth, kSrcTexHeight, 1,
TextureUsage::COLOR_ATTACHMENT);
// Create 1-sample texture.
- Handle dstColorTexture = api.createTexture(
+ Handle const dstColorTexture = api.createTexture(
SamplerType::SAMPLER_2D, 1, kColorTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
// Create a 4-sample render target with the 4-sample texture.
- Handle srcRenderTarget = api.createRenderTarget(
- TargetBufferFlags::COLOR, kSrcTexWidth, kSrcTexHeight, kSampleCount,{{ srcColorTexture }}, {}, {});
+ Handle const srcRenderTarget = api.createRenderTarget(
+ TargetBufferFlags::COLOR, kSrcTexWidth, kSrcTexHeight, kSampleCount,
+ {{ srcColorTexture }}, {}, {});
// Create a 1-sample render target with the 1-sample texture.
- Handle dstRenderTarget = api.createRenderTarget(
- TargetBufferFlags::COLOR, kDstTexWidth, kDstTexHeight, 1, {{ dstColorTexture }}, {}, {});
+ Handle const dstRenderTarget = api.createRenderTarget(
+ TargetBufferFlags::COLOR, kDstTexWidth, kDstTexHeight, 1,
+ {{ dstColorTexture }}, {}, {});
// Prep for rendering.
RenderPassParams params = {};
params.flags.clear = TargetBufferFlags::COLOR;
+ params.flags.discardStart = TargetBufferFlags::ALL;
+ params.flags.discardEnd = TargetBufferFlags::NONE;
params.clearColor = float4(1, 1, 0, 1);
params.viewport.width = kSrcTexWidth;
params.viewport.height = kSrcTexHeight;
PipelineState state = {};
- state.rasterState.colorWrite = true;
- state.rasterState.culling = RasterState::CullingMode::NONE;
state.program = program;
+ state.rasterState.colorWrite = true;
+ state.rasterState.depthWrite = false;
+ state.rasterState.depthFunc = RasterState::DepthFunc::A;
+ state.rasterState.culling = CullingMode::NONE;
+
auto ubuffer = api.createBufferObject(sizeof(MaterialParams),
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
- api.makeCurrent(swapChain, swapChain);
- api.beginFrame(0, 0);
- api.bindUniformBuffer(0, ubuffer);
-
// Draw red triangle into srcRenderTarget.
uploadUniforms(api, ubuffer, {
.color = float4(1, 0, 0, 1),
.scale = float4(1, 1, 0.5, 0),
});
- api.beginRenderPass(srcRenderTarget, params);
- api.draw(state, triangle->getRenderPrimitive(), 1);
- api.endRenderPass();
+
+ // FIXME: on Metal this triangle is not drawn. Can't understand why.
+ api.beginFrame(0, 0);
+ api.beginRenderPass(srcRenderTarget, params);
+ api.bindUniformBuffer(0, ubuffer);
+ api.draw(state, triangle.getRenderPrimitive(), 1);
+ api.endRenderPass();
api.endFrame(0);
// Resolve the MSAA render target into the single-sample render target.
- api.blit(TargetBufferFlags::COLOR, dstRenderTarget,
- {0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTarget,
- {0, 0, kSrcTexWidth, kSrcTexHeight}, SamplerMagFilter::LINEAR);
+ api.blit(TargetBufferFlags::COLOR,
+ dstRenderTarget, {0, 0, kDstTexWidth, kDstTexHeight},
+ srcRenderTarget, {0, 0, kSrcTexWidth, kSrcTexHeight},
+ SamplerMagFilter::NEAREST);
// Grab a screenshot.
- ScreenshotParams sparams { kDstTexWidth, kDstTexHeight, "ColorResolve.png" };
- api.beginFrame(0, 0);
+ ScreenshotParams sparams{ kDstTexWidth, kDstTexHeight, "ColorResolve.png" };
dumpScreenshot(api, dstRenderTarget, &sparams);
- api.commit(swapChain);
- api.endFrame(0);
// Wait for the ReadPixels result to come back.
- api.finish();
- executeCommands();
- getDriver().purge();
+ flushAndWait();
// Check if the image matches perfectly to our golden run.
const uint32_t expected = 0xebfac2ef;
@@ -640,11 +572,9 @@ TEST_F(BackendTest, ColorResolve) {
api.destroyProgram(program);
api.destroyTexture(srcColorTexture);
api.destroyTexture(dstColorTexture);
- api.destroySwapChain(swapChain);
api.destroyRenderTarget(srcRenderTarget);
api.destroyRenderTarget(dstRenderTarget);
- delete triangle;
- executeCommands();
+ flushAndWait();
}
TEST_F(BackendTest, DepthResolve) {
@@ -667,8 +597,6 @@ TEST_F(BackendTest, DepthResolve) {
{
ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform);
Program prog = shaderGen.getProgram(api);
- Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
- prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
prog.uniformBlockBindings({{"params", 1}});
program = api.createProgram(std::move(prog));
}
diff --git a/filament/backend/test/test_FeedbackLoops.cpp b/filament/backend/test/test_FeedbackLoops.cpp
index 24dd7b202a3..871aad05f42 100644
--- a/filament/backend/test/test_FeedbackLoops.cpp
+++ b/filament/backend/test/test_FeedbackLoops.cpp
@@ -50,7 +50,7 @@ layout(location = 0) out vec4 fragColor;
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
// This parameter is ignored for other backends.
-layout(location = 0, set = 1) uniform sampler2D tex;
+layout(location = 0, set = 1) uniform sampler2D test_tex;
uniform Params {
highp float fbWidth;
@@ -61,7 +61,7 @@ uniform Params {
void main() {
vec2 fbsize = vec2(params.fbWidth, params.fbHeight);
vec2 uv = (gl_FragCoord.xy + 0.5) / fbsize;
- fragColor = textureLod(tex, uv, params.sourceLevel);
+ fragColor = textureLod(test_tex, uv, params.sourceLevel);
})";
static uint32_t sPixelHashResult = 0;
@@ -133,24 +133,24 @@ TEST_F(BackendTest, FeedbackLoops) {
// Create a program.
ProgramHandle program;
{
- SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
- .name("backend_test_sib")
+ SamplerInterfaceBlock const sib = filament::SamplerInterfaceBlock::Builder()
+ .name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
ShaderGenerator shaderGen(fullscreenVs, fullscreenFs, sBackend, sIsMobilePlatform, &sib);
Program prog = shaderGen.getProgram(api);
- Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
+ Program::Sampler psamplers[] = { utils::CString("test_tex"), 0 };
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
prog.uniformBlockBindings({{"params", 1}});
program = api.createProgram(std::move(prog));
}
- TrianglePrimitive triangle(getDriverApi());
+ TrianglePrimitive const triangle(getDriverApi());
// Create a texture.
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
- Handle texture = api.createTexture(
+ Handle const texture = api.createTexture(
SamplerType::SAMPLER_2D, kNumLevels, kTexFormat, 1, kTexWidth, kTexHeight, 1, usage);
// Create a RenderTarget for each miplevel.
diff --git a/filament/backend/test/test_LoadImage.cpp b/filament/backend/test/test_LoadImage.cpp
index 9b9dbfdf12d..8e1d8f3b562 100644
--- a/filament/backend/test/test_LoadImage.cpp
+++ b/filament/backend/test/test_LoadImage.cpp
@@ -174,6 +174,41 @@ static const char* getSamplerTypeName(TextureFormat textureFormat) {
default:
return "sampler2D";
}
+
+}
+static SamplerFormat getSamplerFormat(TextureFormat textureFormat) {
+ switch (textureFormat) {
+ case TextureFormat::R8UI:
+ case TextureFormat::R16UI:
+ case TextureFormat::RG8UI:
+ case TextureFormat::RGB8UI:
+ case TextureFormat::R32UI:
+ case TextureFormat::RG16UI:
+ case TextureFormat::RGBA8UI:
+ case TextureFormat::RGB16UI:
+ case TextureFormat::RG32UI:
+ case TextureFormat::RGBA16UI:
+ case TextureFormat::RGB32UI:
+ case TextureFormat::RGBA32UI:
+ return SamplerFormat::UINT;
+
+ case TextureFormat::R8I:
+ case TextureFormat::R16I:
+ case TextureFormat::RG8I:
+ case TextureFormat::RGB8I:
+ case TextureFormat::R32I:
+ case TextureFormat::RG16I:
+ case TextureFormat::RGBA8I:
+ case TextureFormat::RGB16I:
+ case TextureFormat::RG32I:
+ case TextureFormat::RGBA16I:
+ case TextureFormat::RGB32I:
+ case TextureFormat::RGBA32I:
+ return SamplerFormat::INT;
+
+ default:
+ return SamplerFormat::FLOAT;
+ }
}
TEST_F(BackendTest, UpdateImage2D) {
@@ -231,9 +266,10 @@ TEST_F(BackendTest, UpdateImage2D) {
// Test integer format uploads.
// TODO: These cases fail on OpenGL and Vulkan.
- testCases.emplace_back("RGB_INTEGER, UBYTE -> RGB8UI", PixelDataFormat::RGB_INTEGER, PixelDataType::UBYTE, TextureFormat::RGB8UI);
- testCases.emplace_back("RGB_INTEGER, USHORT -> RGB16UI", PixelDataFormat::RGB_INTEGER, PixelDataType::USHORT, TextureFormat::RGB16UI);
- testCases.emplace_back("RGB_INTEGER, INT -> RGB32I", PixelDataFormat::RGB_INTEGER, PixelDataType::INT, TextureFormat::RGB32I);
+ // TODO: These cases now also fail on Metal, but at some point previously worked.
+ testCases.emplace_back("RGB_INTEGER, UBYTE -> RGB8UI", PixelDataFormat::RGB_INTEGER, PixelDataType::UBYTE, TextureFormat::RGB8UI);
+ testCases.emplace_back("RGB_INTEGER, USHORT -> RGB16UI", PixelDataFormat::RGB_INTEGER, PixelDataType::USHORT, TextureFormat::RGB16UI);
+ testCases.emplace_back("RGB_INTEGER, INT -> RGB32I", PixelDataFormat::RGB_INTEGER, PixelDataType::INT, TextureFormat::RGB32I);
// Test uploads with buffer padding.
// TODO: Vulkan crashes with "Assertion failed: (offset + size <= allocationSize)"
@@ -261,48 +297,45 @@ TEST_F(BackendTest, UpdateImage2D) {
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
// Create a program.
- SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
+ SamplerInterfaceBlock const sib = filament::SamplerInterfaceBlock::Builder()
.name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
- .add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
+ .add( {{"tex", SamplerType::SAMPLER_2D, getSamplerFormat(t.textureFormat), Precision::HIGH }} )
.build();
- ProgramHandle program;
- std::string fragment = stringReplace("{samplerType}",
+
+ std::string const fragment = stringReplace("{samplerType}",
getSamplerTypeName(t.textureFormat), fragmentTemplate);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
Program prog = shaderGen.getProgram(api);
- Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
+ Program::Sampler psamplers[] = { utils::CString("test_tex"), 0 };
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
- program = api.createProgram(std::move(prog));
+ ProgramHandle const program = api.createProgram(std::move(prog));
// Create a Texture.
- auto usage = TextureUsage::SAMPLEABLE;
- Handle texture = api.createTexture(SamplerType::SAMPLER_2D, 1,
+ auto usage = TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE;
+ Handle const texture = api.createTexture(SamplerType::SAMPLER_2D, 1,
t.textureFormat, 1, 512, 512, 1u, usage);
// Upload some pixel data.
if (t.uploadSubregions) {
- const auto& pf = t.pixelFormat;
- const auto& pt = t.pixelType;
- PixelBufferDescriptor subregion1 = checkerboardPixelBuffer(pf, pt, 256, t.bufferPadding);
- PixelBufferDescriptor subregion2 = checkerboardPixelBuffer(pf, pt, 256, t.bufferPadding);
- PixelBufferDescriptor subregion3 = checkerboardPixelBuffer(pf, pt, 256, t.bufferPadding);
- PixelBufferDescriptor subregion4 = checkerboardPixelBuffer(pf, pt, 256, t.bufferPadding);
- api.update3DImage(texture, 0, 0, 0, 0, 256, 256, 1, std::move(subregion1));
- api.update3DImage(texture, 0, 256, 0, 0, 256, 256, 1, std::move(subregion2));
- api.update3DImage(texture, 0, 0, 256, 0, 256, 256, 1, std::move(subregion3));
- api.update3DImage(texture, 0, 256, 256, 0, 256, 256, 1, std::move(subregion4));
+ api.update3DImage(texture, 0, 0, 0, 0, 256, 256, 1,
+ checkerboardPixelBuffer(t.pixelFormat, t.pixelType, 256, t.bufferPadding));
+ api.update3DImage(texture, 0, 256, 0, 0, 256, 256, 1,
+ checkerboardPixelBuffer(t.pixelFormat, t.pixelType, 256, t.bufferPadding));
+ api.update3DImage(texture, 0, 0, 256, 0, 256, 256, 1,
+ checkerboardPixelBuffer(t.pixelFormat, t.pixelType, 256, t.bufferPadding));
+ api.update3DImage(texture, 0, 256, 256, 0, 256, 256, 1,
+ checkerboardPixelBuffer(t.pixelFormat, t.pixelType, 256, t.bufferPadding));
} else {
- PixelBufferDescriptor descriptor
- = checkerboardPixelBuffer(t.pixelFormat, t.pixelType, 512, t.bufferPadding);
- api.update3DImage(texture, 0, 0, 0, 0, 512, 512, 1, std::move(descriptor));
+ api.update3DImage(texture, 0, 0, 0, 0, 512, 512, 1,
+ checkerboardPixelBuffer(t.pixelFormat, t.pixelType, 512, t.bufferPadding));
}
SamplerGroup samplers(1);
- SamplerParams sparams = {};
- sparams.filterMag = SamplerMagFilter::LINEAR;
- sparams.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST;
- samplers.setSampler(0, { texture, sparams });
+ samplers.setSampler(0, { texture, {
+ .filterMag = SamplerMagFilter::NEAREST,
+ .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST } });
+
auto sgroup = api.createSamplerGroup(samplers.getSize(), utils::FixedSizeString<32>("Test"));
api.updateSamplerGroup(sgroup, samplers.toBufferDescriptor(api));
@@ -312,7 +345,6 @@ TEST_F(BackendTest, UpdateImage2D) {
readPixelsAndAssertHash(t.name, 512, 512, defaultRenderTarget, expectedHash);
- api.flush();
api.commit(swapChain);
api.endFrame(0);
@@ -320,25 +352,21 @@ TEST_F(BackendTest, UpdateImage2D) {
api.destroySwapChain(swapChain);
api.destroyRenderTarget(defaultRenderTarget);
api.destroyTexture(texture);
-
- // This ensures all driver commands have finished before exiting the test.
- api.finish();
}
+ api.finish();
api.stopCapture();
- executeCommands();
-
- getDriver().purge();
+ flushAndWait();
}
TEST_F(BackendTest, UpdateImageSRGB) {
auto& api = getDriverApi();
api.startCapture();
- PixelDataFormat pixelFormat = PixelDataFormat::RGB;
- PixelDataType pixelType = PixelDataType::UBYTE;
- TextureFormat textureFormat = TextureFormat::SRGB8_A8;
+ PixelDataFormat const pixelFormat = PixelDataFormat::RGBA;
+ PixelDataType const pixelType = PixelDataType::UBYTE;
+ TextureFormat const textureFormat = TextureFormat::SRGB8_A8;
// Create a platform-specific SwapChain and make it current.
auto swapChain = createSwapChain();
@@ -346,22 +374,22 @@ TEST_F(BackendTest, UpdateImageSRGB) {
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
// Create a program.
- SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
+ SamplerInterfaceBlock const sib = filament::SamplerInterfaceBlock::Builder()
.name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
- std::string fragment = stringReplace("{samplerType}",
+ std::string const fragment = stringReplace("{samplerType}",
getSamplerTypeName(textureFormat), fragmentTemplate);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
Program prog = shaderGen.getProgram(api);
- Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
+ Program::Sampler psamplers[] = { utils::CString("test_tex"), 0 };
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
- ProgramHandle program = api.createProgram(std::move(prog));
+ ProgramHandle const program = api.createProgram(std::move(prog));
// Create a texture.
- Handle texture = api.createTexture(SamplerType::SAMPLER_2D, 1,
- textureFormat, 1, 512, 512, 1, TextureUsage::SAMPLEABLE);
+ Handle const texture = api.createTexture(SamplerType::SAMPLER_2D, 1,
+ textureFormat, 1, 512, 512, 1, TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE);
// Create image data.
size_t components; int bpp;
@@ -401,7 +429,7 @@ TEST_F(BackendTest, UpdateImageSRGB) {
renderTriangle(defaultRenderTarget, swapChain, program);
- static const uint32_t expectedHash = 519370995;
+ static const uint32_t expectedHash = 359858623;
readPixelsAndAssertHash("UpdateImageSRGB", 512, 512, defaultRenderTarget, expectedHash);
api.flush();
@@ -415,12 +443,9 @@ TEST_F(BackendTest, UpdateImageSRGB) {
// This ensures all driver commands have finished before exiting the test.
api.finish();
-
api.stopCapture();
- executeCommands();
-
- getDriver().purge();
+ flushAndWait();
}
TEST_F(BackendTest, UpdateImageMipLevel) {
@@ -440,26 +465,26 @@ TEST_F(BackendTest, UpdateImageMipLevel) {
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
.name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
- .add( {{"tex", SamplerType::SAMPLER_3D, SamplerFormat::FLOAT, Precision::HIGH }} )
+ .add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
- std::string fragment = stringReplace("{samplerType}",
+ std::string const fragment = stringReplace("{samplerType}",
getSamplerTypeName(textureFormat), fragmentUpdateImageMip);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
Program prog = shaderGen.getProgram(api);
- Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
+ Program::Sampler psamplers[] = { utils::CString("test_tex"), 0 };
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
- ProgramHandle program = api.createProgram(std::move(prog));
+ ProgramHandle const program = api.createProgram(std::move(prog));
// Create a texture with 3 mip levels.
// Base level: 1024
// Level 1: 512 <-- upload data and sample from this level
// Level 2: 256
Handle texture = api.createTexture(SamplerType::SAMPLER_2D, 3,
- textureFormat, 1, 1024, 1024, 1, TextureUsage::SAMPLEABLE);
+ textureFormat, 1, 1024, 1024, 1, TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE);
// Create image data.
PixelBufferDescriptor descriptor = checkerboardPixelBuffer(pixelFormat, pixelType, 512);
- api.update3DImage(texture, 1, 0, 0, 0, 512, 512, 1, std::move(descriptor));
+ api.update3DImage(texture, /* level*/ 1, 0, 0, 0, 512, 512, 1, std::move(descriptor));
api.beginFrame(0, 0);
@@ -490,12 +515,9 @@ TEST_F(BackendTest, UpdateImageMipLevel) {
// This ensures all driver commands have finished before exiting the test.
api.finish();
-
api.stopCapture();
- executeCommands();
-
- getDriver().purge();
+ flushAndWait();
}
TEST_F(BackendTest, UpdateImage3D) {
@@ -506,7 +528,7 @@ TEST_F(BackendTest, UpdateImage3D) {
PixelDataType pixelType = PixelDataType::FLOAT;
TextureFormat textureFormat = TextureFormat::RGBA16F;
SamplerType samplerType = SamplerType::SAMPLER_2D_ARRAY;
- TextureUsage usage = TextureUsage::SAMPLEABLE;
+ TextureUsage usage = TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE;
// Create a platform-specific SwapChain and make it current.
auto swapChain = createSwapChain();
@@ -517,15 +539,15 @@ TEST_F(BackendTest, UpdateImage3D) {
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
.name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
- .add( {{"tex", SamplerType::SAMPLER_3D, SamplerFormat::FLOAT, Precision::HIGH }} )
+ .add( {{"tex", SamplerType::SAMPLER_2D_ARRAY, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
std::string fragment = stringReplace("{samplerType}",
getSamplerTypeName(samplerType), fragmentUpdateImage3DTemplate);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
Program prog = shaderGen.getProgram(api);
- Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
+ Program::Sampler psamplers[] = { utils::CString("test_tex"), 0 };
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
- ProgramHandle program = api.createProgram(std::move(prog));
+ ProgramHandle const program = api.createProgram(std::move(prog));
// Create a texture.
Handle texture = api.createTexture(samplerType, 1,
@@ -577,12 +599,9 @@ TEST_F(BackendTest, UpdateImage3D) {
// This ensures all driver commands have finished before exiting the test.
api.finish();
-
api.stopCapture();
- executeCommands();
-
- getDriver().purge();
+ flushAndWait();
}
} // namespace test
diff --git a/filament/backend/test/test_ReadPixels.cpp b/filament/backend/test/test_ReadPixels.cpp
index 34b2a12337e..1f000c6e6aa 100644
--- a/filament/backend/test/test_ReadPixels.cpp
+++ b/filament/backend/test/test_ReadPixels.cpp
@@ -23,6 +23,7 @@
#include
#include
+#include
using namespace filament;
using namespace filament::backend;
@@ -107,7 +108,7 @@ TEST_F(ReadPixelsTest, ReadPixels) {
// The size of the actual render target, taking mip level into account;
size_t getRenderTargetSize () const {
- return renderTargetBaseSize >> mipLevel;
+ return std::max(size_t(1), renderTargetBaseSize >> mipLevel);
}
// The rect that read pixels will read from.
@@ -169,7 +170,7 @@ TEST_F(ReadPixelsTest, ReadPixels) {
// The normative read pixels test case. Render a white triangle over a blue background and read
// the full viewport into a pixel buffer.
- TestCase t;
+ TestCase const t0;
// Check that a subregion of the render target can be read into a pixel buffer.
TestCase t2;
@@ -233,7 +234,7 @@ TEST_F(ReadPixelsTest, ReadPixels) {
t8.testName = "readPixels_swapchain";
t8.useDefaultRT = true;
- TestCase testCases[] = { t, t2, t3, t4, t5, t6, t7, t8 };
+ TestCase const testCases[] = { t0, t2, t3, t4, t5, t6, t7, t8 };
// Create programs.
Handle programFloat, programUint;
@@ -264,7 +265,7 @@ TEST_F(ReadPixelsTest, ReadPixels) {
// Create a Texture and RenderTarget to render into.
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
- Handle texture = getDriverApi().createTexture(SamplerType::SAMPLER_2D,
+ Handle const texture = getDriverApi().createTexture(SamplerType::SAMPLER_2D,
t.mipLevels, t.textureFormat, 1, renderTargetBaseSize, renderTargetBaseSize, 1,
usage);
@@ -282,7 +283,7 @@ TEST_F(ReadPixelsTest, ReadPixels) {
{});
}
- TrianglePrimitive triangle(getDriverApi());
+ TrianglePrimitive const triangle(getDriverApi());
RenderPassParams params = {};
fullViewport(params);
@@ -356,7 +357,6 @@ TEST_F(ReadPixelsTest, ReadPixels) {
getDriverApi().beginRenderPass(renderTarget, params);
getDriverApi().endRenderPass();
- getDriverApi().flush();
getDriverApi().commit(swapChain);
getDriverApi().endFrame(0);
@@ -369,11 +369,7 @@ TEST_F(ReadPixelsTest, ReadPixels) {
getDriverApi().destroyProgram(programUint);
// This ensures all driver commands have finished before exiting the test.
- getDriverApi().finish();
-
- executeCommands();
-
- getDriver().purge();
+ flushAndWait();
}
TEST_F(ReadPixelsTest, ReadPixelsPerformance) {
diff --git a/filament/backend/test/test_RenderExternalImage.cpp b/filament/backend/test/test_RenderExternalImage.cpp
index 27519a0a255..2039bb2aae7 100644
--- a/filament/backend/test/test_RenderExternalImage.cpp
+++ b/filament/backend/test/test_RenderExternalImage.cpp
@@ -45,10 +45,10 @@ std::string fragment (R"(#version 450 core
layout(location = 0) out vec4 fragColor;
layout(location = 0) in vec2 uv;
-layout(location = 0, set = 1) uniform sampler2D tex;
+layout(location = 0, set = 1) uniform sampler2D test_tex;
void main() {
- fragColor = texture(tex, uv);
+ fragColor = texture(test_tex, uv);
}
)");
@@ -66,7 +66,7 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
auto swapChain = createSwapChain();
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
- .name("backend_test_sib")
+ .name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
@@ -74,7 +74,7 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
// Create a program that samples a texture.
Program p = shaderGen.getProgram(getDriverApi());
- Program::Sampler sampler { utils::CString("tex"), 0 };
+ Program::Sampler sampler { utils::CString("test_tex"), 0 };
p.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, &sampler, 1);
backend::Handle program = getDriverApi().createProgram(std::move(p));
@@ -146,7 +146,7 @@ TEST_F(BackendTest, RenderExternalImage) {
auto swapChain = createSwapChain();
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
- .name("backend_test_sib")
+ .name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
@@ -154,7 +154,7 @@ TEST_F(BackendTest, RenderExternalImage) {
// Create a program that samples a texture.
Program p = shaderGen.getProgram(getDriverApi());
- Program::Sampler sampler { utils::CString("tex"), 0 };
+ Program::Sampler sampler { utils::CString("test_tex"), 0 };
p.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, &sampler, 1);
auto program = getDriverApi().createProgram(std::move(p));
diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h
index 2442e6c2554..53b08215d99 100644
--- a/filament/include/filament/Engine.h
+++ b/filament/include/filament/Engine.h
@@ -294,9 +294,10 @@ class UTILS_PUBLIC Engine {
/*
* The number of eyes to render when stereoscopic rendering is enabled. Supported values are
- * between 1 and CONFIG_MAX_STEREOSCOPIC_EYES (inclusive).
+ * between 1 and Engine::getMaxStereoscopicEyes() (inclusive).
*
* @see View::setStereoscopicOptions
+ * @see Engine::getMaxStereoscopicEyes
*/
uint8_t stereoscopicEyeCount = 2;
};
@@ -562,6 +563,29 @@ class UTILS_PUBLIC Engine {
*/
bool isStereoSupported() const noexcept;
+ /**
+ * Retrieves the configuration settings of this Engine.
+ *
+ * This method returns the configuration object that was supplied to the Engine's
+ * Builder::config method during the creation of this Engine. If the Builder::config method was
+ * not explicitly called (or called with nullptr), this method returns the default configuration
+ * settings.
+ *
+ * @return a Config object with this Engine's configuration
+ * @see Builder::config
+ */
+ const Config& getConfig() const noexcept;
+
+ /**
+ * Returns the maximum number of stereoscopic eyes supported by Filament. The actual number of
+ * eyes rendered is set at Engine creation time with the Engine::Config::stereoscopicEyeCount
+ * setting.
+ *
+ * @return the max number of stereoscopic eyes supported
+ * @see Engine::Config::stereoscopicEyeCount
+ */
+ static size_t getMaxStereoscopicEyes() noexcept;
+
/**
* @return EntityManager used by filament
*/
diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h
index a58587e9ede..8832e054cf2 100644
--- a/filament/include/filament/View.h
+++ b/filament/include/filament/View.h
@@ -691,11 +691,12 @@ class UTILS_PUBLIC View : public FilamentAPI {
* - punctual lights
*
* Stereo rendering depends on device and platform support. To check if stereo rendering is
- * supported, use Engine::isStereoSupported().
+ * supported, use Engine::isStereoSupported(). If stereo rendering is not supported, then the
+ * stereoscopic options have no effect.
*
* @param options The stereoscopic options to use on this view
*/
- void setStereoscopicOptions(StereoscopicOptions const& options);
+ void setStereoscopicOptions(StereoscopicOptions const& options) noexcept;
/**
* Returns the stereoscopic options associated with this View.
diff --git a/filament/src/Engine.cpp b/filament/src/Engine.cpp
index 01b956484c4..661f183425d 100644
--- a/filament/src/Engine.cpp
+++ b/filament/src/Engine.cpp
@@ -327,10 +327,18 @@ size_t Engine::getMaxAutomaticInstances() const noexcept {
return downcast(this)->getMaxAutomaticInstances();
}
+const Engine::Config& Engine::getConfig() const noexcept {
+ return downcast(this)->getConfig();
+}
+
bool Engine::isStereoSupported() const noexcept {
return downcast(this)->isStereoSupported();
}
+size_t Engine::getMaxStereoscopicEyes() noexcept {
+ return FEngine::getMaxStereoscopicEyes();
+}
+
#if defined(__EMSCRIPTEN__)
void Engine::resetBackendState() noexcept {
downcast(this)->resetBackendState();
diff --git a/filament/src/View.cpp b/filament/src/View.cpp
index dd8e9380a75..bc5da818290 100644
--- a/filament/src/View.cpp
+++ b/filament/src/View.cpp
@@ -283,7 +283,7 @@ bool View::isStencilBufferEnabled() const noexcept {
return downcast(this)->isStencilBufferEnabled();
}
-void View::setStereoscopicOptions(const StereoscopicOptions& options) {
+void View::setStereoscopicOptions(const StereoscopicOptions& options) noexcept {
return downcast(this)->setStereoscopicOptions(options);
}
diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h
index bb3a283ef8d..bbe9c0fea98 100644
--- a/filament/src/details/Engine.h
+++ b/filament/src/details/Engine.h
@@ -184,6 +184,10 @@ class FEngine : public Engine {
bool isStereoSupported() const noexcept { return getDriver().isStereoSupported(); }
+ static size_t getMaxStereoscopicEyes() noexcept {
+ return CONFIG_MAX_STEREOSCOPIC_EYES;
+ }
+
PostProcessManager const& getPostProcessManager() const noexcept {
return mPostProcessManager;
}
diff --git a/filament/src/details/View.cpp b/filament/src/details/View.cpp
index 829c3ecc5d9..fe66b844ca9 100644
--- a/filament/src/details/View.cpp
+++ b/filament/src/details/View.cpp
@@ -1126,9 +1126,7 @@ View::PickingQuery& FView::pick(uint32_t x, uint32_t y, backend::CallbackHandler
return *pQuery;
}
-void FView::setStereoscopicOptions(const StereoscopicOptions& options) {
- ASSERT_PRECONDITION(!options.enabled || mIsStereoSupported,
- "Stereo rendering is not supported.");
+void FView::setStereoscopicOptions(const StereoscopicOptions& options) noexcept {
mStereoscopicOptions = options;
}
diff --git a/filament/src/details/View.h b/filament/src/details/View.h
index c2152a52f55..0f974754d3e 100644
--- a/filament/src/details/View.h
+++ b/filament/src/details/View.h
@@ -168,7 +168,9 @@ class FView : public View {
bool hasDPCF() const noexcept { return mShadowType == ShadowType::DPCF; }
bool hasPCSS() const noexcept { return mShadowType == ShadowType::PCSS; }
bool hasPicking() const noexcept { return mActivePickingQueriesList != nullptr; }
- bool hasInstancedStereo() const noexcept { return mStereoscopicOptions.enabled; }
+ bool hasInstancedStereo() const noexcept {
+ return mIsStereoSupported && mStereoscopicOptions.enabled;
+ }
FrameGraphId renderShadowMaps(FEngine& engine, FrameGraph& fg,
CameraInfo const& cameraInfo, math::float4 const& userTime,
@@ -192,7 +194,7 @@ class FView : public View {
bool isStencilBufferEnabled() const noexcept { return mStencilBufferEnabled; }
- void setStereoscopicOptions(StereoscopicOptions const& options);
+ void setStereoscopicOptions(StereoscopicOptions const& options) noexcept;
FCamera const* getDirectionalLightCamera() const noexcept {
return mShadowMapManager.getDirectionalLightCamera();
diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec
index 24db7659fb0..3d4af657f04 100644
--- a/ios/CocoaPods/Filament.podspec
+++ b/ios/CocoaPods/Filament.podspec
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
- spec.version = "1.47.0"
+ spec.version = "1.48.0"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
- spec.source = { :http => "https://github.com/google/filament/releases/download/v1.47.0/filament-v1.47.0-ios.tgz" }
+ spec.source = { :http => "https://github.com/google/filament/releases/download/v1.48.0/filament-v1.48.0-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
diff --git a/libs/filabridge/include/filament/MaterialEnums.h b/libs/filabridge/include/filament/MaterialEnums.h
index 67cdd8620f9..6a74ac7e3a9 100644
--- a/libs/filabridge/include/filament/MaterialEnums.h
+++ b/libs/filabridge/include/filament/MaterialEnums.h
@@ -28,7 +28,7 @@
namespace filament {
// update this when a new version of filament wouldn't work with older materials
-static constexpr size_t MATERIAL_VERSION = 47;
+static constexpr size_t MATERIAL_VERSION = 48;
/**
* Supported shading models
diff --git a/libs/filamat/src/sca/builtinResource.h b/libs/filamat/src/sca/builtinResource.h
index 53ef69ccc4c..d58f2a9d59a 100644
--- a/libs/filamat/src/sca/builtinResource.h
+++ b/libs/filamat/src/sca/builtinResource.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "glslang/Include/intermediate.h"
+
const TBuiltInResource DefaultTBuiltInResource = {
/* .MaxLights = */ 32,
/* .MaxClipPlanes = */ 6,
diff --git a/libs/viewer/include/viewer/Settings.h b/libs/viewer/include/viewer/Settings.h
index fc46d2887ed..926894a9154 100644
--- a/libs/viewer/include/viewer/Settings.h
+++ b/libs/viewer/include/viewer/Settings.h
@@ -77,6 +77,7 @@ using TemporalAntiAliasingOptions = filament::View::TemporalAntiAliasingOptions;
using VignetteOptions = filament::View::VignetteOptions;
using VsmShadowOptions = filament::View::VsmShadowOptions;
using GuardBandOptions = filament::View::GuardBandOptions;
+using StereoscopicOptions = filament::View::StereoscopicOptions;
using LightManager = filament::LightManager;
// These functions push all editable property values to their respective Filament objects.
@@ -192,6 +193,7 @@ struct ViewSettings {
VignetteOptions vignette;
VsmShadowOptions vsmShadowOptions;
GuardBandOptions guardBand;
+ StereoscopicOptions stereoscopicOptions;
// Custom View Options
ColorGradingSettings colorGrading;
@@ -231,6 +233,7 @@ struct ViewerOptions {
float cameraISO = 100.0f;
float cameraNear = 0.1f;
float cameraFar = 100.0f;
+ float cameraEyeOcularDistance = 0.0f;
float groundShadowStrength = 0.75f;
bool groundPlaneEnabled = false;
bool skyboxEnabled = true;
diff --git a/libs/viewer/include/viewer/ViewerGui.h b/libs/viewer/include/viewer/ViewerGui.h
index 6d6926a9aab..8f84335747c 100644
--- a/libs/viewer/include/viewer/ViewerGui.h
+++ b/libs/viewer/include/viewer/ViewerGui.h
@@ -231,8 +231,6 @@ class UTILS_PUBLIC ViewerGui {
int getCurrentCamera() const { return mCurrentCamera; }
- float getOcularDistance() const { return mOcularDistance; }
-
private:
using SceneMask = gltfio::NodeManager::SceneMask;
@@ -268,9 +266,6 @@ class UTILS_PUBLIC ViewerGui {
SceneMask mVisibleScenes;
bool mShowingRestPose = false;
- // Stereoscopic debugging
- float mOcularDistance = 0.0f;
-
// 0 is the default "free camera". Additional cameras come from the gltf file (1-based index).
int mCurrentCamera = 0;
diff --git a/libs/viewer/src/Settings.cpp b/libs/viewer/src/Settings.cpp
index febeb321fd5..6d1408e7e56 100644
--- a/libs/viewer/src/Settings.cpp
+++ b/libs/viewer/src/Settings.cpp
@@ -302,6 +302,8 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, ViewSett
i = parse(tokens, i + 1, jsonChunk, &out->vsmShadowOptions);
} else if (compare(tok, jsonChunk, "postProcessingEnabled") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->postProcessingEnabled);
+ } else if (compare(tok, jsonChunk, "stereoscopicOptions") == 0) {
+ i = parse(tokens, i + 1, jsonChunk, &out->stereoscopicOptions);
} else {
slog.w << "Invalid view setting key: '" << STR(tok, jsonChunk) << "'" << io::endl;
i = parse(tokens, i + 1);
@@ -500,6 +502,8 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, ViewerOp
i = parse(tokens, i + 1, jsonChunk, &out->cameraNear);
} else if (compare(tok, jsonChunk, "cameraFar") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->cameraFar);
+ } else if (compare(tok, jsonChunk, "cameraEyeOcularDistance") == 0) {
+ i = parse(tokens, i + 1, jsonChunk, &out->cameraEyeOcularDistance);
} else if (compare(tok, jsonChunk, "groundShadowStrength") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->groundShadowStrength);
} else if (compare(tok, jsonChunk, "groundPlaneEnabled") == 0) {
@@ -572,6 +576,7 @@ void applySettings(Engine* engine, const ViewSettings& settings, View* dest) {
dest->setShadowType(settings.shadowType);
dest->setVsmShadowOptions(settings.vsmShadowOptions);
dest->setGuardBandOptions(settings.guardBand);
+ dest->setStereoscopicOptions(settings.stereoscopicOptions);
dest->setPostProcessingEnabled(settings.postProcessingEnabled);
}
@@ -646,6 +651,20 @@ void applySettings(Engine* engine, const ViewerOptions& settings, Camera* camera
camera->setFocusDistance(settings.cameraFocusDistance);
}
engine->setAutomaticInstancingEnabled(settings.autoInstancingEnabled);
+
+ // Eyes are rendered from left-to-right, i.e., eye 0 is rendered to the left side of the
+ // window.
+ // For testing, we want to render a side-by-side layout so users can view with
+ // "cross-eyed" stereo.
+ // For cross-eyed stereo, Eye 0 is really the RIGHT eye, while Eye 1 is the LEFT eye.
+ const auto od = settings.cameraEyeOcularDistance;
+ const auto eyeCount = engine->getConfig().stereoscopicEyeCount;
+ const mat4 rightEye = mat4::translation(double3{ od, 0.0, 0.0}); // right eye
+ const mat4 leftEye = mat4::translation(double3{-od, 0.0, 0.0}); // left eye
+ const mat4 modelMatrices[2] = { rightEye, leftEye };
+ for (int i = 0; i < eyeCount; i++) {
+ camera->setEyeModelMatrix(i, modelMatrices[i % 2]);
+ }
}
constexpr ToneMapper* createToneMapper(const ColorGradingSettings& settings) noexcept {
@@ -857,6 +876,7 @@ static std::ostream& operator<<(std::ostream& out, const ViewerOptions& in) {
<< "\"cameraISO\": " << (in.cameraISO) << ",\n"
<< "\"cameraNear\": " << (in.cameraNear) << ",\n"
<< "\"cameraFar\": " << (in.cameraFar) << ",\n"
+ << "\"cameraEyeOcularDistance\": " << (in.cameraEyeOcularDistance) << ",\n"
<< "\"groundShadowStrength\": " << (in.groundShadowStrength) << ",\n"
<< "\"groundPlaneEnabled\": " << to_string(in.groundPlaneEnabled) << ",\n"
<< "\"skyboxEnabled\": " << to_string(in.skyboxEnabled) << ",\n"
@@ -894,6 +914,7 @@ static std::ostream& operator<<(std::ostream& out, const ViewSettings& in) {
<< "\"shadowType\": " << (in.shadowType) << ",\n"
<< "\"vsmShadowOptions\": " << (in.vsmShadowOptions) << ",\n"
<< "\"guardBand\": " << (in.guardBand) << ",\n"
+ << "\"stereoscopicOptions\": " << (in.stereoscopicOptions) << ",\n"
<< "\"postProcessingEnabled\": " << to_string(in.postProcessingEnabled) << "\n"
<< "}";
}
diff --git a/libs/viewer/src/ViewerGui.cpp b/libs/viewer/src/ViewerGui.cpp
index 37d6420491c..531fca1f34d 100644
--- a/libs/viewer/src/ViewerGui.cpp
+++ b/libs/viewer/src/ViewerGui.cpp
@@ -1067,13 +1067,9 @@ void ViewerGui::updateUserInterface() {
ImGui::ListBox("Cameras", &mCurrentCamera, cstrings.data(), cstrings.size());
}
- StereoscopicOptions stereoOptions = mView->getStereoscopicOptions();
- ImGui::Checkbox("Instanced stereo", &stereoOptions.enabled);
- if (stereoOptions.enabled) {
- ImGui::SliderFloat("Ocular distance", &mOcularDistance, 0.0f, 10.0f);
-
- }
- mView->setStereoscopicOptions(stereoOptions);
+ ImGui::Checkbox("Instanced stereo", &mSettings.view.stereoscopicOptions.enabled);
+ ImGui::SliderFloat(
+ "Ocular distance", &mSettings.viewer.cameraEyeOcularDistance, 0.0f, 1.0f);
ImGui::Unindent();
}
diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp
index 1a09e79f8d9..dab3a2914fc 100644
--- a/samples/gltf_viewer.cpp
+++ b/samples/gltf_viewer.cpp
@@ -1039,25 +1039,6 @@ int main(int argc, char** argv) {
camera->setScaling({1.0 / aspectRatio, 1.0});
}
- if (view->getStereoscopicOptions().enabled) {
- Camera& c = view->getCamera();
- auto od = app.viewer->getOcularDistance();
- // Eyes are rendered from left-to-right, i.e., eye 0 is rendered to the left side of the
- // window.
- // For testing, we want to render a side-by-side layout so users can view with
- // "cross-eyed" stereo.
- // For cross-eyed stereo, Eye 0 is really the RIGHT eye, while Eye 1 is the LEFT eye.
- const mat4 rightEye = mat4::translation(double3{ od, 0.0, 0.0}); // right eye
- const mat4 leftEye = mat4::translation(double3{-od, 0.0, 0.0}); // left eye
- const mat4 modelMatrices[4] = { rightEye, leftEye, rightEye, leftEye };
- for (int i = 0; i < std::min(app.config.stereoscopicEyeCount, 4); i++) {
- c.setEyeModelMatrix(i, modelMatrices[i]);
- }
- } else {
- for (int i = 0; i < app.config.stereoscopicEyeCount; i++) {
- view->getCamera().setEyeModelMatrix(i, {});
- }
- }
static bool stereoscopicEnabled = false;
if (stereoscopicEnabled != view->getStereoscopicOptions().enabled) {
// Stereo was turned on/off.
diff --git a/web/filament-js/extensions.js b/web/filament-js/extensions.js
index 3040bafcd1f..36d0bf988be 100644
--- a/web/filament-js/extensions.js
+++ b/web/filament-js/extensions.js
@@ -339,6 +339,12 @@ Filament.loadClassExtensions = function() {
this._setGuardBandOptions(options);
};
+ /// setStereoscopicOptions ::method::
+ Filament.View.prototype.setStereoscopicOptions = function(overrides) {
+ const options = this.setStereoscopicOptionsDefaults(overrides);
+ this._setStereoscopicOptions(options);
+ }
+
/// BufferObject ::core class::
/// setBuffer ::method::
diff --git a/web/filament-js/filament.d.ts b/web/filament-js/filament.d.ts
index 197a5a7acc5..6d5122e5b7b 100644
--- a/web/filament-js/filament.d.ts
+++ b/web/filament-js/filament.d.ts
@@ -505,6 +505,7 @@ export class View {
public setFogOptions(options: View$FogOptions): void;
public setVignetteOptions(options: View$VignetteOptions): void;
public setGuardBandOptions(options: View$GuardBandOptions): void;
+ public setStereoscopicOptions(options: View$StereoscopicOptions): void;
public setAmbientOcclusion(ambientOcclusion: View$AmbientOcclusion): void;
public getAmbientOcclusion(): View$AmbientOcclusion;
public setBlendMode(mode: View$BlendMode): void;
@@ -546,6 +547,8 @@ export class Engine {
public createTextureFromJpeg(urlOrBuffer: BufferReference, options?: object): Texture;
public createTextureFromPng(urlOrBuffer: BufferReference, options?: object): Texture;
+ public static getMaxStereoscopicEyes(): number;
+
public createIblFromKtx1(urlOrBuffer: BufferReference): IndirectLight;
public createSkyFromKtx1(urlOrBuffer: BufferReference): Skybox;
public createTextureFromKtx1(urlOrBuffer: BufferReference, options?: object): Texture;
diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp
index 90e4171b7a5..bf8e860b5b6 100644
--- a/web/filament-js/jsbindings.cpp
+++ b/web/filament-js/jsbindings.cpp
@@ -400,6 +400,8 @@ class_("Engine")
.function("getActiveFeatureLevel", &Engine::getActiveFeatureLevel)
+ .class_function("getMaxStereoscopicEyes", &Engine::getMaxStereoscopicEyes)
+
.function("_execute", EMBIND_LAMBDA(void, (Engine* engine), {
EM_ASM_INT({
const handle = window.filament_contextHandle;
@@ -654,6 +656,7 @@ class_("View")
.function("_setFogOptions", &View::setFogOptions)
.function("_setVignetteOptions", &View::setVignetteOptions)
.function("_setGuardBandOptions", &View::setGuardBandOptions)
+ .function("_setStereoscopicOptions", &View::setStereoscopicOptions)
.function("setAmbientOcclusion", &View::setAmbientOcclusion)
.function("getAmbientOcclusion", &View::getAmbientOcclusion)
.function("setAntiAliasing", &View::setAntiAliasing)
diff --git a/web/filament-js/package.json b/web/filament-js/package.json
index ef4cd7e79d9..b97c7364479 100644
--- a/web/filament-js/package.json
+++ b/web/filament-js/package.json
@@ -1,6 +1,6 @@
{
"name": "filament",
- "version": "1.47.0",
+ "version": "1.48.0",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",