Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab552d3619 |
@@ -41,8 +41,6 @@ option(FILAMENT_LINUX_IS_MOBILE "Treat Linux as Mobile" OFF)
|
||||
|
||||
option(FILAMENT_ENABLE_ASAN_UBSAN "Enable Address and Undefined Behavior Sanitizers" OFF)
|
||||
|
||||
option(FILAMENT_ENABLE_FEATURE_LEVEL_0 "Enable Feature Level 0" ON)
|
||||
|
||||
set(FILAMENT_NDK_VERSION "" CACHE STRING
|
||||
"Android NDK version or version prefix to be used when building for Android."
|
||||
)
|
||||
@@ -67,9 +65,6 @@ set(FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB "8" CACHE STRING
|
||||
"Size of the Metal handle arena, default 8."
|
||||
)
|
||||
|
||||
# Enable exceptions by default in spirv-cross.
|
||||
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS OFF)
|
||||
|
||||
# ==================================================================================================
|
||||
# CMake policies
|
||||
# ==================================================================================================
|
||||
@@ -342,7 +337,6 @@ endif()
|
||||
|
||||
if (CYGWIN)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
|
||||
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
@@ -379,7 +373,6 @@ endif()
|
||||
# saved by -fno-exception and 10 KiB saved by -fno-rtti).
|
||||
if (ANDROID OR IOS OR WEBGL)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-rtti")
|
||||
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
|
||||
|
||||
if (ANDROID OR WEBGL)
|
||||
# Omitting unwind info prevents the generation of readable stack traces in crash reports on iOS
|
||||
@@ -391,7 +384,6 @@ endif()
|
||||
# std::visit, which is not supported on iOS 11.0 when exceptions are enabled.
|
||||
if (IOS)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-exceptions")
|
||||
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
|
||||
endif()
|
||||
|
||||
# With WebGL, we disable RTTI even for debug builds because we pass emscripten::val back and forth
|
||||
@@ -531,11 +523,6 @@ if (FILAMENT_SUPPORTS_METAL)
|
||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a metal)
|
||||
endif()
|
||||
|
||||
# Disable ESSL 1.0 code generation.
|
||||
if (NOT FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -1)
|
||||
endif()
|
||||
|
||||
# Enable debug info (preserves names in SPIR-V)
|
||||
if (FILAMENT_ENABLE_MATDBG)
|
||||
set(MATC_OPT_FLAGS ${MATC_OPT_FLAGS} -d)
|
||||
|
||||
@@ -8,5 +8,11 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
|
||||
- matc: New option `-1` to disable generation of ESSL 1.0 code in Feature Level 0 materials
|
||||
- matc: Support optimizations for ESSL 1.0 code [⚠️ **Recompile materials**]
|
||||
- engine: Allow instantiating Engine at a given feature level via `Engine::Builder::featureLevel`
|
||||
- matc: Enable `GL_OES_standard_derivatives` extension in ESSL 1.0 shaders
|
||||
- matc: Fix code generation of double sided and masked materials in ESSL 1.0 shaders
|
||||
- filagui: Add support for feature level 0
|
||||
- matc: Add support for post-process materials in feature level 0
|
||||
- engine: Add `Material::getFeatureLevel()`
|
||||
- engine: Add missing `Material::getReflectionMode()` method in Java
|
||||
- engine: Support basic usage of post-processing materials on feature level 0
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.47.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.45.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.47.0'
|
||||
pod 'Filament', '~> 1.45.0'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
@@ -7,24 +7,6 @@ A new header is inserted each time a *tag* is created.
|
||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.47.0
|
||||
- engine: Support up to 4 side-by-side stereoscopic eyes, configurable at Engine creation time. See
|
||||
`Engine::Config::stereoscopicEyeCount`. [⚠️ **Recompile Materials**]
|
||||
|
||||
## v1.46.0
|
||||
|
||||
- engine: Allow instantiating Engine at a given feature level via `Engine::Builder::featureLevel`
|
||||
- matc: Enable `GL_OES_standard_derivatives` extension in ESSL 1.0 shaders
|
||||
- matc: Fix code generation of double sided and masked materials in ESSL 1.0 shaders
|
||||
- filagui: Add support for feature level 0
|
||||
- matc: Add support for post-process materials in feature level 0
|
||||
- engine: Add `Material::getFeatureLevel()`
|
||||
- engine: Add missing `Material::getReflectionMode()` method in Java
|
||||
- engine: Support basic usage of post-processing materials on feature level 0
|
||||
- engine: Fix critical GLES 2.0 bugs
|
||||
- engine: Add `FILAMENT_ENABLE_FEATURE_LEVEL_0` build-time option optionally allow building Filament
|
||||
without FL0 support.
|
||||
|
||||
## v1.45.1
|
||||
|
||||
- engine: Added parameter for configuring JobSystem thread count
|
||||
|
||||
@@ -384,13 +384,6 @@ Java_com_google_android_filament_Engine_nFlushAndWait(JNIEnv*, jclass,
|
||||
engine->flushAndWait();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Engine_nFlush(JNIEnv*, jclass,
|
||||
jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
engine->flush();
|
||||
}
|
||||
|
||||
// Managers...
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <filament/Material.h>
|
||||
|
||||
#include "common/NioUtils.h"
|
||||
#include "common/CallbackUtils.h"
|
||||
|
||||
using namespace filament;
|
||||
|
||||
@@ -272,17 +271,3 @@ Java_com_google_android_filament_Material_nHasParameter(JNIEnv* env, jclass,
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
return (jboolean) hasParameter;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Material_nCompile(JNIEnv *env, jclass clazz,
|
||||
jlong nativeMaterial, jint priority, jint variants, jobject handler, jobject runnable) {
|
||||
Material* material = (Material*) nativeMaterial;
|
||||
JniCallback* jniCallback = JniCallback::make(env, handler, runnable);
|
||||
material->compile(
|
||||
(Material::CompilerPriorityQueue) priority,
|
||||
(UserVariantFilterBit) variants,
|
||||
jniCallback->getHandler(), [jniCallback](Material*){
|
||||
JniCallback::postToJavaAndDestroy(jniCallback);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -98,22 +98,3 @@ Java_com_google_android_filament_Scene_nHasEntity(JNIEnv *env, jclass type, jlon
|
||||
Entity entity = Entity::import(entityId);
|
||||
return (jboolean) scene->hasEntity(entity);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Scene_nGetEntities(JNIEnv *env, jclass ,
|
||||
jlong nativeScene, jintArray outArray, jint length) {
|
||||
Scene const* const scene = (Scene*) nativeScene;
|
||||
if (length < scene->getEntityCount()) {
|
||||
// should not happen because we already checked on the java side
|
||||
return JNI_FALSE;
|
||||
}
|
||||
jint *out = (jint *) env->GetIntArrayElements(outArray, nullptr);
|
||||
scene->forEach([out, length, i = 0](Entity entity)mutable {
|
||||
if (i < length) { // this is just paranoia here
|
||||
out[i++] = (jint) entity.getId();
|
||||
}
|
||||
});
|
||||
env->ReleaseIntArrayElements(outArray, (jint*) out, JNI_ABORT);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
@@ -150,10 +150,8 @@ public class Engine {
|
||||
FEATURE_LEVEL_0,
|
||||
/** OpenGL ES 3.0 features (default) */
|
||||
FEATURE_LEVEL_1,
|
||||
/** OpenGL ES 3.1 features + 16 textures units + cubemap arrays */
|
||||
FEATURE_LEVEL_2,
|
||||
/** OpenGL ES 3.1 features + 31 textures units + cubemap arrays */
|
||||
FEATURE_LEVEL_3,
|
||||
FEATURE_LEVEL_2
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1079,18 +1077,6 @@ public class Engine {
|
||||
nFlushAndWait(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) but does not wait
|
||||
* for commands to be either executed or the hardware finished.
|
||||
*
|
||||
* <p>This is typically used after creating a lot of objects to start draining the command
|
||||
* queue which has a limited size.</p>
|
||||
*/
|
||||
public void flush() {
|
||||
nFlush(getNativeObject());
|
||||
}
|
||||
|
||||
|
||||
@UsedByReflection("TextureHelper.java")
|
||||
public long getNativeObject() {
|
||||
if (mNativeObject == 0) {
|
||||
@@ -1163,7 +1149,6 @@ public class Engine {
|
||||
private static native boolean nIsValidSwapChain(long nativeEngine, long nativeSwapChain);
|
||||
private static native void nDestroyEntity(long nativeEngine, int entity);
|
||||
private static native void nFlushAndWait(long nativeEngine);
|
||||
private static native void nFlush(long nativeEngine);
|
||||
private static native long nGetTransformManager(long nativeEngine);
|
||||
private static native long nGetLightManager(long nativeEngine);
|
||||
private static native long nGetRenderableManager(long nativeEngine);
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.google.android.filament;
|
||||
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Size;
|
||||
|
||||
import com.google.android.filament.proguard.UsedByNative;
|
||||
@@ -239,31 +238,6 @@ public class Material {
|
||||
FRONT_AND_BACK
|
||||
}
|
||||
|
||||
public enum CompilerPriorityQueue {
|
||||
HIGH,
|
||||
LOW
|
||||
}
|
||||
|
||||
public static class UserVariantFilterBit {
|
||||
/** Directional lighting */
|
||||
public static int DIRECTIONAL_LIGHTING = 0x01;
|
||||
/** Dynamic lighting */
|
||||
public static int DYNAMIC_LIGHTING = 0x02;
|
||||
/** Shadow receiver */
|
||||
public static int SHADOW_RECEIVER = 0x04;
|
||||
/** Skinning */
|
||||
public static int SKINNING = 0x08;
|
||||
/** Fog */
|
||||
public static int FOG = 0x10;
|
||||
/** Variance shadow maps */
|
||||
public static int VSM = 0x20;
|
||||
/** Screen-space reflections */
|
||||
public static int SSR = 0x40;
|
||||
/** Instanced stereo rendering */
|
||||
public static int STE = 0x80;
|
||||
public static int ALL = 0xFF;
|
||||
}
|
||||
|
||||
@UsedByNative("Material.cpp")
|
||||
public static class Parameter {
|
||||
private static final Type[] sTypeValues = Type.values();
|
||||
@@ -378,55 +352,6 @@ public class Material {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Asynchronously ensures that a subset of this Material's variants are compiled. After issuing
|
||||
* several compile() calls in a row, it is recommended to call {@link Engine#flush}
|
||||
* such that the backend can start the compilation work as soon as possible.
|
||||
* The provided callback is guaranteed to be called on the main thread after all specified
|
||||
* variants of the material are compiled. This can take hundreds of milliseconds.
|
||||
*<p>
|
||||
* If all the material's variants are already compiled, the callback will be scheduled as
|
||||
* soon as possible, but this might take a few dozen millisecond, corresponding to how
|
||||
* many previous frames are enqueued in the backend. This also varies by backend. Therefore,
|
||||
* it is recommended to only call this method once per material shortly after creation.
|
||||
*</p>
|
||||
*<p>
|
||||
* If the same variant is scheduled for compilation multiple times, the first scheduling
|
||||
* takes precedence; later scheduling are ignored.
|
||||
*</p>
|
||||
*<p>
|
||||
* caveat: A consequence is that if a variant is scheduled on the low priority queue and later
|
||||
* scheduled again on the high priority queue, the later scheduling is ignored.
|
||||
* Therefore, the second callback could be called before the variant is compiled.
|
||||
* However, the first callback, if specified, will trigger as expected.
|
||||
*</p>
|
||||
*<p>
|
||||
* The callback is guaranteed to be called. If the engine is destroyed while some material
|
||||
* variants are still compiling or in the queue, these will be discarded and the corresponding
|
||||
* callback will be called. In that case however the Material pointer passed to the callback
|
||||
* is guaranteed to be invalid (either because it's been destroyed by the user already, or,
|
||||
* because it's been cleaned-up by the Engine).
|
||||
*</p>
|
||||
*<p>
|
||||
* {@link UserVariantFilterBit#ALL} should be used with caution. Only variants that an application
|
||||
* needs should be included in the variants argument. For example, the STE variant is only used
|
||||
* for stereoscopic rendering. If an application is not planning to render in stereo, this bit
|
||||
* should be turned off to avoid unnecessary material compilations.
|
||||
*</p>
|
||||
* @param priority Which priority queue to use, LOW or HIGH.
|
||||
* @param variants Variants to include to the compile command.
|
||||
* @param handler An {@link java.util.concurrent.Executor Executor}. On Android this can also be a {@link android.os.Handler Handler}.
|
||||
* @param callback callback called on the main thread when the compilation is done on
|
||||
* by backend.
|
||||
*/
|
||||
public void compile(@NonNull CompilerPriorityQueue priority,
|
||||
int variants,
|
||||
@Nullable Object handler,
|
||||
@Nullable Runnable callback) {
|
||||
nCompile(getNativeObject(), priority.ordinal(), variants, handler, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this material. Material instances should be freed using
|
||||
* {@link Engine#destroyMaterialInstance(MaterialInstance)}.
|
||||
@@ -1028,7 +953,6 @@ public class Material {
|
||||
private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name);
|
||||
private static native long nGetDefaultInstance(long nativeMaterial);
|
||||
|
||||
private static native void nCompile(long nativeMaterial, int priority, int variants, Object handler, Runnable runnable);
|
||||
private static native String nGetName(long nativeMaterial);
|
||||
private static native int nGetShading(long nativeMaterial);
|
||||
private static native int nGetInterpolation(long nativeMaterial);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.google.android.filament;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
@@ -191,52 +190,6 @@ public class Scene {
|
||||
return mNativeObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of all entities in the Scene. If outArray is provided and large enough,
|
||||
* it is used to store the list and returned, otherwise a new array is allocated and returned.
|
||||
* @param outArray an array to store the list of entities in the scene.
|
||||
* @return outArray if it was used or a newly allocated array.
|
||||
* @see #getEntityCount
|
||||
*/
|
||||
public int[] getEntities(@Nullable int[] outArray) {
|
||||
int c = getEntityCount();
|
||||
if (outArray == null || outArray.length < c) {
|
||||
outArray = new int[c];
|
||||
}
|
||||
boolean success = nGetEntities(getNativeObject(), outArray, outArray.length);
|
||||
if (!success) {
|
||||
throw new IllegalStateException("Error retriving Scene's entities");
|
||||
}
|
||||
return outArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of all entities in the Scene in a newly allocated array.
|
||||
* @return an array containing the list of all entities in the scene.
|
||||
* @see #getEntityCount
|
||||
*/
|
||||
public int[] getEntities() {
|
||||
return getEntities(null);
|
||||
}
|
||||
|
||||
public interface EntityProcessor {
|
||||
void process(@Entity int entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes user functor on each entity in the scene.
|
||||
*
|
||||
* It is not allowed to add or remove an entity from the scene within the functor.
|
||||
*
|
||||
* @param entityProcessor User provided functor called for each entity in the scene
|
||||
*/
|
||||
public void forEach(@NonNull EntityProcessor entityProcessor) {
|
||||
int[] entities = getEntities(null);
|
||||
for (int entity : entities) {
|
||||
entityProcessor.process(entity);
|
||||
}
|
||||
}
|
||||
|
||||
void clearNativeObject() {
|
||||
mNativeObject = 0;
|
||||
}
|
||||
@@ -251,5 +204,4 @@ public class Scene {
|
||||
private static native int nGetRenderableCount(long nativeScene);
|
||||
private static native int nGetLightCount(long nativeScene);
|
||||
private static native boolean nHasEntity(long nativeScene, int entity);
|
||||
private static native boolean nGetEntities(long nativeScene, int[] outArray, int length);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.47.0
|
||||
VERSION_NAME=1.45.0
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
-31
@@ -26,7 +26,6 @@ import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import com.google.android.filament.Fence
|
||||
import com.google.android.filament.IndirectLight
|
||||
import com.google.android.filament.Material
|
||||
import com.google.android.filament.Skybox
|
||||
import com.google.android.filament.View
|
||||
import com.google.android.filament.View.OnPickCallback
|
||||
@@ -393,36 +392,6 @@ class MainActivity : Activity() {
|
||||
Log.i(TAG, "The Filament backend took $total ms to load the model geometry.")
|
||||
modelViewer.engine.destroyFence(it)
|
||||
loadStartFence = null
|
||||
|
||||
val materials = mutableSetOf<Material>()
|
||||
val rcm = modelViewer.engine.renderableManager
|
||||
modelViewer.scene.forEach {
|
||||
val entity = it
|
||||
if (rcm.hasComponent(entity)) {
|
||||
val ri = rcm.getInstance(entity)
|
||||
val c = rcm.getPrimitiveCount(ri)
|
||||
for (i in 0 until c) {
|
||||
val mi = rcm.getMaterialInstanceAt(ri, i)
|
||||
val ma = mi.material
|
||||
materials.add(ma)
|
||||
}
|
||||
}
|
||||
}
|
||||
materials.forEach {
|
||||
it.compile(
|
||||
Material.CompilerPriorityQueue.HIGH,
|
||||
Material.UserVariantFilterBit.DIRECTIONAL_LIGHTING or
|
||||
Material.UserVariantFilterBit.DYNAMIC_LIGHTING or
|
||||
Material.UserVariantFilterBit.SHADOW_RECEIVER,
|
||||
null, null)
|
||||
it.compile(
|
||||
Material.CompilerPriorityQueue.LOW,
|
||||
Material.UserVariantFilterBit.FOG or
|
||||
Material.UserVariantFilterBit.SKINNING or
|
||||
Material.UserVariantFilterBit.SSR or
|
||||
Material.UserVariantFilterBit.VSM,
|
||||
null, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-10
@@ -20,8 +20,6 @@ import android.animation.ValueAnimator
|
||||
import android.app.Activity
|
||||
import android.opengl.Matrix
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.Choreographer
|
||||
import android.view.Surface
|
||||
import android.view.SurfaceView
|
||||
@@ -159,14 +157,6 @@ class MainActivity : Activity() {
|
||||
private fun loadMaterial() {
|
||||
readUncompressedAsset("materials/baked_color.filamat").let {
|
||||
material = Material.Builder().payload(it, it.remaining()).build(engine)
|
||||
material.compile(
|
||||
Material.CompilerPriorityQueue.HIGH,
|
||||
Material.UserVariantFilterBit.ALL,
|
||||
Handler(Looper.getMainLooper())) {
|
||||
android.util.Log.i("hellotriangle",
|
||||
"Material " + material.name + " compiled.")
|
||||
}
|
||||
engine.flush()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3
-28
@@ -218,6 +218,7 @@ set(MATERIAL_SRCS
|
||||
src/materials/colorGrading/customResolveAsSubpass.mat
|
||||
src/materials/debugShadowCascades.mat
|
||||
src/materials/defaultMaterial.mat
|
||||
src/materials/defaultMaterial0.mat
|
||||
src/materials/dof/dof.mat
|
||||
src/materials/dof/dofCoc.mat
|
||||
src/materials/dof/dofDownsample.mat
|
||||
@@ -228,6 +229,7 @@ set(MATERIAL_SRCS
|
||||
src/materials/dof/dofMipmap.mat
|
||||
src/materials/dof/dofMedian.mat
|
||||
src/materials/flare/flare.mat
|
||||
src/materials/blitLow.mat
|
||||
src/materials/bloom/bloomDownsample.mat
|
||||
src/materials/bloom/bloomDownsample2x.mat
|
||||
src/materials/bloom/bloomDownsample9.mat
|
||||
@@ -236,18 +238,13 @@ set(MATERIAL_SRCS
|
||||
src/materials/ssao/bilateralBlurBentNormals.mat
|
||||
src/materials/ssao/mipmapDepth.mat
|
||||
src/materials/skybox.mat
|
||||
src/materials/skybox0.mat
|
||||
src/materials/ssao/sao.mat
|
||||
src/materials/ssao/saoBentNormals.mat
|
||||
src/materials/separableGaussianBlur.mat
|
||||
src/materials/antiAliasing/fxaa.mat
|
||||
src/materials/antiAliasing/taa.mat
|
||||
src/materials/vsmMipmap.mat
|
||||
src/materials/blitLow.mat
|
||||
)
|
||||
|
||||
set(MATERIAL_FL0_SRCS
|
||||
src/materials/defaultMaterial0.mat
|
||||
src/materials/skybox0.mat
|
||||
)
|
||||
|
||||
# Embed the binary resource blob for materials.
|
||||
@@ -274,11 +271,6 @@ if (NOT DFG_LUT_SIZE)
|
||||
endif()
|
||||
message(STATUS "DFG LUT size set to ${DFG_LUT_SIZE}x${DFG_LUT_SIZE}")
|
||||
|
||||
# Whether to include FL0 materials.
|
||||
if (FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||
add_definitions(-DFILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Definitions
|
||||
# ==================================================================================================
|
||||
@@ -320,23 +312,6 @@ foreach (mat_src ${MATERIAL_SRCS})
|
||||
list(APPEND MATERIAL_BINS ${output_path})
|
||||
endforeach()
|
||||
|
||||
if (FILAMENT_ENABLE_FEATURE_LEVEL_0 AND FILAMENT_SUPPORTS_OPENGL)
|
||||
foreach (mat_src ${MATERIAL_FL0_SRCS})
|
||||
get_filename_component(localname "${mat_src}" NAME_WE)
|
||||
get_filename_component(fullname "${mat_src}" ABSOLUTE)
|
||||
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output_path}
|
||||
COMMAND matc -a opengl -p ${MATC_TARGET} ${MATC_OPT_FLAGS} -o ${output_path} ${fullname}
|
||||
MAIN_DEPENDENCY ${fullname}
|
||||
DEPENDS matc
|
||||
COMMENT "Compiling material ${mat_src} to ${output_path}"
|
||||
)
|
||||
list(APPEND MATERIAL_BINS ${output_path})
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
# Additional dependencies on included files for materials
|
||||
|
||||
add_custom_command(
|
||||
|
||||
@@ -113,7 +113,7 @@ public:
|
||||
/**
|
||||
* Helper to create a BufferDescriptor that uses a KNOWN method pointer w/ object passed
|
||||
* by pointer as the callback. e.g.:
|
||||
* auto bd = BufferDescriptor::make<Foo, &Foo::method>(buffer, size, foo);
|
||||
* auto bd = BufferDescriptor::make(buffer, size, &Foo::method, foo);
|
||||
*
|
||||
* @param buffer Memory address of the CPU buffer to reference
|
||||
* @param size Size of the CPU buffer in bytes
|
||||
@@ -121,12 +121,12 @@ public:
|
||||
* @return a new BufferDescriptor
|
||||
*/
|
||||
template<typename T, void(T::*method)(void const*, size_t)>
|
||||
static BufferDescriptor make(void const* buffer, size_t size, T* data,
|
||||
CallbackHandler* handler = nullptr) noexcept {
|
||||
static BufferDescriptor make(
|
||||
void const* buffer, size_t size, T* data, CallbackHandler* handler = nullptr) noexcept {
|
||||
return {
|
||||
buffer, size,
|
||||
handler, [](void* b, size_t s, void* u) {
|
||||
(static_cast<T*>(u)->*method)(b, s);
|
||||
(*static_cast<T**>(u)->*method)(b, s);
|
||||
}, data
|
||||
};
|
||||
}
|
||||
@@ -145,14 +145,14 @@ public:
|
||||
* @return a new BufferDescriptor
|
||||
*/
|
||||
template<typename T>
|
||||
static BufferDescriptor make(void const* buffer, size_t size, T&& functor,
|
||||
CallbackHandler* handler = nullptr) noexcept {
|
||||
static BufferDescriptor make(
|
||||
void const* buffer, size_t size, T&& functor, CallbackHandler* handler = nullptr) noexcept {
|
||||
return {
|
||||
buffer, size,
|
||||
handler, [](void* b, size_t s, void* u) {
|
||||
T* const that = static_cast<T*>(u);
|
||||
that->operator()(b, s);
|
||||
delete that;
|
||||
T& that = *static_cast<T*>(u);
|
||||
that(b, s);
|
||||
delete &that;
|
||||
},
|
||||
new T(std::forward<T>(functor))
|
||||
};
|
||||
@@ -201,7 +201,7 @@ public:
|
||||
return mUser;
|
||||
}
|
||||
|
||||
//! CPU memory-buffer virtual address
|
||||
//! CPU mempry-buffer virtual address
|
||||
void* buffer = nullptr;
|
||||
|
||||
//! CPU memory-buffer size in bytes
|
||||
|
||||
@@ -356,6 +356,13 @@ enum class SamplerFormat : uint8_t {
|
||||
SHADOW = 3 //!< shadow sampler (PCF)
|
||||
};
|
||||
|
||||
//! Texture color space
|
||||
enum class SamplerTransferFunction : uint8_t {
|
||||
UNDEFINED = 0, //!< don't care
|
||||
IDENTITY = 1, //!< sampled as-is
|
||||
SRGB_TO_LINEAR = 2, //!< sampled as sRGB and converted to linear
|
||||
};
|
||||
|
||||
/**
|
||||
* Supported element types
|
||||
*/
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
CallbackHandler* handler = nullptr) noexcept {
|
||||
return { buffer, size, format, type, alignment, left, top, stride,
|
||||
handler, [](void* b, size_t s, void* u) {
|
||||
(static_cast<T*>(u)->*method)(b, s); }, data };
|
||||
(*static_cast<T**>(u)->*method)(b, s); }, data };
|
||||
}
|
||||
|
||||
template<typename T, void(T::*method)(void const*, size_t)>
|
||||
@@ -149,7 +149,7 @@ public:
|
||||
PixelDataFormat format, PixelDataType type, T* data,
|
||||
CallbackHandler* handler = nullptr) noexcept {
|
||||
return { buffer, size, format, type, handler, [](void* b, size_t s, void* u) {
|
||||
(static_cast<T*>(u)->*method)(b, s); }, data };
|
||||
(*static_cast<T**>(u)->*method)(b, s); }, data };
|
||||
}
|
||||
|
||||
template<typename T, void(T::*method)(void const*, size_t)>
|
||||
@@ -157,7 +157,7 @@ public:
|
||||
backend::CompressedPixelDataType format, uint32_t imageSize, T* data,
|
||||
CallbackHandler* handler = nullptr) noexcept {
|
||||
return { buffer, size, format, imageSize, handler, [](void* b, size_t s, void* u) {
|
||||
(static_cast<T*>(u)->*method)(b, s); }, data
|
||||
(*static_cast<T**>(u)->*method)(b, s); }, data
|
||||
};
|
||||
}
|
||||
|
||||
@@ -168,9 +168,9 @@ public:
|
||||
CallbackHandler* handler = nullptr) noexcept {
|
||||
return { buffer, size, format, type, alignment, left, top, stride,
|
||||
handler, [](void* b, size_t s, void* u) {
|
||||
T* const that = static_cast<T*>(u);
|
||||
that->operator()(b, s);
|
||||
delete that;
|
||||
T& that = *static_cast<T*>(u);
|
||||
that(b, s);
|
||||
delete &that;
|
||||
}, new T(std::forward<T>(functor))
|
||||
};
|
||||
}
|
||||
@@ -181,9 +181,9 @@ public:
|
||||
CallbackHandler* handler = nullptr) noexcept {
|
||||
return { buffer, size, format, type,
|
||||
handler, [](void* b, size_t s, void* u) {
|
||||
T* const that = static_cast<T*>(u);
|
||||
that->operator()(b, s);
|
||||
delete that;
|
||||
T& that = *static_cast<T*>(u);
|
||||
that(b, s);
|
||||
delete &that;
|
||||
}, new T(std::forward<T>(functor))
|
||||
};
|
||||
}
|
||||
@@ -194,9 +194,9 @@ public:
|
||||
CallbackHandler* handler = nullptr) noexcept {
|
||||
return { buffer, size, format, imageSize,
|
||||
handler, [](void* b, size_t s, void* u) {
|
||||
T* const that = static_cast<T*>(u);
|
||||
that->operator()(b, s);
|
||||
delete that;
|
||||
T& that = *static_cast<T*>(u);
|
||||
that(b, s);
|
||||
delete &that;
|
||||
}, new T(std::forward<T>(functor))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -170,6 +170,9 @@ MetalShaderCompiler::program_token_t MetalShaderCompiler::createProgram(
|
||||
CompilerPriorityQueue const priorityQueue = program.getPriorityQueue();
|
||||
mCompilerThreadPool.queue(priorityQueue, token,
|
||||
[this, name, device = mDevice, program = std::move(program), token]() {
|
||||
int sleepTime = atoi(name.c_str());
|
||||
sleep(sleepTime);
|
||||
|
||||
MetalFunctionBundle compiledProgram = compileProgram(program, device);
|
||||
|
||||
token->set(compiledProgram);
|
||||
|
||||
@@ -284,7 +284,6 @@ void OpenGLContext::setDefaultState() noexcept {
|
||||
|
||||
if (ext.EXT_clip_cull_distance) {
|
||||
glEnable(GL_CLIP_DISTANCE0);
|
||||
glEnable(GL_CLIP_DISTANCE1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
|
||||
mShaderCompilerService(*this),
|
||||
mHandleAllocator("Handles", driverConfig.handleArenaSize),
|
||||
mSamplerMap(32) {
|
||||
|
||||
|
||||
std::fill(mSamplerBindings.begin(), mSamplerBindings.end(), nullptr);
|
||||
|
||||
// set a reasonable default value for our stream array
|
||||
@@ -268,9 +268,9 @@ void OpenGLDriver::useProgram(OpenGLProgram* p) noexcept {
|
||||
|
||||
if (UTILS_UNLIKELY(mContext.isES2())) {
|
||||
for (uint32_t i = 0; i < Program::UNIFORM_BINDING_COUNT; i++) {
|
||||
auto [id, buffer, age] = mUniformBindings[i];
|
||||
auto [buffer, age] = mUniformBindings[i];
|
||||
if (buffer) {
|
||||
p->updateUniforms(i, id, buffer, age);
|
||||
p->updateUniforms(i, buffer, age);
|
||||
}
|
||||
}
|
||||
// Set the output colorspace for this program (linear or rec709). This in only relevant
|
||||
@@ -479,7 +479,6 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
|
||||
|
||||
GLBufferObject* bo = construct<GLBufferObject>(boh, byteCount, bindingType, usage);
|
||||
if (UTILS_UNLIKELY(bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
||||
bo->gl.id = ++mLastAssignedEmulatedUboId;
|
||||
bo->gl.buffer = malloc(byteCount);
|
||||
memset(bo->gl.buffer, 0, byteCount);
|
||||
} else {
|
||||
@@ -596,9 +595,8 @@ void OpenGLDriver::textureStorage(OpenGLDriver::GLTexture* t,
|
||||
}
|
||||
} else {
|
||||
glTexImage2D(t->gl.target, level, GLint(t->gl.internalFormat),
|
||||
std::max(GLsizei(1), GLsizei(width >> level)),
|
||||
std::max(GLsizei(1), GLsizei(height >> level)),
|
||||
0, format, type, nullptr);
|
||||
GLsizei(width), GLsizei(height), 0,
|
||||
format, type, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2903,11 +2901,7 @@ void OpenGLDriver::bindBufferRange(BufferObjectBinding bindingType, uint32_t ind
|
||||
assert_invariant(offset + size <= ub->byteCount);
|
||||
|
||||
if (UTILS_UNLIKELY(ub->bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
||||
mUniformBindings[index] = {
|
||||
ub->gl.id,
|
||||
static_cast<uint8_t const*>(ub->gl.buffer) + offset,
|
||||
ub->age,
|
||||
};
|
||||
mUniformBindings[index] = { static_cast<uint8_t const*>(ub->gl.buffer) + offset, ub->age };
|
||||
} else {
|
||||
GLenum const target = GLUtils::getBufferBindingType(bindingType);
|
||||
|
||||
|
||||
@@ -83,9 +83,11 @@ public:
|
||||
}
|
||||
|
||||
struct {
|
||||
GLuint id;
|
||||
union {
|
||||
GLenum binding;
|
||||
struct {
|
||||
GLuint id;
|
||||
GLenum binding;
|
||||
};
|
||||
void* buffer;
|
||||
};
|
||||
} gl;
|
||||
@@ -361,8 +363,7 @@ private:
|
||||
void setScissor(Viewport const& scissor) noexcept;
|
||||
|
||||
// ES2 only. Uniform buffer emulation binding points
|
||||
GLuint mLastAssignedEmulatedUboId = 0;
|
||||
std::array<std::tuple<GLuint, void const*, uint16_t>, Program::UNIFORM_BINDING_COUNT> mUniformBindings = {};
|
||||
std::array<std::pair<void const*, uint16_t>, Program::UNIFORM_BINDING_COUNT> mUniformBindings = {};
|
||||
|
||||
// sampler buffer binding points (nullptr if not used)
|
||||
std::array<GLSamplerGroup*, Program::SAMPLER_BINDING_COUNT> mSamplerBindings = {}; // 4 pointers
|
||||
|
||||
@@ -229,16 +229,15 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* const gld) const noexcept {
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
|
||||
void OpenGLProgram::updateUniforms(uint32_t index, GLuint id, void const* buffer, uint16_t age) noexcept {
|
||||
void OpenGLProgram::updateUniforms(uint32_t index, void const* buffer, uint16_t age) noexcept {
|
||||
assert_invariant(mUniformsRecords);
|
||||
assert_invariant(buffer);
|
||||
|
||||
// only update the uniforms if the UBO has changed since last time we updated
|
||||
UniformsRecord const& records = mUniformsRecords[index];
|
||||
if (records.id == id && records.age == age) {
|
||||
if (records.age == age) {
|
||||
return;
|
||||
}
|
||||
records.id = id;
|
||||
records.age = age;
|
||||
|
||||
assert_invariant(records.uniforms.size() == records.locations.size());
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
} gl; // 12 bytes
|
||||
|
||||
// For ES2 only
|
||||
void updateUniforms(uint32_t index, GLuint id, void const* buffer, uint16_t age) noexcept;
|
||||
void updateUniforms(uint32_t index, void const* buffer, uint16_t age) noexcept;
|
||||
void setRec709ColorSpace(bool rec709) const noexcept;
|
||||
|
||||
private:
|
||||
@@ -98,7 +98,6 @@ private:
|
||||
struct UniformsRecord {
|
||||
Program::UniformInfo uniforms;
|
||||
LocationInfo locations;
|
||||
mutable GLuint id = 0;
|
||||
mutable uint16_t age = std::numeric_limits<uint16_t>::max();
|
||||
};
|
||||
UniformsRecord const* mUniformsRecords = nullptr;
|
||||
|
||||
@@ -190,10 +190,8 @@ using namespace glext;
|
||||
|
||||
#if defined(GL_EXT_clip_cull_distance)
|
||||
# define GL_CLIP_DISTANCE0 GL_CLIP_DISTANCE0_EXT
|
||||
# define GL_CLIP_DISTANCE1 GL_CLIP_DISTANCE1_EXT
|
||||
#else
|
||||
# define GL_CLIP_DISTANCE0 0x3000
|
||||
# define GL_CLIP_DISTANCE1 0x3001
|
||||
#endif
|
||||
|
||||
#if defined(GL_KHR_debug)
|
||||
|
||||
@@ -268,18 +268,13 @@ bool VulkanCommands::flush() {
|
||||
VK_NULL_HANDLE,
|
||||
VK_NULL_HANDLE,
|
||||
};
|
||||
uint32_t waitSemaphoreCount = 0;
|
||||
if (mSubmissionSignal) {
|
||||
signals[waitSemaphoreCount++] = mSubmissionSignal;
|
||||
}
|
||||
if (mInjectedSignal) {
|
||||
signals[waitSemaphoreCount++] = mInjectedSignal;
|
||||
}
|
||||
|
||||
VkCommandBuffer const cmdbuffer = currentbuf->buffer();
|
||||
|
||||
VkSubmitInfo submitInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.waitSemaphoreCount = waitSemaphoreCount,
|
||||
.pWaitSemaphores = waitSemaphoreCount > 0 ? signals : nullptr,
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitSemaphores = signals,
|
||||
.pWaitDstStageMask = waitDestStageMasks,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &cmdbuffer,
|
||||
@@ -287,6 +282,19 @@ bool VulkanCommands::flush() {
|
||||
.pSignalSemaphores = &renderingFinished,
|
||||
};
|
||||
|
||||
if (mSubmissionSignal) {
|
||||
signals[submitInfo.waitSemaphoreCount++] = mSubmissionSignal;
|
||||
}
|
||||
|
||||
if (mInjectedSignal) {
|
||||
signals[submitInfo.waitSemaphoreCount++] = mInjectedSignal;
|
||||
}
|
||||
|
||||
// To address a validation warning.
|
||||
if (submitInfo.waitSemaphoreCount == 0) {
|
||||
submitInfo.pWaitSemaphores = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Submitting cmdbuffer=" << cmdbuffer
|
||||
<< " wait=(" << signals[0] << ", " << signals[1] << ") "
|
||||
|
||||
@@ -99,16 +99,11 @@ void VulkanSwapChain::present() {
|
||||
mColors[mCurrentSwapIndex]->transitionLayout(cmdbuf, subresources, VulkanLayout::PRESENT);
|
||||
}
|
||||
mCommands->flush();
|
||||
|
||||
// We only present if it is not headless. No-op for headless (but note that we still need the
|
||||
// flush() in the above line).
|
||||
if (!mHeadless) {
|
||||
VkSemaphore const finishedDrawing = mCommands->acquireFinishedSignal();
|
||||
VkResult const result = mPlatform->present(swapChain, mCurrentSwapIndex, finishedDrawing);
|
||||
ASSERT_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR ||
|
||||
result == VK_ERROR_OUT_OF_DATE_KHR,
|
||||
"Cannot present in swapchain.");
|
||||
}
|
||||
VkSemaphore const finishedDrawing = mCommands->acquireFinishedSignal();
|
||||
VkResult const result = mPlatform->present(swapChain, mCurrentSwapIndex, finishedDrawing);
|
||||
ASSERT_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR
|
||||
|| result == VK_ERROR_OUT_OF_DATE_KHR,
|
||||
"Cannot present in swapchain.");
|
||||
|
||||
// We presented the last acquired buffer.
|
||||
mAcquired = false;
|
||||
|
||||
@@ -286,20 +286,17 @@ public:
|
||||
/** Sets a custom projection matrix for each eye.
|
||||
*
|
||||
* The projectionForCulling, near, and far parameters establish a "culling frustum" which must
|
||||
* encompass anything any eye can see. All projection matrices must be set simultaneously. The
|
||||
* number of stereoscopic eyes is controlled by the stereoscopicEyeCount setting inside of
|
||||
* Engine::Config.
|
||||
* encompass anything either eye can see.
|
||||
*
|
||||
* @param projection an array of projection matrices, only the first config.stereoscopicEyeCount
|
||||
* are read
|
||||
* @param projection an array of projection matrices, only the first
|
||||
* CONFIG_STEREOSCOPIC_EYES (2) are read
|
||||
* @param count size of the projection matrix array to set, must be
|
||||
* >= config.stereoscopicEyeCount
|
||||
* >= CONFIG_STEREOSCOPIC_EYES (2)
|
||||
* @param projectionForCulling custom projection matrix for culling, must encompass both eyes
|
||||
* @param near distance in world units from the camera to the culling near plane. \p near > 0.
|
||||
* @param far distance in world units from the camera to the culling far plane. \p far > \p
|
||||
* near.
|
||||
* @see setCustomProjection
|
||||
* @see Engine::Config::stereoscopicEyeCount
|
||||
*/
|
||||
void setCustomEyeProjection(math::mat4 const* projection, size_t count,
|
||||
math::mat4 const& projectionForCulling, double near, double far);
|
||||
@@ -360,8 +357,8 @@ public:
|
||||
* The projection matrix used for rendering always has its far plane set to infinity. This
|
||||
* is why it may differ from the matrix set through setProjection() or setLensProjection().
|
||||
*
|
||||
* @param eyeId the index of the eye to return the projection matrix for, must be
|
||||
* < config.stereoscopicEyeCount
|
||||
* @param eyeId the index of the eye to return the projection matrix for, must be <
|
||||
* CONFIG_STEREOSCOPIC_EYES (2)
|
||||
* @return The projection matrix used for rendering
|
||||
*
|
||||
* @see setProjection, setLensProjection, setCustomProjection, getCullingProjectionMatrix,
|
||||
@@ -419,7 +416,7 @@ public:
|
||||
* This method is not intended to be called every frame. Instead, to update the position of the
|
||||
* head, use Camera::setModelMatrix.
|
||||
*
|
||||
* @param eyeId the index of the eye to set, must be < config.stereoscopicEyeCount
|
||||
* @param eyeId the index of the eye to set, must be < CONFIG_STEREOSCOPIC_EYES (2)
|
||||
* @param model the model matrix for an individual eye
|
||||
*/
|
||||
void setEyeModelMatrix(uint8_t eyeId, math::mat4 const& model);
|
||||
|
||||
@@ -291,14 +291,6 @@ public:
|
||||
* Currently only respected by the Metal backend.
|
||||
*/
|
||||
size_t textureUseAfterFreePoolSize = 0;
|
||||
|
||||
/*
|
||||
* The number of eyes to render when stereoscopic rendering is enabled. Supported values are
|
||||
* between 1 and CONFIG_MAX_STEREOSCOPIC_EYES (inclusive).
|
||||
*
|
||||
* @see View::setStereoscopicOptions
|
||||
*/
|
||||
uint8_t stereoscopicEyeCount = 2;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -763,10 +763,10 @@ public:
|
||||
* @param handler Handler to dispatch the callback or nullptr for the default handler.
|
||||
*/
|
||||
template<typename T, void(T::*method)(PickingQueryResult const&)>
|
||||
void pick(uint32_t x, uint32_t y, T* instance,
|
||||
backend::CallbackHandler* handler = nullptr) noexcept {
|
||||
void pick(uint32_t x, uint32_t y, T* instance, backend::CallbackHandler* handler = nullptr) noexcept {
|
||||
PickingQuery& query = pick(x, y, [](PickingQueryResult const& result, PickingQuery* pq) {
|
||||
(static_cast<T*>(pq->storage[0])->*method)(result);
|
||||
void* user = pq->storage;
|
||||
(*static_cast<T**>(user)->*method)(result);
|
||||
}, handler);
|
||||
query.storage[0] = instance;
|
||||
}
|
||||
@@ -783,11 +783,11 @@ public:
|
||||
* @param handler Handler to dispatch the callback or nullptr for the default handler.
|
||||
*/
|
||||
template<typename T, void(T::*method)(PickingQueryResult const&)>
|
||||
void pick(uint32_t x, uint32_t y, T instance,
|
||||
backend::CallbackHandler* handler = nullptr) noexcept {
|
||||
void pick(uint32_t x, uint32_t y, T instance, backend::CallbackHandler* handler = nullptr) noexcept {
|
||||
static_assert(sizeof(instance) <= sizeof(PickingQuery::storage), "user data too large");
|
||||
PickingQuery& query = pick(x, y, [](PickingQueryResult const& result, PickingQuery* pq) {
|
||||
T* const that = static_cast<T*>(reinterpret_cast<void*>(pq->storage));
|
||||
void* user = pq->storage;
|
||||
T* that = static_cast<T*>(user);
|
||||
(that->*method)(result);
|
||||
that->~T();
|
||||
}, handler);
|
||||
@@ -804,15 +804,15 @@ public:
|
||||
* @param handler Handler to dispatch the callback or nullptr for the default handler.
|
||||
*/
|
||||
template<typename T>
|
||||
void pick(uint32_t x, uint32_t y, T functor,
|
||||
backend::CallbackHandler* handler = nullptr) noexcept {
|
||||
void pick(uint32_t x, uint32_t y, T functor, backend::CallbackHandler* handler = nullptr) noexcept {
|
||||
static_assert(sizeof(functor) <= sizeof(PickingQuery::storage), "functor too large");
|
||||
PickingQuery& query = pick(x, y, handler,
|
||||
(PickingQueryResultCallback)[](PickingQueryResult const& result, PickingQuery* pq) {
|
||||
T* const that = static_cast<T*>(reinterpret_cast<void*>(pq->storage));
|
||||
that->operator()(result);
|
||||
that->~T();
|
||||
});
|
||||
void* user = pq->storage;
|
||||
T& that = *static_cast<T*>(user);
|
||||
that(result);
|
||||
that.~T();
|
||||
});
|
||||
new(query.storage) T(std::move(functor));
|
||||
}
|
||||
|
||||
|
||||
@@ -426,6 +426,7 @@ bool ChunkSamplerInterfaceBlock::unflatten(Unflattener& unflattener,
|
||||
uint8_t fieldFormat = 0;
|
||||
uint8_t fieldPrecision = 0;
|
||||
bool fieldMultisample = false;
|
||||
uint8_t fieldTransferFunction = 0;
|
||||
|
||||
if (!unflattener.read(&fieldName)) {
|
||||
return false;
|
||||
@@ -447,10 +448,15 @@ bool ChunkSamplerInterfaceBlock::unflatten(Unflattener& unflattener,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!unflattener.read(&fieldTransferFunction)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.add({ fieldName.data(), fieldName.size() }, SamplerInterfaceBlock::Type(fieldType),
|
||||
SamplerInterfaceBlock::Format(fieldFormat),
|
||||
SamplerInterfaceBlock::Precision(fieldPrecision),
|
||||
fieldMultisample);
|
||||
fieldMultisample,
|
||||
SamplerInterfaceBlock::SamplerTransferFunction(fieldTransferFunction));
|
||||
}
|
||||
|
||||
*sib = builder.build();
|
||||
|
||||
@@ -82,8 +82,7 @@ void PerViewUniforms::prepareCamera(FEngine& engine, const CameraInfo& camera) n
|
||||
s.nearOverFarMinusNear = camera.zn / (camera.zf - camera.zn);
|
||||
|
||||
mat4f const& headFromWorld = camera.view;
|
||||
Engine::Config const& config = engine.getConfig();
|
||||
for (int i = 0; i < config.stereoscopicEyeCount; i++) {
|
||||
for (uint8_t i = 0; i < CONFIG_STEREOSCOPIC_EYES; i++) {
|
||||
mat4f const& eyeFromHead = camera.eyeFromView[i]; // identity for monoscopic rendering
|
||||
mat4f const& clipFromEye = camera.eyeProjection[i];
|
||||
// clipFromEye * eyeFromHead * headFromWorld
|
||||
|
||||
@@ -2714,8 +2714,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
|
||||
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
|
||||
backend::SamplerMagFilter filter) noexcept {
|
||||
|
||||
if (UTILS_LIKELY(!translucent && dsrOptions.quality == QualityLevel::LOW &&
|
||||
mEngine.getDriverApi().getFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1)) {
|
||||
if (UTILS_LIKELY(!translucent && dsrOptions.quality == QualityLevel::LOW)) {
|
||||
return opaqueBlit(fg, input, vp, outDesc, filter);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,17 +116,14 @@ void RenderPass::appendCommands(FEngine& engine, CommandTypeFlags const commandT
|
||||
commandCount += 1; // for the sentinel
|
||||
Command* const curr = append(commandCount);
|
||||
|
||||
auto stereoscopicEyeCount =
|
||||
renderFlags & IS_STEREOSCOPIC ? engine.getConfig().stereoscopicEyeCount : 1;
|
||||
|
||||
const float3 cameraPosition(mCameraPosition);
|
||||
const float3 cameraForwardVector(mCameraForwardVector);
|
||||
auto work = [commandTypeFlags, curr, &soa, variant, renderFlags, visibilityMask, cameraPosition,
|
||||
cameraForwardVector, stereoscopicEyeCount]
|
||||
cameraForwardVector]
|
||||
(uint32_t startIndex, uint32_t indexCount) {
|
||||
RenderPass::generateCommands(commandTypeFlags, curr,
|
||||
soa, { startIndex, startIndex + indexCount }, variant, renderFlags, visibilityMask,
|
||||
cameraPosition, cameraForwardVector, stereoscopicEyeCount);
|
||||
cameraPosition, cameraForwardVector);
|
||||
};
|
||||
|
||||
if (vr.size() <= JOBS_PARALLEL_FOR_COMMANDS_COUNT) {
|
||||
@@ -377,8 +374,8 @@ UTILS_NOINLINE
|
||||
void RenderPass::generateCommands(uint32_t commandTypeFlags, Command* const commands,
|
||||
FScene::RenderableSoa const& soa, Range<uint32_t> range,
|
||||
Variant variant, RenderFlags renderFlags,
|
||||
FScene::VisibleMaskType visibilityMask, float3 cameraPosition, float3 cameraForward,
|
||||
uint8_t instancedStereoEyeCount) noexcept {
|
||||
FScene::VisibleMaskType visibilityMask,
|
||||
float3 cameraPosition, float3 cameraForward) noexcept {
|
||||
|
||||
SYSTRACE_CALL();
|
||||
|
||||
@@ -409,13 +406,11 @@ void RenderPass::generateCommands(uint32_t commandTypeFlags, Command* const comm
|
||||
switch (commandTypeFlags & (CommandTypeFlags::COLOR | CommandTypeFlags::DEPTH)) {
|
||||
case CommandTypeFlags::COLOR:
|
||||
curr = generateCommandsImpl<CommandTypeFlags::COLOR>(commandTypeFlags, curr,
|
||||
soa, range, variant, renderFlags, visibilityMask, cameraPosition, cameraForward,
|
||||
instancedStereoEyeCount);
|
||||
soa, range, variant, renderFlags, visibilityMask, cameraPosition, cameraForward);
|
||||
break;
|
||||
case CommandTypeFlags::DEPTH:
|
||||
curr = generateCommandsImpl<CommandTypeFlags::DEPTH>(commandTypeFlags, curr,
|
||||
soa, range, variant, renderFlags, visibilityMask, cameraPosition, cameraForward,
|
||||
instancedStereoEyeCount);
|
||||
soa, range, variant, renderFlags, visibilityMask, cameraPosition, cameraForward);
|
||||
break;
|
||||
default:
|
||||
// we should never end-up here
|
||||
@@ -438,7 +433,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags,
|
||||
Command* UTILS_RESTRICT curr,
|
||||
FScene::RenderableSoa const& UTILS_RESTRICT soa, Range<uint32_t> range,
|
||||
Variant const variant, RenderFlags renderFlags, FScene::VisibleMaskType visibilityMask,
|
||||
float3 cameraPosition, float3 cameraForward, uint8_t instancedStereoEyeCount) noexcept {
|
||||
float3 cameraPosition, float3 cameraForward) noexcept {
|
||||
|
||||
// generateCommands() writes both the draw and depth commands simultaneously such that
|
||||
// we go throw the list of renderables just once.
|
||||
@@ -534,7 +529,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags,
|
||||
// eye count.
|
||||
if (UTILS_UNLIKELY(hasInstancedStereo)) {
|
||||
cmdColor.primitive.instanceCount =
|
||||
(soaInstanceInfo[i].count * instancedStereoEyeCount) |
|
||||
(soaInstanceInfo[i].count * CONFIG_STEREOSCOPIC_EYES) |
|
||||
PrimitiveInfo::USER_INSTANCE_MASK;
|
||||
}
|
||||
|
||||
@@ -560,7 +555,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags,
|
||||
|
||||
if (UTILS_UNLIKELY(hasInstancedStereo)) {
|
||||
cmdColor.primitive.instanceCount =
|
||||
(soaInstanceInfo[i].count * instancedStereoEyeCount) |
|
||||
(soaInstanceInfo[i].count * CONFIG_STEREOSCOPIC_EYES) |
|
||||
PrimitiveInfo::USER_INSTANCE_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,15 +408,13 @@ private:
|
||||
FScene::RenderableSoa const& soa, utils::Range<uint32_t> range,
|
||||
Variant variant, RenderFlags renderFlags,
|
||||
FScene::VisibleMaskType visibilityMask,
|
||||
math::float3 cameraPosition, math::float3 cameraForward,
|
||||
uint8_t instancedStereoEyeCount) noexcept;
|
||||
math::float3 cameraPosition, math::float3 cameraForward) noexcept;
|
||||
|
||||
template<uint32_t commandTypeFlags>
|
||||
static inline Command* generateCommandsImpl(uint32_t extraFlags, Command* curr,
|
||||
FScene::RenderableSoa const& soa, utils::Range<uint32_t> range,
|
||||
Variant variant, RenderFlags renderFlags, FScene::VisibleMaskType visibilityMask,
|
||||
math::float3 cameraPosition, math::float3 cameraForward,
|
||||
uint8_t instancedStereoEyeCount) noexcept;
|
||||
math::float3 cameraPosition, math::float3 cameraForward) noexcept;
|
||||
|
||||
static void setupColorCommand(Command& cmdDraw, Variant variant,
|
||||
FMaterialInstance const* mi, bool inverseFrontFaces) noexcept;
|
||||
|
||||
@@ -108,13 +108,11 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
ShadowMapInfo const& shadowMapInfo,
|
||||
SceneInfo const& sceneInfo) noexcept {
|
||||
|
||||
// reset the visible shadow status
|
||||
mHasVisibleShadows = false;
|
||||
|
||||
FLightManager const& lcm = engine.getLightManager();
|
||||
FLightManager::Instance const li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
FLightManager::ShadowParams const params = lcm.getShadowParams(li);
|
||||
|
||||
// We can't use LISPSM in stable mode
|
||||
const auto direction = lightData.elementAt<FScene::SHADOW_DIRECTION>(index);
|
||||
|
||||
auto [Mv, znear, zfar, lsClippedShadowVolume, vertexCount, visibleShadows] =
|
||||
@@ -139,7 +137,6 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
*/
|
||||
|
||||
mat4f W, Wp, L;
|
||||
// We can't use LISPSM in stable mode
|
||||
const bool useLispsm = params.options.lispsm && !params.options.stable;
|
||||
if (useLispsm) {
|
||||
// Orient the shadow map in the direction of the view vector by constructing a
|
||||
|
||||
@@ -522,7 +522,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
// entire camera frustum, as if we only had a single cascade.
|
||||
ShadowMap& shadowMap = cascadedShadowMaps[0];
|
||||
|
||||
const auto direction = lightData.elementAt<FScene::SHADOW_DIRECTION>(0);
|
||||
const auto direction = options.transform * lightData.elementAt<FScene::DIRECTION>(0);
|
||||
|
||||
// We compute the directional light's model matrix using the origin's as the light position.
|
||||
// The choice of the light's origin initially doesn't matter for a directional light.
|
||||
|
||||
@@ -96,11 +96,11 @@ void UTILS_NOINLINE FCamera::setCustomProjection(mat4 const& p,
|
||||
|
||||
void UTILS_NOINLINE FCamera::setCustomEyeProjection(math::mat4 const* projection, size_t count,
|
||||
math::mat4 const& projectionForCulling, double near, double far) {
|
||||
const Engine::Config& config = mEngine.getConfig();
|
||||
ASSERT_PRECONDITION(count >= config.stereoscopicEyeCount,
|
||||
ASSERT_PRECONDITION(count >= CONFIG_STEREOSCOPIC_EYES,
|
||||
"All eye projections must be supplied together, count must be >= "
|
||||
"config.stereoscopicEyeCount (%d)", config.stereoscopicEyeCount);
|
||||
for (int i = 0; i < config.stereoscopicEyeCount; i++) {
|
||||
"CONFIG_STEREOSCOPIC_EYES(%d)",
|
||||
CONFIG_STEREOSCOPIC_EYES);
|
||||
for (uint8_t i = 0; i < CONFIG_STEREOSCOPIC_EYES; i++) {
|
||||
mEyeProjection[i] = projection[i];
|
||||
}
|
||||
mProjectionForCulling = projectionForCulling;
|
||||
@@ -165,8 +165,7 @@ void UTILS_NOINLINE FCamera::setProjection(Camera::Projection projection,
|
||||
}
|
||||
|
||||
math::mat4 FCamera::getProjectionMatrix(uint8_t eye) const noexcept {
|
||||
UTILS_UNUSED_IN_RELEASE const Engine::Config& config = mEngine.getConfig();
|
||||
assert_invariant(eye < config.stereoscopicEyeCount);
|
||||
assert_invariant(eye < CONFIG_STEREOSCOPIC_EYES);
|
||||
// This is where we transform the user clip-space (GL convention) to our virtual clip-space
|
||||
// (inverted DX convention)
|
||||
// Note that this math ends up setting the projection matrix' p33 to 0, which is where we're
|
||||
@@ -191,13 +190,6 @@ math::mat4 FCamera::getCullingProjectionMatrix() const noexcept {
|
||||
return m * mProjectionForCulling;
|
||||
}
|
||||
|
||||
const math::mat4& FCamera::getUserProjectionMatrix(uint8_t eyeId) const {
|
||||
const Engine::Config& config = mEngine.getConfig();
|
||||
ASSERT_PRECONDITION(eyeId < config.stereoscopicEyeCount,
|
||||
"eyeId must be < config.stereoscopicEyeCount (%d)", config.stereoscopicEyeCount);
|
||||
return mEyeProjection[eyeId];
|
||||
}
|
||||
|
||||
void UTILS_NOINLINE FCamera::setModelMatrix(const mat4f& modelMatrix) noexcept {
|
||||
FTransformManager& transformManager = mEngine.getTransformManager();
|
||||
transformManager.setTransform(transformManager.getInstance(mEntity), modelMatrix);
|
||||
@@ -209,9 +201,8 @@ void UTILS_NOINLINE FCamera::setModelMatrix(const mat4& modelMatrix) noexcept {
|
||||
}
|
||||
|
||||
void UTILS_NOINLINE FCamera::setEyeModelMatrix(uint8_t eyeId, math::mat4 const& model) {
|
||||
const Engine::Config& config = mEngine.getConfig();
|
||||
ASSERT_PRECONDITION(eyeId < config.stereoscopicEyeCount,
|
||||
"eyeId must be < config.stereoscopicEyeCount (%d)", config.stereoscopicEyeCount);
|
||||
ASSERT_PRECONDITION(eyeId < CONFIG_STEREOSCOPIC_EYES,
|
||||
"eyeId must be < CONFIG_STEREOSCOPIC_EYES(%d)", CONFIG_STEREOSCOPIC_EYES);
|
||||
mEyeFromView[eyeId] = inverse(model);
|
||||
}
|
||||
|
||||
@@ -258,15 +249,10 @@ double FCamera::computeEffectiveFov(double fovInDegrees, double focusDistance) n
|
||||
return fov * math::d::RAD_TO_DEG;
|
||||
}
|
||||
|
||||
uint8_t FCamera::getStereoscopicEyeCount() const noexcept {
|
||||
const Engine::Config& config = mEngine.getConfig();
|
||||
return config.stereoscopicEyeCount;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
CameraInfo::CameraInfo(FCamera const& camera) noexcept {
|
||||
for (int i = 0; i < camera.getStereoscopicEyeCount(); i++) {
|
||||
for (uint8_t i = 0; i < CONFIG_STEREOSCOPIC_EYES; i++) {
|
||||
eyeProjection[i] = mat4f{ camera.getProjectionMatrix(i) };
|
||||
}
|
||||
cullingProjection = mat4f{ camera.getCullingProjectionMatrix() };
|
||||
@@ -282,7 +268,7 @@ CameraInfo::CameraInfo(FCamera const& camera) noexcept {
|
||||
|
||||
CameraInfo::CameraInfo(FCamera const& camera, math::mat4 const& inWorldTransform) noexcept {
|
||||
const mat4 modelMatrix{ inWorldTransform * camera.getModelMatrix() };
|
||||
for (int i = 0; i < camera.getStereoscopicEyeCount(); i++) {
|
||||
for (uint8_t i = 0; i < CONFIG_STEREOSCOPIC_EYES; i++) {
|
||||
eyeProjection[i] = mat4f{ camera.getProjectionMatrix(i) };
|
||||
eyeFromView[i] = mat4f{ camera.getEyeFromViewMatrix(i) };
|
||||
}
|
||||
|
||||
@@ -85,7 +85,11 @@ public:
|
||||
math::mat4 getEyeFromViewMatrix(uint8_t eye) const noexcept { return mEyeFromView[eye]; }
|
||||
|
||||
// viewing projection matrix set by the user
|
||||
const math::mat4& getUserProjectionMatrix(uint8_t eyeId) const;
|
||||
const math::mat4& getUserProjectionMatrix(uint8_t eyeId) const {
|
||||
ASSERT_PRECONDITION(eyeId < CONFIG_STEREOSCOPIC_EYES,
|
||||
"eyeId must be < CONFIG_STEREOSCOPIC_EYES(%d)", CONFIG_STEREOSCOPIC_EYES);
|
||||
return mEyeProjection[eyeId];
|
||||
}
|
||||
|
||||
// culling projection matrix set by the user
|
||||
math::mat4 getUserCullingProjectionMatrix() const noexcept { return mProjectionForCulling; }
|
||||
@@ -185,8 +189,6 @@ public:
|
||||
|
||||
static double computeEffectiveFov(double fovInDegrees, double focusDistance) noexcept;
|
||||
|
||||
uint8_t getStereoscopicEyeCount() const noexcept;
|
||||
|
||||
utils::Entity getEntity() const noexcept {
|
||||
return mEntity;
|
||||
}
|
||||
@@ -202,10 +204,10 @@ private:
|
||||
utils::Entity mEntity;
|
||||
|
||||
// For monoscopic cameras, mEyeProjection[0] == mEyeProjection[1].
|
||||
math::mat4 mEyeProjection[CONFIG_MAX_STEREOSCOPIC_EYES]; // projection matrix per eye (infinite far)
|
||||
math::mat4 mProjectionForCulling; // projection matrix (with far plane)
|
||||
math::mat4 mEyeFromView[CONFIG_MAX_STEREOSCOPIC_EYES]; // transforms from the main view (head)
|
||||
// space to each eye's unique view space
|
||||
math::mat4 mEyeProjection[CONFIG_STEREOSCOPIC_EYES]; // projection matrix per eye (infinite far)
|
||||
math::mat4 mProjectionForCulling; // projection matrix (with far plane)
|
||||
math::mat4 mEyeFromView[CONFIG_STEREOSCOPIC_EYES]; // transforms from the main view (head)
|
||||
// space to each eye's unique view space
|
||||
math::double2 mScalingCS = {1.0}; // additional scaling applied to projection
|
||||
math::double2 mShiftCS = {0.0}; // additional translation applied to projection
|
||||
|
||||
@@ -230,15 +232,15 @@ struct CameraInfo {
|
||||
math::mat4f projection;
|
||||
|
||||
// for stereo rendering, one matrix per eye
|
||||
math::mat4f eyeProjection[CONFIG_MAX_STEREOSCOPIC_EYES] = {};
|
||||
math::mat4f eyeProjection[CONFIG_STEREOSCOPIC_EYES] = {};
|
||||
};
|
||||
|
||||
math::mat4f cullingProjection; // projection matrix for culling
|
||||
math::mat4f model; // camera model matrix
|
||||
math::mat4f view; // camera view matrix (inverse(model))
|
||||
math::mat4f eyeFromView[CONFIG_MAX_STEREOSCOPIC_EYES]; // eye view matrix (only for stereoscopic)
|
||||
math::mat4 worldTransform; // world transform (already applied
|
||||
// to model and view)
|
||||
math::mat4f cullingProjection; // projection matrix for culling
|
||||
math::mat4f model; // camera model matrix
|
||||
math::mat4f view; // camera view matrix (inverse(model))
|
||||
math::mat4f eyeFromView[CONFIG_STEREOSCOPIC_EYES]; // eye view matrix (only for stereoscopic)
|
||||
math::mat4 worldTransform; // world transform (already applied
|
||||
// to model and view)
|
||||
math::float4 clipTransform{1, 1, 0, 0}; // clip-space transform, only for VERTEX_DOMAIN_DEVICE
|
||||
float zn{}; // distance (positive) to the near plane
|
||||
float zf{}; // distance (positive) to the far plane
|
||||
|
||||
@@ -244,10 +244,6 @@ void FEngine::init() {
|
||||
|
||||
mActiveFeatureLevel = std::min(mActiveFeatureLevel, driverApi.getFeatureLevel());
|
||||
|
||||
#ifndef FILAMENT_ENABLE_FEATURE_LEVEL_0
|
||||
assert_invariant(mActiveFeatureLevel > FeatureLevel::FEATURE_LEVEL_0);
|
||||
#endif
|
||||
|
||||
slog.i << "Backend feature level: " << int(driverApi.getFeatureLevel()) << io::endl;
|
||||
slog.i << "FEngine feature level: " << int(mActiveFeatureLevel) << io::endl;
|
||||
|
||||
@@ -332,15 +328,12 @@ void FEngine::init() {
|
||||
driverApi.update3DImage(mDummyZeroTexture, 0, 0, 0, 0, 1, 1, 1,
|
||||
{ zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
|
||||
#ifdef FILAMENT_ENABLE_FEATURE_LEVEL_0
|
||||
if (UTILS_UNLIKELY(mActiveFeatureLevel == FeatureLevel::FEATURE_LEVEL_0)) {
|
||||
FMaterial::DefaultMaterialBuilder defaultMaterialBuilder;
|
||||
defaultMaterialBuilder.package(
|
||||
MATERIALS_DEFAULTMATERIAL0_DATA, MATERIALS_DEFAULTMATERIAL0_SIZE);
|
||||
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*const_cast<FEngine*>(this)));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
|
||||
|
||||
FMaterial::DefaultMaterialBuilder defaultMaterialBuilder;
|
||||
@@ -1273,9 +1266,6 @@ Engine::Config Engine::BuilderDetails::validateConfig(const Config* const pConfi
|
||||
// This value gets validated during driver creation, so pass it through
|
||||
config.driverHandleArenaSizeMB = config.driverHandleArenaSizeMB;
|
||||
|
||||
config.stereoscopicEyeCount =
|
||||
std::clamp(config.stereoscopicEyeCount, uint8_t(1), CONFIG_MAX_STEREOSCOPIC_EYES);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,9 +260,6 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
|
||||
mSpecializationConstants.push_back({
|
||||
+ReservedSpecializationConstants::CONFIG_POWER_VR_SHADER_WORKAROUNDS,
|
||||
(bool)powerVrShaderWorkarounds });
|
||||
mSpecializationConstants.push_back({
|
||||
+ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT,
|
||||
(int)engine.getConfig().stereoscopicEyeCount });
|
||||
if (UTILS_UNLIKELY(engine.getShaderLanguage() == ShaderLanguage::ESSL1)) {
|
||||
// The actual value of this spec-constant is set in the OpenGLDriver backend.
|
||||
mSpecializationConstants.push_back({
|
||||
|
||||
@@ -267,16 +267,16 @@ void FScene::prepare(utils::JobSystem& js,
|
||||
// in the code below, we only transform directions, so the translation of the
|
||||
// world transform is irrelevant, and we don't need to use getWorldTransformAccurate()
|
||||
|
||||
mat3 const worldDirectionTransform =
|
||||
mat3::getTransformForNormals(tcm.getWorldTransformAccurate(ti).upperLeft());
|
||||
FLightManager::ShadowParams const params = lcm.getShadowParams(li);
|
||||
float3 const localDirection = worldDirectionTransform * lcm.getLocalDirection(li);
|
||||
double3 const shadowLocalDirection = params.options.transform * localDirection;
|
||||
float3 const localDirection = lcm.getLocalDirection(li);
|
||||
float3 const shadowLocalDirection = params.options.transform * localDirection;
|
||||
mat3 const worldDirectionTransform = tcm.getWorldTransformAccurate(ti).upperLeft();
|
||||
mat3 const shaderWorldTransform = worldTransform.upperLeft() * worldDirectionTransform;
|
||||
|
||||
// using mat3::getTransformForNormals handles non-uniform scaling
|
||||
// note: in the common case of the rigid-body transform, getTransformForNormals() returns
|
||||
// identity.
|
||||
mat3 const worlTransformNormals = mat3::getTransformForNormals(worldTransform.upperLeft());
|
||||
mat3 const worlTransformNormals = mat3::getTransformForNormals(shaderWorldTransform);
|
||||
double3 const d = worlTransformNormals * localDirection;
|
||||
double3 const s = worlTransformNormals * shadowLocalDirection;
|
||||
|
||||
@@ -290,8 +290,10 @@ void FScene::prepare(utils::JobSystem& js,
|
||||
// is pointing down, which is a common case for lights. See ShadowMap.cpp.
|
||||
return transpose(mat3::lookTo(direction, double3{ 1, 0, 0 }));
|
||||
};
|
||||
double3 const worldDirection =
|
||||
mat3::getTransformForNormals(worldDirectionTransform) * shadowLocalDirection;
|
||||
double3 const worldOrigin = transpose(worldTransform.upperLeft()) * worldTransform[3].xyz;
|
||||
mat3 const Mv = getMv(shadowLocalDirection);
|
||||
mat3 const Mv = getMv(worldDirection);
|
||||
double2 const lsReferencePoint = (Mv * worldOrigin).xy;
|
||||
|
||||
constexpr float inf = std::numeric_limits<float>::infinity();
|
||||
|
||||
@@ -118,12 +118,9 @@ FSkybox::FSkybox(FEngine& engine, const Builder& builder) noexcept
|
||||
|
||||
FMaterial const* FSkybox::createMaterial(FEngine& engine) {
|
||||
Material::Builder builder;
|
||||
#ifdef FILAMENT_ENABLE_FEATURE_LEVEL_0
|
||||
if (UTILS_UNLIKELY(engine.getActiveFeatureLevel() == Engine::FeatureLevel::FEATURE_LEVEL_0)) {
|
||||
builder.package(MATERIALS_SKYBOX0_DATA, MATERIALS_SKYBOX0_SIZE);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
builder.package(MATERIALS_SKYBOX_DATA, MATERIALS_SKYBOX_SIZE);
|
||||
}
|
||||
auto material = builder.build(engine);
|
||||
|
||||
@@ -527,7 +527,7 @@ private:
|
||||
|
||||
template<typename Data, typename Setup, typename Execute>
|
||||
FrameGraphPass<Data>& FrameGraph::addPass(char const* name, Setup setup, Execute&& execute) {
|
||||
static_assert(sizeof(Execute) < 2048, "Execute() lambda is capturing too much data.");
|
||||
static_assert(sizeof(Execute) < 1024, "Execute() lambda is capturing too much data.");
|
||||
|
||||
// create the FrameGraph pass
|
||||
auto* const pass = mArena.make<FrameGraphPassConcrete<Data, Execute>>(std::forward<Execute>(execute));
|
||||
|
||||
@@ -82,22 +82,22 @@ uint32_t RenderPassNode::declareRenderTarget(FrameGraph& fg, FrameGraph::Builder
|
||||
RenderPassData data;
|
||||
data.name = name;
|
||||
data.descriptor = descriptor;
|
||||
FrameGraphRenderPass::Attachments const& attachments = data.descriptor.attachments;
|
||||
|
||||
// retrieve the ResourceNode of the attachments coming to us -- this will be used later
|
||||
// to compute the discard flags.
|
||||
|
||||
DependencyGraph const& dependencyGraph = fg.getGraph();
|
||||
auto incomingEdges = dependencyGraph.getIncomingEdges(this);
|
||||
auto outgoingEdges = dependencyGraph.getOutgoingEdges(this);
|
||||
|
||||
for (size_t i = 0; i < RenderPassData::ATTACHMENT_COUNT; i++) {
|
||||
FrameGraphId<FrameGraphTexture> const& handle =
|
||||
data.descriptor.attachments.array[i];
|
||||
if (handle) {
|
||||
data.attachmentInfo[i] = handle;
|
||||
if (descriptor.attachments.array[i]) {
|
||||
data.attachmentInfo[i] = attachments.array[i];
|
||||
|
||||
// TODO: this is not very efficient
|
||||
auto incomingPos = std::find_if(incomingEdges.begin(), incomingEdges.end(),
|
||||
[&dependencyGraph, handle]
|
||||
[&dependencyGraph, handle = descriptor.attachments.array[i]]
|
||||
(DependencyGraph::Edge const* edge) {
|
||||
ResourceNode const* node = static_cast<ResourceNode const*>(
|
||||
dependencyGraph.getNode(edge->from));
|
||||
@@ -111,7 +111,7 @@ uint32_t RenderPassNode::declareRenderTarget(FrameGraph& fg, FrameGraph::Builder
|
||||
}
|
||||
|
||||
// this could be either outgoing or incoming (if there are no outgoing)
|
||||
data.outgoing[i] = fg.getActiveResourceNode(handle);
|
||||
data.outgoing[i] = fg.getActiveResourceNode(descriptor.attachments.array[i]);
|
||||
if (data.outgoing[i] == data.incoming[i]) {
|
||||
data.outgoing[i] = nullptr;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ vertex {
|
||||
|
||||
fragment {
|
||||
void postProcess(inout PostProcessInputs postProcess) {
|
||||
#if FILAMENT_EFFECTIVE_VERSION == 100
|
||||
#if __VERSION__ == 100
|
||||
postProcess.color = texture2D(materialParams_color, variable_vertex.xy);
|
||||
#else
|
||||
postProcess.color = textureLod(materialParams_color, variable_vertex.xy, 0.0);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.47.0"
|
||||
spec.version = "1.45.0"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.47.0/filament-v1.47.0-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.45.0/filament-v1.45.0-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 47;
|
||||
static constexpr size_t MATERIAL_VERSION = 45;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -66,7 +66,6 @@ enum class ReservedSpecializationConstants : uint8_t {
|
||||
CONFIG_POWER_VR_SHADER_WORKAROUNDS = 5,
|
||||
CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP = 6,
|
||||
CONFIG_DEBUG_FROXEL_VISUALIZATION = 7,
|
||||
CONFIG_STEREO_EYE_COUNT = 8,
|
||||
};
|
||||
|
||||
// This value is limited by UBO size, ES3.0 only guarantees 16 KiB.
|
||||
@@ -76,8 +75,7 @@ constexpr size_t CONFIG_MAX_LIGHT_INDEX = CONFIG_MAX_LIGHT_COUNT - 1;
|
||||
|
||||
// The number of specialization constants that Filament reserves for its own use. These are always
|
||||
// the first constants (from 0 to CONFIG_MAX_RESERVED_SPEC_CONSTANTS - 1).
|
||||
// Updating this value necessitates a material version bump.
|
||||
constexpr size_t CONFIG_MAX_RESERVED_SPEC_CONSTANTS = 16;
|
||||
constexpr size_t CONFIG_MAX_RESERVED_SPEC_CONSTANTS = 8;
|
||||
|
||||
// The maximum number of shadowmaps.
|
||||
// There is currently a maximum limit of 128 shadowmaps.
|
||||
@@ -122,10 +120,8 @@ constexpr size_t CONFIG_MAX_BONE_COUNT = 256;
|
||||
// Furthermore, this is constrained by CONFIG_MINSPEC_UBO_SIZE (16 bytes per morph target).
|
||||
constexpr size_t CONFIG_MAX_MORPH_TARGET_COUNT = 256;
|
||||
|
||||
// The max number of eyes supported in stereoscopic mode.
|
||||
// The number of eyes actually rendered is set at Engine creation time, see
|
||||
// Engine::Config::stereoscopicEyeCount.
|
||||
constexpr uint8_t CONFIG_MAX_STEREOSCOPIC_EYES = 4;
|
||||
// The number of eyes in stereoscopic mode.
|
||||
constexpr uint8_t CONFIG_STEREOSCOPIC_EYES = 2;
|
||||
|
||||
} // namespace filament
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
using Format = backend::SamplerFormat;
|
||||
using Precision = backend::Precision;
|
||||
using SamplerParams = backend::SamplerParams;
|
||||
using SamplerTransferFunction = backend::SamplerTransferFunction;
|
||||
|
||||
struct SamplerInfo { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
utils::CString name; // name of this sampler
|
||||
@@ -55,6 +56,7 @@ public:
|
||||
Format format; // format of this sampler
|
||||
Precision precision; // precision of this sampler
|
||||
bool multisample; // multisample capable
|
||||
SamplerTransferFunction transferFunction;
|
||||
};
|
||||
|
||||
class Builder {
|
||||
@@ -73,6 +75,7 @@ public:
|
||||
Format format; // format of this sampler
|
||||
Precision precision; // precision of this sampler
|
||||
bool multisample = false; // multisample capable
|
||||
SamplerTransferFunction transferFunction;
|
||||
};
|
||||
|
||||
// Give a name to this sampler interface block
|
||||
@@ -83,7 +86,8 @@ public:
|
||||
// Add a sampler
|
||||
Builder& add(std::string_view samplerName, Type type, Format format,
|
||||
Precision precision = Precision::MEDIUM,
|
||||
bool multisample = false) noexcept;
|
||||
bool multisample = false,
|
||||
SamplerTransferFunction transferFunction = SamplerTransferFunction::UNDEFINED) noexcept;
|
||||
|
||||
// Add multiple samplers
|
||||
Builder& add(std::initializer_list<ListEntry> list) noexcept;
|
||||
|
||||
@@ -76,7 +76,7 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
math::mat4f worldFromViewMatrix; // clip view -> world : model matrix
|
||||
math::mat4f clipFromViewMatrix; // clip <- view world : projection matrix
|
||||
math::mat4f viewFromClipMatrix; // clip -> view world : inverse projection matrix
|
||||
math::mat4f clipFromWorldMatrix[CONFIG_MAX_STEREOSCOPIC_EYES]; // clip <- view <- world
|
||||
math::mat4f clipFromWorldMatrix[CONFIG_STEREOSCOPIC_EYES]; // clip <- view <- world
|
||||
math::mat4f worldFromClipMatrix; // clip -> view -> world
|
||||
math::mat4f userWorldFromWorldMatrix; // userWorld <- world
|
||||
math::float4 clipTransform; // [sx, sy, tx, ty] only used by VERTEX_DOMAIN_DEVICE
|
||||
@@ -203,7 +203,7 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
float es2Reserved2;
|
||||
|
||||
// bring PerViewUib to 2 KiB
|
||||
math::float4 reserved[40];
|
||||
math::float4 reserved[48];
|
||||
};
|
||||
|
||||
// 2 KiB == 128 float4s
|
||||
|
||||
@@ -44,10 +44,10 @@ SamplerInterfaceBlock::Builder::stageFlags(backend::ShaderStageFlags stageFlags)
|
||||
|
||||
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(
|
||||
std::string_view samplerName, Type type, Format format,
|
||||
Precision precision, bool multisample) noexcept {
|
||||
Precision precision, bool multisample, SamplerTransferFunction transferFunction) noexcept {
|
||||
mEntries.push_back({
|
||||
{ samplerName.data(), samplerName.size() }, { },
|
||||
uint8_t(mEntries.size()), type, format, precision, multisample });
|
||||
uint8_t(mEntries.size()), type, format, precision, multisample, transferFunction });
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ SamplerInterfaceBlock SamplerInterfaceBlock::Builder::build() {
|
||||
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(
|
||||
std::initializer_list<ListEntry> list) noexcept {
|
||||
for (auto& e : list) {
|
||||
add(e.name, e.type, e.format, e.precision, e.multisample);
|
||||
add(e.name, e.type, e.format, e.precision, e.multisample, e.transferFunction);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ foreach (mat_src ${MATERIAL_SRCS})
|
||||
get_filename_component(localname "${mat_src}" NAME_WE)
|
||||
get_filename_component(fullname "${mat_src}" ABSOLUTE)
|
||||
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output_path}
|
||||
COMMAND matc ${MATC_BASE_FLAGS} -o ${output_path} ${fullname}
|
||||
|
||||
@@ -31,6 +31,7 @@ using SamplerType = MaterialBuilder::SamplerType;
|
||||
using SubpassType = MaterialBuilder::SubpassType;
|
||||
using SamplerFormat = MaterialBuilder::SamplerFormat;
|
||||
using ParameterPrecision = MaterialBuilder::ParameterPrecision;
|
||||
using SamplerTransferFunction = MaterialBuilder::SamplerTransferFunction;
|
||||
using OutputTarget = MaterialBuilder::OutputTarget;
|
||||
using OutputQualifier = MaterialBuilder::VariableQualifier;
|
||||
using OutputType = MaterialBuilder::OutputType;
|
||||
@@ -75,6 +76,7 @@ private:
|
||||
static std::unordered_map<std::string, SubpassType> mStringToSubpassType;
|
||||
static std::unordered_map<std::string, SamplerFormat> mStringToSamplerFormat;
|
||||
static std::unordered_map<std::string, ParameterPrecision> mStringToSamplerPrecision;
|
||||
static std::unordered_map<std::string, SamplerTransferFunction> mStringToSamplerTransferFunction;
|
||||
static std::unordered_map<std::string, OutputTarget> mStringToOutputTarget;
|
||||
static std::unordered_map<std::string, OutputQualifier> mStringToOutputQualifier;
|
||||
static std::unordered_map<std::string, OutputType> mStringToOutputType;
|
||||
|
||||
@@ -135,7 +135,6 @@ protected:
|
||||
Optimization mOptimization = Optimization::PERFORMANCE;
|
||||
bool mPrintShaders = false;
|
||||
bool mGenerateDebugInfo = false;
|
||||
bool mIncludeEssl1 = true;
|
||||
utils::bitset32 mShaderModels;
|
||||
struct CodeGenParams {
|
||||
ShaderModel shaderModel;
|
||||
@@ -240,6 +239,7 @@ public:
|
||||
using SubpassType = filament::backend::SubpassType;
|
||||
using SamplerFormat = filament::backend::SamplerFormat;
|
||||
using ParameterPrecision = filament::backend::Precision;
|
||||
using SamplerTransferFunction = filament::backend::SamplerTransferFunction;
|
||||
using Precision = filament::backend::Precision;
|
||||
using CullingMode = filament::backend::CullingMode;
|
||||
using FeatureLevel = filament::backend::FeatureLevel;
|
||||
@@ -272,9 +272,6 @@ public:
|
||||
|
||||
MaterialBuilder& noSamplerValidation(bool enabled) noexcept;
|
||||
|
||||
//! Enable generation of ESSL 1.0 code in FL0 materials.
|
||||
MaterialBuilder& includeEssl1(bool enabled) noexcept;
|
||||
|
||||
//! Set the name of this material.
|
||||
MaterialBuilder& name(const char* name) noexcept;
|
||||
|
||||
@@ -311,11 +308,8 @@ public:
|
||||
*/
|
||||
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
|
||||
SamplerFormat format = SamplerFormat::FLOAT,
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT) noexcept;
|
||||
|
||||
/// @copydoc parameter(SamplerType, SamplerFormat, ParameterPrecision, const char*)
|
||||
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
|
||||
ParameterPrecision precision) noexcept;
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT,
|
||||
SamplerTransferFunction transferFunction = SamplerTransferFunction::UNDEFINED) noexcept;
|
||||
|
||||
|
||||
MaterialBuilder& buffer(filament::BufferInterfaceBlock bib) noexcept;
|
||||
@@ -622,16 +616,20 @@ public:
|
||||
Parameter() noexcept: parameterType(INVALID) {}
|
||||
|
||||
// Sampler
|
||||
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p)
|
||||
: name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER) { }
|
||||
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p,
|
||||
SamplerTransferFunction tf)
|
||||
: name(paramName), size(1), precision(p), samplerType(t), format(f),
|
||||
parameterType(SAMPLER), transferFunction(tf) { }
|
||||
|
||||
// Uniform
|
||||
Parameter(const char* paramName, UniformType t, size_t typeSize, ParameterPrecision p)
|
||||
: name(paramName), size(typeSize), uniformType(t), precision(p), parameterType(UNIFORM) { }
|
||||
: name(paramName), size(typeSize), uniformType(t), precision(p),
|
||||
parameterType(UNIFORM) { }
|
||||
|
||||
// Subpass
|
||||
Parameter(const char* paramName, SubpassType t, SamplerFormat f, ParameterPrecision p)
|
||||
: name(paramName), size(1), precision(p), subpassType(t), format(f), parameterType(SUBPASS) { }
|
||||
: name(paramName), size(1), precision(p), subpassType(t), format(f),
|
||||
parameterType(SUBPASS) { }
|
||||
|
||||
utils::CString name;
|
||||
size_t size;
|
||||
@@ -640,6 +638,7 @@ public:
|
||||
SamplerType samplerType;
|
||||
SubpassType subpassType;
|
||||
SamplerFormat format;
|
||||
SamplerTransferFunction transferFunction;
|
||||
enum {
|
||||
INVALID,
|
||||
UNIFORM,
|
||||
|
||||
@@ -117,6 +117,17 @@ std::unordered_map<std::string, ParameterPrecision>& Enums::getMap<ParameterPrec
|
||||
return mStringToSamplerPrecision;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, SamplerTransferFunction> Enums::mStringToSamplerTransferFunction = {
|
||||
{ "undefined", SamplerTransferFunction::UNDEFINED },
|
||||
{ "identity", SamplerTransferFunction::IDENTITY },
|
||||
{ "srgbToLinear", SamplerTransferFunction::SRGB_TO_LINEAR },
|
||||
};
|
||||
|
||||
template <>
|
||||
std::unordered_map<std::string, SamplerTransferFunction>& Enums::getMap<SamplerTransferFunction>() noexcept {
|
||||
return mStringToSamplerTransferFunction;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, OutputTarget> Enums::mStringToOutputTarget = {
|
||||
{ "color", OutputTarget::COLOR },
|
||||
{ "depth", OutputTarget::DEPTH }
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <spirv_glsl.hpp>
|
||||
#include <spirv_msl.hpp>
|
||||
|
||||
#include "backend/DriverEnums.h"
|
||||
#include "sca/builtinResource.h"
|
||||
#include "sca/GLSLTools.h"
|
||||
|
||||
@@ -33,7 +32,6 @@
|
||||
|
||||
#include "MetalArgumentBuffer.h"
|
||||
#include "SpirvFixup.h"
|
||||
#include "utils/ostream.h"
|
||||
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
@@ -397,9 +395,7 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
|
||||
break;
|
||||
case MaterialBuilder::Optimization::SIZE:
|
||||
case MaterialBuilder::Optimization::PERFORMANCE:
|
||||
if (!fullOptimization(tShader, config, internalConfig)) {
|
||||
return false;
|
||||
}
|
||||
fullOptimization(tShader, config, internalConfig);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -482,7 +478,7 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
}
|
||||
}
|
||||
|
||||
bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
|
||||
void GLSLPostProcessor::fullOptimization(const TShader& tShader,
|
||||
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const {
|
||||
SpirvBlob spirv;
|
||||
|
||||
@@ -550,29 +546,19 @@ bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
*internalConfig.glslOutput = glslCompiler.compile();
|
||||
#else
|
||||
try {
|
||||
*internalConfig.glslOutput = glslCompiler.compile();
|
||||
} catch (spirv_cross::CompilerError e) {
|
||||
slog.e << "ERROR: " << e.what() << io::endl;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// spirv-cross automatically redeclares gl_ClipDistance if it's used. Some drivers don't
|
||||
// like this, so we simply remove it.
|
||||
// According to EXT_clip_cull_distance, gl_ClipDistance can be
|
||||
// "implicitly sized by indexing it only with integral constant expressions".
|
||||
std::string& str = *internalConfig.glslOutput;
|
||||
const std::string clipDistanceDefinition = "out float gl_ClipDistance[2];";
|
||||
const std::string clipDistanceDefinition = "out float gl_ClipDistance[1];";
|
||||
size_t const found = str.find(clipDistanceDefinition);
|
||||
if (found != std::string::npos) {
|
||||
str.replace(found, clipDistanceDefinition.length(), "");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<spvtools::Optimizer> GLSLPostProcessor::createOptimizer(
|
||||
|
||||
@@ -93,7 +93,7 @@ private:
|
||||
ShaderMinifier minifier;
|
||||
};
|
||||
|
||||
bool fullOptimization(const glslang::TShader& tShader,
|
||||
void fullOptimization(const glslang::TShader& tShader,
|
||||
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const;
|
||||
|
||||
void preprocessOptimization(glslang::TShader& tShader,
|
||||
|
||||
@@ -139,13 +139,13 @@ void MaterialBuilderBase::prepare(bool vulkanSemantics,
|
||||
glTargetLanguage,
|
||||
effectiveFeatureLevel,
|
||||
});
|
||||
if (mIncludeEssl1
|
||||
&& featureLevel == filament::backend::FeatureLevel::FEATURE_LEVEL_0
|
||||
&& shaderModel == ShaderModel::MOBILE) {
|
||||
if (featureLevel == filament::backend::FeatureLevel::FEATURE_LEVEL_0
|
||||
&& shaderModel == ShaderModel::MOBILE) {
|
||||
// ESSL1 code may never be compiled to SPIR-V.
|
||||
mCodeGenPermutations.push_back({
|
||||
shaderModel,
|
||||
TargetApi::OPENGL,
|
||||
glTargetLanguage,
|
||||
TargetLanguage::GLSL,
|
||||
filament::backend::FeatureLevel::FEATURE_LEVEL_0
|
||||
});
|
||||
}
|
||||
@@ -248,19 +248,14 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, UniformType type,
|
||||
return parameter(name, 1, type, precision);
|
||||
}
|
||||
|
||||
|
||||
MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType,
|
||||
SamplerFormat format, ParameterPrecision precision) noexcept {
|
||||
SamplerFormat format, ParameterPrecision precision,
|
||||
SamplerTransferFunction transferFunction) noexcept {
|
||||
ASSERT_POSTCONDITION(mParameterCount < MAX_PARAMETERS_COUNT, "Too many parameters");
|
||||
mParameters[mParameterCount++] = { name, samplerType, format, precision };
|
||||
mParameters[mParameterCount++] = { name, samplerType, format, precision, transferFunction };
|
||||
return *this;
|
||||
}
|
||||
|
||||
MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType,
|
||||
ParameterPrecision precision) noexcept {
|
||||
return parameter(name, samplerType, SamplerFormat::FLOAT, precision);
|
||||
}
|
||||
|
||||
template<typename T, typename>
|
||||
MaterialBuilder& MaterialBuilder::constant(const char* name, ConstantType type, T defaultValue) {
|
||||
auto result = std::find_if(mConstants.begin(), mConstants.end(), [name](const Constant& c) {
|
||||
@@ -556,7 +551,8 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
|
||||
assert_invariant(!param.isSubpass());
|
||||
if (param.isSampler()) {
|
||||
sbb.add({ param.name.data(), param.name.size() },
|
||||
param.samplerType, param.format, param.precision);
|
||||
param.samplerType, param.format, param.precision, /*multisample=*/false,
|
||||
param.transferFunction);
|
||||
} else if (param.isUniform()) {
|
||||
ibb.add({{{ param.name.data(), param.name.size() },
|
||||
uint32_t(param.size == 1u ? 0u : param.size), param.uniformType,
|
||||
@@ -1421,15 +1417,15 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo&
|
||||
uniforms.push_back({
|
||||
"objectUniforms.data[0].morphTargetCount",
|
||||
offsetof(PerRenderableUib, data[0].morphTargetCount), 1,
|
||||
UniformType::INT });
|
||||
UniformType::UINT });
|
||||
uniforms.push_back({
|
||||
"objectUniforms.data[0].flagsChannels",
|
||||
offsetof(PerRenderableUib, data[0].flagsChannels), 1,
|
||||
UniformType::INT });
|
||||
UniformType::UINT });
|
||||
uniforms.push_back({
|
||||
"objectUniforms.data[0].objectId",
|
||||
offsetof(PerRenderableUib, data[0].objectId), 1,
|
||||
UniformType::INT });
|
||||
UniformType::UINT });
|
||||
uniforms.push_back({
|
||||
"objectUniforms.data[0].userData",
|
||||
offsetof(PerRenderableUib, data[0].userData), 1,
|
||||
@@ -1565,9 +1561,4 @@ MaterialBuilder& MaterialBuilder::noSamplerValidation(bool enabled) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
MaterialBuilder& MaterialBuilder::includeEssl1(bool enabled) noexcept {
|
||||
mIncludeEssl1 = enabled;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace filamat
|
||||
|
||||
@@ -65,6 +65,7 @@ void MaterialSamplerInterfaceBlockChunk::flatten(Flattener& f) {
|
||||
f.writeUint8(static_cast<uint8_t>(sInfo.format));
|
||||
f.writeUint8(static_cast<uint8_t>(sInfo.precision));
|
||||
f.writeBool(sInfo.multisample);
|
||||
f.writeUint8(static_cast<uint8_t>(sInfo.transferFunction));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,36 +151,6 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
|
||||
out << "#define FILAMENT_HAS_FEATURE_INSTANCING\n";
|
||||
}
|
||||
|
||||
// During compilation and optimization, __VERSION__ reflects the shader language version of the
|
||||
// intermediate code, not the version of the final code. spirv-cross automatically adapts
|
||||
// certain language features (e.g. fragment output) but leaves others untouched (e.g. sampler
|
||||
// functions, bit shift operations). Client code may have to make decisions based on this
|
||||
// information, so define a FILAMENT_EFFECTIVE_VERSION constant.
|
||||
const char *effective_version;
|
||||
if (mTargetLanguage == TargetLanguage::GLSL) {
|
||||
effective_version = "__VERSION__";
|
||||
} else {
|
||||
switch (mShaderModel) {
|
||||
case ShaderModel::MOBILE:
|
||||
if (mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
|
||||
effective_version = "300";
|
||||
} else {
|
||||
effective_version = "100";
|
||||
}
|
||||
break;
|
||||
case ShaderModel::DESKTOP:
|
||||
if (mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_2) {
|
||||
effective_version = "450";
|
||||
} else {
|
||||
effective_version = "410";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
generateDefine(out, "FILAMENT_EFFECTIVE_VERSION", effective_version);
|
||||
|
||||
if (stage == ShaderStage::VERTEX) {
|
||||
CodeGenerator::generateDefine(out, "FLIP_UV_ATTRIBUTE", material.flipUV);
|
||||
CodeGenerator::generateDefine(out, "LEGACY_MORPHING", material.useLegacyMorphing);
|
||||
@@ -283,13 +253,10 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
|
||||
generateSpecializationConstant(out, "CONFIG_POWER_VR_SHADER_WORKAROUNDS",
|
||||
+ReservedSpecializationConstants::CONFIG_POWER_VR_SHADER_WORKAROUNDS, false);
|
||||
|
||||
generateSpecializationConstant(out, "CONFIG_STEREO_EYE_COUNT",
|
||||
+ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT, 2);
|
||||
|
||||
// CONFIG_MAX_STEREOSCOPIC_EYES is used to size arrays and on Adreno GPUs + vulkan, this has to
|
||||
// CONFIG_STEREOSCOPIC_EYES is used to size arrays and on Adreno GPUs + vulkan, this has to
|
||||
// be explicitly, statically defined (as in #define). Otherwise (using const int for
|
||||
// example), we'd run into a GPU crash.
|
||||
out << "#define CONFIG_MAX_STEREOSCOPIC_EYES " << (int) CONFIG_MAX_STEREOSCOPIC_EYES << "\n";
|
||||
out << "#define CONFIG_STEREOSCOPIC_EYES " << (int) CONFIG_STEREOSCOPIC_EYES << "\n";
|
||||
|
||||
if (mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) {
|
||||
// On ES2 since we don't have post-processing, we need to emulate EGL_GL_COLORSPACE_KHR,
|
||||
@@ -301,9 +268,8 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
|
||||
out << '\n';
|
||||
out << SHADERS_COMMON_DEFINES_GLSL_DATA;
|
||||
|
||||
if (material.featureLevel == FeatureLevel::FEATURE_LEVEL_0 &&
|
||||
(mFeatureLevel > FeatureLevel::FEATURE_LEVEL_0
|
||||
|| mTargetLanguage == TargetLanguage::SPIRV)) {
|
||||
if (mFeatureLevel > FeatureLevel::FEATURE_LEVEL_0 &&
|
||||
material.featureLevel == FeatureLevel::FEATURE_LEVEL_0) {
|
||||
// Insert compatibility definitions for ESSL 1.0 functions which were removed in ESSL 3.0.
|
||||
|
||||
// This is the minimum required value according to the OpenGL ES Shading Language Version
|
||||
@@ -491,14 +457,11 @@ io::sstream& CodeGenerator::generateOutput(io::sstream& out, ShaderStage type,
|
||||
const char* materialTypeString = getOutputTypeName(materialOutputType);
|
||||
const char* typeString = getOutputTypeName(outputType);
|
||||
|
||||
bool generate_essl3_code = mTargetLanguage == TargetLanguage::SPIRV
|
||||
|| mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1;
|
||||
|
||||
out << "\n#define FRAG_OUTPUT" << index << " " << name.c_str();
|
||||
if (generate_essl3_code) {
|
||||
out << "\n#define FRAG_OUTPUT_AT" << index << " output_" << name.c_str();
|
||||
} else {
|
||||
if (mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) {
|
||||
out << "\n#define FRAG_OUTPUT_AT" << index << " gl_FragColor";
|
||||
} else {
|
||||
out << "\n#define FRAG_OUTPUT_AT" << index << " output_" << name.c_str();
|
||||
}
|
||||
out << "\n#define FRAG_OUTPUT_MATERIAL_TYPE" << index << " " << materialTypeString;
|
||||
out << "\n#define FRAG_OUTPUT_PRECISION" << index << " " << precisionString;
|
||||
@@ -506,7 +469,7 @@ io::sstream& CodeGenerator::generateOutput(io::sstream& out, ShaderStage type,
|
||||
out << "\n#define FRAG_OUTPUT_SWIZZLE" << index << " " << swizzleString;
|
||||
out << "\n";
|
||||
|
||||
if (generate_essl3_code) {
|
||||
if (mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
|
||||
out << "\nlayout(location=" << index << ") out " << precisionString << " "
|
||||
<< typeString << " output_" << name.c_str() << ";\n";
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
|
||||
{ "worldFromViewMatrix", 0, Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 },
|
||||
{ "clipFromViewMatrix", 0, Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 },
|
||||
{ "viewFromClipMatrix", 0, Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 },
|
||||
{ "clipFromWorldMatrix", CONFIG_MAX_STEREOSCOPIC_EYES,
|
||||
{ "clipFromWorldMatrix", CONFIG_STEREOSCOPIC_EYES,
|
||||
Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 },
|
||||
{ "worldFromClipMatrix", 0, Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 },
|
||||
{ "userWorldFromWorldMatrix",0,Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 },
|
||||
|
||||
@@ -34,7 +34,6 @@ struct Config {
|
||||
filament::camutils::Mode cameraMode = filament::camutils::Mode::ORBIT;
|
||||
bool resizeable = true;
|
||||
bool headless = false;
|
||||
int stereoscopicEyeCount = 2;
|
||||
|
||||
// Provided to indicate GPU preference for vulkan
|
||||
std::string vulkanGPUHint;
|
||||
|
||||
@@ -85,8 +85,6 @@ public:
|
||||
PostRenderCallback postRender = PostRenderCallback(),
|
||||
size_t width = 1024, size_t height = 640);
|
||||
|
||||
void reconfigureCameras() { mReconfigureCameras = true; }
|
||||
|
||||
filament::Material const* getDefaultMaterial() const noexcept { return mDefaultMaterial; }
|
||||
filament::Material const* getTransparentMaterial() const noexcept { return mTransparentMaterial; }
|
||||
IBL* getIBL() const noexcept { return mIBL.get(); }
|
||||
@@ -191,7 +189,6 @@ private:
|
||||
void fixupMouseCoordinatesForHdpi(ssize_t& x, ssize_t& y) const;
|
||||
|
||||
FilamentApp* const mFilamentApp = nullptr;
|
||||
Config mConfig;
|
||||
const bool mIsHeadless;
|
||||
|
||||
SDL_Window* mWindow = nullptr;
|
||||
@@ -254,7 +251,6 @@ private:
|
||||
float mCameraFocalLength = 28.0f;
|
||||
float mCameraNear = 0.1f;
|
||||
float mCameraFar = 100.0f;
|
||||
bool mReconfigureCameras = false;
|
||||
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
filament::backend::VulkanPlatform* mVulkanPlatform = nullptr;
|
||||
|
||||
@@ -448,11 +448,6 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback,
|
||||
preRender(mEngine, window->mViews[0]->getView(), mScene, renderer);
|
||||
}
|
||||
|
||||
if (mReconfigureCameras) {
|
||||
window->configureCamerasForWindow();
|
||||
mReconfigureCameras = false;
|
||||
}
|
||||
|
||||
if (renderer->beginFrame(window->getSwapChain())) {
|
||||
for (filament::View* offscreenView : mOffscreenViews) {
|
||||
renderer->render(offscreenView);
|
||||
@@ -573,7 +568,7 @@ void FilamentApp::initSDL() {
|
||||
|
||||
FilamentApp::Window::Window(FilamentApp* filamentApp,
|
||||
const Config& config, std::string title, size_t w, size_t h)
|
||||
: mFilamentApp(filamentApp), mConfig(config), mIsHeadless(config.headless) {
|
||||
: mFilamentApp(filamentApp), mIsHeadless(config.headless) {
|
||||
const int x = SDL_WINDOWPOS_CENTERED;
|
||||
const int y = SDL_WINDOWPOS_CENTERED;
|
||||
uint32_t windowFlags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
@@ -601,9 +596,6 @@ FilamentApp::Window::Window(FilamentApp* filamentApp,
|
||||
}
|
||||
#endif
|
||||
|
||||
Engine::Config engineConfig = {};
|
||||
engineConfig.stereoscopicEyeCount = config.stereoscopicEyeCount;
|
||||
|
||||
if (backend == Engine::Backend::VULKAN) {
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
mFilamentApp->mVulkanPlatform =
|
||||
@@ -612,14 +604,12 @@ FilamentApp::Window::Window(FilamentApp* filamentApp,
|
||||
.backend(backend)
|
||||
.platform(mFilamentApp->mVulkanPlatform)
|
||||
.featureLevel(config.featureLevel)
|
||||
.config(&engineConfig)
|
||||
.build();
|
||||
#endif
|
||||
}
|
||||
return Engine::Builder()
|
||||
.backend(backend)
|
||||
.featureLevel(config.featureLevel)
|
||||
.config(&engineConfig)
|
||||
.build();
|
||||
};
|
||||
|
||||
@@ -885,23 +875,12 @@ void FilamentApp::Window::configureCamerasForWindow() {
|
||||
|
||||
double near = mFilamentApp->mCameraNear;
|
||||
double far = mFilamentApp->mCameraFar;
|
||||
if (mMainView->getView()->getStereoscopicOptions().enabled) {
|
||||
mat4 projections[4];
|
||||
projections[0] = Camera::projection(mFilamentApp->mCameraFocalLength, 1.0, near, far);
|
||||
projections[1] = projections[0];
|
||||
// simulate foveated rendering
|
||||
projections[2] = Camera::projection(mFilamentApp->mCameraFocalLength * 2.0, 1.0, near, far);
|
||||
projections[3] = projections[2];
|
||||
mMainCamera->setCustomEyeProjection(projections, 4, projections[0], near, far);
|
||||
} else {
|
||||
mMainCamera->setLensProjection(mFilamentApp->mCameraFocalLength, 1.0, near, far);
|
||||
}
|
||||
mMainCamera->setLensProjection(mFilamentApp->mCameraFocalLength, 1.0, near, far);
|
||||
mDebugCamera->setProjection(45.0, double(width) / height, 0.0625, 4096, Camera::Fov::VERTICAL);
|
||||
|
||||
auto aspectRatio = double(mainWidth) / height;
|
||||
if (mMainView->getView()->getStereoscopicOptions().enabled) {
|
||||
const int ec = mConfig.stereoscopicEyeCount;
|
||||
aspectRatio = double(mainWidth) / ec / height;
|
||||
aspectRatio = double(mainWidth) / 2.0 / height;
|
||||
}
|
||||
mMainCamera->setScaling({1.0 / aspectRatio, 1.0});
|
||||
|
||||
|
||||
@@ -176,11 +176,6 @@ if (WEBGL_PTHREADS)
|
||||
target_compile_definitions(gltfio_core PUBLIC -DFILAMENT_WASM_THREADS)
|
||||
endif()
|
||||
|
||||
set(GLTFIO_WARNINGS -Wall -Werror)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(gltfio_core PRIVATE ${GLTFIO_WARNINGS})
|
||||
endif()
|
||||
|
||||
if (NOT WEBGL AND NOT ANDROID AND NOT IOS)
|
||||
|
||||
# ==================================================================================================
|
||||
@@ -190,6 +185,10 @@ if (NOT WEBGL AND NOT ANDROID AND NOT IOS)
|
||||
target_link_libraries(${TARGET} PUBLIC filamat gltfio_core)
|
||||
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Libs)
|
||||
|
||||
# ==================================================================================================
|
||||
# Compiler flags
|
||||
# ==================================================================================================
|
||||
if (NOT MSVC)
|
||||
target_compile_options(${TARGET} PRIVATE -Wno-deprecated-register)
|
||||
endif()
|
||||
@@ -230,7 +229,7 @@ if (TNT_DEV AND NOT WEBGL AND NOT ANDROID AND NOT IOS)
|
||||
|
||||
target_link_libraries(${TEST_TARGET} PRIVATE ${TARGET} gtest uberarchive)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(${TEST_TARGET} PRIVATE ${GLTFIO_WARNINGS})
|
||||
target_compile_options(${TEST_TARGET} PRIVATE -Wno-deprecated-register)
|
||||
endif()
|
||||
set_target_properties(${TEST_TARGET} PROPERTIES FOLDER Tests)
|
||||
endif()
|
||||
|
||||
@@ -69,12 +69,9 @@ class UTILS_PUBLIC ResourceLoader {
|
||||
public:
|
||||
using BufferDescriptor = filament::backend::BufferDescriptor;
|
||||
|
||||
explicit ResourceLoader(const ResourceConfiguration& config);
|
||||
ResourceLoader(const ResourceConfiguration& config);
|
||||
~ResourceLoader();
|
||||
|
||||
|
||||
void setConfiguration(const ResourceConfiguration& config);
|
||||
|
||||
/**
|
||||
* Feeds the binary content of an external resource into the loader's URI cache.
|
||||
*
|
||||
@@ -157,6 +154,7 @@ public:
|
||||
private:
|
||||
bool loadResources(FFilamentAsset* asset, bool async);
|
||||
void normalizeSkinningWeights(FFilamentAsset* asset) const;
|
||||
AssetPool* mPool;
|
||||
struct Impl;
|
||||
Impl* pImpl;
|
||||
};
|
||||
|
||||
@@ -118,6 +118,21 @@ Material* ArchiveCache::getMaterial(const ArchiveRequirements& reqs) {
|
||||
mMaterials[i] = Material::Builder()
|
||||
.package(spec.package, spec.packageByteCount)
|
||||
.build(mEngine);
|
||||
|
||||
// Don't attempt to precompile shaders on WebGL.
|
||||
// Chrome already suffers from slow shader compilation:
|
||||
// https://github.com/google/filament/issues/6615
|
||||
// Precompiling shaders exacerbates the problem.
|
||||
#if !defined(__EMSCRIPTEN__)
|
||||
// First compile high priority variants
|
||||
mMaterials[i]->compile(Material::CompilerPriorityQueue::HIGH,
|
||||
UserVariantFilterBit::DIRECTIONAL_LIGHTING |
|
||||
UserVariantFilterBit::DYNAMIC_LIGHTING |
|
||||
UserVariantFilterBit::SHADOW_RECEIVER);
|
||||
|
||||
// and then, everything else at low priority
|
||||
mMaterials[i]->compile(Material::CompilerPriorityQueue::LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
return mMaterials[i];
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/EntityManager.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Log.h>
|
||||
@@ -769,6 +768,7 @@ void FAssetLoader::createRenderable(const cgltf_node* node, Entity entity, const
|
||||
|
||||
void FAssetLoader::createMaterialVariants(const cgltf_mesh* mesh, Entity entity,
|
||||
FFilamentAsset* fAsset, FFilamentInstance* instance) {
|
||||
const cgltf_data* srcAsset = fAsset->mSourceAsset->hierarchy;
|
||||
UvMap uvmap {};
|
||||
for (cgltf_size prim = 0, n = mesh->primitives_count; prim < n; ++prim) {
|
||||
const cgltf_primitive& srcPrim = mesh->primitives[prim];
|
||||
@@ -1076,7 +1076,7 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive& inPrim, const char* na
|
||||
.build(mEngine);
|
||||
outPrim->targets = targets;
|
||||
fAsset->mMorphTargetBuffers.push_back(targets);
|
||||
UTILS_UNUSED_IN_RELEASE cgltf_accessor const* previous = nullptr;
|
||||
const cgltf_accessor* previous = nullptr;
|
||||
for (int tindex = 0; tindex < targetsCount; ++tindex) {
|
||||
const cgltf_morph_target& inTarget = inPrim.targets[tindex];
|
||||
for (cgltf_size aindex = 0; aindex < inTarget.attributes_count; ++aindex) {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <draco/compression/decode.h>
|
||||
#endif
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#if GLTFIO_DRACO_SUPPORTED
|
||||
@@ -66,7 +65,7 @@ DracoMesh::~DracoMesh() {
|
||||
}
|
||||
|
||||
// Gets the number of components in the given cgltf vector type, or -1 for matrices.
|
||||
UTILS_UNUSED_IN_RELEASE static int getNumComponents(cgltf_type ctype) {
|
||||
static int getNumComponents(cgltf_type ctype) {
|
||||
return ((int) ctype) <= 4 ? ((int) ctype) : -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace utils {
|
||||
|
||||
namespace filament::gltfio {
|
||||
|
||||
struct Wireframe;
|
||||
class Wireframe;
|
||||
|
||||
// Encapsulates VertexBuffer::setBufferAt() or IndexBuffer::setBuffer().
|
||||
struct BufferSlot {
|
||||
|
||||
@@ -116,7 +116,7 @@ Texture* Ktx2Provider::pushTexture(const uint8_t* data, size_t byteCount,
|
||||
}
|
||||
|
||||
JobSystem* js = &mEngine->getJobSystem();
|
||||
item->job = jobs::createJob(*js, mDecoderRootJob, [item] {
|
||||
item->job = jobs::createJob(*js, mDecoderRootJob, [this, item] {
|
||||
using Result = ktxreader::Ktx2Reader::Result;
|
||||
const bool success = Result::SUCCESS == item->async->doTranscoding();
|
||||
item->transcoderState.store(success ? TranscoderState::SUCCESS : TranscoderState::ERROR);
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
#include <geometry/Transcoder.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Systrace.h>
|
||||
@@ -75,15 +74,15 @@ enum class CacheResult {
|
||||
};
|
||||
|
||||
struct ResourceLoader::Impl {
|
||||
explicit Impl(const ResourceConfiguration& config) :
|
||||
Impl(const ResourceConfiguration& config) :
|
||||
mEngine(config.engine),
|
||||
mNormalizeSkinningWeights(config.normalizeSkinningWeights),
|
||||
mGltfPath(config.gltfPath ? config.gltfPath : ""),
|
||||
mUriDataCache(std::make_shared<UriDataCache>()) {}
|
||||
|
||||
Engine* const mEngine;
|
||||
bool mNormalizeSkinningWeights;
|
||||
std::string mGltfPath;
|
||||
const bool mNormalizeSkinningWeights;
|
||||
const std::string mGltfPath;
|
||||
|
||||
// User-provided resource data with URI string keys, populated with addResourceData().
|
||||
// This is used on platforms without traditional file systems, such as Android, iOS, and WebGL.
|
||||
@@ -244,7 +243,7 @@ static void decodeMeshoptCompression(cgltf_data* data) {
|
||||
void* destination = malloc(compression->count * compression->stride);
|
||||
assert_invariant(destination);
|
||||
|
||||
UTILS_UNUSED_IN_RELEASE int error = 0;
|
||||
int error = 0;
|
||||
switch (compression->mode) {
|
||||
case cgltf_meshopt_compression_mode_invalid:
|
||||
break;
|
||||
@@ -321,11 +320,6 @@ ResourceLoader::~ResourceLoader() {
|
||||
delete pImpl;
|
||||
}
|
||||
|
||||
void ResourceLoader::setConfiguration(const ResourceConfiguration& config) {
|
||||
pImpl->mNormalizeSkinningWeights = config.normalizeSkinningWeights;
|
||||
pImpl->mGltfPath = config.gltfPath;
|
||||
}
|
||||
|
||||
void ResourceLoader::addResourceData(const char* uri, BufferDescriptor&& buffer) {
|
||||
pImpl->addResourceData(uri, std::move(buffer));
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ Texture* StbProvider::pushTexture(const uint8_t* data, size_t byteCount,
|
||||
}
|
||||
|
||||
JobSystem* js = &mEngine->getJobSystem();
|
||||
info->decoderJob = jobs::createJob(*js, mDecoderRootJob, [info] {
|
||||
info->decoderJob = jobs::createJob(*js, mDecoderRootJob, [this, info] {
|
||||
auto& source = info->sourceBuffer;
|
||||
int width, height, comp;
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ using namespace backend;
|
||||
using namespace gltfio;
|
||||
using namespace utils;
|
||||
|
||||
constexpr uint32_t WIDTH = 64;
|
||||
constexpr uint32_t HEIGHT = 64;
|
||||
|
||||
char const* ANIMATED_MORPH_CUBE_GLB = "AnimatedMorphCube.glb";
|
||||
|
||||
static std::ifstream::pos_type getFileSize(const char* filename) {
|
||||
@@ -175,6 +178,7 @@ do { \
|
||||
TEST_F(glTFIOTest, AnimatedMorphCubeTransforms) {
|
||||
FilamentAsset const& morphCubeAsset = *mData[ANIMATED_MORPH_CUBE_GLB]->getAsset();
|
||||
auto const& transformManager = mEngine->getTransformManager();
|
||||
auto const& renderableManager = mEngine->getRenderableManager();
|
||||
Entity const* renderables = morphCubeAsset.getRenderableEntities();
|
||||
|
||||
EXPECT_EQ(morphCubeAsset.getRenderableEntityCount(), 1u);
|
||||
|
||||
@@ -60,7 +60,7 @@ private:
|
||||
// This variable is to implement a *hanging* effect for /api/status. The call to /api/status
|
||||
// will always block until statusMaterialId is updated again. The client is expected to keep
|
||||
// calling /api/status (a constant "pull" to simulate a push).
|
||||
std::atomic<uint64_t> mCurrentStatus = 0;
|
||||
std::atomic_uint64_t mCurrentStatus = 0;
|
||||
};
|
||||
|
||||
} // filament::matdbg
|
||||
|
||||
@@ -127,19 +127,3 @@ async function statusLoop(isConnected, onStatus) {
|
||||
setTimeout(() => statusLoop(isConnected, onStatus), STATUS_LOOP_TIMEOUT)
|
||||
}
|
||||
}
|
||||
|
||||
// Use browser User-agent to guess the current backend. This is mainly for matinfo which does
|
||||
// not have a running backend.
|
||||
function guessBackend() {
|
||||
const AGENTS_TO_BACKEND = [
|
||||
['Mac OS', 'metal'],
|
||||
['Windows', 'opengl'],
|
||||
['Linux', 'vulkan'],
|
||||
];
|
||||
|
||||
const result = AGENTS_TO_BACKEND.filter((agent_backend) => {
|
||||
return window.navigator.userAgent.search(agent_backend[0]);
|
||||
}).map((agent_backend) => agent_backend[1]);
|
||||
|
||||
return result.length > 0 ? result[0] : null;
|
||||
}
|
||||
|
||||
+65
-237
@@ -25,8 +25,6 @@ const LANGUAGE_CHOICES = {
|
||||
'metal': ['msl'],
|
||||
};
|
||||
|
||||
const BACKENDS = Object.keys(LANGUAGE_CHOICES);
|
||||
|
||||
const MATERIAL_INFO_KEY_TO_STRING = {
|
||||
'model': 'shading model',
|
||||
'vertex_domain': 'vertex domain',
|
||||
@@ -56,6 +54,19 @@ const BACKGROUND_COLOR = '#5362e5';
|
||||
const HOVER_BACKGROUND_COLOR = '#b3c2ff';
|
||||
const CODE_VIEWER_BOTTOM_ROW_HEIGHT = 60;
|
||||
const REGULAR_FONT_SIZE = 12;
|
||||
const MENU_HR = `
|
||||
display: block;
|
||||
height: 1px;
|
||||
border: 0px;
|
||||
border-top: 1px solid ${UNSELECTED_COLOR};
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
margin: 3px 0 8px 0;
|
||||
`;
|
||||
const MENU_SECTION_TITLE = `
|
||||
font-size: 16px;
|
||||
color: ${UNSELECTED_COLOR};
|
||||
`;
|
||||
|
||||
// Set up the Monaco editor. See also CodeViewer
|
||||
const kMonacoBaseUrl = 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.25.2/min/';
|
||||
@@ -74,14 +85,6 @@ window.MonacoEnvironment = {
|
||||
}
|
||||
};
|
||||
|
||||
const _validDict = (obj) => {
|
||||
return obj && Object.keys(obj) > 0;
|
||||
}
|
||||
|
||||
const _isMatInfoMode = (database) => {
|
||||
return Object.keys(database).length == 1;
|
||||
}
|
||||
|
||||
class Button extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
@@ -219,19 +222,11 @@ class CodeViewer extends LitElement {
|
||||
scrollBeyondLastLine: false,
|
||||
readOnly: false,
|
||||
minimap: { enabled: false },
|
||||
automaticLayout: true,
|
||||
|
||||
// Workaround see https://github.com/microsoft/monaco-editor/issues/3217
|
||||
fontLigatures: '',
|
||||
automaticLayout: true
|
||||
});
|
||||
const KeyMod = monaco.KeyMod, KeyCode = monaco.KeyCode;
|
||||
this.editor.onDidChangeModelContent(this._onEdit.bind(this));
|
||||
this.editor.addCommand(KeyMod.CtrlCmd | KeyCode.KEY_S, this._rebuild.bind(this));
|
||||
|
||||
// It might be that the code is available before the editor has been created.
|
||||
if (this.code && this.code.length > 0) {
|
||||
this.editor.setValue(this.code);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -259,17 +254,13 @@ class CodeViewer extends LitElement {
|
||||
|
||||
updated(props) {
|
||||
if (props.has('code') && this.code.length > 0) {
|
||||
// Note that the prop might have been updated before the editor is available.
|
||||
if (this.editor) {
|
||||
this.editor.setValue(this.code);
|
||||
}
|
||||
this.editor.setValue(this.code);
|
||||
}
|
||||
if ((props.has('expectedWidth') || props.has('expectedHeight')) &&
|
||||
(this.expectedWidth > 0 && (this.expectedHeight - CODE_VIEWER_BOTTOM_ROW_HEIGHT) > 0)) {
|
||||
const actualWidth = Math.floor(this.expectedWidth);
|
||||
const actualHeight = (Math.floor(this.expectedHeight) - CODE_VIEWER_BOTTOM_ROW_HEIGHT);
|
||||
this._editorDiv.style.width = actualWidth + 'px';
|
||||
this._editorDiv.style.height = actualHeight + 'px';
|
||||
this._editorDiv.style.width = Math.floor(this.expectedWidth) + 'px';
|
||||
this._editorDiv.style.height =
|
||||
(Math.floor(this.expectedHeight) - CODE_VIEWER_BOTTOM_ROW_HEIGHT) + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,12 +311,12 @@ class CodeViewer extends LitElement {
|
||||
}
|
||||
customElements.define("code-viewer", CodeViewer);
|
||||
|
||||
class MenuSection extends LitElement {
|
||||
class MaterialInfo extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
info: {type: Object, state: true},
|
||||
showing: {type: Boolean, state: true},
|
||||
title: {type: String, attribute: 'title'},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
@@ -333,23 +324,18 @@ class MenuSection extends LitElement {
|
||||
:host {
|
||||
font-size: ${unsafeCSS(REGULAR_FONT_SIZE)}px;
|
||||
color: ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
}
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
color: ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
cursor: pointer;
|
||||
}
|
||||
.container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.section-title {
|
||||
${unsafeCSS(MENU_SECTION_TITLE)}
|
||||
cursor: pointer;
|
||||
}
|
||||
hr {
|
||||
display: block;
|
||||
height: 1px;
|
||||
border: 0px;
|
||||
border-top: 1px solid ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
margin: 3px 0 8px 0;
|
||||
${unsafeCSS(MENU_HR)}
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
}
|
||||
.expander {
|
||||
display: flex;
|
||||
@@ -360,48 +346,9 @@ class MenuSection extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
_showClick() {
|
||||
this.showing = !this.showing;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.showing = true;
|
||||
}
|
||||
|
||||
render() {
|
||||
const expandedIcon = this.showing ? '-' : '+';
|
||||
const slot = (() => html`<slot></slot>`)();
|
||||
return html`
|
||||
<div class="container">
|
||||
<div class="section-title expander" @click="${this._showClick}">
|
||||
<span>${this.title}</span> <span>${expandedIcon}</span>
|
||||
</div>
|
||||
<hr />
|
||||
${this.showing ? slot : []}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('menu-section', MenuSection);
|
||||
|
||||
class MaterialInfo extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
info: {type: Object, state: true},
|
||||
};
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
:host {
|
||||
font-size: ${unsafeCSS(REGULAR_FONT_SIZE)}px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.info = null;
|
||||
}
|
||||
|
||||
@@ -409,7 +356,12 @@ class MaterialInfo extends LitElement {
|
||||
return this.info && Object.keys(this.info).length > 0;
|
||||
}
|
||||
|
||||
_showClick() {
|
||||
this.showing = !this.showing;
|
||||
}
|
||||
|
||||
render() {
|
||||
const expandedIcon = this._hasInfo() ? (this.showing ? '-' : '+') : '';
|
||||
let infoDivs = [];
|
||||
if (this._hasInfo()) {
|
||||
if (this.info.shading && this.info.shading.material_domain === 'surface') {
|
||||
@@ -435,122 +387,22 @@ class MaterialInfo extends LitElement {
|
||||
);
|
||||
}
|
||||
}
|
||||
const shouldHide = infoDivs.length == 0;
|
||||
if (infoDivs.length > 0) {
|
||||
return html`
|
||||
<menu-section title="Material Details">
|
||||
${infoDivs}
|
||||
</menu-section>
|
||||
`;
|
||||
let divClass = 'container';
|
||||
if (infoDivs.length == 0) {
|
||||
divClass += ' hide';
|
||||
}
|
||||
return html``;
|
||||
}
|
||||
}
|
||||
customElements.define('material-info', MaterialInfo);
|
||||
|
||||
class AdvancedOptions extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
currentBackend: {type: String, attribute: 'current-backend'},
|
||||
availableBackends: {type: Array, state: true},
|
||||
};
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
:host {
|
||||
font-size: ${unsafeCSS(REGULAR_FONT_SIZE)}px;
|
||||
}
|
||||
.option {
|
||||
border: 1px solid ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
border-radius: 5px;
|
||||
padding: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
}
|
||||
label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 5px;
|
||||
}
|
||||
label input {
|
||||
margin: 0 4px 0 0;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
}
|
||||
.option-heading {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
get _backendOptionForm() {
|
||||
return this.renderRoot.querySelector('#backend-option-form');
|
||||
}
|
||||
|
||||
updated(props) {
|
||||
if (props.has('currentBackend') || props.has('availableBackends')) {
|
||||
// Clear the radio button selections. The correct option will be selected
|
||||
// in _backendOption().
|
||||
if (this._backendOptionForm) {
|
||||
this._backendOptionForm.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_backendOption() {
|
||||
if (this.availableBackends.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const onChange = (ev) => {
|
||||
const backend = ev.currentTarget.getAttribute('name');
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(
|
||||
'option-backend',
|
||||
{detail: backend, bubbles: true, composed: true}));
|
||||
}
|
||||
const div = this.availableBackends.map((backend) => {
|
||||
const selected = backend == this.currentBackend;
|
||||
return html`
|
||||
<label>
|
||||
<input type="radio" name="${backend}"
|
||||
?checked=${selected} @change=${onChange}/>
|
||||
${backend}
|
||||
</label>
|
||||
`;
|
||||
});
|
||||
|
||||
return html`
|
||||
<div class="option">
|
||||
<div class="option-heading">Current Backend</div>
|
||||
<form action="" id="backend-option-form">
|
||||
${div}
|
||||
</form>
|
||||
<div class="${divClass}">
|
||||
<div class="section-title expander" @click="${this._showClick}">
|
||||
<span>Material Details</span> <span>${expandedIcon}</span>
|
||||
</div>
|
||||
<hr />
|
||||
${this.showing ? infoDivs : []}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.availableBackends = [];
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<menu-section title="Advanced Options">
|
||||
${this._backendOption() ?? nothing}
|
||||
</menu-section>
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('advanced-options', AdvancedOptions);
|
||||
|
||||
customElements.define('material-info', MaterialInfo);
|
||||
|
||||
class MaterialSidePanel extends LitElement {
|
||||
// Setting the style in render() has poor performance implications. We use it simply to avoid
|
||||
@@ -572,6 +424,9 @@ class MaterialSidePanel extends LitElement {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
.material-section {
|
||||
${MENU_SECTION_TITLE}
|
||||
}
|
||||
.materials {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -603,6 +458,9 @@ class MaterialSidePanel extends LitElement {
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
}
|
||||
hr {
|
||||
${MENU_HR}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -626,10 +484,6 @@ class MaterialSidePanel extends LitElement {
|
||||
return this.renderRoot.querySelector('#material-info');
|
||||
}
|
||||
|
||||
get _advancedOptions() {
|
||||
return this.renderRoot.querySelector('#advanced-options');
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.connected = false;
|
||||
@@ -674,9 +528,9 @@ class MaterialSidePanel extends LitElement {
|
||||
});
|
||||
}
|
||||
if (props.has('currentMaterial')) {
|
||||
if (this.currentBackend && this.database && this.currentMaterial) {
|
||||
if (this.currentBackend && this.database && this.activeShaders && this.currentMaterial) {
|
||||
const material = this.database[this.currentMaterial];
|
||||
const activeVariants = _validDict(this.activeShaders) ? this.activeShaders[this.currentMaterial].variants : [];
|
||||
const activeVariants = this.activeShaders[this.currentMaterial].variants;
|
||||
const materialShaders = material[this.currentBackend];
|
||||
let variants = [];
|
||||
for (const [index, shader] of materialShaders.entries()) {
|
||||
@@ -692,11 +546,6 @@ class MaterialSidePanel extends LitElement {
|
||||
if (this.currentMaterial && this.database) {
|
||||
const material = this.database[this.currentMaterial];
|
||||
this._materialInfo.info = material;
|
||||
|
||||
// The matinfo usecase
|
||||
if (_isMatInfoMode(this.database)) {
|
||||
this._advancedOptions.availableBackends = BACKENDS.filter((backend) => !!material[backend]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -801,29 +650,23 @@ class MaterialSidePanel extends LitElement {
|
||||
${shaderDiv ?? nothing}
|
||||
`;
|
||||
});
|
||||
if (mats.length > 0) {
|
||||
return html`<menu-section title="${title}">${mats}</menu-section>`;
|
||||
}
|
||||
return null;
|
||||
return html`
|
||||
<div class="materials">
|
||||
<div class="material-section">
|
||||
${title}
|
||||
</div>
|
||||
<hr />
|
||||
${mats}
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
let advancedOptions = null;
|
||||
// Currently we only have one advanced option and it's only for when we're in matinfo
|
||||
if (_isMatInfoMode(this.database)) {
|
||||
advancedOptions =
|
||||
(() => html`
|
||||
<advanced-options id="advanced-options"
|
||||
current-backend=${this.currentBackend}></advanced-options>
|
||||
`)();
|
||||
}
|
||||
|
||||
return html`
|
||||
<style>${this.dynamicStyle()}</style>
|
||||
<div class="container">
|
||||
<div class="title">matdbg</div>
|
||||
${sections("Surface", "surface") ?? nothing}
|
||||
${sections("Post-processing", "postpro") ?? nothing}
|
||||
${sections("Surface", "surface")}
|
||||
${sections("Post-processing", "postpro")}
|
||||
<material-info id="material-info"></material-info>
|
||||
${advancedOptions ?? nothing}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -951,12 +794,6 @@ class MatdbgViewer extends LitElement {
|
||||
}
|
||||
);
|
||||
|
||||
this.addEventListener('option-backend',
|
||||
(ev) => {
|
||||
this.currentBackend = ev.detail;
|
||||
}
|
||||
);
|
||||
|
||||
addEventListener('resize', this._onResize.bind(this));
|
||||
}
|
||||
|
||||
@@ -1038,7 +875,7 @@ class MatdbgViewer extends LitElement {
|
||||
material.active = material.active || shader.active;
|
||||
}
|
||||
}
|
||||
if (_validDict(this.activeShaders)) {
|
||||
if (this.activeShaders) {
|
||||
let backends = {};
|
||||
for (let matid in this.activeShaders) {
|
||||
const backend = this.activeShaders[matid].backend;
|
||||
@@ -1052,9 +889,6 @@ class MatdbgViewer extends LitElement {
|
||||
if (backendList.length > 0) {
|
||||
this.currentBackend = backendList[0];
|
||||
}
|
||||
} else if (!this.currentBackend) {
|
||||
// Make a guess on the backend if one wasn't from activeShaders.
|
||||
this.currentBackend = guessBackend();
|
||||
}
|
||||
|
||||
this._sidepanel.database = this.database;
|
||||
@@ -1067,12 +901,6 @@ class MatdbgViewer extends LitElement {
|
||||
this.database[matInfo.matid] = matInfo;
|
||||
this.database = this.database;
|
||||
}
|
||||
|
||||
// In the `matinfo -w` usecase, we assume the current material to be the only
|
||||
// material available in the database.
|
||||
if (_isMatInfoMode(this.database)) {
|
||||
this.currentMaterial = Object.keys(this.database)[0];
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
/* compound assignment products by a scalar
|
||||
*/
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
template<typename U>
|
||||
constexpr QUATERNION<T>& operator*=(U v) {
|
||||
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
|
||||
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
template<typename U>
|
||||
constexpr QUATERNION<T>& operator/=(U v) {
|
||||
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
|
||||
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
|
||||
@@ -125,25 +125,25 @@ public:
|
||||
* q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w);
|
||||
*
|
||||
*/
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(QUATERNION<T> q, U scalar) {
|
||||
// don't pass q by reference because we need a copy anyway
|
||||
return QUATERNION<arithmetic_result_t<T, U>>(q *= scalar);
|
||||
return q *= scalar;
|
||||
}
|
||||
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(U scalar, QUATERNION<T> q) {
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(T scalar, QUATERNION<U> q) {
|
||||
// don't pass q by reference because we need a copy anyway
|
||||
return QUATERNION<arithmetic_result_t<T, U>>(q *= scalar);
|
||||
return q *= scalar;
|
||||
}
|
||||
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator/(QUATERNION<T> q, U scalar) {
|
||||
// don't pass q by reference because we need a copy anyway
|
||||
return QUATERNION<arithmetic_result_t<T, U>>(q /= scalar);
|
||||
return q /= scalar;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <math.h>
|
||||
#include <random>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -325,103 +324,3 @@ TEST_F(QuatTest, NaN) {
|
||||
EXPECT_NEAR(qs[2], 0.5, 0.1);
|
||||
EXPECT_NEAR(qs[3], 0.5, 0.1);
|
||||
}
|
||||
|
||||
TEST_F(QuatTest, Conversions) {
|
||||
quat qd;
|
||||
quatf qf;
|
||||
float3 vf;
|
||||
double3 vd;
|
||||
double d = 0.0;
|
||||
float f = 0.0f;
|
||||
|
||||
static_assert(std::is_same<details::arithmetic_result_t<float, float>, float>::value);
|
||||
static_assert(std::is_same<details::arithmetic_result_t<float, double>, double>::value);
|
||||
static_assert(std::is_same<details::arithmetic_result_t<double, float>, double>::value);
|
||||
static_assert(std::is_same<details::arithmetic_result_t<double, double>, double>::value);
|
||||
|
||||
{
|
||||
auto r1 = qd * d;
|
||||
auto r2 = qd * f;
|
||||
auto r3 = qf * d;
|
||||
auto r4 = qf * f;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = qd / d;
|
||||
auto r2 = qd / f;
|
||||
auto r3 = qf / d;
|
||||
auto r4 = qf / f;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = d * qd;
|
||||
auto r2 = f * qd;
|
||||
auto r3 = d * qf;
|
||||
auto r4 = f * qf;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = qd * vd;
|
||||
auto r2 = qf * vd;
|
||||
auto r3 = qd * vf;
|
||||
auto r4 = qf * vf;
|
||||
static_assert(std::is_same<decltype(r1), double3>::value);
|
||||
static_assert(std::is_same<decltype(r2), double3>::value);
|
||||
static_assert(std::is_same<decltype(r3), double3>::value);
|
||||
static_assert(std::is_same<decltype(r4), float3>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = qd * qd;
|
||||
auto r2 = qf * qd;
|
||||
auto r3 = qd * qf;
|
||||
auto r4 = qf * qf;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = dot(qd, qd);
|
||||
auto r2 = dot(qf, qd);
|
||||
auto r3 = dot(qd, qf);
|
||||
auto r4 = dot(qf, qf);
|
||||
static_assert(std::is_same<decltype(r1), double>::value);
|
||||
static_assert(std::is_same<decltype(r2), double>::value);
|
||||
static_assert(std::is_same<decltype(r3), double>::value);
|
||||
static_assert(std::is_same<decltype(r4), float>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = cross(qd, qd);
|
||||
auto r2 = cross(qf, qd);
|
||||
auto r3 = cross(qd, qf);
|
||||
auto r4 = cross(qf, qf);
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename L, typename R, typename = void>
|
||||
struct has_divide_assign : std::false_type {};
|
||||
|
||||
template <typename L, typename R>
|
||||
struct has_divide_assign<L, R,
|
||||
decltype(std::declval<L&>() /= std::declval<R>(), void())> : std::true_type {};
|
||||
|
||||
// Static assertions to validate the availability of the /= operator for specific type
|
||||
// combinations. The first static_assert checks that the quat does not have a /= operator with Foo.
|
||||
// This ensures that quat does not provide an inappropriate overload that could be erroneously
|
||||
// selected.
|
||||
struct Foo {};
|
||||
static_assert(!has_divide_assign<quat, Foo>::value);
|
||||
static_assert(has_divide_assign<quat, float>::value);
|
||||
|
||||
@@ -169,9 +169,8 @@ public:
|
||||
// the caller must ensure the object will outlive the Job
|
||||
template<typename T, void(T::*method)(JobSystem&, Job*)>
|
||||
Job* createJob(Job* parent, T* data) noexcept {
|
||||
Job* job = create(parent, +[](void* storage, JobSystem& js, Job* job) {
|
||||
T* const that = static_cast<T*>(reinterpret_cast<void**>(storage)[0]);
|
||||
(that->*method)(js, job);
|
||||
Job* job = create(parent, [](void* user, JobSystem& js, Job* job) {
|
||||
(*static_cast<T**>(user)->*method)(js, job);
|
||||
});
|
||||
if (job) {
|
||||
job->storage[0] = data;
|
||||
@@ -183,8 +182,8 @@ public:
|
||||
template<typename T, void(T::*method)(JobSystem&, Job*)>
|
||||
Job* createJob(Job* parent, T data) noexcept {
|
||||
static_assert(sizeof(data) <= sizeof(Job::storage), "user data too large");
|
||||
Job* job = create(parent, [](void* storage, JobSystem& js, Job* job) {
|
||||
T* const that = static_cast<T*>(storage);
|
||||
Job* job = create(parent, [](void* user, JobSystem& js, Job* job) {
|
||||
T* that = static_cast<T*>(user);
|
||||
(that->*method)(js, job);
|
||||
that->~T();
|
||||
});
|
||||
@@ -198,10 +197,10 @@ public:
|
||||
template<typename T>
|
||||
Job* createJob(Job* parent, T functor) noexcept {
|
||||
static_assert(sizeof(functor) <= sizeof(Job::storage), "functor too large");
|
||||
Job* job = create(parent, [](void* storage, JobSystem& js, Job* job){
|
||||
T* const that = static_cast<T*>(storage);
|
||||
that->operator()(js, job);
|
||||
that->~T();
|
||||
Job* job = create(parent, [](void* user, JobSystem& js, Job* job){
|
||||
T& that = *static_cast<T*>(user);
|
||||
that(js, job);
|
||||
that.~T();
|
||||
});
|
||||
if (job) {
|
||||
new(job->storage) T(std::move(functor));
|
||||
@@ -253,7 +252,7 @@ public:
|
||||
void signal() noexcept;
|
||||
|
||||
/*
|
||||
* Add job to this thread's execution queue and keep a reference to it.
|
||||
* Add job to this thread's execution queue and and keep a reference to it.
|
||||
* Current thread must be owned by JobSystem's thread pool. See adopt().
|
||||
*
|
||||
* This job MUST BE waited on with wait(), or released with release().
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace utils {
|
||||
|
||||
// we use a non-inlined, not marked as "no return" function for aborting so that we can set
|
||||
|
||||
+42
-145
@@ -41,8 +41,6 @@
|
||||
|
||||
#include <camutils/Manipulator.h>
|
||||
|
||||
#include <private/filament/EngineEnums.h>
|
||||
|
||||
#include <getopt/getopt.h>
|
||||
|
||||
#include <utils/NameComponentManager.h>
|
||||
@@ -55,12 +53,9 @@
|
||||
#include <imgui.h>
|
||||
#include <filagui/ImGuiExtensions.h>
|
||||
|
||||
#include <cgltf.h>
|
||||
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "generated/resources/gltf_demo.h"
|
||||
@@ -183,13 +178,10 @@ static void printUsage(char* name) {
|
||||
" Set the camera mode: orbit (default) or flight\n"
|
||||
" Flight mode uses the following controls:\n"
|
||||
" Click and drag the mouse to pan the camera\n"
|
||||
" Use the scroll wheel to adjust movement speed\n"
|
||||
" Use the scroll weel to adjust movement speed\n"
|
||||
" W / S: forward / backward\n"
|
||||
" A / D: left / right\n"
|
||||
" E / Q: up / down\n\n"
|
||||
" --eyes=<stereoscopic eyes>, -y <stereoscopic eyes>\n"
|
||||
" Sets the number of stereoscopic eyes (default: 2) when stereoscopic rendering is\n"
|
||||
" enabled.\n\n"
|
||||
" --split-view, -v\n"
|
||||
" Splits the window into 4 views\n\n"
|
||||
" --vulkan-gpu-hint=<hint>, -g\n"
|
||||
@@ -221,7 +213,6 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) {
|
||||
{ "ubershader", no_argument, nullptr, 'u' },
|
||||
{ "actual-size", no_argument, nullptr, 's' },
|
||||
{ "camera", required_argument, nullptr, 'c' },
|
||||
{ "eyes", required_argument, nullptr, 'y' },
|
||||
{ "recompute-aabb", no_argument, nullptr, 'r' },
|
||||
{ "settings", required_argument, nullptr, 't' },
|
||||
{ "split-view", no_argument, nullptr, 'v' },
|
||||
@@ -268,19 +259,6 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) {
|
||||
std::cerr << "Unrecognized camera mode. Must be 'flight'|'orbit'.\n";
|
||||
}
|
||||
break;
|
||||
case 'y': {
|
||||
int eyeCount = 0;
|
||||
try {
|
||||
eyeCount = std::stoi(arg);
|
||||
} catch (std::invalid_argument &e) { }
|
||||
if (eyeCount >= 1 && eyeCount <= CONFIG_MAX_STEREOSCOPIC_EYES) {
|
||||
app->config.stereoscopicEyeCount = eyeCount;
|
||||
} else {
|
||||
std::cerr << "Eye count must be between 1 and CONFIG_MAX_STEREOSCOPIC_EYES ("
|
||||
<< (int) CONFIG_MAX_STEREOSCOPIC_EYES << ") (inclusive).\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'e':
|
||||
app->config.headless = true;
|
||||
break;
|
||||
@@ -507,57 +485,6 @@ static void onClick(App& app, View* view, ImVec2 pos) {
|
||||
});
|
||||
}
|
||||
|
||||
static utils::Path getPathForAsset(std::string_view string) {
|
||||
utils::Path filename{ string };
|
||||
if (!filename.exists()) {
|
||||
std::cerr << "file " << filename << " not found!" << std::endl;
|
||||
return {};
|
||||
}
|
||||
if (filename.isDirectory()) {
|
||||
auto files = filename.listContents();
|
||||
for (const auto& file: files) {
|
||||
if (file.getExtension() == "gltf" || file.getExtension() == "glb") {
|
||||
filename = file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filename.isDirectory()) {
|
||||
std::cerr << "no glTF file found in " << filename << std::endl;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
||||
static bool checkAsset(const utils::Path& filename) {
|
||||
// Peek at the file size to allow pre-allocation.
|
||||
long const contentSize = static_cast<long>(getFileSize(filename.c_str()));
|
||||
if (contentSize <= 0) {
|
||||
std::cerr << "Unable to open " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Consume the glTF file.
|
||||
std::ifstream in(filename.c_str(), std::ifstream::binary | std::ifstream::in);
|
||||
std::vector<uint8_t> buffer(static_cast<unsigned long>(contentSize));
|
||||
if (!in.read((char*) buffer.data(), contentSize)) {
|
||||
std::cerr << "Unable to read " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the glTF file and create Filament entities.
|
||||
cgltf_options options{};
|
||||
cgltf_data* sourceAsset;
|
||||
cgltf_result result = cgltf_parse(&options, buffer.data(), contentSize, &sourceAsset);
|
||||
if (result != cgltf_result_success) {
|
||||
slog.e << "Unable to parse glTF file." << io::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
App app;
|
||||
|
||||
@@ -569,10 +496,24 @@ int main(int argc, char** argv) {
|
||||
utils::Path filename;
|
||||
int const num_args = argc - optionIndex;
|
||||
if (num_args >= 1) {
|
||||
filename = getPathForAsset(argv[optionIndex]);
|
||||
if (filename.isEmpty()) {
|
||||
filename = argv[optionIndex];
|
||||
if (!filename.exists()) {
|
||||
std::cerr << "file " << filename << " not found!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (filename.isDirectory()) {
|
||||
auto files = filename.listContents();
|
||||
for (const auto& file : files) {
|
||||
if (file.getExtension() == "gltf" || file.getExtension() == "glb") {
|
||||
filename = file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filename.isDirectory()) {
|
||||
std::cerr << "no glTF file found in " << filename << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto loadAsset = [&app](const utils::Path& filename) {
|
||||
@@ -593,49 +534,14 @@ int main(int argc, char** argv) {
|
||||
|
||||
// Parse the glTF file and create Filament entities.
|
||||
app.asset = app.assetLoader->createAsset(buffer.data(), buffer.size());
|
||||
app.instance = app.asset->getInstance();
|
||||
buffer.clear();
|
||||
buffer.shrink_to_fit();
|
||||
|
||||
if (!app.asset) {
|
||||
std::cerr << "Unable to parse " << filename << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// pre-compile all material variants
|
||||
std::set<Material*> materials;
|
||||
RenderableManager const& rcm = app.engine->getRenderableManager();
|
||||
Slice<Entity> const renderables{
|
||||
app.asset->getRenderableEntities(), app.asset->getRenderableEntityCount() };
|
||||
for (Entity const e: renderables) {
|
||||
auto ri = rcm.getInstance(e);
|
||||
size_t const c = rcm.getPrimitiveCount(ri);
|
||||
for (size_t i = 0; i < c; i++) {
|
||||
MaterialInstance* const mi = rcm.getMaterialInstanceAt(ri, i);
|
||||
Material* ma = const_cast<Material *>(mi->getMaterial());
|
||||
materials.insert(ma);
|
||||
}
|
||||
}
|
||||
for (Material* ma : materials) {
|
||||
// Don't attempt to precompile shaders on WebGL.
|
||||
// Chrome already suffers from slow shader compilation:
|
||||
// https://github.com/google/filament/issues/6615
|
||||
// Precompiling shaders exacerbates the problem.
|
||||
#if !defined(__EMSCRIPTEN__)
|
||||
// First compile high priority variants
|
||||
ma->compile(Material::CompilerPriorityQueue::HIGH,
|
||||
UserVariantFilterBit::DIRECTIONAL_LIGHTING |
|
||||
UserVariantFilterBit::DYNAMIC_LIGHTING |
|
||||
UserVariantFilterBit::SHADOW_RECEIVER);
|
||||
|
||||
// and then, everything else at low priority, except STE, which is very uncommon.
|
||||
ma->compile(Material::CompilerPriorityQueue::LOW,
|
||||
UserVariantFilterBit::FOG |
|
||||
UserVariantFilterBit::SKINNING |
|
||||
UserVariantFilterBit::SSR |
|
||||
UserVariantFilterBit::VSM);
|
||||
#endif
|
||||
}
|
||||
|
||||
app.instance = app.asset->getInstance();
|
||||
buffer.clear();
|
||||
buffer.shrink_to_fit();
|
||||
};
|
||||
|
||||
auto loadResources = [&app] (const utils::Path& filename) {
|
||||
@@ -653,8 +559,6 @@ int main(int argc, char** argv) {
|
||||
app.resourceLoader->addTextureProvider("image/png", app.stbDecoder);
|
||||
app.resourceLoader->addTextureProvider("image/jpeg", app.stbDecoder);
|
||||
app.resourceLoader->addTextureProvider("image/ktx2", app.ktxDecoder);
|
||||
} else {
|
||||
app.resourceLoader->setConfiguration(configuration);
|
||||
}
|
||||
|
||||
if (!app.resourceLoader->asyncBeginLoad(app.asset)) {
|
||||
@@ -1042,27 +946,25 @@ int main(int argc, char** argv) {
|
||||
if (view->getStereoscopicOptions().enabled) {
|
||||
Camera& c = view->getCamera();
|
||||
auto od = app.viewer->getOcularDistance();
|
||||
// Eyes are rendered from left-to-right, i.e., eye 0 is rendered to the left side of the
|
||||
// window.
|
||||
// Eye 0 is always rendered to the left side of the screen; Eye 1, the right side.
|
||||
// For testing, we want to render a side-by-side layout so users can view with
|
||||
// "cross-eyed" stereo.
|
||||
// For cross-eyed stereo, Eye 0 is really the RIGHT eye, while Eye 1 is the LEFT eye.
|
||||
const mat4 rightEye = mat4::translation(double3{ od, 0.0, 0.0}); // right eye
|
||||
const mat4 leftEye = mat4::translation(double3{-od, 0.0, 0.0}); // left eye
|
||||
const mat4 modelMatrices[4] = { rightEye, leftEye, rightEye, leftEye };
|
||||
for (int i = 0; i < std::min(app.config.stereoscopicEyeCount, 4); i++) {
|
||||
c.setEyeModelMatrix(i, modelMatrices[i]);
|
||||
}
|
||||
c.setEyeModelMatrix(0, rightEye);
|
||||
c.setEyeModelMatrix(1, leftEye);
|
||||
mat4 projections[2];
|
||||
// Use an aspect ratio of 1.0. The viewport will be taken into account in
|
||||
// FilamentApp.cpp.
|
||||
projections[0] = mat4::perspective(70.0, 1.0, .1, 10.0);
|
||||
projections[1] = mat4::perspective(70.0, 1.0, .1, 10.0);
|
||||
c.setCustomEyeProjection(projections, 2, projections[0], .1, 10.0);
|
||||
// FIXME: the aspect ratio will be incorrect until configureCamerasForWindow is
|
||||
// triggered, which will happen the next time the window is resized.
|
||||
} else {
|
||||
for (int i = 0; i < app.config.stereoscopicEyeCount; i++) {
|
||||
view->getCamera().setEyeModelMatrix(i, {});
|
||||
}
|
||||
}
|
||||
static bool stereoscopicEnabled = false;
|
||||
if (stereoscopicEnabled != view->getStereoscopicOptions().enabled) {
|
||||
// Stereo was turned on/off.
|
||||
FilamentApp::get().reconfigureCameras();
|
||||
stereoscopicEnabled = view->getStereoscopicOptions().enabled;
|
||||
view->getCamera().setEyeModelMatrix(0, {});
|
||||
view->getCamera().setEyeModelMatrix(1, {});
|
||||
}
|
||||
|
||||
app.scene.groundMaterial->setDefaultParameter(
|
||||
@@ -1119,19 +1021,14 @@ int main(int argc, char** argv) {
|
||||
filamentApp.animate(animate);
|
||||
filamentApp.resize(resize);
|
||||
|
||||
filamentApp.setDropHandler([&](std::string_view path) {
|
||||
utils::Path const filename = getPathForAsset(path);
|
||||
if (!filename.isEmpty()) {
|
||||
if (checkAsset(filename)) {
|
||||
app.resourceLoader->asyncCancelLoad();
|
||||
app.resourceLoader->evictResourceData();
|
||||
app.viewer->removeAsset();
|
||||
app.assetLoader->destroyAsset(app.asset);
|
||||
loadAsset(filename);
|
||||
loadResources(filename);
|
||||
app.viewer->setAsset(app.asset, app.instance);
|
||||
}
|
||||
}
|
||||
filamentApp.setDropHandler([&] (std::string_view path) {
|
||||
app.resourceLoader->asyncCancelLoad();
|
||||
app.resourceLoader->evictResourceData();
|
||||
app.viewer->removeAsset();
|
||||
app.assetLoader->destroyAsset(app.asset);
|
||||
loadAsset(path);
|
||||
loadResources(path);
|
||||
app.viewer->setAsset(app.asset, app.instance);
|
||||
});
|
||||
|
||||
filamentApp.run(app.config, setup, cleanup, gui, preRender, postRender);
|
||||
|
||||
@@ -25,7 +25,7 @@ highp mat4 getViewFromClipMatrix() {
|
||||
/** @public-api */
|
||||
highp mat4 getClipFromWorldMatrix() {
|
||||
#if defined(VARIANT_HAS_INSTANCED_STEREO)
|
||||
int eye = instance_index % CONFIG_STEREO_EYE_COUNT;
|
||||
int eye = instance_index % CONFIG_STEREOSCOPIC_EYES;
|
||||
return frameUniforms.clipFromWorldMatrix[eye];
|
||||
#else
|
||||
return frameUniforms.clipFromWorldMatrix[0];
|
||||
|
||||
@@ -57,10 +57,10 @@ void main() {
|
||||
fragColor.xy = computeDepthMomentsVSM(depth);
|
||||
fragColor.zw = computeDepthMomentsVSM(-1.0 / depth); // requires at least RGBA16F
|
||||
#elif defined(VARIANT_HAS_PICKING)
|
||||
#if FILAMENT_EFFECTIVE_VERSION == 100
|
||||
outPicking.a = mod(float(object_uniforms_objectId / 65536), 256.0) / 255.0;
|
||||
outPicking.b = mod(float(object_uniforms_objectId / 256), 256.0) / 255.0;
|
||||
outPicking.g = mod(float(object_uniforms_objectId) , 256.0) / 255.0;
|
||||
#if MATERIAL_FEATURE_LEVEL == 0
|
||||
outPicking.a = float((object_uniforms_objectId / 65536) % 256) / 255.0;
|
||||
outPicking.b = float((object_uniforms_objectId / 256) % 256) / 255.0;
|
||||
outPicking.g = float( object_uniforms_objectId % 256) / 255.0;
|
||||
outPicking.r = vertex_position.z / vertex_position.w;
|
||||
#else
|
||||
outPicking.x = intBitsToFloat(object_uniforms_objectId);
|
||||
|
||||
+16
-19
@@ -27,8 +27,9 @@ void main() {
|
||||
#if !defined(FILAMENT_HAS_FEATURE_INSTANCING)
|
||||
#error Instanced stereo not supported at this feature level
|
||||
#endif
|
||||
// Calculate the logical instance index, which is the instance index within a single eye.
|
||||
logical_instance_index = instance_index / CONFIG_STEREO_EYE_COUNT;
|
||||
// The lowest bit of the instance index represents the eye.
|
||||
// This logic must be updated if CONFIG_STEREOSCOPIC_EYES changes
|
||||
logical_instance_index = instance_index >> 1;
|
||||
#endif
|
||||
|
||||
initObjectUniforms();
|
||||
@@ -216,26 +217,22 @@ void main() {
|
||||
vertex_position = position;
|
||||
|
||||
#if defined(VARIANT_HAS_INSTANCED_STEREO)
|
||||
// This logic must be updated if CONFIG_STEREOSCOPIC_EYES changes
|
||||
// We're transforming a vertex whose x coordinate is within the range (-w to w).
|
||||
// To move it to the correct portion of the viewport, we need to modify the x coordinate.
|
||||
// To move it to the correct half of the viewport, we need to modify the x coordinate:
|
||||
// Eye 0 (left half): (-w to 0)
|
||||
// Eye 1 (right half): ( 0 to w)
|
||||
// It's important to do this after computing vertex_position.
|
||||
int eyeIndex = instance_index % CONFIG_STEREO_EYE_COUNT;
|
||||
int eyeIndex = instance_index % 2;
|
||||
float eyeShift = float(eyeIndex) * 2.0f - 1.0f; // eye 0: -1.0, eye 1: 1.0
|
||||
position.x = position.x * 0.5f + (position.w * 0.5 * eyeShift);
|
||||
|
||||
float ndcViewportWidth = 2.0 / float(CONFIG_STEREO_EYE_COUNT); // the width of ndc space is 2
|
||||
float eyeZeroMidpoint = -1.0f + ndcViewportWidth / 2.0;
|
||||
|
||||
float transform = eyeZeroMidpoint + ndcViewportWidth * float(eyeIndex);
|
||||
position.x *= 1.0 / float(CONFIG_STEREO_EYE_COUNT);
|
||||
position.x += transform * position.w;
|
||||
|
||||
// A fragment is clipped when gl_ClipDistance is negative (outside the clip plane).
|
||||
|
||||
float leftClip = position.x +
|
||||
(1.0 - ndcViewportWidth * float(eyeIndex)) * position.w;
|
||||
float rightClip = position.x +
|
||||
(1.0 - ndcViewportWidth * float(eyeIndex + 1)) * position.w;
|
||||
FILAMENT_CLIPDISTANCE[0] = leftClip;
|
||||
FILAMENT_CLIPDISTANCE[1] = -rightClip;
|
||||
// A fragment is clipped when gl_ClipDistance is negative (outside the clip plane). So,
|
||||
// Eye 0 should have a positive value when x is < 0
|
||||
// -position.x
|
||||
// Eye 1 should have a positive value when x is > 0
|
||||
// position.x
|
||||
FILAMENT_CLIPDISTANCE[0] = position.x * eyeShift;
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
|
||||
@@ -40,7 +40,7 @@ LAYOUT_LOCATION(11) VARYING highp vec4 vertex_lightSpacePosition;
|
||||
// However, this extension is not supported by glslang, so we instead write to
|
||||
// filament_gl_ClipDistance, which will get decorated at the SPIR-V stage to refer to the built-in.
|
||||
// The location here does not matter, so long as it doesn't conflict with others.
|
||||
LAYOUT_LOCATION(100) out float filament_gl_ClipDistance[2];
|
||||
LAYOUT_LOCATION(100) out float filament_gl_ClipDistance[1];
|
||||
#define FILAMENT_CLIPDISTANCE filament_gl_ClipDistance
|
||||
#else
|
||||
// If we're on Desktop GL (or not running shaders through glslang), we're free to use gl_ClipDistance
|
||||
|
||||
+2
-11
@@ -14977,12 +14977,7 @@ string CompilerGLSL::flags_to_qualifiers_glsl(const SPIRType &type, const Bitset
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
|
||||
if (type.basetype == SPIRType::UInt && is_legacy_es())
|
||||
{
|
||||
// HACK: This is a bool. See comment in type_to_glsl().
|
||||
qual += "lowp ";
|
||||
}
|
||||
else if (flags.get(DecorationRelaxedPrecision))
|
||||
if (flags.get(DecorationRelaxedPrecision))
|
||||
{
|
||||
bool implied_fmediump = type.basetype == SPIRType::Float &&
|
||||
options.fragment.default_float_precision == Options::Mediump &&
|
||||
@@ -15508,11 +15503,7 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
|
||||
if (type.basetype == SPIRType::UInt && is_legacy())
|
||||
{
|
||||
if (options.es)
|
||||
// HACK: spirv-cross changes bools into uints and generates code which compares them to
|
||||
// zero. Input code will have already been validated as not to have contained any uints,
|
||||
// so any remaining uints must in fact be bools. However, simply returning "bool" here
|
||||
// will result in invalid code. Instead, return an int.
|
||||
return backend.basic_int_type;
|
||||
SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy ESSL.");
|
||||
else
|
||||
require_extension_internal("GL_EXT_gpu_shader4");
|
||||
}
|
||||
|
||||
@@ -62,9 +62,6 @@ static void usage(char* name) {
|
||||
" MATC --api opengl --api metal ...\n\n"
|
||||
" --feature-level, -l\n"
|
||||
" Specify the maximum feature level allowed (default is 3).\n\n"
|
||||
" --no-essl1, -1\n"
|
||||
" Don't generate ESSL 1.0 code even for Feature Level 0 mobile shaders.\n"
|
||||
" Shaders are still validated against ESSL 1.0.\n\n"
|
||||
" --define, -D\n"
|
||||
" Add a preprocessor define macro via <macro>=<value>. <value> defaults to 1 if omitted.\n"
|
||||
" Can be repeated to specify multiple definitions:\n"
|
||||
@@ -174,7 +171,7 @@ static void parseDefine(std::string defineString, Config::StringReplacementMap&
|
||||
}
|
||||
|
||||
bool CommandlineConfig::parse() {
|
||||
static constexpr const char* OPTSTR = "hLxo:f:dm:a:l:p:D:T:OSEr:vV:gtwF1";
|
||||
static constexpr const char* OPTSTR = "hLxo:f:dm:a:l:p:D:T:OSEr:vV:gtwF";
|
||||
static const struct option OPTIONS[] = {
|
||||
{ "help", no_argument, nullptr, 'h' },
|
||||
{ "license", no_argument, nullptr, 'L' },
|
||||
@@ -190,7 +187,6 @@ bool CommandlineConfig::parse() {
|
||||
{ "preprocessor-only", no_argument, nullptr, 'E' },
|
||||
{ "api", required_argument, nullptr, 'a' },
|
||||
{ "feature-level", required_argument, nullptr, 'l' },
|
||||
{ "no-essl1", no_argument, nullptr, '1' },
|
||||
{ "define", required_argument, nullptr, 'D' },
|
||||
{ "template", required_argument, nullptr, 'T' },
|
||||
{ "reflect", required_argument, nullptr, 'r' },
|
||||
@@ -274,9 +270,6 @@ bool CommandlineConfig::parse() {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '1':
|
||||
mIncludeEssl1 = false;
|
||||
break;
|
||||
case 'D':
|
||||
parseDefine(arg, mDefines);
|
||||
break;
|
||||
|
||||
@@ -119,10 +119,6 @@ public:
|
||||
return mNoSamplerValidation;
|
||||
}
|
||||
|
||||
bool includeEssl1() const noexcept {
|
||||
return mIncludeEssl1;
|
||||
}
|
||||
|
||||
filament::UserVariantFilterMask getVariantFilter() const noexcept {
|
||||
return mVariantFilter;
|
||||
}
|
||||
@@ -154,7 +150,6 @@ protected:
|
||||
StringReplacementMap mDefines;
|
||||
StringReplacementMap mTemplateMap;
|
||||
filament::UserVariantFilterMask mVariantFilter = 0;
|
||||
bool mIncludeEssl1 = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "ParametersProcessor.h"
|
||||
|
||||
#include <GlslangToSpv.h>
|
||||
#include "glslang/Include/intermediate.h"
|
||||
|
||||
#include "sca/builtinResource.h"
|
||||
|
||||
@@ -399,7 +398,6 @@ bool MaterialCompiler::run(const Config& config) {
|
||||
|
||||
builder
|
||||
.noSamplerValidation(config.noSamplerValidation())
|
||||
.includeEssl1(config.includeEssl1())
|
||||
.includeCallback(includer)
|
||||
.fileName(materialFilePath.getName().c_str())
|
||||
.platform(config.getPlatform())
|
||||
|
||||
@@ -180,6 +180,19 @@ static bool processParameter(MaterialBuilder& builder, const JsonishObject& json
|
||||
}
|
||||
}
|
||||
|
||||
const JsonishValue* transferFunctionValue = jsonObject.getValue("transferFunction");
|
||||
if (transferFunctionValue) {
|
||||
if (transferFunctionValue->getType() != JsonishValue::STRING) {
|
||||
std::cerr << "parameters: transferFunction must be a STRING." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto transferFunctionString = formatValue->toJsonString();
|
||||
if (!Enums::isValid<SamplerTransferFunction>(transferFunctionString->getString())){
|
||||
return logEnumIssue("parameters", *transferFunctionString, Enums::map<SamplerTransferFunction>());
|
||||
}
|
||||
}
|
||||
|
||||
auto typeString = typeValue->toJsonString()->getString();
|
||||
auto nameString = nameValue->toJsonString()->getString();
|
||||
|
||||
@@ -205,22 +218,22 @@ static bool processParameter(MaterialBuilder& builder, const JsonishObject& json
|
||||
return false;
|
||||
}
|
||||
|
||||
MaterialBuilder::SamplerType type = Enums::toEnum<SamplerType>(typeString);
|
||||
if (precisionValue && formatValue) {
|
||||
auto format = Enums::toEnum<SamplerFormat>(formatValue->toJsonString()->getString());
|
||||
auto precision =
|
||||
Enums::toEnum<ParameterPrecision>(precisionValue->toJsonString()->getString());
|
||||
builder.parameter(nameString.c_str(), type, format, precision);
|
||||
} else if (formatValue) {
|
||||
auto format = Enums::toEnum<SamplerFormat>(formatValue->toJsonString()->getString());
|
||||
builder.parameter(nameString.c_str(), type, format);
|
||||
} else if (precisionValue) {
|
||||
auto precision =
|
||||
Enums::toEnum<ParameterPrecision>(precisionValue->toJsonString()->getString());
|
||||
builder.parameter(nameString.c_str(), type, precision);
|
||||
} else {
|
||||
builder.parameter(nameString.c_str(), type);
|
||||
SamplerType type = Enums::toEnum<SamplerType>(typeString);
|
||||
SamplerFormat format = SamplerFormat::FLOAT;
|
||||
if (formatValue) {
|
||||
format = Enums::toEnum<SamplerFormat>(formatValue->toJsonString()->getString());
|
||||
}
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT;
|
||||
if (precisionValue) {
|
||||
precision =
|
||||
Enums::toEnum<ParameterPrecision>(precisionValue->toJsonString()->getString());
|
||||
}
|
||||
SamplerTransferFunction transferFunction = SamplerTransferFunction::UNDEFINED;
|
||||
if (transferFunctionValue) {
|
||||
transferFunction =
|
||||
Enums::toEnum<SamplerTransferFunction>(transferFunctionValue->toJsonString()->getString());
|
||||
}
|
||||
builder.parameter(nameString.c_str(), type, format, precision, transferFunction);
|
||||
} else {
|
||||
std::cerr << "parameters: the type '" << typeString
|
||||
<< "' for parameter with name '" << nameString << "' is neither a valid uniform "
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.47.0",
|
||||
"version": "1.45.0",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user