Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
791f51dcb4 | ||
|
|
4621f3ec5d | ||
|
|
ab9c09d0d9 | ||
|
|
dbf51c1c7d |
@@ -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
@@ -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
@@ -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
@@ -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,3 +1,4 @@
|
||||
|
||||
plugins {
|
||||
id 'groovy-gradle-plugin'
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
android {
|
||||
namespace 'com.google.android.filament.filamat'
|
||||
|
||||
flavorDimensions "functionality"
|
||||
productFlavors {
|
||||
full {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
+8
-11
@@ -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
+2
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
+3
-15
@@ -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,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
@@ -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"
|
||||
|
||||
@@ -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 @@
|
||||
24.0.8215888
|
||||
23.1.7779620
|
||||
+13
-39
@@ -118,7 +118,6 @@ counter-increment: h6;margin-right:10px}
|
||||
<a href="#materialdefinitions/materialblock/shading:customsurfaceshading" class="level3"><span class="tocNumber">4.2.31 </span>Shading: customSurfaceShading</a><br>
|
||||
<a href="#materialdefinitions/vertexblock" class="level2"><span class="tocNumber">4.3 </span>Vertex block</a><br>
|
||||
<a href="#materialdefinitions/vertexblock/materialvertexinputs" class="level3"><span class="tocNumber">4.3.1 </span>Material vertex inputs</a><br>
|
||||
<a href="#materialdefinitions/vertexblock/customvertexattributes" class="level3"><span class="tocNumber">4.3.2 </span>Custom vertex attributes</a><br>
|
||||
<a href="#materialdefinitions/fragmentblock" class="level2"><span class="tocNumber">4.4 </span>Fragment block</a><br>
|
||||
<a href="#materialdefinitions/fragmentblock/preparematerialfunction" class="level3"><span class="tocNumber">4.4.1 </span>prepareMaterial function</a><br>
|
||||
<a href="#materialdefinitions/fragmentblock/materialfragmentinputs" class="level3"><span class="tocNumber">4.4.2 </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"> </a><a class="target" name="materialdefinitions/materialblock/vertexandattributes:variables"> </a><a class="target" name="toc4.2.8"> </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"> </a><a class="target" name="materialdefinitions/vertexblock/customvertexattributes"> </a><a class="target" name="toc4.3.2"> </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"> </a><a class="target" name="materialdefinitions/fragmentblock"> </a><a class="target" name="toc4.4"> </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
@@ -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()`.
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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], ¶ms);
|
||||
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, ¶ms);
|
||||
|
||||
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
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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(){}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ material {
|
||||
|
||||
vertex {
|
||||
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
|
||||
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.normalizedUV);
|
||||
postProcess.vertex.xy = postProcess.normalizedUV;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user