Compare commits

..
Author SHA1 Message Date
Eliza Velasquez ab552d3619 wip: color space stuff 2023-11-13 14:32:31 -08:00
100 changed files with 461 additions and 1243 deletions
-13
View File
@@ -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 -2
View File
@@ -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
+2 -2
View File
@@ -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
-18
View File
@@ -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 -1
View File
@@ -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.
@@ -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)
}
}
}
@@ -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
View File
@@ -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);
}
}
+6 -12
View File
@@ -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);
+5 -4
View File
@@ -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());
+1 -2
View File
@@ -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;
-2
View File
@@ -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)
+17 -9
View File
@@ -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;
+7 -10
View File
@@ -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);
-8
View File
@@ -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;
};
+12 -12
View File
@@ -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));
}
+7 -1
View File
@@ -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();
+1 -2
View File
@@ -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
+1 -2
View File
@@ -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);
}
+9 -14
View File
@@ -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;
}
}
+2 -4
View File
@@ -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;
+1 -4
View File
@@ -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
+1 -1
View File
@@ -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.
+9 -23
View File
@@ -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) };
}
+16 -14
View File
@@ -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
+1 -11
View File
@@ -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;
}
-3
View File
@@ -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({
+8 -6
View File
@@ -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();
+1 -4
View File
@@ -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);
+1 -1
View File
@@ -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));
+6 -6
View File
@@ -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;
}
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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;
}
-1
View File
@@ -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}
+2
View File
@@ -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;
+12 -13
View File
@@ -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,
+11
View File
@@ -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 }
+3 -17
View File
@@ -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(
+1 -1
View File
@@ -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,
+12 -21
View File
@@ -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));
}
}
+8 -45
View File
@@ -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";
}
+1 -1
View File
@@ -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;
+3 -24
View File
@@ -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});
+5 -6
View File
@@ -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()
+2 -4
View File
@@ -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;
};
+15
View File
@@ -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];
+2 -2
View File
@@ -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) {
+1 -2
View File
@@ -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;
}
+1 -1
View File
@@ -71,7 +71,7 @@ namespace utils {
namespace filament::gltfio {
struct Wireframe;
class Wireframe;
// Encapsulates VertexBuffer::setBufferAt() or IndexBuffer::setBuffer().
struct BufferSlot {
+1 -1
View File
@@ -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);
+4 -10
View File
@@ -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));
}
+1 -1
View File
@@ -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;
+4
View File
@@ -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);
+1 -1
View File
@@ -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
-16
View File
@@ -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
View File
@@ -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];
}
})();
}
}
+9 -9
View File
@@ -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;
}
};
-101
View File
@@ -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);
+9 -10
View File
@@ -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().
-2
View File
@@ -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
View File
@@ -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);
+1 -1
View File
@@ -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];
+4 -4
View File
@@ -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
View File
@@ -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)
+1 -1
View File
@@ -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
View File
@@ -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");
}
+1 -8
View File
@@ -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;
-5
View File
@@ -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;
};
}
-2
View File
@@ -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())
+28 -15
View File
@@ -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 -1
View File
@@ -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",