Compare commits

..
Author SHA1 Message Date
Benjamin Doherty 791f51dcb4 Update glslang to e3bca2a 2022-05-04 12:29:21 -07:00
Benjamin Doherty 4621f3ec5d Filament specific changes 2022-05-04 12:06:26 -07:00
Benjamin Doherty ab9c09d0d9 Update spirv-tools to 46492aa 2022-05-04 12:00:04 -07:00
Benjamin Doherty dbf51c1c7d Update SPIRV-Cross to 0c8a79b 2022-05-04 11:07:15 -07:00
1431 changed files with 62959 additions and 17713 deletions
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.23.0'
implementation 'com.google.android.filament:filament-android:1.21.3'
}
```
@@ -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:
```
pod 'Filament', '~> 1.23.0'
pod 'Filament', '~> 1.21.3'
```
### Snapshots
+4 -4
View File
@@ -50,13 +50,13 @@ Do not push to origin yet.
git cherry-pick rc/$RELEASE
```
Update the headers. The "main branch" header becomes a header for $NEXT_RELEASE, and a new "main
branch" header is added.
Update the headers. The "Next release" header becomes a header for $NEXT_RELEASE, and a new "Next
release" header is added.
For example, this:
```
## main branch
## Next release (main branch)
- foo
- bar
@@ -68,7 +68,7 @@ For example, this:
becomes:
```
## main branch
## Next release (main branch)
## v1.9.4
- foo
+1 -26
View File
@@ -3,37 +3,12 @@
This file contains one line summaries of commits that are worthy of mentioning in release notes.
A new header is inserted each time a *tag* is created.
## main branch
## v1.23.0
- engine: Changed UBOs layout [⚠️ **Material breakage**].
- engine: Normals on morphed models have been fixed (core Filament change).
- Java: View has several minor changes due to generated code, such as field ordering.
- gltfio: Fix crash when reloading glTF assets.
- gltfio: introduce cross-fade animation API [**NEW API**].
## v1.22.2
- Java: Minor API change: rename `ssctStartTraceDistance` to `ssctShadowDistance`. [⚠️ **API Change**]
- Java: Minor API change: rename `blendingMode` to `blendMode`. [⚠️ **API Change**]
- engine: Fix some memory leaks.
## v1.22.1
- Metal: Shaders now use `half` floating-point arithmetic when possible for improved performance. [⚠️ **Recompile Materials**]
- engine: add support for presentation time in `Renderer`
- engine: added guard bands support for screen-space effects
- gltfio: Add multi-scene support.
- gltfio: Various glTF-related cleanup and enhancements.
- gltfio: Add support for KHR_texture_basisu.
## v1.22.1 (currently main branch)
## v1.22.0
- engine: Changed UBOs layout [⚠️ **Material breakage**].
- engine: Improve effects relying on mipmapping
- engine: Fix assert seen with VSM shadows.
- WebGL: Fix `isTextureFormatSupported` for ETC2 formats.
## v1.21.3
+6 -10
View File
@@ -81,10 +81,10 @@ buildscript {
'minSdk': 19,
'targetSdk': 31,
'compileSdk': 31,
'kotlin': '1.6.21',
'kotlin_coroutines': '1.6.1',
'kotlin': '1.6.10',
'kotlin_coroutines': '1.6.0',
'buildTools': '32.0.0',
'ndk': '24.0.8215888'
'ndk': '23.1.7779620'
]
ext.deps = [
@@ -101,12 +101,11 @@ buildscript {
dependencies {
// NOTE: See TODO in gradle.properties once we move to Gradle 7.4
classpath 'com.android.tools.build:gradle:7.2.0'
classpath 'com.android.tools.build:gradle:7.1.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
}
ext.cmakeArgs = [
"--no-warn-unused-cli",
"-DANDROID_PIE=ON",
"-DANDROID_PLATFORM=21",
"-DANDROID_STL=c++_static",
@@ -118,6 +117,8 @@ buildscript {
ext.cppFlags = [
"-std=c++17",
"-Wno-unused-command-line-argument",
"-Wl,--hash-style=both", // Required to support API levels below 23
"-fno-stack-protector",
"-fno-exceptions",
"-fno-unwind-tables",
@@ -130,13 +131,8 @@ buildscript {
"-fomit-frame-pointer",
"-ffunction-sections",
"-fdata-sections",
"-no-canonical-prefixes",
"-Wformat",
"-Werror=format-security",
"-Wno-unused-command-line-argument",
"-Wl,--gc-sections",
"-Wl,-Bsymbolic-functions",
"-Wl,--hash-style=both", // Required to support API levels below 23
]
ext.abis = abis
+1
View File
@@ -1,3 +1,4 @@
plugins {
id 'groovy-gradle-plugin'
}
-2
View File
@@ -1,6 +1,4 @@
android {
namespace 'com.google.android.filament.filamat'
flavorDimensions "functionality"
productFlavors {
full {
-4
View File
@@ -1,7 +1,3 @@
android {
namespace 'com.google.android.filament'
}
dependencies {
implementation deps.androidx.annotations
}
@@ -156,9 +156,12 @@ Java_com_google_android_filament_Renderer_nResetUserTime(JNIEnv*, jclass, jlong
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_Renderer_nSetDisplayInfo(JNIEnv*, jclass, jlong nativeRenderer, jfloat refreshRate) {
Java_com_google_android_filament_Renderer_nSetDisplayInfo(JNIEnv*, jclass, jlong nativeRenderer,
jfloat refreshRate, jlong presentationDeadlineNanos, jlong vsyncOffsetNanos) {
Renderer *renderer = (Renderer *) nativeRenderer;
renderer->setDisplayInfo({ .refreshRate = refreshRate });
renderer->setDisplayInfo({ .refreshRate = refreshRate,
.presentationDeadlineNanos = (uint64_t)presentationDeadlineNanos,
.vsyncOffsetNanos = (uint64_t)vsyncOffsetNanos });
}
extern "C" JNIEXPORT void JNICALL
@@ -180,10 +183,3 @@ Java_com_google_android_filament_Renderer_nSetClearOptions(JNIEnv *, jclass ,
.clear = (bool) clear,
.discard = (bool) discard});
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_Renderer_nSetPresentationTime(JNIEnv *, jclass ,
jlong nativeRenderer, jlong monotonicClockNanos) {
Renderer *renderer = (Renderer *) nativeRenderer;
renderer->setPresentationTime(monotonicClockNanos);
}
+2 -10
View File
@@ -259,14 +259,14 @@ Java_com_google_android_filament_View_nSetAmbientOcclusionOptions(JNIEnv*, jclas
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_View_nSetSSCTOptions(JNIEnv *, jclass, jlong nativeView,
jfloat ssctLightConeRad, jfloat ssctShadowDistance, jfloat ssctContactDistanceMax,
jfloat ssctLightConeRad, jfloat ssctStartTraceDistance, jfloat ssctContactDistanceMax,
jfloat ssctIntensity, jfloat ssctLightDirX, jfloat ssctLightDirY, jfloat ssctLightDirZ,
jfloat ssctDepthBias, jfloat ssctDepthSlopeBias, jint ssctSampleCount,
jint ssctRayCount, jboolean ssctEnabled) {
View* view = (View*) nativeView;
View::AmbientOcclusionOptions options = view->getAmbientOcclusionOptions();
options.ssct.lightConeRad = ssctLightConeRad;
options.ssct.shadowDistance = ssctShadowDistance;
options.ssct.shadowDistance = ssctStartTraceDistance;
options.ssct.contactDistanceMax = ssctContactDistanceMax;
options.ssct.intensity = ssctIntensity;
options.ssct.lightDirection = math::float3{ ssctLightDirX, ssctLightDirY, ssctLightDirZ };
@@ -461,11 +461,3 @@ Java_com_google_android_filament_View_nPick(JNIEnv* env, jclass,
JniCallback::postToJavaAndDestroy(callback);
}, callback->getHandler());
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_View_nSetGuardBandOptions(JNIEnv *, jclass,
jlong nativeView, jboolean enabled) {
View* view = (View*) nativeView;
view->setGuardBandOptions({ .enabled = (bool)enabled });
}
@@ -104,12 +104,12 @@ public class MorphTargetBuffer {
}
/**
* Updates float4 positions for the given morph target.
* Updates positions of morph target at the index.
*
* @param engine {@link Engine} instance
* @param targetIndex The index of morph target to be updated
* @param positions An array with at least count*4 floats
* @param count Number of float4 vectors in positions to be consumed
* @param positions Pointer to at least count positions
* @param count Number of position elements in positions
*/
public void setPositionsAt(@NonNull Engine engine,
@IntRange(from = 0) int targetIndex,
@@ -122,15 +122,12 @@ public class MorphTargetBuffer {
}
/**
* Updates tangents for the given morph target.
*
* These quaternions must be represented as signed shorts, where real numbers in the [-1,+1]
* range multiplied by 32767.
* Updates tangents of morph target at the index.
*
* @param engine {@link Engine} instance
* @param targetIndex The index of morph target to be updated
* @param tangents An array with at least "count*4" shorts
* @param count number of short4 quaternions in tangents
* @param tangents Pointer to at least count tangents
* @param count Number of tangent elements in tangents
*/
public void setTangentsAt(@NonNull Engine engine,
@IntRange(from = 0) int targetIndex,
@@ -143,14 +140,14 @@ public class MorphTargetBuffer {
}
/**
* @return number of vertices in this {@link MorphTargetBuffer}
* @return number of vertex count in this {@link MorphTargetBuffer}
*/
public int getVertexCount() {
return nGetVertexCount(mNativeObject);
}
/**
* @return number of morph targets in this {@link MorphTargetBuffer}
* @return number of target count in this {@link MorphTargetBuffer}
*/
public int getCount() {
return nGetCount(mNativeObject);
@@ -61,17 +61,13 @@ public class Renderer {
/**
* How far in advance a buffer must be queued for presentation at a given time in ns
* On Android you can use {@link android.view.Display#getPresentationDeadlineNanos()}.
* @deprecated this value is ignored
*/
@Deprecated
public long presentationDeadlineNanos = 0;
/**
* Offset by which vsyncSteadyClockTimeNano provided in beginFrame() is offset in ns
* On Android you can use {@link android.view.Display#getAppVsyncOffsetNanos()}.
* @deprecated this value is ignored
*/
@Deprecated
public long vsyncOffsetNanos = 0;
};
@@ -179,7 +175,8 @@ public class Renderer {
*/
public void setDisplayInfo(@NonNull DisplayInfo info) {
mDisplayInfo = info;
nSetDisplayInfo(getNativeObject(), info.refreshRate);
nSetDisplayInfo(getNativeObject(),
info.refreshRate, info.presentationDeadlineNanos, info.vsyncOffsetNanos);
}
/**
@@ -250,23 +247,6 @@ public class Renderer {
return mEngine;
}
/**
* Set the time at which the frame must be presented to the display.
* <p>
* This must be called between {@link #beginFrame} and {@link #endFrame}.
* </p>
*
* @param monotonicClockNanos The time in nanoseconds corresponding to the system monotonic
* up-time clock. The presentation time is typically set in the
* middle of the period of interest and cannot be too far in the
* future as it is limited by how many buffers are available in
* the display sub-system. Typically it is set to 1 or 2 vsync
* periods away.
*/
public void setPresentationTime(long monotonicClockNanos) {
nSetPresentationTime(getNativeObject(), monotonicClockNanos);
}
/**
* Sets up a frame for this <code>Renderer</code>.
* <p><code>beginFrame</code> manages frame pacing, and returns whether or not a frame should be
@@ -684,7 +664,6 @@ public class Renderer {
mNativeObject = 0;
}
private static native void nSetPresentationTime(long nativeObject, long monotonicClockNanos);
private static native boolean nBeginFrame(long nativeRenderer, long nativeSwapChain, long frameTimeNanos);
private static native void nEndFrame(long nativeRenderer);
private static native void nRender(long nativeRenderer, long nativeView);
@@ -706,7 +685,8 @@ public class Renderer {
Object handler, Runnable callback);
private static native double nGetUserTime(long nativeRenderer);
private static native void nResetUserTime(long nativeRenderer);
private static native void nSetDisplayInfo(long nativeRenderer, float refreshRate);
private static native void nSetDisplayInfo(long nativeRenderer,
float refreshRate, long presentationDeadlineNanos, long vsyncOffsetNanos);
private static native void nSetFrameRateOptions(long nativeRenderer,
float interval, float headRoomRatio, float scaleRate, int history);
private static native void nSetClearOptions(long nativeRenderer,
File diff suppressed because it is too large Load Diff
@@ -157,6 +157,8 @@ public class DisplayHelper {
info = new Renderer.DisplayInfo();
}
info.refreshRate = DisplayHelper.getRefreshRate(display);
info.presentationDeadlineNanos = DisplayHelper.getPresentationDeadlineNanos(display);
info.vsyncOffsetNanos = DisplayHelper.getAppVsyncOffsetNanos(display);
return info;
}
+7 -9
View File
@@ -1,8 +1,6 @@
apply plugin: 'kotlin-android'
android {
namespace 'com.google.android.filament.utils'
sourceSets {
main {
kotlin.srcDirs += "src/main/java"
@@ -12,14 +10,14 @@ android {
defaultConfig {
missingDimensionStrategy 'functionality', 'full'
}
// No need to package up the following shared libs, which arise as a side effect of our
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
// dependencies, these shared libs already get pulled in, so we need to avoid the error:
// "More than one file was found with OS independent path ..."
packagingOptions {
// No need to package up the following shared libs, which arise as a side effect of our
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
// dependencies, these shared libs already get pulled in, so we need to avoid the error:
// "More than one file was found with OS independent path ..."
jniLibs {
excludes += ['lib/*/libfilament-jni.so', 'lib/*/libgltfio-jni.so']
}
exclude 'lib/*/libfilament-jni.so'
exclude 'lib/*/libgltfio-jni.so'
}
}
+6 -9
View File
@@ -40,33 +40,30 @@ set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,
set(GLTFIO_SRCS
${GLTFIO_DIR}/include/gltfio/Animator.h
${GLTFIO_DIR}/include/gltfio/AssetLoader.h
${GLTFIO_DIR}/include/gltfio/MaterialProvider.h
${GLTFIO_DIR}/include/gltfio/ResourceLoader.h
${GLTFIO_DIR}/include/gltfio/FilamentAsset.h
${GLTFIO_DIR}/include/gltfio/FilamentInstance.h
${GLTFIO_DIR}/include/gltfio/MaterialProvider.h
${GLTFIO_DIR}/include/gltfio/NodeManager.h
${GLTFIO_DIR}/include/gltfio/ResourceLoader.h
${GLTFIO_DIR}/include/gltfio/TextureProvider.h
${GLTFIO_DIR}/include/gltfio/math.h
${GLTFIO_DIR}/src/Animator.cpp
${GLTFIO_DIR}/src/AssetLoader.cpp
${GLTFIO_DIR}/src/DependencyGraph.cpp
${GLTFIO_DIR}/src/DependencyGraph.h
${GLTFIO_DIR}/src/DracoCache.cpp
${GLTFIO_DIR}/src/DracoCache.h
${GLTFIO_DIR}/src/DependencyGraph.cpp
${GLTFIO_DIR}/src/DependencyGraph.h
${GLTFIO_DIR}/src/FFilamentAsset.h
${GLTFIO_DIR}/src/FFilamentInstance.h
${GLTFIO_DIR}/src/FilamentAsset.cpp
${GLTFIO_DIR}/src/FFilamentInstance.h
${GLTFIO_DIR}/src/FilamentInstance.cpp
${GLTFIO_DIR}/src/FNodeManager.h
${GLTFIO_DIR}/src/GltfEnums.h
${GLTFIO_DIR}/src/Ktx2Provider.cpp
${GLTFIO_DIR}/src/MaterialProvider.cpp
${GLTFIO_DIR}/src/NodeManager.cpp
${GLTFIO_DIR}/src/ResourceLoader.cpp
${GLTFIO_DIR}/src/StbProvider.cpp
${GLTFIO_DIR}/src/TangentsJob.cpp
${GLTFIO_DIR}/src/TangentsJob.h
${GLTFIO_DIR}/src/TangentsJob.cpp
${GLTFIO_DIR}/src/UbershaderLoader.cpp
${GLTFIO_DIR}/src/Wireframe.cpp
${GLTFIO_DIR}/src/Wireframe.h
+6 -9
View File
@@ -1,6 +1,4 @@
android {
namespace 'com.google.android.filament.gltfio'
flavorDimensions "functionality"
productFlavors {
full {
@@ -17,14 +15,13 @@ android {
}
}
}
// No need to package up the following shared libs, which arise as a side effect of our
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
// dependencies, these shared libs already get pulled in, so we need to avoid the error:
// "More than one file was found with OS independent path ..."
packagingOptions {
// No need to package up the following shared libs, which arise as a side effect of our
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
// dependencies, these shared libs already get pulled in, so we need to avoid the error:
// "More than one file was found with OS independent path ..."
jniLibs {
excludes += ['lib/*/libfilament-jni.so']
}
exclude 'lib/*/libfilament-jni.so'
}
}
@@ -36,13 +36,6 @@ Java_com_google_android_filament_gltfio_Animator_nUpdateBoneMatrices(JNIEnv*, jc
animator->updateBoneMatrices();
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_Animator_nApplyCrossFade(JNIEnv*, jclass, jlong nativeAnimator,
jint previousAnimIndex, jfloat previousAnimTime, jfloat alpha) {
Animator* animator = (Animator*) nativeAnimator;
animator->applyCrossFade(previousAnimIndex, previousAnimTime, alpha);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_Animator_nResetBoneMatrices(JNIEnv*, jclass, jlong nativeAnimator) {
Animator* animator = (Animator*) nativeAnimator;
@@ -120,34 +120,10 @@ extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_FilamentAsset_nGetLightEntities(JNIEnv* env, jclass,
jlong nativeAsset, jintArray result) {
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
const jsize available = env->GetArrayLength(result);
const size_t minCount = std::min(available, (jsize) asset->getLightEntityCount());
if (minCount == 0) {
return;
}
jsize available = env->GetArrayLength(result);
Entity* entities = (Entity*) env->GetIntArrayElements(result, nullptr);
std::copy_n(asset->getLightEntities(), minCount, entities);
env->ReleaseIntArrayElements(result, (jint*) entities, 0);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_gltfio_FilamentAsset_nGetRenderableEntityCount(JNIEnv*, jclass,
jlong nativeAsset) {
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
return asset->getRenderableEntityCount();
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_FilamentAsset_nGetRenderableEntities(JNIEnv* env, jclass,
jlong nativeAsset, jintArray result) {
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
const jsize available = env->GetArrayLength(result);
const size_t minCount = std::min(available, (jsize) asset->getRenderableEntityCount());
if (minCount == 0) {
return;
}
Entity* entities = (Entity*) env->GetIntArrayElements(result, nullptr);
std::copy_n(asset->getRenderableEntities(), minCount, entities);
std::copy_n(asset->getLightEntities(),
std::min(available, (jsize) asset->getLightEntityCount()), entities);
env->ReleaseIntArrayElements(result, (jint*) entities, 0);
}
@@ -155,13 +131,10 @@ extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_FilamentAsset_nGetCameraEntities(JNIEnv* env, jclass,
jlong nativeAsset, jintArray result) {
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
const jsize available = env->GetArrayLength(result);
const size_t minCount = std::min(available, (jsize) asset->getCameraEntityCount());
if (minCount == 0) {
return;
}
jsize available = env->GetArrayLength(result);
Entity* entities = (Entity*) env->GetIntArrayElements(result, nullptr);
std::copy_n(asset->getCameraEntities(), minCount, entities);
std::copy_n(asset->getCameraEntities(),
std::min(available, (jsize) asset->getCameraEntityCount()), entities);
env->ReleaseIntArrayElements(result, (jint*) entities, 0);
}
@@ -66,27 +66,6 @@ public class Animator {
nUpdateBoneMatrices(getNativeObject());
}
/**
* Applies a blended transform to the union of nodes affected by two animations.
* Used for cross-fading from a previous skinning-based animation or rigid body animation.
*
* First, this stashes the current transform hierarchy into a transient memory buffer.
*
* Next, this applies previousAnimIndex / previousAnimTime to the actual asset by internally
* calling applyAnimation().
*
* Finally, the stashed local transforms are lerped (via the scale / translation / rotation
* components) with their live counterparts, and the results are pushed to the asset.
*
* To achieve a cross fade effect with skinned models, clients will typically call animator
* methods in this order: (1) applyAnimation (2) applyCrossFade (3) updateBoneMatrices. The
* animation that clients pass to applyAnimation is the "current" animation corresponding to
* alpha=1, while the "previous" animation passed to applyCrossFade corresponds to alpha=0.
*/
public void applyCrossFade(int previousAnimIndex, float previousAnimTime, float alpha) {
nApplyCrossFade(getNativeObject(), previousAnimIndex, previousAnimTime, alpha);
}
/**
* Pass the identity matrix into all bone nodes, useful for returning to the T pose.
*
@@ -139,7 +118,6 @@ public class Animator {
private static native void nApplyAnimation(long nativeAnimator, int index, float time);
private static native void nUpdateBoneMatrices(long nativeAnimator);
private static native void nApplyCrossFade(long nativeAnimator, int animIndex, float animTime, float alpha);
private static native void nResetBoneMatrices(long nativeAnimator);
private static native int nGetAnimationCount(long nativeAnimator);
private static native float nGetAnimationDuration(long nativeAnimator, int index);
@@ -30,9 +30,9 @@ import com.google.android.filament.MaterialInstance;
*
* <p>For usage instructions, see the documentation for {@link AssetLoader}.</p>
*
* <p>This class owns a hierarchy of entities that have been loaded from a glTF asset. Every entity
* has a <code>TransformManager</code> component, and some entities also have compnents managed by
* <code>NameComponentManager</code>, <code>RenderableManager</code>, and others.</p>
* <p>This class owns a hierarchy of entities that have been loaded from a glTF asset. Every entity has
* a <code>TransformManager</code> component, and some entities also have
* <code>NameComponentManager</code> and/or <code>RenderableManager</code> components.</p>
*
* <p>In addition to the aforementioned entities, an asset has strong ownership over a list of
* <code>VertexBuffer</code>, <code>IndexBuffer</code>, <code>MaterialInstance</code>, and
@@ -113,15 +113,6 @@ public class FilamentAsset {
return result;
}
/**
* Gets only the entities that have renderable components.
*/
public @NonNull @Entity int[] getRenderableEntities() {
int[] result = new int[nGetRenderableEntityCount(mNativeObject)];
nGetRenderableEntities(mNativeObject, result);
return result;
}
/**
* Gets only the entities that have camera components.
*
@@ -330,9 +321,6 @@ public class FilamentAsset {
private static native int nGetLightEntityCount(long nativeAsset);
private static native void nGetLightEntities(long nativeAsset, int[] result);
private static native int nGetRenderableEntityCount(long nativeAsset);
private static native void nGetRenderableEntities(long nativeAsset, int[] result);
private static native int nGetCameraEntityCount(long nativeAsset);
private static native void nGetCameraEntities(long nativeAsset, int[] result);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.23.0
VERSION_NAME=1.21.3
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+1 -1
View File
@@ -1,6 +1,6 @@
#Wed Nov 17 10:40:18 PST 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
@@ -25,8 +25,6 @@ clean.doFirst {
}
android {
namespace 'com.google.android.filament.gltf'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.gltf"
@@ -34,7 +32,6 @@ android {
targetSdkVersion versions.targetSdk
missingDimensionStrategy 'functionality', 'full'
}
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
// is not configuration-cache friendly yet; this is only useful for Play publication
dependenciesInfo {
@@ -16,8 +16,6 @@ clean.doFirst {
}
android {
namespace 'com.google.android.filament.hellocam'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.hellocamera"
@@ -16,8 +16,6 @@ clean.doFirst {
}
android {
namespace 'com.google.android.filament.hellotriangle'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.hellotriangle"
@@ -22,8 +22,6 @@ clean.doFirst {
}
android {
namespace 'com.google.android.filament.ibl'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.ibl"
@@ -15,8 +15,6 @@ clean.doFirst {
delete "src/main/assets"
}
android {
namespace 'com.google.android.filament.litcube'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.litcube"
@@ -4,8 +4,6 @@ apply plugin: 'kotlin-android'
project.ext.isSample = true
android {
namespace 'com.google.android.filament.livewallpaper'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.livewallpaper"
@@ -19,8 +19,6 @@ clean.doFirst {
}
android {
namespace 'com.google.android.filament.material_builder'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.material_builder"
@@ -15,8 +15,6 @@ clean.doFirst {
delete "src/main/assets"
}
android {
namespace 'com.google.android.filament.multiview'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.multiview"
@@ -18,8 +18,6 @@ clean.doFirst {
}
android {
namespace 'com.google.android.filament.pagecurl'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.pagecurl"
@@ -16,8 +16,6 @@ clean.doFirst {
}
android {
namespace 'com.google.android.filament.streamtest'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.streamtest"
@@ -16,8 +16,6 @@ clean.doFirst {
}
android {
namespace 'com.google.android.filament.textureview'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.textureview"
@@ -22,8 +22,6 @@ clean.doFirst {
}
android {
namespace 'com.google.android.filament.textured'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.textured"
@@ -16,8 +16,6 @@ clean.doFirst {
}
android {
namespace 'com.google.android.filament.transparentrendering'
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.textureview"
+1 -2
View File
@@ -49,8 +49,7 @@ FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/ndk.version)}
# Install the required NDK version specifically (if not present)
if [[ ! -d "${ANDROID_HOME}/ndk/$FILAMENT_NDK_VERSION" ]]; then
# NOTE: We MUST use Java 1.8 to run sdkmanager currently, it fails starting with Java 11
JAVA_HOME=${JAVA_HOME_8_X64} ${ANDROID_HOME}/tools/bin/sdkmanager "ndk;$FILAMENT_NDK_VERSION" > /dev/null
${ANDROID_HOME}/tools/bin/sdkmanager "ndk;$FILAMENT_NDK_VERSION" > /dev/null
fi
# Only build 1 64 bit target during presubmit to cut down build times during presubmit
+1 -1
View File
@@ -1 +1 @@
24.0.8215888
23.1.7779620
+13 -39
View File
@@ -118,7 +118,6 @@ counter-increment: h6;margin-right:10px}
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/materialblock/shading:customsurfaceshading" class="level3"><span class="tocNumber">4.2.31&nbsp; </span>Shading: customSurfaceShading</a><br>
&nbsp;&nbsp;<a href="#materialdefinitions/vertexblock" class="level2"><span class="tocNumber">4.3&nbsp; </span>Vertex block</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/vertexblock/materialvertexinputs" class="level3"><span class="tocNumber">4.3.1&nbsp; </span>Material vertex inputs</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/vertexblock/customvertexattributes" class="level3"><span class="tocNumber">4.3.2&nbsp; </span>Custom vertex attributes</a><br>
&nbsp;&nbsp;<a href="#materialdefinitions/fragmentblock" class="level2"><span class="tocNumber">4.4&nbsp; </span>Fragment block</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/fragmentblock/preparematerialfunction" class="level3"><span class="tocNumber">4.4.1&nbsp; </span>prepareMaterial function</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#materialdefinitions/fragmentblock/materialfragmentinputs" class="level3"><span class="tocNumber">4.4.2&nbsp; </span>Material fragment inputs</a><br>
@@ -1537,7 +1536,7 @@ non-shader data.
</p><dl><dt>Type</dt><dd><p> array of <code>string</code>
</p></dd><dt>Value</dt><dd><p> Each entry must be any of <code>dynamicLighting</code>, <code>directionalLighting</code>, <code>shadowReceiver</code>,<code>skinning</code> or <code>ssr</code>.
</p></dd><dt>Value</dt><dd><p> Each entry must be any of <code>dynamicLighting</code>, <code>directionalLighting</code>, <code>shadowReceiver</code> or <code>skinning</code>.
</p></dd><dt>Description</dt><dd><p> Used to specify a list of shader variants that the application guarantees will never be
needed. These shader variants are skipped during the code generation phase, thus reducing
@@ -1562,9 +1561,7 @@ non-shader data.
</li>
<li class="minus"><code>fog</code>, used when global fog is applied to the scene
</li>
<li class="minus"><code>vsm</code>, used when VSM shadows are enabled and the object is a shadow receiver
</li>
<li class="minus"><code>ssr</code>, used when screen-space reflections are enabled in the View</li></ul>
<li class="minus"><code>vsm</code>, used when VSM shadows are enabled and the object is a shadow receiver</li></ul>
<p></p><pre class="listing tilde"><code><span class="line">material {</span>
<span class="line"> name : <span class="hljs-string">"Invisible shadow plane"</span>,</span>
@@ -1610,8 +1607,7 @@ non-shader data.
</p><dl><dt>Type</dt><dd><p> array of <code>string</code>
</p></dd><dt>Value</dt><dd><p> Each entry must be any of <code>uv0</code>, <code>uv1</code>, <code>color</code>, <code>position</code>, <code>tangents</code>, <code>custom0</code>
through <code>custom7</code>.
</p></dd><dt>Value</dt><dd><p> Each entry must be any of <code>uv0</code>, <code>uv1</code>, <code>color</code>, <code>position</code>, <code>tangents</code>.
</p></dd><dt>Description</dt><dd><p> Lists the vertex attributes required by the material. The <code>position</code> attribute is always
required and does not need to be specified. The <code>tangents</code> attribute is automatically required
@@ -1626,8 +1622,7 @@ non-shader data.
<span class="line"> },</span>
<span class="line"> ],</span>
<span class="line"> requires : [</span>
<span class="line"> uv0,</span>
<span class="line"> custom0</span>
<span class="line"> uv0</span>
<span class="line"> ],</span>
<span class="line"> shadingModel : lit,</span>
<span class="line">}</span>
@@ -1636,7 +1631,6 @@ non-shader data.
<span class="line"> void material(inout MaterialInputs material) {</span>
<span class="line"> prepareMaterial(material);</span>
<span class="line"> material.baseColor = texture(materialParams_texture, getUV0());</span>
<span class="line"> material.baseColor.rgb *= getCustom0().rgb;</span>
<span class="line"> }</span>
<span class="line">}</span></code></pre>
<a class="target" name="vertexandattributes:variables">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:variables">&nbsp;</a><a class="target" name="toc4.2.8">&nbsp;</a><h3>Vertex and attributes: variables</h3>
@@ -1765,9 +1759,8 @@ non-shader data.
render target is brightened.
</li>
<li class="minus"><strong class="asterisk">Masked</strong>: blending is disabled. This blending mode enables alpha masking. The alpha channel
of the material's output defines whether a fragment is discarded or not. Additionally,
ALPHA_TO_COVERAGE is enabled for non-translucent views. See the maskThreshold section for more
information.</li></ul>
of the material's output defines whether a fragment is discarded or not. See the maskThreshold
section for more information.</li></ul>
<p></p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
<span class="line"> blending : transparent</span>
@@ -1858,9 +1851,8 @@ and sorting issues are minimized or eliminated</span></center></div></center>
</p></dd><dt>Value</dt><dd><p> A value between <code>0.0</code> and <code>1.0</code>. Defaults to <code>0.4</code>.
</p></dd><dt>Description</dt><dd><p> Sets the minimum alpha value a fragment must have to not be discarded when the <code>blending</code> mode
is set to <code>masked</code>. If the fragment is not discarded, its source alpha is set to 1. When the
blending mode is not <code>masked</code>, this value is ignored. This value can be used to controlled the
appearance of alpha-masked objects.
is set to <code>masked</code>. When the blending mode is not <code>masked</code>, this value is ignored. This value
can be used to controlled the appearance of alpha-masked objects.
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
<span class="line"> blending : masked,</span>
@@ -2282,31 +2274,15 @@ APIs listed in the <a href="#shaderpublicapis">Shader public APIs</a> section.
this behavior using the <code>flipUV</code> property and setting it to <code>false</code>.</p></div>
<p></p>
<a class="target" name="customvertexattributes">&nbsp;</a><a class="target" name="materialdefinitions/vertexblock/customvertexattributes">&nbsp;</a><a class="target" name="toc4.3.2">&nbsp;</a><h3>Custom vertex attributes</h3>
<p>
You can use up to 8 custom vertex attributes, all of type <code>float4</code>. These attributes can be accessed
using the vertex block shader functions <code>getCustom0()</code> to <code>getCustom7()</code>. However, before using
custom attributes, you <em class="asterisk">must</em> declare those attributes as required in the <code>requires</code> property of
the material:
</p><pre class="listing tilde"><code><span class="line">material {</span>
<span class="line"> requires : [</span>
<span class="line"> custom0,</span>
<span class="line"> custom1,</span>
<span class="line"> custom2</span>
<span class="line"> ]</span>
<span class="line">}</span></code></pre>
<a class="target" name="fragmentblock">&nbsp;</a><a class="target" name="materialdefinitions/fragmentblock">&nbsp;</a><a class="target" name="toc4.4">&nbsp;</a><h2>Fragment block</h2>
<p>
The fragment block must be used to control the fragment shading stage of the material. The fragment
The fragment block must be used to control the fragment shading stage of the material. The vertex
block must contain valid
<a href="https://www.khronos.org/registry/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf">ESSL 3.0</a>
code (the version of GLSL supported in OpenGL ES 3.0). You are free to create multiple functions
inside the fragment block but you <strong class="asterisk">must</strong> declare the <code>material</code> function:
inside the vertex block but you <strong class="asterisk">must</strong> declare the <code>material</code> function:
</p><pre class="listing tilde"><code><span class="line">fragment {</span>
<span class="line"> <span class="hljs-type">void</span> material(<span class="hljs-keyword">inout</span> MaterialInputs material) {</span>
@@ -2340,7 +2316,7 @@ standard lit shading model:
Note that you <strong class="asterisk">must</strong> call <code>prepareMaterial(material)</code> before exiting the <code>material()</code> function.
This <code>prepareMaterial</code> function sets up the internal state of the material model. Some of the APIs
This <code>prepareMaterial</code> function sets up the internal state of the material mdoel. Some of the APIs
described in the Fragment APIs section - like <code>shading_normal</code> for instance - can only be accessed
<em class="underscore">after</em> invoking <code>prepareMaterial()</code>.
@@ -2640,7 +2616,7 @@ type aliases:
<p>
</p><div class="table"><table class="table"><tbody><tr><th style="text-align:left"> Name </th><th style="text-align:center"> Type </th><th style="text-align:left"> Description </th></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getResolution()</strong> </td><td style="text-align:center"> float4 </td><td style="text-align:left"> Dimensions of the view's effective viewport in pixels: <code>width</code>, <code>height</code>, <code>1 / width</code>, <code>1 / height</code>. This might be different from <code>View::getViewport()</code> for instance because of added rendering guard-bands. This can be used in conjunction with <code>getNormalizedViewportCoord()</code> to generate pixel coordinates. </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getResolution()</strong> </td><td style="text-align:center"> float4 </td><td style="text-align:left"> Resolution of the view in pixels: <code>width</code>, <code>height</code>, <code>1 / width</code>, <code>1 / height</code> </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getWorldCameraPosition()</strong> </td><td style="text-align:center"> float3 </td><td style="text-align:left"> Position of the camera/eye in world space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getWorldOffset()</strong> </td><td style="text-align:center"> float3 </td><td style="text-align:left"> The shift required to obtain API-level world space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getTime()</strong> </td><td style="text-align:center"> float </td><td style="text-align:left"> Current time as a remainder of 1 second. Yields a value between 0 and 1 </td></tr>
@@ -2845,9 +2821,7 @@ variants:
</li>
<li class="minus"><code>fog</code>, used when global fog is applied to the scene
</li>
<li class="minus"><code>vsm</code>, used when VSM shadows are enabled and the object is a shadow receiver
</li>
<li class="minus"><code>ssr</code>, used when screen-space reflections are enabled in the View</li></ul>
<li class="minus"><code>vsm</code>, used when VSM shadows are enabled and the object is a shadow receiver</li></ul>
<p></p><p>
+5 -25
View File
@@ -1125,8 +1125,7 @@ Type
: array of `string`
Value
: Each entry must be any of `uv0`, `uv1`, `color`, `position`, `tangents`, `custom0`
through `custom7`.
: Each entry must be any of `uv0`, `uv1`, `color`, `position`, `tangents`.
Description
: Lists the vertex attributes required by the material. The `position` attribute is always
@@ -1143,8 +1142,7 @@ material {
},
],
requires : [
uv0,
custom0
uv0
],
shadingModel : lit,
}
@@ -1153,7 +1151,6 @@ fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = texture(materialParams_texture, getUV0());
material.baseColor.rgb *= getCustom0().rgb;
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1844,30 +1841,13 @@ struct MaterialVertexInputs {
of the current mesh: `material.uv0 = vec2(mesh_uv0.x, 1.0 - mesh_uv0.y)`. You can control
this behavior using the `flipUV` property and setting it to `false`.
### Custom vertex attributes
You can use up to 8 custom vertex attributes, all of type `float4`. These attributes can be accessed
using the vertex block shader functions `getCustom0()` to `getCustom7()`. However, before using
custom attributes, you *must* declare those attributes as required in the `requires` property of
the material:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
requires : [
custom0,
custom1,
custom2
]
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Fragment block
The fragment block must be used to control the fragment shading stage of the material. The fragment
The fragment block must be used to control the fragment shading stage of the material. The vertex
block must contain valid
[ESSL 3.0](https://www.khronos.org/registry/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf)
code (the version of GLSL supported in OpenGL ES 3.0). You are free to create multiple functions
inside the fragment block but you **must** declare the `material` function:
inside the vertex block but you **must** declare the `material` function:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GLSL
fragment {
@@ -1902,7 +1882,7 @@ fragment {
### prepareMaterial function
Note that you **must** call `prepareMaterial(material)` before exiting the `material()` function.
This `prepareMaterial` function sets up the internal state of the material model. Some of the APIs
This `prepareMaterial` function sets up the internal state of the material mdoel. Some of the APIs
described in the Fragment APIs section - like `shading_normal` for instance - can only be accessed
_after_ invoking `prepareMaterial()`.
+19 -43
View File
@@ -15,17 +15,22 @@
*/
// If you are bundling this with rollup, webpack, or esbuild, the following URL should be trimmed.
import { LitElement, html, css } from "https://unpkg.com/lit?module";
import { LitElement, html, css } from "https://unpkg.com/lit-element?module";
// This little utility checks if the Filament module is ready for action.
// If so, it immediately calls the given function. If not, it asks the Filament
// loader to call it as soon as the module becomes ready.
// To allow the DOM to render before the Filament WASM module is ready, we maintain a little
// queue of tasks that get invoked as soon as the module is done loading.
class FilamentTasks {
constructor() {
this.tasks = []
if (!Filament.Engine) {
Filament.init([], () => { for (const task of this.tasks) task(); });
}
}
add(callback) {
if (Filament.isReady) {
callback();
if (!Filament.Engine) {
this.tasks.push(callback);
} else {
Filament.init([], callback);
callback();
}
}
}
@@ -63,7 +68,6 @@ class FilamentViewer extends LitElement {
this.sky = null; // Path to skybox ktx.
this.enableDrop = null; // Enables drag and drop.
this.intensity = 30000; // Intensity of the image based light.
this.materialVariant = 0; // Index of material variant.
// Private properties:
this.filamentTasks = new FilamentTasks();
@@ -80,7 +84,6 @@ class FilamentViewer extends LitElement {
sky: { type: String },
enableDrop: { type: Boolean },
intensity: { type: Number },
materialVariant: { type: Number },
}
}
@@ -113,7 +116,6 @@ class FilamentViewer extends LitElement {
if (props.has("intensity") && this.indirectLight) {
this.indirectLight.setIntensity(this.intensity);
}
if (props.has("materialVariant") && this.asset) this._applyMaterialVariant();
}
static get styles() {
@@ -246,7 +248,7 @@ class FilamentViewer extends LitElement {
return response.arrayBuffer();
}).then(arrayBuffer => {
const ktxData = new Uint8Array(arrayBuffer);
this.indirectLight = this.engine.createIblFromKtx1(ktxData);
this.indirectLight = this.engine.createIblFromKtx(ktxData);
this.indirectLight.setIntensity(this.intensity);
this.scene.setIndirectLight(this.indirectLight);
});
@@ -264,7 +266,7 @@ class FilamentViewer extends LitElement {
return response.arrayBuffer();
}).then(arrayBuffer => {
const ktxData = new Uint8Array(arrayBuffer);
this.skybox = this.engine.createSkyFromKtx1(ktxData);
this.skybox = this.engine.createSkyFromKtx(ktxData);
this.scene.setSkybox(this.skybox);
});
}
@@ -309,7 +311,7 @@ class FilamentViewer extends LitElement {
asyncInterval: 30
};
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider) => {
const doneAddingResources = resourceLoader => {
this.srcBlobResources = {};
resourceLoader.asyncBeginLoad(this.asset);
const timer = setInterval(() => {
@@ -318,8 +320,6 @@ class FilamentViewer extends LitElement {
if (progress >= 1) {
clearInterval(timer);
resourceLoader.delete();
stbProvider.delete();
ktx2Provider.delete();
this.animator = this.asset.getAnimator();
this.animationStartTime = Date.now();
}
@@ -337,20 +337,13 @@ class FilamentViewer extends LitElement {
config.recomputeBoundingBoxes,
config.ignoreBindTransform);
const stbProvider = new Filament.gltfio$StbProvider(this.engine);
const ktx2Provider = new Filament.gltfio$Ktx2Provider(this.engine);
resourceLoader.addStbProvider("image/jpeg", stbProvider);
resourceLoader.addStbProvider("image/png", stbProvider);
resourceLoader.addKtx2Provider("image/ktx2", ktx2Provider);
let remaining = Object.keys(this.srcBlobResources).length;
for (const name in this.srcBlobResources) {
this.srcBlobResources[name].arrayBuffer().then(buffer => {
const desc = getBufferDescriptor(new Uint8Array(buffer));
resourceLoader.addResourceData(name, getBufferDescriptor(desc));
if (--remaining === 0) {
doneAddingResources(resourceLoader, stbProvider, ktx2Provider);
doneAddingResources(resourceLoader);
}
});
}
@@ -382,7 +375,6 @@ class FilamentViewer extends LitElement {
this.asset.loadResources(() => {
this.animator = this.asset.getAnimator();
this.animationStartTime = Date.now();
this._applyMaterialVariant();
}, null, basePath);
this._updateOverlay();
@@ -391,11 +383,9 @@ class FilamentViewer extends LitElement {
_updateAsset() {
// Invoke the first glTF animation if it exists.
if (this.animator) {
if (this.animator.getAnimationCount() > 0) {
const ms = Date.now() - this.animationStartTime;
this.animator.applyAnimation(0, ms / 1000);
}
if (this.animator && this.animator.getAnimationCount() > 0) {
const ms = Date.now() - this.animationStartTime;
this.animator.applyAnimation(0, ms / 1000);
this.animator.updateBoneMatrices();
}
@@ -436,20 +426,6 @@ class FilamentViewer extends LitElement {
window.requestAnimationFrame(this._renderFrame.bind(this));
}
_applyMaterialVariant() {
if (!this.hasAttribute("materialVariant")) {
return;
}
const names = this.asset.getMaterialVariantNames();
const index = this.materialVariant;
if (index < 0 || index >= names.length) {
console.error(`Material variant ${index} does not exist in this asset.`);
return;
}
console.info(this.src, `Applying material variant: ${names[index]}`);
this.asset.applyMaterialVariant(index);
}
}
customElements.define("filament-viewer", FilamentViewer);
+1 -1
View File
@@ -43,7 +43,7 @@ filament-viewer::part(canvas) {
</p>
</main>
<script src="https://unpkg.com/filament@1.22.0/filament.js"></script>
<script src="https://unpkg.com/filament/filament.js"></script>
<script src="https://unpkg.com/gltumble"></script>
<script src="filament-viewer.js" type="module"></script>
</body>
-28
View File
@@ -456,34 +456,6 @@ add_custom_command(
APPEND
)
add_custom_command(
OUTPUT "${MATERIAL_DIR}/separableGaussianBlur1L.filamat"
DEPENDS src/materials/separableGaussianBlur.vs
DEPENDS src/materials/separableGaussianBlur.fs
APPEND
)
add_custom_command(
OUTPUT "${MATERIAL_DIR}/separableGaussianBlur2L.filamat"
DEPENDS src/materials/separableGaussianBlur.vs
DEPENDS src/materials/separableGaussianBlur.fs
APPEND
)
add_custom_command(
OUTPUT "${MATERIAL_DIR}/separableGaussianBlur3L.filamat"
DEPENDS src/materials/separableGaussianBlur.vs
DEPENDS src/materials/separableGaussianBlur.fs
APPEND
)
add_custom_command(
OUTPUT "${MATERIAL_DIR}/separableGaussianBlur4L.filamat"
DEPENDS src/materials/separableGaussianBlur.vs
DEPENDS src/materials/separableGaussianBlur.fs
APPEND
)
add_custom_command(
OUTPUT ${RESGEN_OUTPUTS}
COMMAND resgen ${RESGEN_FLAGS} ${MATERIAL_BINS}
-1
View File
@@ -389,7 +389,6 @@ if (APPLE)
test/test_MRT.cpp
test/test_LoadImage.cpp
test/test_RenderExternalImage.cpp
test/test_StencilBuffer.cpp
)
target_link_libraries(backend_test PRIVATE
+18 -52
View File
@@ -719,7 +719,7 @@ enum class SamplerCompareMode : uint8_t {
COMPARE_TO_TEXTURE = 1
};
//! comparison function for the depth / stencil sampler
//! comparison function for the depth sampler
enum class SamplerCompareFunc : uint8_t {
// don't change the enums values
LE = 0, //!< Less or equal
@@ -728,8 +728,8 @@ enum class SamplerCompareFunc : uint8_t {
G, //!< Strictly greater than
E, //!< Equal
NE, //!< Not equal
A, //!< Always. Depth / stencil testing is deactivated.
N //!< Never. The depth / stencil test always fails.
A, //!< Always. Depth testing is deactivated.
N //!< Never. The depth test always fails.
};
//! Sampler paramters
@@ -785,18 +785,6 @@ enum class BlendFunction : uint8_t {
SRC_ALPHA_SATURATE //!< f(src, dst) = (1,1,1) * min(src.a, 1 - dst.a), 1
};
//! stencil operation
enum class StencilOperation : uint8_t {
KEEP, //!< Keeps the current value.
ZERO, //!< Sets the value to 0.
REPLACE, //!< Sets the value to the stencil reference value.
INCR, //!< Increments the current value. Clamps to the maximum representable unsigned value.
INCR_WRAP, //!< Increments the current value. Wraps value to zero when incrementing the maximum representable unsigned value.
DECR, //!< Decrements the current value. Clamps to 0.
DECR_WRAP, //!< Decrements the current value. Wraps value to the maximum representable unsigned value when decrementing a value of zero.
INVERT, //!< Bitwise inverts the current value.
};
//! Stream for external textures
enum class StreamType {
NATIVE, //!< Not synchronized but copy-free. Good for video.
@@ -829,11 +817,9 @@ struct RasterState {
using DepthFunc = backend::SamplerCompareFunc;
using BlendEquation = backend::BlendEquation;
using BlendFunction = backend::BlendFunction;
using StencilFunction = backend::SamplerCompareFunc;
using StencilOperation = backend::StencilOperation;
RasterState() noexcept { // NOLINT
static_assert(sizeof(RasterState) == sizeof(uint64_t),
static_assert(sizeof(RasterState) == sizeof(uint32_t),
"RasterState size not what was intended");
culling = CullingMode::BACK;
blendEquationRGB = BlendEquation::ADD;
@@ -842,10 +828,6 @@ struct RasterState {
blendFunctionSrcAlpha = BlendFunction::ONE;
blendFunctionDstRGB = BlendFunction::ZERO;
blendFunctionDstAlpha = BlendFunction::ZERO;
stencilFunc = StencilFunction::A;
stencilOpStencilFail = StencilOperation::KEEP;
stencilOpDepthFail = StencilOperation::KEEP;
stencilOpDepthStencilPass = StencilOperation::KEEP;
}
bool operator == (RasterState rhs) const noexcept { return u == rhs.u; }
@@ -874,56 +856,40 @@ struct RasterState {
union {
struct {
//! culling mode
CullingMode culling : 2; // 2
CullingMode culling : 2; // 2
//! blend equation for the red, green and blue components
BlendEquation blendEquationRGB : 3; // 5
BlendEquation blendEquationRGB : 3; // 5
//! blend equation for the alpha component
BlendEquation blendEquationAlpha : 3; // 8
BlendEquation blendEquationAlpha : 3; // 8
//! blending function for the source color
BlendFunction blendFunctionSrcRGB : 4; // 12
BlendFunction blendFunctionSrcRGB : 4; // 12
//! blending function for the source alpha
BlendFunction blendFunctionSrcAlpha : 4; // 16
BlendFunction blendFunctionSrcAlpha : 4; // 16
//! blending function for the destination color
BlendFunction blendFunctionDstRGB : 4; // 20
BlendFunction blendFunctionDstRGB : 4; // 20
//! blending function for the destination alpha
BlendFunction blendFunctionDstAlpha : 4; // 24
BlendFunction blendFunctionDstAlpha : 4; // 24
//! Whether depth-buffer writes are enabled
bool depthWrite : 1; // 25
bool depthWrite : 1; // 25
//! Depth test function
DepthFunc depthFunc : 3; // 28
DepthFunc depthFunc : 3; // 28
//! Whether color-buffer writes are enabled
bool colorWrite : 1; // 29
bool colorWrite : 1; // 29
//! use alpha-channel as coverage mask for anti-aliasing
bool alphaToCoverage : 1; // 30
bool alphaToCoverage : 1; // 30
//! whether front face winding direction must be inverted
bool inverseFrontFaces : 1; // 31
bool inverseFrontFaces : 1; // 31
//! Whether stencil-buffer writes are enabled
bool stencilWrite : 1; // 32
//! Stencil reference value
uint8_t stencilRef : 8; // 40
//! Stencil test function
StencilFunction stencilFunc : 3; // 43
//! Stencil operation when stencil test fails
StencilOperation stencilOpStencilFail : 3; // 46
//! padding, must be 0
uint8_t padding0 : 2; // 48
//! Stencil operation when stencil test passes but depth test fails
StencilOperation stencilOpDepthFail : 3; // 51
//! Stencil operation when both stencil and depth test pass
StencilOperation stencilOpDepthStencilPass : 3; // 54
//! padding, must be 0
uint8_t padding1 : 2; // 56
//! padding, must be 0
uint8_t padding2 : 8; // 64
uint8_t padding : 1; // 32
};
uint64_t u = 0;
uint32_t u = 0;
};
};
@@ -26,7 +26,6 @@
#include <stdint.h>
#include <limits>
#include <type_traits>
namespace filament::backend {
@@ -34,7 +34,6 @@
#include <utils/compiler.h>
#include <utils/ThreadUtils.h>
#include <cstddef>
#include <functional>
#include <tuple>
#include <thread>
@@ -67,8 +67,6 @@ public:
utils::Invocable<utils::io::ostream&(utils::io::ostream& out)>&& logger);
// sets one of the program's shader (e.g. vertex, fragment)
// string-based shaders are null terminated, consequently the size parameter must include the
// null terminating character.
Program& shader(Shader shader, void const* data, size_t size) noexcept;
// sets the 'bindingPoint' uniform block's name for this program.
@@ -86,14 +84,10 @@ public:
Program& setSamplerGroup(size_t bindingPoint, ShaderStageFlags stageFlags,
Sampler const* samplers, size_t count) noexcept;
// string-based shaders are null terminated, consequently the size parameter must include the
// null terminating character.
Program& withVertexShader(void const* data, size_t size) {
return shader(Shader::VERTEX, data, size);
}
// string-based shaders are null terminated, consequently the size parameter must include the
// null terminating character.
Program& withFragmentShader(void const* data, size_t size) {
return shader(Shader::FRAGMENT, data, size);
}
+1 -4
View File
@@ -346,11 +346,8 @@ MetalProgram::MetalProgram(id<MTLDevice> device, const Program& program) noexcep
continue;
}
assert_invariant( source[source.size() - 1] == '\0' );
// the shader string is null terminated and the length includes the null character
NSString* objcSource = [[NSString alloc] initWithBytes:source.data()
length:source.size() - 1
length:source.size()
encoding:NSUTF8StringEncoding];
NSError* error = nil;
// When options is nil, Metal uses the most recent language version available.
-17
View File
@@ -255,23 +255,6 @@ constexpr inline GLenum getDepthFunc(SamplerCompareFunc func) noexcept {
return getTextureCompareFunc(func);
}
constexpr inline GLenum getStencilFunc(SamplerCompareFunc func) noexcept {
return getTextureCompareFunc(func);
}
constexpr inline GLenum getStencilOp(StencilOperation op) noexcept {
switch (op) {
case StencilOperation::KEEP: return GL_KEEP;
case StencilOperation::ZERO: return GL_ZERO;
case StencilOperation::REPLACE: return GL_REPLACE;
case StencilOperation::INCR: return GL_INCR;
case StencilOperation::INCR_WRAP: return GL_INCR_WRAP;
case StencilOperation::DECR: return GL_DECR;
case StencilOperation::DECR_WRAP: return GL_DECR_WRAP;
case StencilOperation::INVERT: return GL_INVERT;
}
}
constexpr inline GLenum getFormat(PixelDataFormat format) noexcept {
using PixelDataFormat = PixelDataFormat;
switch (format) {
@@ -101,9 +101,6 @@ public:
inline void colorMask(GLboolean flag) noexcept;
inline void depthMask(GLboolean flag) noexcept;
inline void depthFunc(GLenum func) noexcept;
inline void stencilFunc(GLenum func, GLint ref, GLuint mask) noexcept;
inline void stencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) noexcept;
inline void stencilMask(GLuint mask) noexcept;
inline void polygonOffset(GLfloat factor, GLfloat units) noexcept;
inline void beginQuery(GLenum target, GLuint query) noexcept;
inline void endQuery(GLenum target) noexcept;
@@ -292,23 +289,6 @@ private:
GLboolean colorMask = GL_TRUE;
GLboolean depthMask = GL_TRUE;
GLenum depthFunc = GL_LESS;
struct StencilFunc {
GLenum func = GL_ALWAYS;
GLint ref = 0;
GLuint mask = ~GLuint(0);
bool operator != (StencilFunc const& rhs) const noexcept {
return func != rhs.func || ref != rhs.ref || mask != rhs.mask;
}
} stencilFunc;
struct StencilOp {
GLenum sfail = GL_KEEP;
GLenum dpfail = GL_KEEP;
GLenum dppass = GL_KEEP;
bool operator != (StencilOp const& rhs) const noexcept {
return sfail != rhs.sfail || dpfail != rhs.dpfail || dppass != rhs.dppass;
}
} stencilOp;
GLuint stencilMask = ~GLuint(0);
} raster;
struct PolygonOffset {
@@ -654,27 +634,6 @@ void OpenGLContext::depthFunc(GLenum func) noexcept {
});
}
void OpenGLContext::stencilFunc(GLenum func, GLint ref, GLuint mask) noexcept {
// WARNING: don't call this without updating mRasterState
update_state(state.raster.stencilFunc, {func, ref, mask}, [&]() {
glStencilFunc(func, ref, mask);
});
}
void OpenGLContext::stencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) noexcept {
// WARNING: don't call this without updating mRasterState
update_state(state.raster.stencilOp, {sfail, dpfail, dppass}, [&]() {
glStencilOp(sfail, dpfail, dppass);
});
}
void OpenGLContext::stencilMask(GLuint mask) noexcept {
// WARNING: don't call this without updating mRasterState
update_state(state.raster.stencilMask, mask, [&]() {
glStencilMask(mask);
});
}
void OpenGLContext::polygonOffset(GLfloat factor, GLfloat units) noexcept {
update_state(state.polygonOffset, { factor, units }, [&]() {
if (factor != 0 || units != 0) {
@@ -294,19 +294,6 @@ void OpenGLDriver::setRasterStateSlow(RasterState rs) noexcept {
gl.depthMask(GLboolean(rs.depthWrite));
}
// stencil test / operation
if (rs.stencilFunc == RasterState::StencilFunction::A && !rs.stencilWrite) {
gl.disable(GL_STENCIL_TEST);
} else {
gl.enable(GL_STENCIL_TEST);
gl.stencilFunc(getStencilFunc(rs.stencilFunc), rs.stencilRef, ~GLuint(0));
gl.stencilOp(getStencilOp(rs.stencilOpStencilFail),
getStencilOp(rs.stencilOpDepthFail),
getStencilOp(rs.stencilOpDepthStencilPass));
GLuint stencilMask = rs.stencilWrite ? ~GLuint(0) : 0x00;
gl.stencilMask(stencilMask);
}
// write masks
gl.colorMask(GLboolean(rs.colorWrite));
@@ -186,11 +186,7 @@ highp uint packHalf2x16(vec2 v) {
GLuint shaderId = glCreateShader(glShaderType);
{ // scope for source/length (we don't want them to leak out)
const char* const source = shaderView.data();
// the shader string is null terminated and the length includes the null character
const GLint length = (GLint)shaderView.length() - 1;
assert_invariant( source[length] == '\0' );
const GLint length = (GLint)shaderView.length();
glShaderSource(shaderId, 1, &source, &length);
glCompileShader(shaderId);
#ifndef NDEBUG
+10 -12
View File
@@ -1633,21 +1633,19 @@ void VulkanDriver::blit(TargetBufferFlags buffers, Handle<HwRenderTarget> dst, V
VkFilter vkfilter = filter == SamplerMagFilter::NEAREST ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
// The Y inversion below makes it so that Vk matches GL and Metal.
const VkExtent2D srcExtent = srcTarget->getExtent();
const int32_t srcLeft = srcRect.left;
const int32_t srcTop = srcExtent.height - srcRect.bottom - srcRect.height;
const int32_t srcRight = srcRect.left + srcRect.width;
const int32_t srcBottom = srcTop + srcRect.height;
const VkOffset3D srcOffsets[2] = { { srcLeft, srcTop, 0 }, { srcRight, srcBottom, 1 }};
const int32_t srcLeft = std::min(srcRect.left, (int32_t) srcExtent.width);
const int32_t srcBottom = std::min(srcRect.bottom, (int32_t) srcExtent.height);
const int32_t srcRight = std::min(srcRect.left + srcRect.width, srcExtent.width);
const int32_t srcTop = std::min(srcRect.bottom + srcRect.height, srcExtent.height);
const VkOffset3D srcOffsets[2] = { { srcLeft, srcBottom, 0 }, { srcRight, srcTop, 1 }};
const VkExtent2D dstExtent = dstTarget->getExtent();
const int32_t dstLeft = dstRect.left;
const int32_t dstTop = dstExtent.height - dstRect.bottom - dstRect.height;
const int32_t dstRight = dstRect.left + dstRect.width;
const int32_t dstBottom = dstTop + dstRect.height;
const VkOffset3D dstOffsets[2] = { { dstLeft, dstTop, 0 }, { dstRight, dstBottom, 1 }};
const int32_t dstLeft = std::min(dstRect.left, (int32_t) dstExtent.width);
const int32_t dstBottom = std::min(dstRect.bottom, (int32_t) dstExtent.height);
const int32_t dstRight = std::min(dstRect.left + dstRect.width, dstExtent.width);
const int32_t dstTop = std::min(dstRect.bottom + dstRect.height, dstExtent.height);
const VkOffset3D dstOffsets[2] = { { dstLeft, dstBottom, 0 }, { dstRight, dstTop, 1 }};
if (any(buffers & TargetBufferFlags::DEPTH) && srcTarget->hasDepth() && dstTarget->hasDepth()) {
mBlitter.blitDepth({dstTarget, dstOffsets, srcTarget, srcOffsets});
@@ -546,7 +546,6 @@ void transitionImageLayout(VkCommandBuffer cmdbuffer, VulkanLayoutTransition tra
if (transition.oldLayout == transition.newLayout) {
return;
}
assert_invariant(transition.image != VK_NULL_HANDLE && "Please call bindToSwapChain.");
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = transition.oldLayout;
+5 -32
View File
@@ -20,26 +20,17 @@
#include <utils/Hash.h>
#include <fstream>
#include "ShaderGenerator.h"
#include "TrianglePrimitive.h"
static constexpr size_t CONFIG_MIN_COMMAND_BUFFERS_SIZE = 1 * 1024 * 1024;
static constexpr size_t CONFIG_COMMAND_BUFFERS_SIZE = 3 * CONFIG_MIN_COMMAND_BUFFERS_SIZE;
namespace test {
using namespace filament;
using namespace filament::backend;
#ifndef IOS
#include <imageio/ImageEncoder.h>
#include <image/ColorTransform.h>
using namespace image;
#endif
namespace test {
Backend BackendTest::sBackend = Backend::NOOP;
bool BackendTest::sIsMobilePlatform = false;
@@ -140,38 +131,20 @@ void BackendTest::renderTriangle(Handle<HwRenderTarget> renderTarget,
}
void BackendTest::readPixelsAndAssertHash(const char* testName, size_t width, size_t height,
Handle<HwRenderTarget> rt, uint32_t expectedHash, bool exportScreenshot) {
Handle<HwRenderTarget> rt, uint32_t expectedHash) {
void* buffer = calloc(1, width * height * 4);
struct Capture {
uint32_t expectedHash;
char* name;
bool exportScreenshot;
size_t width, height;
};
auto* c = new Capture();
Capture* c = new Capture();
c->expectedHash = expectedHash;
c->name = strdup(testName);
c->exportScreenshot = exportScreenshot;
c->width = width;
c->height = height;
PixelBufferDescriptor pbd(buffer, width * height * 4, PixelDataFormat::RGBA, PixelDataType::UBYTE,
1, 0, 0, width, [](void* buffer, size_t size, void* user) {
auto* c = (Capture*)user;
// Export a screenshot, if requested.
if (c->exportScreenshot) {
#ifndef IOS
LinearImage image(c->width, c->height, 4);
image = toLinearWithAlpha<uint8_t>(c->width, c->height, c->width * 4,
(uint8_t*) buffer);
const std::string png = std::string(c->name) + ".png";
std::ofstream outputStream(png.c_str(), std::ios::binary | std::ios::trunc);
ImageEncoder::encode(outputStream, ImageEncoder::Format::PNG, image, "",
png);
#endif
}
Capture* c = (Capture*)user;
// Hash the contents of the buffer and check that they match.
uint32_t hash = utils::hash::murmur3((const uint32_t*) buffer, size / 4, 0);
+1 -2
View File
@@ -56,8 +56,7 @@ protected:
filament::backend::Handle<filament::backend::HwProgram> program);
void readPixelsAndAssertHash(const char* testName, size_t width, size_t height,
filament::backend::Handle<filament::backend::HwRenderTarget> rt, uint32_t expectedHash,
bool exportScreenshot = false);
filament::backend::Handle<filament::backend::HwRenderTarget> rt, uint32_t expectedHash);
filament::backend::DriverApi& getDriverApi() { return *commandStream; }
filament::backend::Driver& getDriver() { return *driver; }
-153
View File
@@ -866,157 +866,4 @@ TEST_F(BackendTest, Blit2DTextureArray) {
api.stopCapture(0);
}
TEST_F(BackendTest, BlitRegion) {
auto& api = getDriverApi();
constexpr int kSrcTexWidth = 1024;
constexpr int kSrcTexHeight = 1024;
constexpr auto kSrcTexFormat = TextureFormat::RGBA8;
constexpr int kDstTexWidth = 384;
constexpr int kDstTexHeight = 384;
constexpr auto kDstTexFormat = TextureFormat::RGBA8;
constexpr int kNumLevels = 3;
// 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 source texture.
Handle<HwTexture> 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;
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
// Create a destination texture.
Handle<HwTexture> dstTexture = api.createTexture(
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
// Create a RenderTarget for each texture's miplevel.
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
Handle<HwRenderTarget> dstRenderTargets[kNumLevels];
for (uint8_t level = 0; level < kNumLevels; level++) {
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, { srcTexture, level, 0 }, {}, {});
dstRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
kDstTexWidth >> level, kDstTexHeight >> level, 1, { dstTexture, level, 0 }, {}, {});
}
// Blit one-quarter of src level 1 to dst level 0.
const int srcLevel = 1;
Viewport srcRect = {
.left = (kSrcTexWidth >> srcLevel) / 2,
.bottom = (kSrcTexHeight >> srcLevel) / 2,
.width = (kSrcTexWidth >> srcLevel) / 2,
.height = (kSrcTexHeight >> srcLevel) / 2,
};
Viewport dstRect = {
.left = 10,
.bottom = 10,
.width = kDstTexWidth - 10,
.height = kDstTexHeight - 10,
};
api.blit(TargetBufferFlags::COLOR0, dstRenderTargets[0],
dstRect, srcRenderTargets[srcLevel],
srcRect, 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);
// Grab a screenshot.
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "BlitRegion.png" };
api.beginFrame(0, 0);
dumpScreenshot(api, dstRenderTargets[0], &params);
api.commit(swapChain);
api.endFrame(0);
// Wait for the ReadPixels result to come back.
api.finish();
executeCommands();
getDriver().purge();
// Cleanup.
api.destroyTexture(srcTexture);
api.destroyTexture(dstTexture);
api.destroySwapChain(swapChain);
for (auto rt : srcRenderTargets) api.destroyRenderTarget(rt);
for (auto rt : dstRenderTargets) api.destroyRenderTarget(rt);
executeCommands();
}
TEST_F(BackendTest, BlitRegionToSwapChain) {
auto& api = getDriverApi();
constexpr int kSrcTexWidth = 1024;
constexpr int kSrcTexHeight = 1024;
constexpr auto kSrcTexFormat = TextureFormat::RGBA8;
constexpr int kDstTexWidth = 512;
constexpr int kDstTexHeight = 512;
constexpr int kNumLevels = 3;
// Create a SwapChain and make it current.
auto swapChain = createSwapChain();
Handle<HwRenderTarget> dstRenderTarget = api.createDefaultRenderTarget();
api.makeCurrent(swapChain, swapChain);
// Create a source texture.
Handle<HwTexture> 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;
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
// Create a RenderTarget for each texture's miplevel.
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
for (uint8_t level = 0; level < kNumLevels; level++) {
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, { srcTexture, level, 0 }, {}, {});
}
// Blit one-quarter of src level 1 to dst level 0.
const int srcLevel = 1;
Viewport srcRect = {
.left = (kSrcTexWidth >> srcLevel) / 2,
.bottom = (kSrcTexHeight >> srcLevel) / 2,
.width = (kSrcTexWidth >> srcLevel) / 2,
.height = (kSrcTexHeight >> srcLevel) / 2,
};
Viewport dstRect = {
.left = 10,
.bottom = 10,
.width = kDstTexWidth - 10,
.height = kDstTexHeight - 10,
};
api.beginFrame(0, 0);
api.blit(TargetBufferFlags::COLOR0, dstRenderTarget,
dstRect, srcRenderTargets[srcLevel],
srcRect, SamplerMagFilter::LINEAR);
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "BlitRegionToSwapChain.png" };
dumpScreenshot(api, dstRenderTarget, &params);
api.commit(swapChain);
api.endFrame(0);
// Wait for the ReadPixels result to come back.
api.finish();
executeCommands();
getDriver().purge();
// Cleanup.
api.destroyTexture(srcTexture);
api.destroySwapChain(swapChain);
for (auto rt : srcRenderTargets) api.destroyRenderTarget(rt);
executeCommands();
}
} // namespace test
@@ -1,150 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "BackendTest.h"
#include "ShaderGenerator.h"
#include "TrianglePrimitive.h"
using namespace filament;
using namespace filament::backend;
namespace {
////////////////////////////////////////////////////////////////////////////////////////////////////
// Shaders
////////////////////////////////////////////////////////////////////////////////////////////////////
std::string vertex (R"(#version 450 core
layout(location = 0) in vec4 mesh_position;
void main() {
gl_Position = vec4(mesh_position.xy, 0.0, 1.0);
#if defined(TARGET_VULKAN_ENVIRONMENT)
// In Vulkan, clip space is Y-down. In OpenGL and Metal, clip space is Y-up.
gl_Position.y = -gl_Position.y;
#endif
}
)");
std::string fragment (R"(#version 450 core
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = vec4(1.0);
}
)");
}
namespace test {
// 1. Clear the stencil buffer to all zeroes.
// 2. Render a small triangle only to the stencil buffer and set the operation to write ones.
// 3. Enable a "== 0" stencil test and enable color writes.
// 4. Render a larger triangle to the SwapChain.
// 5. The larger triangle should have a "hole" in the middle.
TEST_F(BackendTest, StencilBuffer) {
auto& api = getDriverApi();
// The test is executed within this block scope to force destructors to run before
// executeCommands().
{
// Create a platform-specific SwapChain and make it current.
auto swapChain = createSwapChain();
api.makeCurrent(swapChain, swapChain);
// Create a program.
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
Program p = shaderGen.getProgram();
ProgramHandle program = api.createProgram(std::move(p));
// We'll be using a triangle as geometry.
TrianglePrimitive smallTriangle(api);
static filament::math::float2 vertices[3] = {
{ -0.5, -0.5 },
{ 0.5, -0.5 },
{ -0.5, 0.5 }
};
smallTriangle.updateVertices(vertices);
TrianglePrimitive triangle(api);
// Create two textures: a color and a stencil, and an associated RenderTarget.
auto colorTexture = getDriverApi().createTexture(SamplerType::SAMPLER_2D, 1,
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT);
auto stencilTexture = getDriverApi().createTexture(SamplerType::SAMPLER_2D, 1,
TextureFormat::STENCIL8, 1, 512, 512, 1, TextureUsage::STENCIL_ATTACHMENT);
auto renderTarget = getDriverApi().createRenderTarget(
TargetBufferFlags::COLOR0 | TargetBufferFlags::STENCIL, 512, 512, 1,
{{colorTexture}}, {}, {{stencilTexture}});
// Step 1: Clear the stencil buffer to all zeroes and the color buffer to blue.
// Render a small triangle only to the stencil buffer, increasing the stencil buffer to 1.
RenderPassParams params = {};
params.flags.clear = TargetBufferFlags::COLOR0 | TargetBufferFlags::STENCIL;
params.viewport = {0, 0, 512, 512};
params.clearColor = math::float4(0.0f, 0.0f, 1.0f, 1.0f);
params.clearStencil = 0u;
params.flags.discardStart = TargetBufferFlags::ALL;
params.flags.discardEnd = TargetBufferFlags::NONE;
PipelineState ps = {};
ps.program = program;
ps.rasterState.colorWrite = false;
ps.rasterState.depthWrite = false;
ps.rasterState.stencilWrite = true;
ps.rasterState.stencilOpDepthStencilPass = StencilOperation::INCR;
api.makeCurrent(swapChain, swapChain);
api.beginFrame(0, 0);
api.beginRenderPass(renderTarget, params);
api.draw(ps, smallTriangle.getRenderPrimitive(), 1);
api.endRenderPass();
// Step 2: Render a larger triangle with the stencil test enabled.
params.flags.clear = TargetBufferFlags::NONE;
params.flags.discardStart = TargetBufferFlags::NONE;
ps.rasterState.colorWrite = true;
ps.rasterState.stencilWrite = false;
ps.rasterState.stencilOpDepthStencilPass = StencilOperation::KEEP;
ps.rasterState.stencilFunc = RasterState::StencilFunction::E;
ps.rasterState.stencilRef = 0u;
api.beginRenderPass(renderTarget, params);
api.draw(ps, triangle.getRenderPrimitive(), 1);
api.endRenderPass();
readPixelsAndAssertHash("StencilBuffer", 512, 512, renderTarget, 0x3B1AEF0F, true);
api.commit(swapChain);
api.endFrame(0);
api.destroyProgram(program);
api.destroySwapChain(swapChain);
api.destroyTexture(colorTexture);
api.destroyTexture(stencilTexture);
api.destroyRenderTarget(renderTarget);
}
flushAndWait();
getDriver().purge();
}
} // namespace test
+12 -18
View File
@@ -78,49 +78,43 @@ public:
};
/**
* Updates positions for the given morph target.
*
* This is equivalent to the float4 method, but uses 1.0 for the 4th component.
* Updates the position of morph target at the index.
*
* Both positions and tangents must be provided.
*
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
* @param targetIndex the index of morph target to be updated.
* @param positions pointer to at least "count" positions
* @param count number of float3 vectors in positions
* @param offset offset into the target buffer, expressed as a number of float4 vectors
* @param weights pointer to at least count positions
* @param count number of position elements in positions
* @see setTangentsAt
*/
void setPositionsAt(Engine& engine, size_t targetIndex,
math::float3 const* positions, size_t count, size_t offset = 0);
/**
* Updates positions for the given morph target.
* Updates the position of morph target at the index.
*
* Both positions and tangents must be provided.
*
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
* @param targetIndex the index of morph target to be updated.
* @param positions pointer to at least "count" positions
* @param count number of float4 vectors in positions
* @param offset offset into the target buffer, expressed as a number of float4 vectors
* @see setTangentsAt
* @param weights pointer to at least count positions
* @param count number of position elements in positions
* @see setPositionsAt
*/
void setPositionsAt(Engine& engine, size_t targetIndex,
math::float4 const* positions, size_t count, size_t offset = 0);
/**
* Updates tangents for the given morph target.
* Updates the position of morph target at the index.
*
* These quaternions must be represented as signed shorts, where real numbers in the [-1,+1]
* range multiplied by 32767.
* Both positions and tangents must be provided.
*
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
* @param targetIndex the index of morph target to be updated.
* @param tangents pointer to at least "count" tangents
* @param count number of short4 quaternions in tangents
* @param offset offset into the target buffer, expressed as a number of short4 vectors
* @see setPositionsAt
* @param tangents pointer to at least count tangents
* @param count number of tangent elements in tangents
* @see setTangentsAt
*/
void setTangentsAt(Engine& engine, size_t targetIndex,
math::short4 const* tangents, size_t count, size_t offset = 0);
+32 -47
View File
@@ -25,9 +25,6 @@ namespace filament {
class Texture;
/**
* Generic quality level.
*/
enum class QualityLevel : uint8_t {
LOW,
MEDIUM,
@@ -72,8 +69,8 @@ enum class BlendMode : uint8_t {
*
*/
struct DynamicResolutionOptions {
math::float2 minScale = {0.5f, 0.5f}; //!< minimum scale factors in x and y %codegen_java_float%
math::float2 maxScale = {1.0f, 1.0f}; //!< maximum scale factors in x and y %codegen_java_float%
math::float2 minScale = math::float2(0.5f); //!< minimum scale factors in x and y
math::float2 maxScale = math::float2(1.0f); //!< maximum scale factors in x and y
float sharpness = 0.9f; //!< sharpness when QualityLevel::MEDIUM or higher is used [0 (disabled), 1 (sharpest)]
bool enabled = false; //!< enable or disable dynamic resolution
bool homogeneousScaling = false; //!< set to true to force homogeneous scaling
@@ -128,8 +125,8 @@ struct BloomOptions {
ADD, //!< Bloom is modulated by the strength parameter and added to the scene
INTERPOLATE //!< Bloom is interpolated with the scene using the strength parameter
};
Texture* dirt = nullptr; //!< user provided dirt texture %codegen_skip_json% %codegen_skip_javascript%
float dirtStrength = 0.2f; //!< strength of the dirt texture %codegen_skip_json% %codegen_skip_javascript%
Texture* dirt = nullptr; //!< user provided dirt texture
float dirtStrength = 0.2f; //!< strength of the dirt texture
float strength = 0.10f; //!< bloom's strength between 0.0 and 1.0
uint32_t resolution = 360; //!< resolution of vertical axis (2^levels to 2048)
float anamorphism = 1.0f; //!< bloom x/y aspect-ratio (1/32 to 32)
@@ -154,16 +151,16 @@ struct BloomOptions {
* Options to control fog in the scene
*/
struct FogOptions {
float distance = 0.0f; //!< distance in world units from the camera where the fog starts ( >= 0.0 )
float maximumOpacity = 1.0f; //!< fog's maximum opacity between 0 and 1
float height = 0.0f; //!< fog's floor in world units
float heightFalloff = 1.0f; //!< how fast fog dissipates with altitude
LinearColor color = {0.5f, 0.5f, 0.5f};//!< fog's color (linear), see fogColorFromIbl
float density = 0.1f; //!< fog's density at altitude given by 'height'
float inScatteringStart = 0.0f; //!< distance in world units from the camera where in-scattering starts
float inScatteringSize = -1.0f; //!< size of in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
bool fogColorFromIbl = false; //!< Fog color will be modulated by the IBL color in the view direction.
bool enabled = false; //!< enable or disable fog
float distance = 0.0f; //!< distance in world units from the camera where the fog starts ( >= 0.0 )
float maximumOpacity = 1.0f; //!< fog's maximum opacity between 0 and 1
float height = 0.0f; //!< fog's floor in world units
float heightFalloff = 1.0f; //!< how fast fog dissipates with altitude
LinearColor color{0.5f}; //!< fog's color (linear), see fogColorFromIbl
float density = 0.1f; //!< fog's density at altitude given by 'height'
float inScatteringStart = 0.0f; //!< distance in world units from the camera where in-scattering starts
float inScatteringSize = -1.0f; //!< size of in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
bool fogColorFromIbl = false; //!< Fog color will be modulated by the IBL color in the view direction.
bool enabled = false; //!< enable or disable fog
};
/**
@@ -177,9 +174,8 @@ struct FogOptions {
*/
struct DepthOfFieldOptions {
enum class Filter : uint8_t {
NONE,
UNUSED,
MEDIAN
NONE = 0,
MEDIAN = 2
};
float cocScale = 1.0f; //!< circle of confusion scale factor (amount of blur)
float maxApertureDiameter = 0.01f; //!< maximum aperture diameter in meters (zero to disable rotation)
@@ -231,7 +227,7 @@ struct VignetteOptions {
float midPoint = 0.5f; //!< high values restrict the vignette closer to the corners, between 0 and 1
float roundness = 0.5f; //!< controls the shape of the vignette, from a rounded rectangle (0.0), to an oval (0.5), to a circle (1.0)
float feather = 0.5f; //!< softening amount of the vignette effect, between 0 and 1
LinearColorA color = {0.0f, 0.0f, 0.0f, 1.0f}; //!< color of the vignette effect, alpha is currently ignored
LinearColorA color{0.0f, 0.0f, 0.0f, 1.0f}; //!< color of the vignette effect, alpha is currently ignored
bool enabled = false; //!< enables or disables the vignette effect
};
@@ -275,18 +271,17 @@ struct AmbientOcclusionOptions {
* Ambient shadows from dominant light
*/
struct Ssct {
float lightConeRad = 1.0f; //!< full cone angle in radian, between 0 and pi/2
float shadowDistance = 0.3f; //!< how far shadows can be cast
float contactDistanceMax = 1.0f; //!< max distance for contact
float intensity = 0.8f; //!< intensity
math::float3 lightDirection = { 0, -1, 0 }; //!< light direction
float depthBias = 0.01f; //!< depth bias in world units (mitigate self shadowing)
float depthSlopeBias = 0.01f; //!< depth slope bias (mitigate self shadowing)
uint8_t sampleCount = 4; //!< tracing sample count, between 1 and 255
uint8_t rayCount = 1; //!< # of rays to trace, between 1 and 255
bool enabled = false; //!< enables or disables SSCT
};
Ssct ssct; // %codegen_skip_javascript% %codegen_java_flatten%
float lightConeRad = 1.0f; //!< full cone angle in radian, between 0 and pi/2
float shadowDistance = 0.3f; //!< how far shadows can be cast
float contactDistanceMax = 1.0f; //!< max distance for contact
float intensity = 0.8f; //!< intensity
math::float3 lightDirection{ 0, -1, 0 }; //!< light direction
float depthBias = 0.01f; //!< depth bias in world units (mitigate self shadowing)
float depthSlopeBias = 0.01f; //!< depth slope bias (mitigate self shadowing)
uint8_t sampleCount = 4; //!< tracing sample count, between 1 and 255
uint8_t rayCount = 1; //!< # of rays to trace, between 1 and 255
bool enabled = false; //!< enables or disables SSCT
} ssct;
};
/**
@@ -333,31 +328,21 @@ struct ScreenSpaceReflectionsOptions {
bool enabled = false;
};
/**
* Options for the screen-space guard band.
* A guard band can be enabled to avoid some artifacts towards the edge of the screen when
* using screen-space effects such as SSAO. Enabling the guard band reduces performance slightly.
* Currently the guard band can only be enabled or disabled.
*/
struct GuardBandOptions {
bool enabled = false;
};
/**
* List of available post-processing anti-aliasing techniques.
* @see setAntiAliasing, getAntiAliasing, setSampleCount
*/
enum class AntiAliasing : uint8_t {
NONE, //!< no anti aliasing performed as part of post-processing
FXAA //!< FXAA is a low-quality but very efficient type of anti-aliasing. (default).
NONE = 0, //!< no anti aliasing performed as part of post-processing
FXAA = 1 //!< FXAA is a low-quality but very efficient type of anti-aliasing. (default).
};
/**
* List of available post-processing dithering techniques.
*/
enum class Dithering : uint8_t {
NONE, //!< No dithering
TEMPORAL //!< Temporal dithering (default)
NONE = 0, //!< No dithering
TEMPORAL = 1 //!< Temporal dithering (default)
};
/**
+5 -16
View File
@@ -80,8 +80,11 @@ public:
// refresh-rate of the display in Hz. set to 0 for offscreen or turn off frame-pacing.
float refreshRate = 60.0f;
[[deprecated]] uint64_t presentationDeadlineNanos = 0;
[[deprecated]] uint64_t vsyncOffsetNanos = 0;
// how far in advance a buffer must be queued for presentation at a given time in ns
uint64_t presentationDeadlineNanos = 0;
// offset by which vsyncSteadyClockTimeNano provided in beginFrame() is offset in ns
uint64_t vsyncOffsetNanos = 0;
};
/**
@@ -240,20 +243,6 @@ public:
bool beginFrame(SwapChain* swapChain,
uint64_t vsyncSteadyClockTimeNano = 0u);
/**
* Set the time at which the frame must be presented to the display.
*
* This must be called between beginFrame() and endFrame().
*
* @param monotonic_clock_ns the time in nanoseconds corresponding to the system monotonic up-time clock.
* the presentation time is typically set in the middle of the period
* of interest. The presentation time cannot be too far in the
* future because it is limited by how many buffers are available in
* the display sub-system. Typically it is set to 1 or 2 vsync periods
* away.
*/
void setPresentationTime(int64_t monotonic_clock_ns);
/**
* Render a View into this renderer's window.
*
-15
View File
@@ -84,7 +84,6 @@ public:
using VsmShadowOptions = VsmShadowOptions;
using SoftShadowOptions = SoftShadowOptions;
using ScreenSpaceReflectionsOptions = ScreenSpaceReflectionsOptions;
using GuardBandOptions = GuardBandOptions;
/**
* Sets the View's name. Only useful for debugging.
@@ -346,20 +345,6 @@ public:
*/
ScreenSpaceReflectionsOptions const& getScreenSpaceReflectionsOptions() const noexcept;
/**
* Enables or disable screen-space guard band. Disabled by default.
*
* @param options guard band options
*/
void setGuardBandOptions(GuardBandOptions options) noexcept;
/**
* Returns screen-space guard band options.
*
* @return guard band options
*/
GuardBandOptions const& getGuardBandOptions() const noexcept;
/**
* Enables or disable multi-sample anti-aliasing (MSAA). Disabled by default.
*
+94 -78
View File
@@ -1108,6 +1108,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
mi->setParameter("level", float(inSubDesc.level));
mi->setParameter("layer", float(inSubDesc.layer));
mi->setParameter("reinhard", reinhard ? uint32_t(1) : uint32_t(0));
mi->setParameter("resolution", float4{
tempDesc.width, tempDesc.height, 1.0f / tempDesc.width, 1.0f / tempDesc.height });
mi->setParameter("axis",float2{ 1.0f / inDesc.width, 0 });
mi->setParameter("count", (int32_t)m);
mi->setParameter("kernel", kernel, m);
@@ -1129,6 +1131,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
});
mi->setParameter("level", 0.0f);
mi->setParameter("layer", 0.0f);
mi->setParameter("resolution",
float4{ width, height, 1.0f / width, 1.0f / height });
mi->setParameter("axis", float2{ 0, 1.0f / tempDesc.height });
mi->commit(driver);
// we don't need to call use() here, since it's the same material
@@ -1526,7 +1530,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
mi->setParameter("cocClamp", float2{
-(dofOptions.maxForegroundCOC ? dofOptions.maxForegroundCOC : DOF_DEFAULT_MAX_COC),
dofOptions.maxBackgroundCOC ? dofOptions.maxBackgroundCOC : DOF_DEFAULT_MAX_COC});
mi->setParameter("texelSize", float2{ 1.0f / colorDesc.width, 1.0f / colorDesc.height });
mi->setParameter("uvscale", float4{ width, height,
1.0f / colorDesc.width, 1.0f / colorDesc.height });
commitAndRender(out, material, driver);
});
@@ -1581,15 +1586,15 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
const PipelineState pipeline(material.getPipelineState(mEngine, variant));
for (size_t level = 0 ; level < mipmapCount - 1u ; level++) {
const float w = FTexture::valueForLevel(level, desc.width);
const float h = FTexture::valueForLevel(level, desc.height);
uint32_t w = FTexture::valueForLevel(level, desc.width);
uint32_t h = FTexture::valueForLevel(level, desc.height);
auto const& out = resources.getRenderPassInfo(data.rp[level]);
driver.setMinMaxLevels(inOutColor, level, level);
driver.setMinMaxLevels(inOutCoc, level, level);
mi->setParameter("mip", uint32_t(level));
mi->setParameter("weightScale", 0.5f / float(1u<<level)); // FIXME: halfres?
mi->setParameter("texelSize", float2{ 1.0f / w, 1.0f / h });
mi->setParameter("pixelSize", 1.0f / float2{w, h});
mi->commit(driver);
render(out, pipeline, driver);
}
@@ -1608,12 +1613,10 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
// the DoF effect resolution?
// Size of a tile in full-resolution pixels -- must match TILE_SIZE in dofDilate.mat
const size_t tileSize = 16;
// we assume the width/height is already multiple of 16
assert_invariant(!(colorDesc.width & 0xF) && !(colorDesc.height & 0xF));
const uint32_t tileBufferWidth = colorDesc.width / dofResolution;
const uint32_t tileBufferHeight = colorDesc.height / dofResolution;
const size_t tileReductionCount = ctz(tileSize / dofResolution);
// round the width/height to 16 (tile size), divide by scale (1 or 2) for halfres
const uint32_t tileBufferWidth = ((colorDesc.width + (tileSize - 1u)) & ~(tileSize - 1u)) / dofResolution;
const uint32_t tileBufferHeight = ((colorDesc.height + (tileSize - 1u)) & ~(tileSize - 1u)) / dofResolution;
const size_t tileReductionCount = std::log2(tileSize / dofResolution);
struct PostProcessDofTiling1 {
FrameGraphId<FrameGraphTexture> inCocMinMax;
@@ -1624,11 +1627,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
for (size_t i = 0; i < tileReductionCount; i++) {
auto& ppDoFTiling = fg.addPass<PostProcessDofTiling1>("DoF Tiling",
[&](FrameGraph::Builder& builder, auto& data) {
// this must be true by construction
assert_invariant(((tileBufferWidth >> i) & 1u) == 0);
assert_invariant(((tileBufferHeight >> i) & 1u) == 0);
data.inCocMinMax = builder.sample(inTilesCocMinMax);
data.outTilesCocMinMax = builder.createTexture("dof tiles output", {
.width = tileBufferWidth >> (i + 1u),
@@ -1640,6 +1640,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto const& inputDesc = resources.getDescriptor(data.inCocMinMax);
auto const& outputDesc = resources.getDescriptor(data.outTilesCocMinMax);
auto const& out = resources.getRenderPassInfo();
auto inCocMinMax = resources.getTexture(data.inCocMinMax);
auto const& material = (!textureSwizzleSupported && (i == 0)) ?
@@ -1647,7 +1648,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
getPostProcessMaterial("dofTiles");
FMaterialInstance* const mi = material.getMaterialInstance(mEngine);
mi->setParameter("cocMinMax", inCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("texelSize", float2{ 1.0f / inputDesc.width, 1.0f / inputDesc.height });
mi->setParameter("uvscale", float4{
outputDesc.width, outputDesc.height,
1.0f / inputDesc.width, 1.0f / inputDesc.height });
commitAndRender(out, material, driver);
});
inTilesCocMinMax = ppDoFTiling->outTilesCocMinMax;
@@ -1709,14 +1712,16 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
data.coc = builder.sample(ppDoFMipmap->inOutCoc);
data.tilesCocMinMax = builder.sample(dilated);
// The DoF buffer (output) doesn't need to be a multiple of 8 because it's not
// mipmapped. We just need to adjust the uv properly.
data.outColor = builder.createTexture("dof color output", {
.width = colorDesc.width / dofResolution,
.height = colorDesc.height / dofResolution,
.width = (colorDesc.width + (dofResolution / 2u)) / dofResolution,
.height = (colorDesc.height + (dofResolution / 2u)) / dofResolution,
.format = fg.getDescriptor(data.color).format
});
data.outAlpha = builder.createTexture("dof alpha output", {
.width = colorDesc.width / dofResolution,
.height = colorDesc.height / dofResolution,
.width = builder.getDescriptor(data.outColor).width,
.height = builder.getDescriptor(data.outColor).height,
.format = TextureFormat::R8
});
data.outColor = builder.write(data.outColor, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
@@ -1733,6 +1738,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax);
auto const& inputDesc = resources.getDescriptor(data.coc);
auto const& outputDesc = resources.getDescriptor(data.outColor);
auto const& tilesDesc = resources.getDescriptor(data.tilesCocMinMax);
auto const& material = getPostProcessMaterial("dof");
FMaterialInstance* const mi = material.getMaterialInstance(mEngine);
@@ -1745,11 +1752,19 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
{ .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("tiles", tilesCocMinMax,
{ .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("cocToTexelScale", float2{
bokehAspectRatio / (inputDesc.width * dofResolution),
1.0 / (inputDesc.height * dofResolution)
});
mi->setParameter("cocToPixelScale", (1.0f / dofResolution));
mi->setParameter("uvscale", float4{
outputDesc.width / float(inputDesc.width),
outputDesc.height / float(inputDesc.height),
outputDesc.width / float(tileSize / dofResolution * tilesDesc.width),
outputDesc.height / float(tileSize / dofResolution * tilesDesc.height)
});
mi->setParameter("ringCounts", float4{
dofOptions.foregroundRingCount ? dofOptions.foregroundRingCount : DOF_DEFAULT_RING_COUNT,
dofOptions.backgroundRingCount ? dofOptions.backgroundRingCount : DOF_DEFAULT_RING_COUNT,
@@ -1764,6 +1779,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
* DoF median
*/
struct PostProcessDofMedian {
FrameGraphId<FrameGraphTexture> inColor;
FrameGraphId<FrameGraphTexture> inAlpha;
@@ -1794,11 +1810,18 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
auto inAlpha = resources.getTexture(data.inAlpha);
auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax);
auto const& outputDesc = resources.getDescriptor(data.outColor);
auto const& tilesDesc = resources.getDescriptor(data.tilesCocMinMax);
auto const& material = getPostProcessMaterial("dofMedian");
FMaterialInstance* const mi = material.getMaterialInstance(mEngine);
mi->setParameter("dof", inColor, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("alpha", inAlpha, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("uvscale", float2{
outputDesc.width / float(tileSize / dofResolution * tilesDesc.width),
outputDesc.height / float(tileSize / dofResolution * tilesDesc.height)
});
commitAndRender(out, material, driver);
});
@@ -1834,6 +1857,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
},
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto const& dofDesc = resources.getDescriptor(data.dof);
auto const& tilesDesc = resources.getDescriptor(data.tilesCocMinMax);
auto const& out = resources.getRenderPassInfo();
auto color = resources.getTexture(data.color);
@@ -1847,6 +1872,12 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
mi->setParameter("dof", dof, { .filterMag = SamplerMagFilter::NEAREST });
mi->setParameter("alpha", alpha, { .filterMag = SamplerMagFilter::NEAREST });
mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("uvscale", float4{
colorDesc.width / (dofDesc.width * float(dofResolution)),
colorDesc.height / (dofDesc.height * float(dofResolution)),
colorDesc.width / (tilesDesc.width * float(tileSize)),
colorDesc.height / (tilesDesc.height * float(tileSize))
});
commitAndRender(out, material, driver);
});
@@ -2652,43 +2683,66 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::opaqueBlit(FrameGraph& fg,
return ppBlit->output;
}
FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool translucent,
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> input,
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter) noexcept {
FrameGraphId<FrameGraphTexture> PostProcessManager::blendBlit(
FrameGraph& fg, bool translucent, DynamicResolutionOptions dsrOptions,
FrameGraphId<FrameGraphTexture> input, filament::Viewport const& vp,
FrameGraphTexture::Descriptor const& outDesc) noexcept {
if (UTILS_LIKELY(!translucent && dsrOptions.quality == QualityLevel::LOW)) {
return opaqueBlit(fg, input, vp, outDesc, filter);
}
Handle<HwRenderPrimitive> fullScreenRenderPrimitive = mEngine.getFullScreenRenderPrimitive();
// The code below cannot handle sub-resources
assert_invariant(fg.getSubResourceDescriptor(input).layer == 0);
assert_invariant(fg.getSubResourceDescriptor(input).level == 0);
const bool lowQualityFallback = translucent && dsrOptions.quality != QualityLevel::LOW;
if (lowQualityFallback) {
bool lowQualityFallback = false;
if (translucent && dsrOptions.quality != QualityLevel::LOW) {
// FidelityFX-FSR doesn't support the alpha channel currently
dsrOptions.quality = QualityLevel::LOW;
lowQualityFallback = true;
}
const bool twoPassesEASU = mWorkaroundSplitEasu &&
(dsrOptions.quality == QualityLevel::MEDIUM
|| dsrOptions.quality == QualityLevel::HIGH);
// helper to set the EASU uniforms
auto setEasuUniforms = [vp](FMaterialInstance* mi,
FrameGraphTexture::Descriptor const& inputDesc,
FrameGraphTexture::Descriptor const& outputDesc) {
FSRUniforms uniforms{};
FSR_ScalingSetup(&uniforms, {
.input = vp,
.inputWidth = inputDesc.width,
.inputHeight = inputDesc.height,
.outputWidth = outputDesc.width,
.outputHeight = outputDesc.height,
});
mi->setParameter("EasuCon0", uniforms.EasuCon0);
mi->setParameter("EasuCon1", uniforms.EasuCon1);
mi->setParameter("EasuCon2", uniforms.EasuCon2);
mi->setParameter("EasuCon3", uniforms.EasuCon3);
mi->setParameter("textureSize",
float2{ inputDesc.width, inputDesc.height });
};
// helper to enable blending
auto enableTranslucentBlending = [](PipelineState& pipeline) {
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA;
pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
};
struct QuadBlitData {
FrameGraphId<FrameGraphTexture> input;
FrameGraphId<FrameGraphTexture> output;
FrameGraphId<FrameGraphTexture> depth;
};
auto& ppQuadBlit = fg.addPass<QuadBlitData>(dsrOptions.enabled ? "upscaling" : "compositing",
auto& ppQuadBlit = fg.addPass<QuadBlitData>(dsrOptions.enabled ? "quad scaling" : "blendBlit",
[&](FrameGraph::Builder& builder, auto& data) {
data.input = builder.sample(input);
data.output = builder.createTexture("upscaled output", outDesc);
data.output = builder.createTexture("scaled output", outDesc);
if (twoPassesEASU) {
// FIXME: it would be better to use the stencil buffer in this case (less bandwidth)
data.depth = builder.createTexture("upscaled output depth", {
// FIXME: it would be better to use the stencil buffer in this case
data.depth = builder.createTexture("scaled output depth", {
.width = outDesc.width,
.height = outDesc.height,
.format = TextureFormat::DEPTH16
@@ -2701,38 +2755,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
.attachments = { .color = { data.output }, .depth = { data.depth }},
.clearFlags = TargetBufferFlags::DEPTH });
},
[this, twoPassesEASU, dsrOptions, vp, translucent, filter](FrameGraphResources const& resources,
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
// helper to set the EASU uniforms
auto setEasuUniforms = [vp, backend = mEngine.getBackend()](FMaterialInstance* mi,
FrameGraphTexture::Descriptor const& inputDesc,
FrameGraphTexture::Descriptor const& outputDesc) {
FSRUniforms uniforms{};
FSR_ScalingSetup(&uniforms, {
.backend = backend,
.input = vp,
.inputWidth = inputDesc.width,
.inputHeight = inputDesc.height,
.outputWidth = outputDesc.width,
.outputHeight = outputDesc.height,
});
mi->setParameter("EasuCon0", uniforms.EasuCon0);
mi->setParameter("EasuCon1", uniforms.EasuCon1);
mi->setParameter("EasuCon2", uniforms.EasuCon2);
mi->setParameter("EasuCon3", uniforms.EasuCon3);
mi->setParameter("textureSize",
float2{ inputDesc.width, inputDesc.height });
};
// helper to enable blending
auto enableTranslucentBlending = [](PipelineState& pipeline) {
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA;
pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
};
auto color = resources.getTexture(data.input);
auto const& inputDesc = resources.getDescriptor(data.input);
auto const& outputDesc = resources.getDescriptor(data.output);
@@ -2748,7 +2773,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
auto* mi = splitEasuMaterial->getMaterialInstance(mEngine);
setEasuUniforms(mi, inputDesc, outputDesc);
mi->setParameter("color", color, {
.filterMag = SamplerMagFilter::LINEAR
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR
});
mi->setParameter("resolution",
float4{ outputDesc.width, outputDesc.height,
@@ -2767,8 +2793,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
setEasuUniforms(mi, inputDesc, outputDesc);
}
mi->setParameter("color", color, {
.filterMag = (dsrOptions.quality == QualityLevel::LOW) ?
filter : SamplerMagFilter::LINEAR
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR
});
mi->setParameter("resolution",
float4{ outputDesc.width, outputDesc.height,
@@ -2786,8 +2812,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
// --------------------------------------------------------------------------------
// render pass with draw calls
auto fullScreenRenderPrimitive = mEngine.getFullScreenRenderPrimitive();
auto out = resources.getRenderPassInfo();
if (UTILS_UNLIKELY(twoPassesEASU)) {
@@ -2857,14 +2881,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
return output;
}
FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool translucent,
FrameGraphId<FrameGraphTexture> input, filament::Viewport const& vp,
FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter) noexcept {
// for now, we implement this by calling upscale() with the low-quality setting.
return upscale(fg, translucent, { .quality = QualityLevel::LOW }, input, vp, outDesc, filter);
}
FrameGraphId<FrameGraphTexture> PostProcessManager::resolveBaseLevel(FrameGraph& fg,
const char* outputBufferName, FrameGraphId<FrameGraphTexture> input) noexcept {
// Don't do anything if we're not a MSAA buffer
+3 -8
View File
@@ -211,15 +211,10 @@ public:
FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter = backend::SamplerMagFilter::LINEAR) noexcept;
FrameGraphId<FrameGraphTexture> upscale(FrameGraph& fg, bool translucent,
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> input,
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter = backend::SamplerMagFilter::LINEAR) noexcept;
FrameGraphId<FrameGraphTexture> blit(FrameGraph& fg, bool translucent,
FrameGraphId<FrameGraphTexture> blendBlit(
FrameGraph& fg, bool translucent, DynamicResolutionOptions dsrOptions,
FrameGraphId<FrameGraphTexture> input, filament::Viewport const& vp,
FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter = backend::SamplerMagFilter::LINEAR) noexcept;
FrameGraphTexture::Descriptor const& outDesc) noexcept;
// resolve base level of input and outputs a 1-level texture
FrameGraphId<FrameGraphTexture> resolveBaseLevel(FrameGraph& fg,
+14 -16
View File
@@ -51,7 +51,6 @@ RenderPass::RenderPass(RenderPass const& rhs) = default;
RenderPass::~RenderPass() noexcept = default;
RenderPass::Command* RenderPass::append(size_t count) noexcept {
// this is like a "in-place" realloc(). Works only with LinearAllocator.
Command* const curr = mCommandArena.alloc<Command>(count);
assert_invariant(mCommandBegin == nullptr || curr == mCommandEnd);
if (mCommandBegin == nullptr) {
@@ -302,10 +301,9 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
auto const* const UTILS_RESTRICT soaWorldAABBCenter = soa.data<FScene::WORLD_AABB_CENTER>();
auto const* const UTILS_RESTRICT soaVisibility = soa.data<FScene::VISIBILITY_STATE>();
auto const* const UTILS_RESTRICT soaPrimitives = soa.data<FScene::PRIMITIVES>();
auto const* const UTILS_RESTRICT soaSkinning = soa.data<FScene::SKINNING_BUFFER>();
auto const* const UTILS_RESTRICT soaMorphing = soa.data<FScene::MORPHING_BUFFER>();
auto const* const UTILS_RESTRICT soaVisibilityMask = soa.data<FScene::VISIBLE_MASK>();
auto const* const UTILS_RESTRICT soaInstanceCount = soa.data<FScene::INSTANCE_COUNT>();
auto const* const UTILS_RESTRICT soaInstanceCount = soa.data<FScene::INSTANCE_COUNT>();
const bool hasShadowing = renderFlags & HAS_SHADOWING;
const bool viewInverseFrontFaces = renderFlags & HAS_INVERSE_FRONT_FACES;
@@ -398,7 +396,6 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
const bool writeDepthForShadowCasters = depthContainsShadowCasters & shadowCaster;
const Slice<FRenderPrimitive>& primitives = soaPrimitives[i];
const FRenderableManager::SkinningBindingInfo& skinning = soaSkinning[i];
const FRenderableManager::MorphingBindingInfo& morphing = soaMorphing[i];
/*
@@ -415,8 +412,6 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
cmdColor.primitive.primitiveHandle = primitive.getHwHandle();
RenderPass::setupColorCommand(cmdColor, variant, mi, inverseFrontFaces);
cmdColor.primitive.skinningHandle = skinning.handle;
cmdColor.primitive.skinningOffset = skinning.offset;
cmdColor.primitive.morphWeightBuffer = morphing.handle;
cmdColor.primitive.morphTargetBuffer = morphTargets.buffer->getHwHandle();
@@ -511,8 +506,6 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
cmdDepth.primitive.mi = mi;
cmdDepth.primitive.rasterState.culling = mi->getCullingMode();
cmdDepth.primitive.skinningHandle = skinning.handle;
cmdDepth.primitive.skinningOffset = skinning.offset;
cmdDepth.primitive.morphWeightBuffer = morphing.handle;
cmdDepth.primitive.morphTargetBuffer = morphTargets.buffer->getHwHandle();
@@ -559,18 +552,22 @@ void RenderPass::Executor::execute(const char* name,
engine.flush();
driver.beginRenderPass(renderTarget, params);
recordDriverCommands(engine, driver, mBegin, mEnd, params.readOnlyDepthStencil);
recordDriverCommands(engine, driver, mBegin, mEnd, mRenderableSoa, params.readOnlyDepthStencil);
driver.endRenderPass();
}
UTILS_NOINLINE // no need to be inlined
void RenderPass::Executor::recordDriverCommands(FEngine& engine, backend::DriverApi& driver,
const Command* first, const Command* last, uint16_t readOnlyDepthStencil) const noexcept {
void RenderPass::Executor::recordDriverCommands(FEngine& engine,
backend::DriverApi& driver,
const Command* first, const Command* last,
FScene::RenderableSoa const& soa, uint16_t readOnlyDepthStencil) const noexcept {
SYSTRACE_CALL();
if (first != last) {
SYSTRACE_VALUE32("commandCount", last - first);
auto const* const UTILS_RESTRICT soaSkinning = soa.data<FScene::SKINNING_BUFFER>();
PolygonOffset dummyPolyOffset;
PipelineState pipeline{ .polygonOffset = mPolygonOffset };
PolygonOffset* const pPipelinePolygonOffset =
@@ -617,13 +614,14 @@ void RenderPass::Executor::recordDriverCommands(FEngine& engine, backend::Driver
driver.bindUniformBufferRange(BindingPoints::PER_RENDERABLE,
uboHandle, offset, sizeof(PerRenderableUib));
if (UTILS_UNLIKELY(info.skinningHandle)) {
auto skinning = soaSkinning[info.index];
if (UTILS_UNLIKELY(skinning.handle)) {
// note: we can't bind less than CONFIG_MAX_BONE_COUNT due to glsl limitations
driver.bindUniformBufferRange(BindingPoints::PER_RENDERABLE_BONES,
info.skinningHandle,
info.skinningOffset * sizeof(PerRenderableUibBone),
skinning.handle,
skinning.offset * sizeof(PerRenderableUibBone),
CONFIG_MAX_BONE_COUNT * sizeof(PerRenderableUibBone));
// note: even if only skinning is enabled, binding morphTargetBuffer is needed.
// note: even if skinning is only enabled, binding morphTargetBuffer is needed.
driver.bindSamplers(BindingPoints::PER_RENDERABLE_MORPHING,
info.morphTargetBuffer);
}
@@ -645,7 +643,7 @@ void RenderPass::Executor::recordDriverCommands(FEngine& engine, backend::Driver
// ------------------------------------------------------------------------------------------------
RenderPass::Executor::Executor(RenderPass const* pass, Command const* b, Command const* e) noexcept
: mEngine(pass->mEngine), mBegin(b), mEnd(e),
: mEngine(pass->mEngine), mBegin(b), mEnd(e), mRenderableSoa(*pass->mRenderableSoa),
mCustomCommands(pass->mCustomCommands), mUboHandle(pass->mUboHandle),
mPolygonOffset(pass->mPolygonOffset),
mPolygonOffsetOverride(pass->mPolygonOffsetOverride) {
+13 -17
View File
@@ -213,28 +213,22 @@ public:
return boolish ? std::numeric_limits<uint64_t>::max() : uint64_t(0);
}
struct PrimitiveInfo { // 48 bytes
union {
FMaterialInstance const* mi;
uint64_t padding = {}; // ensures mi is 8 bytes on all archs
}; // 8 bytes
backend::RasterState rasterState; // 8 bytes
struct PrimitiveInfo { // 32 bytes
FMaterialInstance const* mi = nullptr; // 8 bytes (4)
backend::Handle<backend::HwRenderPrimitive> primitiveHandle; // 4 bytes
backend::Handle<backend::HwBufferObject> skinningHandle; // 4 bytes
backend::Handle<backend::HwBufferObject> morphWeightBuffer; // 4 bytes
backend::Handle<backend::HwSamplerGroup> morphTargetBuffer; // 4 bytes
uint32_t index = 0; // 4 bytes
uint32_t skinningOffset = 0; // 4 bytes
backend::RasterState rasterState; // 4 bytes
uint16_t index = 0; // 2 bytes
uint16_t instanceCount; // 2 bytes
Variant materialVariant; // 1 byte
uint8_t reserved[5] = {}; // 5 bytes
uint8_t reserved[11 - sizeof(void*)] = {}; // 3 bytes (7)
};
static_assert(sizeof(PrimitiveInfo) == 48);
static_assert(sizeof(PrimitiveInfo) == 32);
struct alignas(8) Command { // 64 bytes
struct alignas(8) Command { // 40 bytes
CommandKey key = 0; // 8 bytes
PrimitiveInfo primitive; // 48 bytes
uint64_t reserved = 0; // 8 bytes
PrimitiveInfo primitive; // 32 bytes
bool operator < (Command const& rhs) const noexcept { return key < rhs.key; }
// placement new declared as "throw" to avoid the compiler's null-check
inline void* operator new (std::size_t, void* ptr) {
@@ -242,7 +236,7 @@ public:
return ptr;
}
};
static_assert(sizeof(Command) == 64);
static_assert(sizeof(Command) == 40);
static_assert(std::is_trivially_destructible_v<Command>,
"Command isn't trivially destructible");
@@ -252,7 +246,7 @@ public:
// Arena used for commands
using Arena = utils::Arena<
utils::LinearAllocator, // note: can't change this allocator
utils::LinearAllocator,
utils::LockingPolicy::NoLock,
utils::TrackingPolicy::HighWatermark,
utils::AreaPolicy::StaticArea>;
@@ -322,6 +316,7 @@ public:
FEngine& mEngine;
Command const* mBegin;
Command const* mEnd;
FScene::RenderableSoa const& mRenderableSoa;
const CustomCommandVector mCustomCommands;
const backend::Handle<backend::HwBufferObject> mUboHandle;
const backend::PolygonOffset mPolygonOffset;
@@ -330,7 +325,8 @@ public:
Executor(RenderPass const* pass, Command const* b, Command const* e) noexcept;
void recordDriverCommands(FEngine& engine, backend::DriverApi& driver,
const Command* first, const Command* last, uint16_t readOnlyDepthStencil) const noexcept;
const Command* first, const Command* last,
FScene::RenderableSoa const& soa, uint16_t readOnlyDepthStencil) const noexcept;
public:
Executor(Executor const& rhs);
-4
View File
@@ -32,10 +32,6 @@ void Renderer::render(View const* view) {
upcast(this)->render(upcast(view));
}
void Renderer::setPresentationTime(int64_t monotonic_clock_ns) {
upcast(this)->setPresentationTime(monotonic_clock_ns);
}
bool Renderer::beginFrame(SwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano) {
return upcast(this)->beginFrame(upcast(swapChain), vsyncSteadyClockTimeNano);
}
+2 -2
View File
@@ -22,6 +22,7 @@
#include "details/Engine.h"
#include "details/Scene.h"
#include "details/View.h"
#include <backend/DriverEnums.h>
@@ -30,11 +31,10 @@
#include <limits>
using namespace filament::math;
using namespace utils;
namespace filament {
using namespace math;
using namespace backend;
// do this only if depth-clamp is available
+2 -36
View File
@@ -30,43 +30,9 @@
namespace filament {
class FView;
class RenderPass;
// The value of the 'VISIBLE_MASK' after culling. Each bit represents visibility in a frustum
// (either camera or light).
//
// 1
// bits 5 ... 7 6 5 4 3 2 1 0
// +------------------------------------------------------+
// VISIBLE_RENDERABLE X
// VISIBLE_DIR_SHADOW_RENDERABLE X
// VISIBLE_SPOT_SHADOW_RENDERABLE_0 X
// VISIBLE_SPOT_SHADOW_RENDERABLE_1 X
// ...
// A "shadow renderable" is a renderable rendered to the shadow map during a shadow pass:
// PCF shadows: only shadow casters
// VSM shadows: both shadow casters and shadow receivers
static constexpr size_t VISIBLE_RENDERABLE_BIT = 0u;
static constexpr size_t VISIBLE_DIR_SHADOW_RENDERABLE_BIT = 1u;
static constexpr size_t VISIBLE_SPOT_SHADOW_RENDERABLE_N_BIT(size_t n) { return n + 2; }
static constexpr Culler::result_type VISIBLE_DIR_SHADOW_RENDERABLE = 1u << VISIBLE_DIR_SHADOW_RENDERABLE_BIT;
static constexpr Culler::result_type VISIBLE_SPOT_SHADOW_RENDERABLE_N(size_t n) {
return 1u << VISIBLE_SPOT_SHADOW_RENDERABLE_N_BIT(n);
}
// ORing of all the VISIBLE_SPOT_SHADOW_RENDERABLE bits
static constexpr Culler::result_type VISIBLE_SPOT_SHADOW_RENDERABLE =
(0xFFu >> (sizeof(Culler::result_type) * 8u - CONFIG_MAX_SHADOW_CASTING_SPOTS)) << 2u;
// Because we're using a uint16_t for the visibility mask, we're limited to 14 spot light shadows.
// (2 of the bits are used for visible renderables + directional light shadow casters).
static_assert(CONFIG_MAX_SHADOW_CASTING_SPOTS <= sizeof(Culler::result_type) * 8 - 2,
"CONFIG_MAX_SHADOW_CASTING_SPOTS cannot be higher than 14.");
class ShadowMap {
public:
explicit ShadowMap(FEngine& engine) noexcept;
@@ -141,7 +107,7 @@ public:
SceneInfo& sceneInfo) noexcept;
void render(FScene const& scene, utils::Range<uint32_t> range,
FScene::VisibleMaskType visibilityMask, RenderPass* pass) noexcept;
FScene::VisibleMaskType visibilityMask, RenderPass* const pass) noexcept;
// Do we have visible shadows. Valid after calling update().
bool hasVisibleShadows() const noexcept { return mHasVisibleShadows; }
+4 -1
View File
@@ -24,6 +24,8 @@
#include <fg/FrameGraph.h>
#include <private/filament/SibGenerator.h>
#include <utils/debug.h>
#include <utils/FixedCapacityVector.h>
@@ -115,7 +117,8 @@ void ShadowMapManager::addSpotShadowMap(size_t lightIndex,
mSpotShadowMaps.emplace_back(shadowMap, lightIndex, options);
}
FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine& engine,
FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg,
FEngine& engine, backend::DriverApi& driver,
RenderPass const& pass, FView& view) noexcept {
constexpr size_t MAX_SHADOW_LAYERS =
+4 -1
View File
@@ -29,6 +29,7 @@
#include <private/backend/DriverApi.h>
#include <private/backend/DriverApiForward.h>
#include <private/backend/SamplerGroup.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
@@ -39,11 +40,13 @@
#include <array>
#include <memory>
#include <vector>
namespace filament {
class FView;
class FrameGraph;
class ShadowMap;
class RenderPass;
struct ShadowMappingUniforms {
@@ -86,7 +89,7 @@ public:
FScene::RenderableSoa& renderableData, FScene::LightSoa& lightData) noexcept;
// Renders all the shadow maps.
FrameGraphId<FrameGraphTexture> render(FrameGraph& fg, FEngine& engine,
FrameGraphId<FrameGraphTexture> render(FrameGraph& fg, FEngine& engine, backend::DriverApi& driver,
RenderPass const& pass, FView& view) noexcept;
ShadowMap* getCascadeShadowMap(size_t cascade) noexcept {
-8
View File
@@ -123,14 +123,6 @@ const View::ScreenSpaceReflectionsOptions& View::getScreenSpaceReflectionsOption
return upcast(this)->getScreenSpaceReflectionsOptions();
}
void View::setGuardBandOptions(GuardBandOptions options) noexcept {
upcast(this)->setGuardBandOptions(options);
}
GuardBandOptions const& View::getGuardBandOptions() const noexcept {
return upcast(this)->getGuardBandOptions();
}
void View::setColorGrading(ColorGrading* colorGrading) noexcept {
return upcast(this)->setColorGrading(upcast(colorGrading));
}
+7
View File
@@ -477,6 +477,13 @@ public:
float dzn = -1.0f;
float dzf = 1.0f;
} shadowmap;
struct {
bool enabled = true;
int sampleCount = 7;
int spiralTurns = 1;
int kernelSize = 23;
float stddev = 8.0f;
} ssao;
struct {
bool camera_at_origin = true;
struct {
+70 -35
View File
@@ -66,6 +66,8 @@ FRenderer::FRenderer(FEngine& engine) :
mPerRenderPassArena(engine.getPerRenderPassAllocator())
{
FDebugRegistry& debugRegistry = engine.getDebugRegistry();
debugRegistry.registerProperty("d.ssao.enabled",
&engine.debug.ssao.enabled);
debugRegistry.registerProperty("d.renderer.doFrameCapture",
&engine.debug.renderer.doFrameCapture);
@@ -175,10 +177,6 @@ void FRenderer::initializeClearFlags() {
| TargetBufferFlags::DEPTH_AND_STENCIL;
}
void FRenderer::setPresentationTime(int64_t monotonic_clock_ns) {
FEngine::DriverApi& driver = mEngine.getDriverApi();
driver.setPresentationTime(monotonic_clock_ns);
}
bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano) {
assert_invariant(swapChain);
@@ -192,6 +190,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
const time_point<steady_clock> appVsync(vsyncSteadyClockTimeNano ? userVsync : now);
mFrameId++;
mViewRenderedCount = 0;
{ // scope for frame id trace
char buf[64];
@@ -231,7 +230,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
* to ignore the return value and render the frame anyways -- which is perfectly fine.
* The remaining work will be done when the first render() call is made.
*/
auto beginFrameInternal = [this, appVsync]() {
auto beginFrameInternal = [this, appVsync, vsyncSteadyClockTimeNano]() {
FEngine& engine = mEngine;
FEngine::DriverApi& driver = engine.getDriverApi();
@@ -244,6 +243,38 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
.historySize = mFrameRateOptions.history
}, mFrameId);
if (false && vsyncSteadyClockTimeNano) { // work in progress
const size_t interval = mFrameRateOptions.interval; // user requested swap-interval;
const steady_clock::duration refreshPeriod(uint64_t(1e9 / mDisplayInfo.refreshRate));
const steady_clock::duration presentationDeadline(mDisplayInfo.presentationDeadlineNanos);
const steady_clock::duration vsyncOffset(mDisplayInfo.vsyncOffsetNanos);
// hardware vsync timestamp
steady_clock::time_point hwVsync = appVsync - vsyncOffset;
// compute our desired presentation time. We can't pick a desired presentation time
// that's too far, or we won't be able to dequeue buffers.
steady_clock::time_point desiredPresentationTime = hwVsync + 2 * interval * refreshPeriod;
// Compute the deadline. This deadline is when the GPU must be finished.
// The deadline has 1ms backed in it on Android.
UTILS_UNUSED_IN_RELEASE
steady_clock::time_point deadline = desiredPresentationTime - presentationDeadline;
// one important thing is to make sure that the deadline is comfortably later than
// when the gpu will finish, otherwise we'll have inconsistent latency/frames.
// TODO: evaluate if we can make it in time, and if not why.
// If the problem is cpu+gpu latency we can try to push the desired presentation time
// further away, but this has limits, as only 2 buffers are dequeuable.
// If the problem is the gpu is overwhelmed, then we need to
// - see if there is more headroom in dynamic resolution
// - or start skipping frames. Ideally lower the framerate to
// presentation time is set to the middle of the period we're interested in
steady_clock::time_point presentationTime = desiredPresentationTime - refreshPeriod / 2;
driver.setPresentationTime(presentationTime.time_since_epoch().count());
}
// ask the engine to do what it needs to (e.g. updates light buffer, materials...)
engine.prepare();
};
@@ -420,9 +451,13 @@ void FRenderer::render(FView const* view) {
}
if (UTILS_LIKELY(view && view->getScene())) {
// NOTE: in the past we tried to kick the GPU here with a flush (b2cdf9f), but this
// was problematic on certain devices. b/232224942
if (mViewRenderedCount) {
// this is a good place to kick the GPU, since we've rendered a View before
// and we're about to render another one.
mEngine.getDriverApi().flush();
}
renderInternal(view);
mViewRenderedCount++;
}
}
@@ -469,7 +504,6 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
auto vignetteOptions = view.getVignetteOptions();
auto colorGrading = view.getColorGrading();
auto ssReflectionsOptions = view.getScreenSpaceReflectionsOptions();
auto guardBandOptions = view.getGuardBandOptions();
const uint8_t msaaSampleCount = msaaOptions.enabled ? msaaOptions.sampleCount : 1u;
if (!hasPostProcess) {
// disable all effects that are part of post-processing
@@ -532,15 +566,12 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
CameraInfo cameraInfo = view.computeCameraInfo(engine);
// when colorgrading-as-subpass is active, we know that many other effects are disabled
// such as dof, bloom. Moreover, if fxaa and scaling are not enabled, we're essentially in
// such as dof, bloom. Moreover if fxaa and scaling are not enabled, we're essentially in
// a very fast rendering path -- in this case, we would need an extra blit to "resolve" the
// buffer padding (because there are no other pass that can do it as a side effect).
// In this case, it is better to skip the padding, which won't be helping much.
const bool noBufferPadding = colorGradingConfig.asSubpass && !hasFXAA && !scaled;
// guardBand must be a multiple of 16 to guarantee the same exact rendering up to 4 mip levels.
float guardBand = guardBandOptions.enabled ? 16.0f : 0.0f;
if (hasPostProcess && !noBufferPadding) {
// We always pad the rendering viewport to dimensions multiple of 16, this guarantees
// that up to 4 mipmap levels are possible with an exact 1:2 scale. This also helps
@@ -555,14 +586,10 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// Without post-processing, we usually draw directly into
// the SwapChain, and we might want to keep it this way.
auto round = [](uint32_t x) {
constexpr uint32_t rounding = 16u;
return (x + (rounding - 1u)) & ~(rounding - 1u);
};
// compute the new rendering width and height, multiple of 16.
const float width = float(round(svp.width )) + 2.0f * guardBand;
const float height = float(round(svp.height)) + 2.0f * guardBand;
constexpr uint32_t rounding = 16u;
const float width = float( (svp.width + (rounding - 1u)) & ~(rounding - 1u) );
const float height = float( (svp.height + (rounding - 1u)) & ~(rounding - 1u) );
// scale the field-of-view up, so it covers exactly the extra pixels
const float3 clipSpaceScaling{
@@ -577,8 +604,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// note: this creates an asymmetric frustum -- but we eventually copy only the
// left/bottom part, which is a symmetric region.
const float2 clipSpaceTranslation{
1.0f - clipSpaceScaling.x - 2.0f * guardBand / width,
1.0f - clipSpaceScaling.y - 2.0f * guardBand / height
1.0f - clipSpaceScaling.x,
1.0f - clipSpaceScaling.y
};
mat4f ts = mat4f::scaling(clipSpaceScaling);
@@ -590,8 +617,6 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// adjust svp to the new, larger, rendering dimensions
svp.width = uint32_t(width);
svp.height = uint32_t(height);
xvp.left = int32_t(guardBand);
xvp.bottom = int32_t(guardBand);
}
view.prepare(engine, driver, arena, svp, cameraInfo, getShaderUserTime(), needsAlphaChannel);
@@ -960,7 +985,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// --------------------------------------------------------------------------------------------
// Post Processing...
UTILS_UNUSED_IN_RELEASE auto const& inputDesc = fg.getDescriptor(input);
auto const& inputDesc = fg.getDescriptor(input);
assert_invariant(inputDesc.width == svp.width);
assert_invariant(inputDesc.height == svp.height);
@@ -992,7 +1017,6 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
bloomOptions, vignetteOptions);
// the padded buffer is resolved now
xvp.left = xvp.bottom = 0;
svp = xvp;
}
}
@@ -1001,16 +1025,19 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
!hasColorGrading || needsAlphaChannel);
// the padded buffer is resolved now
xvp.left = xvp.bottom = 0;
svp = xvp;
}
if (scaled) {
mightNeedFinalBlit = false;
auto viewport = DEBUG_DYNAMIC_SCALING ? xvp : vp;
input = ppm.upscale(fg, blending, dsrOptions, input, xvp, {
.width = viewport.width, .height = viewport.height,
.format = colorGradingConfig.ldrFormat });
xvp.left = xvp.bottom = 0;
svp = xvp;
if (UTILS_LIKELY(!blending && dsrOptions.quality == QualityLevel::LOW)) {
input = ppm.opaqueBlit(fg, input, xvp, {
.width = viewport.width, .height = viewport.height,
.format = colorGradingConfig.ldrFormat }, SamplerMagFilter::LINEAR);
} else {
input = ppm.blendBlit(fg, blending, dsrOptions, input, xvp, {
.width = viewport.width, .height = viewport.height,
.format = colorGradingConfig.ldrFormat });
}
}
}
@@ -1036,14 +1063,22 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
(outputIsSwapChain &&
(msaaSampleCount > 1 ||
colorGradingConfig.asSubpass ||
ssReflectionsOptions.enabled))) {
ssReflectionsOptions.enabled)))
{
assert_invariant(!scaled);
input = ppm.blit(fg, blending, input, xvp, {
.width = vp.width, .height = vp.height,
.format = colorGradingConfig.ldrFormat }, SamplerMagFilter::NEAREST);
if (UTILS_LIKELY(!blending)) {
input = ppm.opaqueBlit(fg, input, xvp, {
.width = vp.width, .height = vp.height,
.format = colorGradingConfig.ldrFormat }, SamplerMagFilter::NEAREST);
} else {
input = ppm.blendBlit(fg, blending, { .quality = QualityLevel::LOW }, input, xvp, {
.width = vp.width, .height = vp.height,
.format = colorGradingConfig.ldrFormat});
}
}
}
// auto debug = structure
// fg.forwardResource(fgViewRenderTarget, debug ? debug : input);
+2 -4
View File
@@ -75,9 +75,6 @@ public:
// renders a single standalone view. The view must have a a custom rendertarget.
void renderStandaloneView(FView const* view);
void setPresentationTime(int64_t monotonic_clock_ns);
// start a frame
bool beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano);
@@ -102,7 +99,7 @@ public:
void setDisplayInfo(DisplayInfo const& info) noexcept {
mDisplayInfo.refreshRate = info.refreshRate;
mDisplayInfo = info;
}
void setFrameRateOptions(FrameRateOptions const& options) noexcept {
@@ -164,6 +161,7 @@ private:
FSwapChain* mSwapChain = nullptr;
size_t mCommandsHighWatermark = 0;
uint32_t mFrameId = 0;
uint32_t mViewRenderedCount = 0;
FrameInfoManager mFrameInfoManager;
backend::TextureFormat mHdrTranslucent;
backend::TextureFormat mHdrQualityMedium;
+11 -11
View File
@@ -32,7 +32,6 @@
#include <algorithm>
using namespace filament::backend;
using namespace filament::math;
using namespace utils;
@@ -197,9 +196,7 @@ void FScene::prepare(const mat4& worldOriginTransform, bool shadowReceiversAreCa
}
}
void FScene::updateUBOs(
Range<uint32_t> visibleRenderables,
Handle<HwBufferObject> renderableUbh) noexcept {
void FScene::updateUBOs(utils::Range<uint32_t> visibleRenderables, backend::Handle<backend::HwBufferObject> renderableUbh) noexcept {
FEngine::DriverApi& driver = mEngine.getDriverApi();
FRenderableManager& rcm = mEngine.getRenderableManager();
@@ -222,7 +219,7 @@ void FScene::updateUBOs(
// Using mat3f::getTransformForNormals handles non-uniform scaling, but DOESN'T guarantee that
// the transformed normals will have unit-length, therefore they need to be normalized
// in the shader (that's already the case anyway, since normalization is needed after
// in the shader (that's already the case anyways, since normalization is needed after
// interpolation).
//
// We pre-scale normals by the inverse of the largest scale factor to avoid
@@ -250,17 +247,20 @@ void FScene::updateUBOs(
hasContactShadows = hasContactShadows || visibility.screenSpaceContactShadows;
UniformBuffer::setUniform(buffer,
offset + offsetof(PerRenderableUib, flagsChannels),
PerRenderableUib::packFlagsChannels(
offset + offsetof(PerRenderableUib, flags),
PerRenderableUib::packFlags(
visibility.skinning,
visibility.morphing,
visibility.screenSpaceContactShadows,
sceneData.elementAt<CHANNELS>(i)));
visibility.screenSpaceContactShadows));
UniformBuffer::setUniform(buffer,
offset + offsetof(PerRenderableUib, morphTargetCount),
sceneData.elementAt<MORPHING_BUFFER>(i).count);
UniformBuffer::setUniform(buffer,
offset + offsetof(PerRenderableUib, channels),
(uint32_t)sceneData.elementAt<CHANNELS>(i));
UniformBuffer::setUniform(buffer,
offset + offsetof(PerRenderableUib, objectId),
rcm.getEntity(ri).getId()); // we could also store the entity in sceneData
@@ -287,7 +287,7 @@ void FScene::terminate(FEngine& engine) {
}
void FScene::prepareDynamicLights(const CameraInfo& camera, ArenaScope& rootArena,
Handle<HwBufferObject> lightUbh) noexcept {
backend::Handle<backend::HwBufferObject> lightUbh) noexcept {
FEngine::DriverApi& driver = mEngine.getDriverApi();
FLightManager& lcm = mEngine.getLightManager();
FScene::LightSoa& lightData = getLightData();
@@ -450,7 +450,7 @@ bool FScene::hasContactShadows() const noexcept {
}
UTILS_NOINLINE
void FScene::forEach(Invocable<void(Entity)>&& functor) const noexcept {
void FScene::forEach(Invocable<void(utils::Entity)>&& functor) const noexcept {
std::for_each(mEntities.begin(), mEntities.end(), std::move(functor));
}
+2 -2
View File
@@ -84,8 +84,8 @@ public:
enum {
RENDERABLE_INSTANCE, // 4 | instance of the Renderable component
WORLD_TRANSFORM, // 16 | instance of the Transform component
VISIBILITY_STATE, // 2 | visibility data of the component
SKINNING_BUFFER, // 8 | bones uniform buffer handle, offset
VISIBILITY_STATE, // 1 | visibility data of the component
SKINNING_BUFFER, // 8 | bones uniform buffer handle, count, offset
MORPHING_BUFFER, // 16 | weights uniform buffer handle, count, morph targets
WORLD_AABB_CENTER, // 12 | world-space bounding box center of the renderable
VISIBLE_MASK, // 2 | each bit represents a visibility in a pass
+2 -5
View File
@@ -17,6 +17,7 @@
#include "details/View.h"
#include "Culler.h"
#include "DFG.h"
#include "Froxelizer.h"
#include "RenderPrimitive.h"
#include "ResourceAllocator.h"
@@ -886,7 +887,7 @@ void FView::updatePrimitivesLod(FEngine& engine, const CameraInfo&,
FrameGraphId<FrameGraphTexture> FView::renderShadowMaps(FrameGraph& fg, FEngine& engine,
FEngine::DriverApi& driver,
RenderPass const& pass) noexcept {
return mShadowMapManager.render(fg, engine, pass, *this);
return mShadowMapManager.render(fg, engine, driver, pass, *this);
}
void FView::commitFrameHistory(FEngine& engine) noexcept {
@@ -953,10 +954,6 @@ void FView::setScreenSpaceReflectionsOptions(ScreenSpaceReflectionsOptions optio
mScreenSpaceReflectionsOptions = options;
}
void FView::setGuardBandOptions(GuardBandOptions options) noexcept {
mGuardBandOptions = options;
}
void FView::setAmbientOcclusionOptions(AmbientOcclusionOptions options) noexcept {
options.radius = math::max(0.0f, options.radius);
options.power = std::max(0.0f, options.power);
+33 -7
View File
@@ -73,7 +73,40 @@ class FMaterialInstance;
class FRenderer;
class FScene;
// The value of the 'VISIBLE_MASK' after culling. Each bit represents visibility in a frustum
// (either camera or light).
//
// 1
// bits 5 ... 7 6 5 4 3 2 1 0
// +------------------------------------------------------+
// VISIBLE_RENDERABLE X
// VISIBLE_DIR_SHADOW_RENDERABLE X
// VISIBLE_SPOT_SHADOW_RENDERABLE_0 X
// VISIBLE_SPOT_SHADOW_RENDERABLE_1 X
// ...
// A "shadow renderable" is a renderable rendered to the shadow map during a shadow pass:
// PCF shadows: only shadow casters
// VSM shadows: both shadow casters and shadow receivers
static constexpr size_t VISIBLE_RENDERABLE_BIT = 0u;
static constexpr size_t VISIBLE_DIR_SHADOW_RENDERABLE_BIT = 1u;
static constexpr size_t VISIBLE_SPOT_SHADOW_RENDERABLE_N_BIT(size_t n) { return n + 2; }
static constexpr Culler::result_type VISIBLE_RENDERABLE = 1u << VISIBLE_RENDERABLE_BIT;
static constexpr Culler::result_type VISIBLE_DIR_SHADOW_RENDERABLE = 1u << VISIBLE_DIR_SHADOW_RENDERABLE_BIT;
static constexpr Culler::result_type VISIBLE_SPOT_SHADOW_RENDERABLE_N(size_t n) {
return 1u << VISIBLE_SPOT_SHADOW_RENDERABLE_N_BIT(n);
}
// ORing of all the VISIBLE_SPOT_SHADOW_RENDERABLE bits
static constexpr Culler::result_type VISIBLE_SPOT_SHADOW_RENDERABLE =
(0xFFu >> (sizeof(Culler::result_type) * 8u - CONFIG_MAX_SHADOW_CASTING_SPOTS)) << 2u;
// Because we're using a uint16_t for the visibility mask, we're limited to 14 spot light shadows.
// (2 of the bits are used for visible renderables + directional light shadow casters).
static_assert(CONFIG_MAX_SHADOW_CASTING_SPOTS <= sizeof(Culler::result_type) * 8 - 2,
"CONFIG_MAX_SHADOW_CASTING_SPOTS cannot be higher than 14.");
// ------------------------------------------------------------------------------------------------
@@ -232,12 +265,6 @@ public:
return mScreenSpaceReflectionsOptions;
}
void setGuardBandOptions(GuardBandOptions options) noexcept;
GuardBandOptions const& getGuardBandOptions() const noexcept {
return mGuardBandOptions;
}
void setColorGrading(FColorGrading* colorGrading) noexcept {
mColorGrading = colorGrading == nullptr ? mDefaultColorGrading : colorGrading;
}
@@ -500,7 +527,6 @@ private:
TemporalAntiAliasingOptions mTemporalAntiAliasingOptions;
MultiSampleAntiAliasingOptions mMultiSampleAntiAliasingOptions;
ScreenSpaceReflectionsOptions mScreenSpaceReflectionsOptions;
GuardBandOptions mGuardBandOptions;
BlendMode mBlendMode = BlendMode::OPAQUE;
const FColorGrading* mColorGrading = nullptr;
const FColorGrading* mDefaultColorGrading = nullptr;
-5
View File
@@ -215,11 +215,6 @@ void FrameGraph::execute(backend::DriverApi& driver) noexcept {
driver.popGroupMarker();
}
// NOTE: in the past we tried to make this flush conditional (b2cdf9f), but this
// was problematic on certain devices. b/232224942
driver.flush();
driver.popGroupMarker();
}
+4 -10
View File
@@ -39,15 +39,6 @@ using namespace math;
#pragma clang diagnostic pop
void FSR_ScalingSetup(FSRUniforms* outUniforms, FSRScalingConfig config) noexcept {
// FsrEasu API claims it needs the left-top offset, however that's not true with OpenGL,
// in which case it uses the left-bottom offset.
auto yoffset = config.input.bottom;
if (config.backend == backend::Backend::METAL ||
config.backend == backend::Backend::VULKAN) {
yoffset = config.inputHeight - (config.input.bottom + config.input.height);
}
FsrEasuConOffset( outUniforms->EasuCon0.v, outUniforms->EasuCon1.v,
outUniforms->EasuCon2.v, outUniforms->EasuCon3.v,
// Viewport size (top left aligned) in the input image which is to be scaled.
@@ -57,7 +48,10 @@ void FSR_ScalingSetup(FSRUniforms* outUniforms, FSRScalingConfig config) noexcep
// The output resolution.
config.outputWidth, config.outputHeight,
// Input image offset
config.input.left, yoffset);
config.input.left, config.input.bottom);
// FIXME: FsrEasu api claims it needs the top,left offset, but when using that we get
// some bad artifacts. To investigate. For reference:
// top = config.inputHeight - (config.input.bottom + config.input.height)
}
void FSR_SharpeningSetup(FSRUniforms* outUniforms, FSRSharpeningConfig config) noexcept {
-1
View File
@@ -26,7 +26,6 @@
namespace filament {
struct FSRScalingConfig {
filament::backend::Backend backend;
filament::Viewport input; // region of source to be scaled
uint32_t inputWidth; // width of source
uint32_t inputHeight; // height of source
@@ -29,7 +29,6 @@ vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = materialParams.viewport.xy + postProcess.normalizedUV * materialParams.viewport.zw;
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.vertex.xy);
}
}
+11 -4
View File
@@ -38,7 +38,7 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV;
}
}
@@ -204,15 +204,22 @@ void postProcess(inout PostProcessInputs postProcess) {
float depth = textureLod(materialParams_depth, uv.xy, 0.0).r;
#if HISTORY_REPROJECTION
uv.zw = uvToRenderTargetUV(uv.zw);
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
// on metal/vulkan postProcess.normalizedUV has its origin at the left-top, but
// our projection matrix screen-space's origin is left-bottom
uv.w = 1.0 - uv.w;
#endif
// reproject history to current frame
highp vec4 q = materialParams.reprojection * vec4(uv.zw, depth, 1.0);
uv.zw = (q.xy * (1.0 / q.w)) * 0.5 + 0.5;
uv.zw = uvToRenderTargetUV(uv.zw);
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
// on metal/vulkan after we applied the reprojection, we need to correct our uv back
uv.w = 1.0 - uv.w;
#endif
#endif
// read center color and history samples
vec4 color = textureLod(materialParams_color, uv.xy, 0.0);
vec4 color = textureLodOffset(materialParams_color, uv.xy, 0.0, ivec2( 0, 0));
#if FILTER_HISTORY
vec4 history = sampleTextureCatmullRom(materialParams_history, uv.zw,
vec2(textureSize(materialParams_history, 0)));
-1
View File
@@ -28,7 +28,6 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = materialParams.viewport.xy + postProcess.normalizedUV * materialParams.viewport.zw;
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.vertex.xy);
}
}
@@ -29,7 +29,7 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV;
}
}
@@ -26,7 +26,7 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV;
}
}
@@ -77,7 +77,6 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = materialParams.viewport.xy + postProcess.normalizedUV * materialParams.viewport.zw;
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.vertex.xy);
}
}
@@ -32,6 +32,12 @@ material {
framebufferFetch: true
}
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = postProcess.normalizedUV;
}
}
fragment {
void dummy(){}
+7 -2
View File
@@ -35,6 +35,11 @@ material {
type : float,
name : bokehAngle,
},
{
type : float4,
name : uvscale,
precision: high
},
{
type : float4,
name : ringCounts,
@@ -63,7 +68,7 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex = postProcess.normalizedUV.xyxy * materialParams.uvscale;
}
}
@@ -573,7 +578,7 @@ void backgroundTile(inout vec4 background, inout float bgOpacity,
}
void postProcess(inout PostProcessInputs postProcess) {
vec2 tiles = textureLod(materialParams_tiles, variable_vertex.xy, 0.0).rg;
vec2 tiles = textureLod(materialParams_tiles, variable_vertex.zw, 0.0).rg;
/*
* Tiles that are neither foreground or background (in focus) can be skipped
+3 -3
View File
@@ -20,8 +20,8 @@ material {
name : cocClamp
},
{
type : float2,
name : texelSize,
type : float4,
name : uvscale,
precision: high
}
],
@@ -50,7 +50,7 @@ vertex {
void dummy(){}
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = (postProcess.normalizedUV * materialParams.uvscale.xy) * materialParams.uvscale.zw;
}
}
+18 -8
View File
@@ -20,6 +20,11 @@ material {
type : sampler2d,
name : alpha,
precision: medium
},
{
type : float4,
name : uvscale,
precision: high
}
],
variables : [
@@ -32,7 +37,8 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV;
postProcess.vertex.zw = postProcess.normalizedUV * materialParams.uvscale.zw;
}
}
@@ -43,19 +49,23 @@ fragment {
void dummy(){}
void postProcess(inout PostProcessInputs postProcess) {
highp vec2 uv = variable_vertex.xy;
vec2 tiles = textureLod(materialParams_tiles, uv, 0.0).rg;
highp vec2 uv2 = variable_vertex.zw;
vec2 tiles = textureLod(materialParams_tiles, uv2, 0.0).rg;
vec4 color;
if (isTrivialTile(tiles)) {
color = textureLod(materialParams_color, uv, 0.0);
highp vec2 uv0 = variable_vertex.xy;
color = textureLod(materialParams_color, uv0, 0.0);
} else if (isFastTile(tiles) && (abs(tiles.r) >= MAX_IN_FOCUS_COC + 1.0)) {
// we can only handle fast tiles that don't have an alpha channel here
color = textureLod(materialParams_dof, uv, 0.0);
highp vec2 uv1 = variable_vertex.xy * materialParams.uvscale.xy;
color = textureLod(materialParams_dof, uv1, 0.0);
} else {
float alpha = textureLod(materialParams_alpha, uv, 0.0).r;
vec4 dof = textureLod(materialParams_dof, uv, 0.0);
color = textureLod(materialParams_color, uv, 0.0);
highp vec2 uv0 = variable_vertex.xy;
highp vec2 uv1 = variable_vertex.xy * materialParams.uvscale.xy;
float alpha = textureLod(materialParams_alpha, uv1, 0.0).r;
vec4 dof = textureLod(materialParams_dof, uv1, 0.0);
color = textureLod(materialParams_color, uv0, 0.0);
color = dof + (1.0 - alpha) * color;
}
+1 -1
View File
@@ -17,7 +17,7 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV;
}
}
+3 -17
View File
@@ -20,8 +20,8 @@ material {
name : cocClamp
},
{
type : float2,
name : texelSize,
type : float4,
name : uvscale,
precision: high
}
],
@@ -50,21 +50,7 @@ vertex {
void dummy(){}
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
// It works to fix-up the UV *before* applying the offsets because materialParams.texelSize
// corresponds to one texel.
// on GL: v0 = v - 0.5 * texel (1)
// v1 = v - 0.5 * texel + 1 * texel
// = v + 0.5 * texel (2)
// on MTL/VK: v0 = 1 - ((1 - v) - 0.5 * texel)
// = v + 0.5 * texel (3)
// v1 = 1 - ((1 - v) - 0.5 * texel + 1 * texel)
// = v - 0.5 * texel (4)
// Because the all the operations on the 4 texels in the fragment shader don't depend on
// the order they're fetched, it all works out.
postProcess.normalizedUV = uvToRenderTargetUV(postProcess.normalizedUV);
// offset UVs by -0.5 texel because we use textureLodOffset() in the fragment shader
postProcess.vertex.xy = postProcess.normalizedUV - 0.5 * materialParams.texelSize;
postProcess.vertex.xy = (postProcess.normalizedUV * materialParams.uvscale.xy * 2.0 - 0.5) * materialParams.uvscale.zw;
}
}
+8 -2
View File
@@ -15,6 +15,11 @@ material {
type : sampler2d,
name : tiles,
precision: medium
},
{
type : float2,
name : uvscale,
precision: high
}
],
variables : [
@@ -27,7 +32,8 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV;
postProcess.vertex.zw = postProcess.vertex.xy * materialParams.uvscale;
}
}
@@ -115,7 +121,7 @@ vec4 median(ivec2 ij) {
}
void postProcess(inout PostProcessInputs postProcess) {
vec2 tiles = textureLod(materialParams_tiles, variable_vertex.xy, 0.0).rg;
vec2 tiles = textureLod(materialParams_tiles, variable_vertex.zw, 0.0).rg;
vec4 dof = vec4(0.0);
if (!isTrivialTile(tiles)) {
+2 -4
View File
@@ -21,7 +21,7 @@ material {
},
{
type : float2,
name : texelSize
name : pixelSize
}
],
variables : [
@@ -46,9 +46,7 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
// see explanation in dofDownSample.mat
postProcess.normalizedUV = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV - 0.5 * materialParams.texelSize;
postProcess.vertex.xy = postProcess.normalizedUV - materialParams.pixelSize * 0.5;
}
}
+3 -5
View File
@@ -7,8 +7,8 @@ material {
precision: medium
},
{
type : float2,
name : texelSize,
type : float4,
name : uvscale,
precision: high
}
],
@@ -22,9 +22,7 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
// see explanation in dofDownSample.mat
postProcess.normalizedUV = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV - 0.5 * materialParams.texelSize;
postProcess.vertex.xy = (postProcess.normalizedUV * materialParams.uvscale.xy * 2.0 - 0.5) * materialParams.uvscale.zw;
}
}
@@ -7,8 +7,8 @@ material {
precision: medium
},
{
type : float2,
name : texelSize,
type : float4,
name : uvscale,
precision: high
}
],
@@ -22,9 +22,7 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
// see explanation in dofDownSample.mat
postProcess.normalizedUV = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV - 0.5 * materialParams.texelSize;
postProcess.vertex.xy = (postProcess.normalizedUV * materialParams.uvscale.xy * 2.0 - 0.5) * materialParams.uvscale.zw;
}
}
+7 -1
View File
@@ -68,7 +68,13 @@ vertex {
void dummy(){ }
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV;
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
// On metal/vulkan postProcess.normalizedUV has its origin at the left-top, but we need a
// uniform coordinate space. So, we flip the y coordinate so we have bottom-left UV
// coordinates across all backends.
postProcess.vertex.y = 1.0 - postProcess.vertex.y;
#endif
}
}
-1
View File
@@ -52,7 +52,6 @@ material {
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.normalizedUV = uvToRenderTargetUV(postProcess.normalizedUV);
postProcess.vertex.xy = postProcess.normalizedUV * materialParams.resolution.xy;
}
}

Some files were not shown because too many files have changed in this diff Show More