Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be2096d1f4 | ||
|
|
cad722cb9a | ||
|
|
ffeaae8903 |
@@ -6,3 +6,5 @@
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
|
||||
- engine: add `MaterialInstance::setConstant()` and `MaterialInstance::getConstant()` methods. These allow for per-material instance specialization constant overrides.
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.71.1'
|
||||
implementation 'com.google.android.filament:filament-android:1.71.2'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -50,7 +50,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.71.1'
|
||||
pod 'Filament', '~> 1.71.2'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <filament/Texture.h>
|
||||
#include <filament/TextureSampler.h>
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
|
||||
#include <math/mat3.h>
|
||||
#include <math/mat4.h>
|
||||
#include <math/vec2.h>
|
||||
@@ -246,6 +248,69 @@ Java_com_google_android_filament_MaterialInstance_nSetFloatParameterArray(JNIEnv
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetConstantBool(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
jboolean result = instance->getConstant<bool>(name);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetConstantFloat(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
jfloat result = instance->getConstant<float>(name);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetConstantInt(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
jint result = instance->getConstant<int32_t>(name);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetConstantBool(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_, jboolean x) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
instance->setConstant<bool>(name, x);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetConstantFloat(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_, jfloat x) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
instance->setConstant<float>(name, x);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetConstantInt(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_, jint x) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
instance->setConstant<int32_t>(name, x);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
// defined in TextureSampler.cpp
|
||||
namespace filament::JniUtils {
|
||||
TextureSampler from_long(jlong params) noexcept;
|
||||
@@ -580,3 +645,17 @@ Java_com_google_android_filament_MaterialInstance_nGetTransparencyMode(JNIEnv*,
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
return (jint) instance->getTransparencyMode();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nCompile(JNIEnv *env, jclass clazz,
|
||||
jlong nativeMaterialInstance, jint priority, jint variants, jobject handler, jobject runnable) {
|
||||
MaterialInstance* materialInstance = (MaterialInstance*) nativeMaterialInstance;
|
||||
JniCallback* jniCallback = JniCallback::make(env, handler, runnable);
|
||||
materialInstance->compile(
|
||||
(MaterialInstance::CompilerPriorityQueue) priority,
|
||||
(UserVariantFilterBit) variants,
|
||||
jniCallback->getHandler(), [jniCallback](MaterialInstance*){
|
||||
JniCallback::postToJavaAndDestroy(jniCallback);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -522,11 +522,19 @@ public class Material {
|
||||
* 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>
|
||||
*<p>
|
||||
* Note that it is possible to override specialization constants on a per-MaterialInstance basis
|
||||
* (see {@link MaterialInstance#setConstant}). In that case, the programs compiled by a call to
|
||||
* Material::compile() may not be reusable by that MaterialInstance. It's better to call
|
||||
* MaterialInstance::compile() in cases where you intend to override specialization constants.
|
||||
*</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.
|
||||
*
|
||||
* @see MaterialInstance#compile
|
||||
*/
|
||||
public void compile(@NonNull CompilerPriorityQueue priority,
|
||||
int variants,
|
||||
|
||||
@@ -18,6 +18,7 @@ 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;
|
||||
@@ -142,6 +143,28 @@ public class MaterialInstance {
|
||||
return mMaterial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously ensures that a subset of this MaterialInstance's variants are compiled.
|
||||
*
|
||||
* <p>This function behaves identically to {@link Material#compile}, but takes into account
|
||||
* the specific constants overridden by {@link #setConstant}.</p>
|
||||
*
|
||||
* @param priority Priority of the compile command.
|
||||
* @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.
|
||||
*
|
||||
* @see Material#compile
|
||||
* @see #setConstant
|
||||
*/
|
||||
public void compile(@NonNull Material.CompilerPriorityQueue priority,
|
||||
int variants,
|
||||
@Nullable Object handler,
|
||||
@Nullable Runnable callback) {
|
||||
nCompile(getNativeObject(), priority.ordinal(), variants, handler, callback);
|
||||
}
|
||||
|
||||
/** @return the name associated with this instance */
|
||||
@NonNull
|
||||
public String getName() {
|
||||
@@ -402,6 +425,69 @@ public class MaterialInstance {
|
||||
nSetParameterFloat4(getNativeObject(), name, color[0], color[1], color[2], color[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides a specialization constant of this material instance.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @param value The value of the constant.
|
||||
* @see Material.Builder#constant
|
||||
*/
|
||||
public void setConstant(@NonNull String name, boolean value) {
|
||||
nSetConstantBool(getNativeObject(), name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides a specialization constant of this material instance.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @param value The value of the constant.
|
||||
* @see Material.Builder#constant
|
||||
*/
|
||||
public void setConstant(@NonNull String name, float value) {
|
||||
nSetConstantFloat(getNativeObject(), name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides a specialization constant of this material instance.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @param value The value of the constant.
|
||||
* @see Material.Builder#constant
|
||||
*/
|
||||
public void setConstant(@NonNull String name, int value) {
|
||||
nSetConstantInt(getNativeObject(), name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a specialization constant by name.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @return The value of the constant.
|
||||
*/
|
||||
public boolean getConstantBoolean(@NonNull String name) {
|
||||
return nGetConstantBool(getNativeObject(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a specialization constant by name.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @return The value of the constant.
|
||||
*/
|
||||
public float getConstantFloat(@NonNull String name) {
|
||||
return nGetConstantFloat(getNativeObject(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a specialization constant by name.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @return The value of the constant.
|
||||
*/
|
||||
public int getConstantInt(@NonNull String name) {
|
||||
return nGetConstantInt(getNativeObject(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set-up a custom scissor rectangle; by default it is disabled.
|
||||
*
|
||||
@@ -937,6 +1023,17 @@ public class MaterialInstance {
|
||||
@NonNull String name, int element, @NonNull @Size(min = 1) float[] v,
|
||||
@IntRange(from = 0) int offset, @IntRange(from = 1) int count);
|
||||
|
||||
private static native boolean nGetConstantBool(long nativeMaterialInstance, @NonNull String name);
|
||||
private static native float nGetConstantFloat(long nativeMaterialInstance, @NonNull String name);
|
||||
private static native int nGetConstantInt(long nativeMaterialInstance, @NonNull String name);
|
||||
|
||||
private static native void nSetConstantBool(long nativeMaterialInstance,
|
||||
@NonNull String name, boolean x);
|
||||
private static native void nSetConstantFloat(long nativeMaterialInstance,
|
||||
@NonNull String name, float x);
|
||||
private static native void nSetConstantInt(long nativeMaterialInstance,
|
||||
@NonNull String name, int x);
|
||||
|
||||
private static native void nSetParameterTexture(long nativeMaterialInstance,
|
||||
@NonNull String name, long nativeTexture, long sampler);
|
||||
|
||||
@@ -1000,4 +1097,5 @@ public class MaterialInstance {
|
||||
private static native int nGetDepthFunc(long nativeMaterialInstance);
|
||||
private static native void nSetTransparencyMode(long nativeMaterialInstance, int mode);
|
||||
private static native int nGetTransparencyMode(long nativeMaterialInstance);
|
||||
private static native void nCompile(long nativeMaterialInstance, int priority, int variants, Object handler, Runnable callback);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.71.1
|
||||
VERSION_NAME=1.71.2
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -139,10 +139,8 @@ public:
|
||||
Builder& package(const void* UTILS_NONNULL payload, size_t size);
|
||||
|
||||
template<typename T>
|
||||
using is_supported_constant_parameter_t = std::enable_if_t<
|
||||
std::is_same_v<int32_t, T> ||
|
||||
std::is_same_v<float, T> ||
|
||||
std::is_same_v<bool, T>>;
|
||||
using is_supported_constant_parameter_t =
|
||||
MaterialInstance::is_supported_constant_parameter_t<T>;
|
||||
|
||||
/**
|
||||
* Specialize a constant parameter specified in the material definition with a concrete
|
||||
@@ -243,11 +241,18 @@ public:
|
||||
* for stereoscopic rendering. If an application is not planning to render in stereo, this bit
|
||||
* should be turned off to avoid unnecessary material compilations.
|
||||
*
|
||||
* Note that it is possible to override specialization constants on a per-MaterialInstance basis
|
||||
* (@see MaterialInstance::setConstant). In that case, the programs compiled by a call to
|
||||
* Material::compile() may not be reusable by that MaterialInstance. It's better to call
|
||||
* MaterialInstance::compile() in cases where you intend to override specialization constants.
|
||||
*
|
||||
* @param priority Which priority queue to use, LOW or HIGH.
|
||||
* @param variants Variants to include to the compile command.
|
||||
* @param handler Handler to dispatch the callback or nullptr for the default handler
|
||||
* @param callback callback called on the main thread when the compilation is done on
|
||||
* by backend.
|
||||
*
|
||||
* @see Material::compile
|
||||
*/
|
||||
void compile(CompilerPriorityQueue priority,
|
||||
UserVariantFilterMask variants,
|
||||
|
||||
@@ -94,6 +94,12 @@ public:
|
||||
std::is_same_v<math::mat3f, T>
|
||||
>;
|
||||
|
||||
template<typename T>
|
||||
using is_supported_constant_parameter_t = std::enable_if_t<
|
||||
std::is_same_v<int32_t, T> ||
|
||||
std::is_same_v<float, T> ||
|
||||
std::is_same_v<bool, T>>;
|
||||
|
||||
/**
|
||||
* Creates a new MaterialInstance using another MaterialInstance as a template for initialization.
|
||||
* The new MaterialInstance is an instance of the same Material of the template instance and
|
||||
@@ -276,6 +282,91 @@ public:
|
||||
return getParameter<T>(name, strlen(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides a specialization constant of this material instance.
|
||||
*
|
||||
* @tparam T The type of the constant. Must be int32_t, float, or bool.
|
||||
* @param name The name of the constant as defined in the material. Cannot be nullptr.
|
||||
* @param nameLength Length in `char` of the name parameter.
|
||||
* @param value The value of the constant.
|
||||
*
|
||||
* @see Material::Builder::constant
|
||||
*/
|
||||
template<typename T, typename = is_supported_constant_parameter_t<T>>
|
||||
void setConstant(const char* UTILS_NONNULL name, size_t nameLength, T value);
|
||||
|
||||
/** inline helper to provide the name as a null-terminated string literal */
|
||||
template<typename T, typename = is_supported_constant_parameter_t<T>>
|
||||
void setConstant(StringLiteral const name, T value) {
|
||||
setConstant<T>(name.data, name.size, value);
|
||||
}
|
||||
|
||||
/** inline helper to provide the name as a null-terminated C string */
|
||||
template<typename T, typename = is_supported_constant_parameter_t<T>>
|
||||
void setConstant(const char* UTILS_NONNULL name, T value) {
|
||||
setConstant<T>(name, strlen(name), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a specialization constant by name.
|
||||
*
|
||||
* @tparam T The type of the constant. Must be int32_t, float, or bool.
|
||||
* @param name The name of the constant as defined in the material. Cannot be nullptr.
|
||||
* @param nameLength Length in `char` of the name parameter.
|
||||
* @return The value of the constant.
|
||||
*/
|
||||
template<typename T, typename = is_supported_constant_parameter_t<T>>
|
||||
T getConstant(const char* UTILS_NONNULL name, size_t nameLength) const;
|
||||
|
||||
/** inline helper to provide the name as a null-terminated C string */
|
||||
template<typename T, typename = is_supported_constant_parameter_t<T>>
|
||||
T getConstant(StringLiteral const name) const {
|
||||
return getConstant<T>(name.data, name.size);
|
||||
}
|
||||
|
||||
/** inline helper to provide the name as a null-terminated C string */
|
||||
template<typename T, typename = is_supported_constant_parameter_t<T>>
|
||||
T getConstant(const char* UTILS_NONNULL name) const {
|
||||
return getConstant<T>(name, strlen(name));
|
||||
}
|
||||
|
||||
using CompilerPriorityQueue = backend::CompilerPriorityQueue;
|
||||
|
||||
/**
|
||||
* Asynchronously ensures that a subset of this MaterialInstance's variants are compiled.
|
||||
*
|
||||
* This function behaves identically to Material::compile(), but takes into account the
|
||||
* specific constants overridden by setConstant().
|
||||
*
|
||||
* @param priority Which priority queue to use, LOW or HIGH.
|
||||
* @param variants Variants to include to the compile command.
|
||||
* @param handler Handler to dispatch the callback or nullptr for the default handler
|
||||
* @param callback callback called on the main thread when the compilation is done on
|
||||
* by backend.
|
||||
*
|
||||
* @see Material::compile
|
||||
* @see setConstant
|
||||
*/
|
||||
void compile(CompilerPriorityQueue priority,
|
||||
UserVariantFilterMask variants,
|
||||
backend::CallbackHandler* UTILS_NULLABLE handler = nullptr,
|
||||
utils::Invocable<void(MaterialInstance* UTILS_NONNULL)>&& callback = {}) noexcept;
|
||||
|
||||
inline void compile(CompilerPriorityQueue priority,
|
||||
UserVariantFilterBit variants,
|
||||
backend::CallbackHandler* UTILS_NULLABLE handler = nullptr,
|
||||
utils::Invocable<void(MaterialInstance* UTILS_NONNULL)>&& callback = {}) noexcept {
|
||||
compile(priority, UserVariantFilterMask(variants), handler,
|
||||
std::forward<utils::Invocable<void(MaterialInstance* UTILS_NONNULL)>>(callback));
|
||||
}
|
||||
|
||||
inline void compile(CompilerPriorityQueue priority,
|
||||
backend::CallbackHandler* UTILS_NULLABLE handler = nullptr,
|
||||
utils::Invocable<void(MaterialInstance* UTILS_NONNULL)>&& callback = {}) noexcept {
|
||||
compile(priority, UserVariantFilterBit::ALL, handler,
|
||||
std::forward<utils::Invocable<void(MaterialInstance* UTILS_NONNULL)>>(callback));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set-up a custom scissor rectangle; by default it is disabled.
|
||||
*
|
||||
|
||||
@@ -182,15 +182,11 @@ Program::SpecializationConstant LocalProgramCache::getConstantImpl(
|
||||
std::string_view name) const noexcept {
|
||||
assert_invariant(mMaterial != nullptr);
|
||||
|
||||
MaterialDefinition const& definition = mMaterial->getDefinition();
|
||||
auto it = definition.specializationConstantsNameToIndex.find(name);
|
||||
if (it != definition.specializationConstantsNameToIndex.cend()) {
|
||||
return getConstantImpl(it->second + CONFIG_MAX_RESERVED_SPEC_CONSTANTS);
|
||||
}
|
||||
auto const& constants = mMaterial->getDefinition().specializationConstantsNameToIndex;
|
||||
auto it = constants.find(name);
|
||||
FILAMENT_CHECK_PRECONDITION(it != constants.end()) << "Constant " << name << " does not exist";
|
||||
|
||||
CString name_cstring(name);
|
||||
PANIC_PRECONDITION("No such constant exists: %s", name_cstring.c_str());
|
||||
return {};
|
||||
return getConstantImpl(it->second + CONFIG_MAX_RESERVED_SPEC_CONSTANTS);
|
||||
}
|
||||
|
||||
void LocalProgramCache::setConstants(
|
||||
@@ -240,6 +236,13 @@ void LocalProgramCache::setConstants(
|
||||
}
|
||||
}
|
||||
|
||||
void LocalProgramCache::setConstants(
|
||||
FixedCapacityVector<Program::SpecializationConstant> constants) noexcept {
|
||||
assert_invariant(mMaterial != nullptr);
|
||||
|
||||
setConstantsImpl(std::move(constants));
|
||||
}
|
||||
|
||||
void LocalProgramCache::setConstantsImpl(
|
||||
FixedCapacityVector<Program::SpecializationConstant> constants) noexcept {
|
||||
FEngine& engine = mMaterial->getEngine();
|
||||
|
||||
@@ -119,7 +119,14 @@ public:
|
||||
std::pair<std::string_view, backend::Program::SpecializationConstant>>
|
||||
constants) noexcept;
|
||||
|
||||
// Set constants list directly.
|
||||
void setConstants(utils::FixedCapacityVector<backend::Program::SpecializationConstant>
|
||||
constants) noexcept;
|
||||
|
||||
private:
|
||||
// Apply any pending specialization constants. Invalidates programs as necessary.
|
||||
void flushConstants() const;
|
||||
|
||||
backend::Handle<backend::HwProgram> prepareProgramSlow(backend::DriverApi& driver,
|
||||
Variant const variant,
|
||||
backend::CompilerPriorityQueue const priorityQueue) const noexcept;
|
||||
|
||||
@@ -233,6 +233,26 @@ template UTILS_PUBLIC mat3f MaterialInstance::getParameter<mat3f> (const ch
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
template<typename T, typename>
|
||||
void MaterialInstance::setConstant(const char* name, size_t nameLength, T value) {
|
||||
downcast(this)->setConstantImpl(std::string_view{name, nameLength}, value);
|
||||
}
|
||||
|
||||
template UTILS_PUBLIC void MaterialInstance::setConstant<int32_t>(const char* name, size_t nameLength, int32_t value);
|
||||
template UTILS_PUBLIC void MaterialInstance::setConstant<float>(const char* name, size_t nameLength, float value);
|
||||
template UTILS_PUBLIC void MaterialInstance::setConstant<bool>(const char* name, size_t nameLength, bool value);
|
||||
|
||||
template<typename T, typename>
|
||||
T MaterialInstance::getConstant(const char* name, size_t nameLength) const {
|
||||
return downcast(this)->getConstantImpl<T>(std::string_view{name, nameLength});
|
||||
}
|
||||
|
||||
template UTILS_PUBLIC int32_t MaterialInstance::getConstant<int32_t>(const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC float MaterialInstance::getConstant<float>(const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC bool MaterialInstance::getConstant<bool>(const char* name, size_t nameLength) const;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
Material const* MaterialInstance::getMaterial() const noexcept {
|
||||
return downcast(this)->getMaterial();
|
||||
}
|
||||
@@ -403,4 +423,10 @@ void MaterialInstance::commit(Engine& engine) const {
|
||||
downcast(this)->commit(downcast(engine));
|
||||
}
|
||||
|
||||
void MaterialInstance::compile(CompilerPriorityQueue const priority,
|
||||
UserVariantFilterMask const variants, CallbackHandler* handler,
|
||||
utils::Invocable<void(MaterialInstance*)>&& callback) noexcept {
|
||||
downcast(this)->compile(priority, variants, handler, std::move(callback));
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -186,12 +186,10 @@ void PostProcessManager::PostProcessMaterial::loadMaterial(FEngine& engine) cons
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
FMaterial* PostProcessManager::PostProcessMaterial::getMaterial(FEngine& engine,
|
||||
DriverApi& driver, Variant::type_t const variant) const noexcept {
|
||||
FMaterial* PostProcessManager::PostProcessMaterial::getMaterial(FEngine& engine) const noexcept {
|
||||
if (UTILS_UNLIKELY(mSize)) {
|
||||
loadMaterial(engine);
|
||||
}
|
||||
mMaterial->prepareProgram(driver, Variant{ variant }, CompilerPriorityQueue::CRITICAL);
|
||||
return mMaterial;
|
||||
}
|
||||
|
||||
@@ -249,6 +247,20 @@ void PostProcessManager::bindPerRenderableDescriptorSet(DriverApi& driver) const
|
||||
{ { 0, 0 }, driver });
|
||||
}
|
||||
|
||||
FMaterialInstance* PostProcessManager::getMaterialInstance(backend::DriverApi& driver,
|
||||
FMaterial const* ma, Variant::type_t variant) const {
|
||||
FMaterialInstance* mi = mMaterialInstanceManager.getMaterialInstance(ma);
|
||||
mi->prepareProgram(driver, Variant{ variant }, backend::CompilerPriorityQueue::CRITICAL);
|
||||
return mi;
|
||||
}
|
||||
|
||||
FMaterialInstance* PostProcessManager::getMaterialInstanceWithTag(backend::DriverApi& driver,
|
||||
FMaterial const* ma, uint32_t tag, Variant::type_t variant) const {
|
||||
FMaterialInstance* mi = mMaterialInstanceManager.getMaterialInstance(ma, tag);
|
||||
mi->prepareProgram(driver, Variant { variant }, backend::CompilerPriorityQueue::CRITICAL);
|
||||
return mi;
|
||||
}
|
||||
|
||||
UboManager* PostProcessManager::getUboManager() const noexcept {
|
||||
return mEngine.getUboManager();
|
||||
}
|
||||
@@ -468,9 +480,10 @@ void PostProcessManager::unbindAllDescriptorSets(DriverApi& driver) noexcept {
|
||||
|
||||
UTILS_NOINLINE
|
||||
PipelineState PostProcessManager::getPipelineState(
|
||||
FMaterial const* const ma, Variant::type_t const variant) const noexcept {
|
||||
FMaterialInstance const* const mi, Variant::type_t const variant) const noexcept {
|
||||
FMaterial const* const ma = mi->getMaterial();
|
||||
return {
|
||||
.program = ma->getProgram(Variant{ variant }),
|
||||
.program = mi->getProgram(Variant{ variant }),
|
||||
.vertexBufferInfo = mFullScreenQuadVbih,
|
||||
.pipelineLayout = {
|
||||
.setLayout = {
|
||||
@@ -478,7 +491,7 @@ PipelineState PostProcessManager::getPipelineState(
|
||||
mPerRenderableDslh,
|
||||
ma->getDescriptorSetLayout().getHandle()
|
||||
}},
|
||||
.rasterState = ma->getRasterState()
|
||||
.rasterState = mi->getRasterState()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -518,8 +531,7 @@ void PostProcessManager::commitAndRenderFullScreenQuad(DriverApi& driver,
|
||||
PostProcessVariant const variant) const noexcept {
|
||||
mi->commit(driver, getUboManager());
|
||||
mi->use(driver);
|
||||
FMaterial const* const ma = mi->getMaterial();
|
||||
PipelineState const pipeline = getPipelineState(ma, variant);
|
||||
PipelineState const pipeline = getPipelineState(mi, variant);
|
||||
|
||||
assert_invariant(
|
||||
((out.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH)
|
||||
@@ -636,12 +648,12 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
|
||||
auto in = resources.getTexture(data.depth);
|
||||
auto& material = getPostProcessMaterial("mipmapDepth");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterialInstance* const mi = getMaterialInstance(ma);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterialInstance* const mi = getMaterialInstance(driver, ma);
|
||||
// Only the depth texture is changing in the material instance (no UBO updates),
|
||||
// we do not move getMaterialInstance() inside the loop.
|
||||
|
||||
auto pipeline = getPipelineState(ma);
|
||||
auto pipeline = getPipelineState(mi);
|
||||
|
||||
// The first mip already exists, so we process n-1 lods
|
||||
for (size_t level = 0; level < levelCount - 1; level++) {
|
||||
@@ -1001,14 +1013,13 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
#endif
|
||||
auto& material = getPostProcessMaterial(materialName);
|
||||
|
||||
FMaterial* ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial* ma = material.getMaterial(mEngine);
|
||||
ma->getPrograms().setConstants({
|
||||
{ "useVisibilityBitmasks", options.gtao.useVisibilityBitmasks },
|
||||
{ "linearThickness", options.gtao.linearThickness },
|
||||
});
|
||||
|
||||
ma = material.getMaterial(mEngine, driver);
|
||||
FMaterialInstance* const mi = getMaterialInstance(ma);
|
||||
FMaterialInstance* const mi = getMaterialInstance(driver, ma);
|
||||
|
||||
// Set AO type specific material parameters
|
||||
switch (aoType) {
|
||||
@@ -1084,7 +1095,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
mi->commit(driver, getUboManager());
|
||||
mi->use(driver);
|
||||
|
||||
auto pipeline = getPipelineState(ma);
|
||||
auto pipeline = getPipelineState(mi);
|
||||
pipeline.rasterState.depthFunc = RasterState::DepthFunc::L;
|
||||
assert_invariant(ssao.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH);
|
||||
renderFullScreenQuad(ssao, pipeline, driver);
|
||||
@@ -1194,8 +1205,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
|
||||
auto& material = config.bentNormals ?
|
||||
getPostProcessMaterial("bilateralBlurBentNormals") :
|
||||
getPostProcessMaterial("bilateralBlur");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterialInstance* const mi = getMaterialInstance(ma);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterialInstance* const mi = getMaterialInstance(driver, ma);
|
||||
mi->setParameter("ssao", ssao, { /* only reads level 0 */ });
|
||||
mi->setParameter("axis", axis / float2{desc.width, desc.height});
|
||||
mi->setParameter("kernel", kGaussianSamples, kGaussianCount);
|
||||
@@ -1205,7 +1216,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
|
||||
mi->commit(driver, getUboManager());
|
||||
mi->use(driver);
|
||||
|
||||
auto pipeline = getPipelineState(ma);
|
||||
auto pipeline = getPipelineState(mi);
|
||||
pipeline.rasterState.depthFunc = RasterState::DepthFunc::L;
|
||||
renderFullScreenQuad(blurred, pipeline, driver);
|
||||
unbindAllDescriptorSets(driver);
|
||||
@@ -1364,7 +1375,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
|
||||
"separableGaussianBlur4L"sv : "separableGaussianBlur4"sv; break;
|
||||
}
|
||||
auto const& separableGaussianBlur = getPostProcessMaterial(materialName);
|
||||
auto ma = separableGaussianBlur.getMaterial(mEngine, driver);
|
||||
auto ma = separableGaussianBlur.getMaterial(mEngine);
|
||||
|
||||
const size_t kernelStorageSize = ma->reflect("kernel")->size;
|
||||
float2 kernel[64];
|
||||
@@ -1887,9 +1898,10 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto inOutCoc = resources.getTexture(data.inOutCoc);
|
||||
|
||||
auto const& material = getPostProcessMaterial("dofMipmap");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterialInstance* const mi = getMaterialInstance(driver, ma);
|
||||
|
||||
auto const pipeline = getPipelineState(ma, variant);
|
||||
auto const pipeline = getPipelineState(mi, variant);
|
||||
|
||||
for (size_t level = 0 ; level < mipmapCount - 1u ; level++) {
|
||||
const float w = FTexture::valueForLevel(level, desc.width);
|
||||
@@ -1897,7 +1909,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto const& out = resources.getRenderPassInfo(data.rp[level]);
|
||||
auto inColor = driver.createTextureView(inOutColor, level, 1);
|
||||
auto inCoc = driver.createTextureView(inOutCoc, level, 1);
|
||||
FMaterialInstance* const mi = getMaterialInstance(ma);
|
||||
// FIXME: is this necessary?
|
||||
FMaterialInstance* const mi = getMaterialInstance(driver, ma);
|
||||
|
||||
mi->setParameter("color", inColor, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||
@@ -2426,9 +2439,9 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
|
||||
auto const& outDesc = resources.getDescriptor(data.out);
|
||||
|
||||
auto const& material = getPostProcessMaterial("bloomUpsample");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
|
||||
auto pipeline = getPipelineState(ma);
|
||||
auto pipeline = getPipelineState(getMaterialInstance(driver, ma));
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE;
|
||||
|
||||
@@ -2436,7 +2449,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
|
||||
// Note that we wouldn't want to use the same instance for each pass since that
|
||||
// would imply using the same UBOs, which implies synchronization across the
|
||||
// passes.
|
||||
FMaterialInstance* mi = getMaterialInstance(ma);
|
||||
FMaterialInstance* mi = getMaterialInstance(driver, ma);
|
||||
auto hwDstRT = resources.getRenderPassInfo(data.outRT[i - 1]);
|
||||
hwDstRT.params.flags.discardStart = TargetBufferFlags::NONE; // b/c we'll blend
|
||||
hwDstRT.params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
@@ -2569,11 +2582,12 @@ void PostProcessManager::colorGradingSubpass(DriverApi& driver,
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
auto const& material = getPostProcessMaterial("colorGradingAsSubpass");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver, variant);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
// the UBO has been set and committed in colorGradingPrepareSubpass()
|
||||
FMaterialInstance const* mi = mMaterialInstanceManager.getMaterialInstance(ma, colorGradingConfig.translucent);
|
||||
FMaterialInstance const* mi =
|
||||
getMaterialInstanceWithTag(driver, ma, colorGradingConfig.translucent, variant);
|
||||
mi->use(driver);
|
||||
auto const pipeline = getPipelineState(ma, variant);
|
||||
auto const pipeline = getPipelineState(mi, variant);
|
||||
driver.nextSubpass();
|
||||
driver.scissor(mi->getScissor());
|
||||
driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1);
|
||||
@@ -2581,8 +2595,8 @@ void PostProcessManager::colorGradingSubpass(DriverApi& driver,
|
||||
|
||||
void PostProcessManager::customResolvePrepareSubpass(DriverApi& driver, CustomResolveOp const op) noexcept {
|
||||
auto const& material = getPostProcessMaterial("customResolveAsSubpass");
|
||||
auto const ma = material.getMaterial(mEngine, driver, PostProcessVariant::OPAQUE);
|
||||
auto* const mi = mMaterialInstanceManager.getMaterialInstance(ma, 0);
|
||||
auto const ma = material.getMaterial(mEngine);
|
||||
auto* const mi = getMaterialInstance(driver, ma, 0);
|
||||
mi->setParameter("direction", op == CustomResolveOp::COMPRESS ? 1.0f : -1.0f),
|
||||
mi->commit(driver, getUboManager());
|
||||
}
|
||||
@@ -2592,12 +2606,12 @@ void PostProcessManager::customResolveSubpass(DriverApi& driver) noexcept {
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& material = getPostProcessMaterial("customResolveAsSubpass");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
// the UBO has been set and committed in customResolvePrepareSubpass()
|
||||
FMaterialInstance const* mi = mMaterialInstanceManager.getMaterialInstance(ma, 0);
|
||||
FMaterialInstance const* mi = getMaterialInstance(driver, ma, 0);
|
||||
mi->use(driver);
|
||||
|
||||
auto const pipeline = getPipelineState(ma);
|
||||
auto const pipeline = getPipelineState(mi);
|
||||
driver.nextSubpass();
|
||||
driver.scissor(mi->getScissor());
|
||||
driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1);
|
||||
@@ -2633,8 +2647,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::customResolveUncompressPass(
|
||||
void PostProcessManager::clearAncillaryBuffersPrepare(DriverApi& driver,
|
||||
Variant::type_t variant) noexcept {
|
||||
auto const& material = getPostProcessMaterial("clearDepth");
|
||||
auto const ma = material.getMaterial(mEngine, driver, variant);
|
||||
auto const mi = mMaterialInstanceManager.getMaterialInstance(ma, 0);
|
||||
auto const ma = material.getMaterial(mEngine);
|
||||
auto const mi = getMaterialInstanceWithTag(driver, ma, 0, variant);
|
||||
mi->commit(driver, getUboManager());
|
||||
}
|
||||
|
||||
@@ -2649,13 +2663,13 @@ void PostProcessManager::clearAncillaryBuffers(DriverApi& driver,
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& material = getPostProcessMaterial("clearDepth");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver, variant);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
|
||||
// the UBO has been set and committed in clearAncillaryBuffersPrepare()
|
||||
FMaterialInstance const* const mi = mMaterialInstanceManager.getMaterialInstance(ma, 0);
|
||||
FMaterialInstance const* const mi = getMaterialInstanceWithTag(driver, ma, 0, variant);
|
||||
mi->use(driver);
|
||||
|
||||
auto pipeline = getPipelineState(ma, variant);
|
||||
auto pipeline = getPipelineState(mi, variant);
|
||||
pipeline.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
|
||||
driver.scissor(mi->getScissor());
|
||||
@@ -2665,7 +2679,7 @@ void PostProcessManager::clearAncillaryBuffers(DriverApi& driver,
|
||||
void PostProcessManager::fogPrepare(DriverApi& driver) noexcept {
|
||||
// ensures the material is loaded and material instance created
|
||||
auto const& material = getPostProcessMaterial("fog");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver, PostProcessVariant::OPAQUE);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterialInstance const* mi = ma->getDefaultInstance();
|
||||
mi->commit(driver, getUboManager());
|
||||
}
|
||||
@@ -2676,11 +2690,11 @@ void PostProcessManager::fog(DriverApi& driver) noexcept {
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& material = getPostProcessMaterial("fog");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterialInstance const* mi = ma->getDefaultInstance();
|
||||
mi->use(driver);
|
||||
|
||||
auto pipeline = getPipelineState(ma, Variant::NO_VARIANT);
|
||||
auto pipeline = getPipelineState(mi, Variant::NO_VARIANT);
|
||||
driver.scissor(mi->getScissor());
|
||||
driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1);
|
||||
}
|
||||
@@ -2937,7 +2951,7 @@ void PostProcessManager::TaaJitterCamera(
|
||||
void PostProcessManager::configureTemporalAntiAliasingMaterial(backend::DriverApi& driver,
|
||||
TemporalAntiAliasingOptions const& taaOptions) noexcept {
|
||||
|
||||
FMaterial* const ma = getPostProcessMaterial("taa").getMaterial(mEngine, driver);
|
||||
FMaterial* const ma = getPostProcessMaterial("taa").getMaterial(mEngine);
|
||||
ma->getPrograms().setConstants({
|
||||
{ "upscaling", taaOptions.upscaling > 1.0f },
|
||||
{ "historyReprojection", taaOptions.historyReprojection },
|
||||
@@ -2956,7 +2970,7 @@ FMaterialInstance* PostProcessManager::configureColorGradingMaterial(backend::Dr
|
||||
PostProcessMaterial const& material, FColorGrading const* colorGrading,
|
||||
ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions,
|
||||
uint32_t const width, uint32_t const height) noexcept {
|
||||
FMaterial* ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial* ma = material.getMaterial(mEngine);
|
||||
ma->getPrograms().setConstants({
|
||||
{ "isOneDimensional", colorGrading->isOneDimensional() },
|
||||
{ "isLDR", colorGrading->isLDR() },
|
||||
@@ -2965,8 +2979,9 @@ FMaterialInstance* PostProcessManager::configureColorGradingMaterial(backend::Dr
|
||||
PostProcessVariant const variant = colorGradingConfig.translucent
|
||||
? PostProcessVariant::TRANSLUCENT
|
||||
: PostProcessVariant::OPAQUE;
|
||||
ma = material.getMaterial(mEngine, driver, variant);
|
||||
FMaterialInstance* mi = mMaterialInstanceManager.getMaterialInstance(ma, colorGradingConfig.translucent);
|
||||
ma = material.getMaterial(mEngine);
|
||||
FMaterialInstance* mi =
|
||||
getMaterialInstanceWithTag(driver, ma, colorGradingConfig.translucent, variant);
|
||||
|
||||
const SamplerParams params = SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
@@ -3078,9 +3093,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
|
||||
PostProcessVariant const variant = colorGradingConfig.translucent ?
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver, variant);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
|
||||
FMaterialInstance* mi = getMaterialInstance(ma);
|
||||
FMaterialInstance* mi = getMaterialInstance(driver, ma);
|
||||
mi->setParameter("color", color, SamplerParams{}); // nearest
|
||||
mi->setParameter("depth", depth, SamplerParams{}); // nearest
|
||||
mi->setParameter("history", history, SamplerParams{
|
||||
@@ -3120,7 +3135,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
|
||||
if (colorGradingConfig.asSubpass) {
|
||||
out.params.subpassMask = 1;
|
||||
}
|
||||
auto const pipeline = getPipelineState(ma, variant);
|
||||
auto const pipeline = getPipelineState(mi, variant);
|
||||
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1);
|
||||
@@ -3202,7 +3217,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
|
||||
mi->commit(driver, getUboManager());
|
||||
mi->use(driver);
|
||||
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine, driver), variant);
|
||||
auto pipeline = getPipelineState(mi, variant);
|
||||
if (mode == RcasMode::BLENDED) {
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
@@ -3295,7 +3310,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
|
||||
|
||||
auto out = resources.getRenderPassInfo();
|
||||
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine, driver));
|
||||
auto pipeline = getPipelineState(mi);
|
||||
if (blended) {
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
@@ -3509,15 +3524,15 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
||||
auto out = resources.getRenderPassInfo();
|
||||
|
||||
if (UTILS_UNLIKELY(twoPassesEASU)) {
|
||||
auto pipeline0 = getPipelineState(splitEasuMaterial->getMaterial(mEngine, driver));
|
||||
auto pipeline1 = getPipelineState(easuMaterial->getMaterial(mEngine, driver));
|
||||
auto pipeline0 = getPipelineState(getMaterialInstance(mEngine, driver, *splitEasuMaterial));
|
||||
auto pipeline1 = getPipelineState(getMaterialInstance(mEngine, driver, *easuMaterial));
|
||||
pipeline1.rasterState.depthFunc = SamplerCompareFunc::NE;
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
driver.draw(pipeline0, mFullScreenQuadRph, 0, 3, 1);
|
||||
driver.draw(pipeline1, mFullScreenQuadRph, 0, 3, 1);
|
||||
driver.endRenderPass();
|
||||
} else {
|
||||
auto pipeline = getPipelineState(easuMaterial->getMaterial(mEngine, driver));
|
||||
auto pipeline = getPipelineState(getMaterialInstance(mEngine, driver, *easuMaterial));
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
}
|
||||
unbindAllDescriptorSets(driver);
|
||||
@@ -3569,8 +3584,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool co
|
||||
|
||||
PostProcessMaterial const& material =
|
||||
getPostProcessMaterial(layer ? "blitArray" : "blitLow");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
auto* mi = getMaterialInstance(ma);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
auto* mi = getMaterialInstance(driver, ma);
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMag = filterMag,
|
||||
.filterMin = filterMin
|
||||
@@ -3588,7 +3603,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool co
|
||||
mi->commit(driver, getUboManager());
|
||||
mi->use(driver);
|
||||
|
||||
auto pipeline = getPipelineState(ma);
|
||||
auto pipeline = getPipelineState(mi);
|
||||
if (translucent) {
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
@@ -3883,10 +3898,10 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
|
||||
// set uniforms
|
||||
|
||||
PostProcessMaterial const& material = getPostProcessMaterial("blitArray");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
// It should be ok to not move this getMaterialInstance to inside the loop, since
|
||||
// this is a pass meant for debug.
|
||||
auto* mi = getMaterialInstance(ma);
|
||||
auto* mi = getMaterialInstance(driver, ma);
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMag = filterMag,
|
||||
.filterMin = filterMin
|
||||
@@ -3900,7 +3915,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
|
||||
mi->commit(driver, getUboManager());
|
||||
mi->use(driver);
|
||||
|
||||
auto pipeline = getPipelineState(ma);
|
||||
auto pipeline = getPipelineState(mi);
|
||||
if (translucent) {
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
|
||||
@@ -357,13 +357,7 @@ public:
|
||||
|
||||
void terminate(FEngine& engine) noexcept;
|
||||
|
||||
FMaterial* getMaterial(FEngine& engine, backend::DriverApi& driver,
|
||||
Variant::type_t variant) const noexcept;
|
||||
|
||||
FMaterial* getMaterial(FEngine& engine, backend::DriverApi& driver,
|
||||
PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept {
|
||||
return getMaterial(engine, driver, Variant::type_t(variant));
|
||||
}
|
||||
FMaterial* getMaterial(FEngine& engine) const noexcept;
|
||||
|
||||
private:
|
||||
void loadMaterial(FEngine& engine) const noexcept;
|
||||
@@ -390,11 +384,12 @@ public:
|
||||
|
||||
void bindPerRenderableDescriptorSet(backend::DriverApi& driver) const noexcept;
|
||||
|
||||
backend::PipelineState getPipelineState(FMaterial const* ma, Variant::type_t variant) const noexcept;
|
||||
backend::PipelineState getPipelineState(FMaterialInstance const* mi,
|
||||
Variant::type_t variant) const noexcept;
|
||||
|
||||
backend::PipelineState getPipelineState(FMaterial const* ma,
|
||||
PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept {
|
||||
return getPipelineState(ma, Variant::type_t(variant));
|
||||
backend::PipelineState getPipelineState(FMaterialInstance const* mi,
|
||||
PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept {
|
||||
return getPipelineState(mi, Variant::type_t(variant));
|
||||
}
|
||||
|
||||
void renderFullScreenQuad(FrameGraphResources::RenderPassInfo const& out,
|
||||
@@ -424,27 +419,47 @@ public:
|
||||
|
||||
void resetForRender();
|
||||
|
||||
|
||||
MaterialInstanceManager& getMaterialInstanceManager() noexcept {
|
||||
return mMaterialInstanceManager;
|
||||
}
|
||||
|
||||
// Helper to get a MaterialInstance from a FMaterial
|
||||
// This currently just call FMaterial::getDefaultInstance().
|
||||
FMaterialInstance* getMaterialInstance(FMaterial const* ma) {
|
||||
return mMaterialInstanceManager.getMaterialInstance(ma);
|
||||
}
|
||||
|
||||
// Helper to get a MaterialInstance from a PostProcessMaterial.
|
||||
FMaterialInstance* getMaterialInstance(FEngine& engine, backend::DriverApi& driver,
|
||||
PostProcessMaterial const& material, PostProcessVariant variant = PostProcessVariant::OPAQUE) {
|
||||
FMaterial const* ma = material.getMaterial(engine, driver, variant);
|
||||
return getMaterialInstance(ma);
|
||||
}
|
||||
|
||||
static void unbindAllDescriptorSets(backend::DriverApi& driver) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
// Helpers to get MaterialInstances.
|
||||
//
|
||||
// These funcions additionally ensure that the necessary shader programs are compiled via
|
||||
// prepareProgram().
|
||||
FMaterialInstance* getMaterialInstance(backend::DriverApi& driver, FMaterial const* ma,
|
||||
Variant::type_t variant) const;
|
||||
|
||||
FMaterialInstance* getMaterialInstance(backend::DriverApi& driver, FMaterial const* ma,
|
||||
PostProcessVariant variant = PostProcessVariant::OPAQUE) const {
|
||||
return getMaterialInstance(driver, ma, Variant::type_t(variant));
|
||||
}
|
||||
|
||||
FMaterialInstance* getMaterialInstance(FEngine& engine, backend::DriverApi& driver,
|
||||
PostProcessMaterial const& material,
|
||||
PostProcessVariant variant = PostProcessVariant::OPAQUE) const {
|
||||
return getMaterialInstance(driver, material.getMaterial(engine), Variant::type_t(variant));
|
||||
}
|
||||
|
||||
FMaterialInstance* getMaterialInstanceWithTag(backend::DriverApi& driver, FMaterial const* ma,
|
||||
uint32_t tag, Variant::type_t variant) const;
|
||||
|
||||
FMaterialInstance* getMaterialInstanceWithTag(backend::DriverApi& driver, FMaterial const* ma,
|
||||
uint32_t tag, PostProcessVariant variant = PostProcessVariant::OPAQUE) const {
|
||||
return getMaterialInstanceWithTag(driver, ma, tag, Variant::type_t(variant));
|
||||
}
|
||||
|
||||
FMaterialInstance* getMaterialInstanceWithTag(FEngine& engine, backend::DriverApi& driver,
|
||||
PostProcessMaterial const& material, uint32_t tag,
|
||||
PostProcessVariant variant = PostProcessVariant::OPAQUE) const {
|
||||
return getMaterialInstanceWithTag(driver, material.getMaterial(engine), tag,
|
||||
Variant::type_t(variant));
|
||||
}
|
||||
|
||||
UboManager* getUboManager() const noexcept;
|
||||
|
||||
backend::RenderPrimitiveHandle mFullScreenQuadRph;
|
||||
|
||||
@@ -243,8 +243,8 @@ void RenderPass::appendCommands(FEngine const& engine, backend::DriverApi& drive
|
||||
// This must be done from the main thread.
|
||||
for (Command const* first = curr, *last = curr + commandCount ; first != last ; ++first) {
|
||||
if (UTILS_LIKELY((first->key & CUSTOM_MASK) == uint64_t(CustomCommand::PASS))) {
|
||||
auto ma = first->info.mi->getMaterial();
|
||||
ma->prepareProgram(driver, first->info.materialVariant, CompilerPriorityQueue::CRITICAL);
|
||||
first->info.mi->prepareProgram(driver, first->info.materialVariant,
|
||||
CompilerPriorityQueue::CRITICAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,16 +426,18 @@ void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant,
|
||||
bool const isBlendingCommand = !hasScreenSpaceRefraction &&
|
||||
(blendingMode != BlendingMode::OPAQUE && blendingMode != BlendingMode::MASKED);
|
||||
|
||||
RasterState rasterState = mi->getRasterState();
|
||||
|
||||
uint64_t keyDraw = cmdDraw.key;
|
||||
keyDraw &= ~(PASS_MASK | BLENDING_MASK | MATERIAL_MASK);
|
||||
keyDraw |= uint64_t(hasScreenSpaceRefraction ? Pass::REFRACT : Pass::COLOR);
|
||||
keyDraw |= uint64_t(CustomCommand::PASS);
|
||||
keyDraw |= mi->getSortingKey(); // already all set-up for direct or'ing
|
||||
keyDraw |= makeField(variant.key, MATERIAL_VARIANT_KEY_MASK, MATERIAL_VARIANT_KEY_SHIFT);
|
||||
keyDraw |= makeField(ma->getRasterState().alphaToCoverage, BLENDING_MASK, BLENDING_SHIFT);
|
||||
keyDraw |= makeField(rasterState.alphaToCoverage, BLENDING_MASK, BLENDING_SHIFT);
|
||||
|
||||
cmdDraw.key = isBlendingCommand ? keyBlending : keyDraw;
|
||||
cmdDraw.info.rasterState = ma->getRasterState();
|
||||
cmdDraw.info.rasterState = rasterState;
|
||||
|
||||
// for SSR pass, the blending mode of opaques (including MASKED) must be off
|
||||
// see Material.cpp.
|
||||
@@ -446,10 +448,6 @@ void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant,
|
||||
BlendFunction::ZERO : cmdDraw.info.rasterState.blendFunctionDstAlpha;
|
||||
|
||||
cmdDraw.info.rasterState.inverseFrontFaces = inverseFrontFaces;
|
||||
cmdDraw.info.rasterState.culling = mi->getCullingMode();
|
||||
cmdDraw.info.rasterState.colorWrite = mi->isColorWriteEnabled();
|
||||
cmdDraw.info.rasterState.depthWrite = mi->isDepthWriteEnabled();
|
||||
cmdDraw.info.rasterState.depthFunc = mi->getDepthFunc();
|
||||
cmdDraw.info.rasterState.depthClamp = hasDepthClamp;
|
||||
cmdDraw.info.materialVariant = variant;
|
||||
// we keep "RasterState::colorWrite" to the value set by material (could be disabled)
|
||||
@@ -1090,8 +1088,7 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
|
||||
mi->use(driver, info.materialVariant);
|
||||
}
|
||||
|
||||
assert_invariant(ma);
|
||||
pipeline.program = ma->getProgram(info.materialVariant);
|
||||
pipeline.program = mi->getProgram(info.materialVariant);
|
||||
|
||||
if (UTILS_UNLIKELY(memcmp(&pipeline, ¤tPipeline, sizeof(PipelineState)) != 0)) {
|
||||
currentPipeline = pipeline;
|
||||
|
||||
@@ -636,7 +636,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::gaussianBlurSeparatedPass(
|
||||
|
||||
// get the material
|
||||
auto const& separableGaussianBlur = ppm.getPostProcessMaterial("gaussian");
|
||||
auto const ma = separableGaussianBlur.getMaterial(engine, driver);
|
||||
auto const ma = separableGaussianBlur.getMaterial(engine);
|
||||
|
||||
// Generates half of a Gaussian kernel (center + one side)
|
||||
auto generateGaussianWeights = [](std::array<float, 32>& weights,
|
||||
@@ -685,7 +685,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::gaussianBlurSeparatedPass(
|
||||
for (auto const mi : miList) {
|
||||
mi->use(driver);
|
||||
driver.scissor(mi->getScissor());
|
||||
driver.draw(ppm.getPipelineState(ma), engine.getFullScreenRenderPrimitive(), 0, 3, 1);
|
||||
driver.draw(ppm.getPipelineState(mi), engine.getFullScreenRenderPrimitive(), 0, 3, 1);
|
||||
}
|
||||
driver.endRenderPass();
|
||||
|
||||
@@ -733,12 +733,12 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::vsmMipmapPass(
|
||||
ppm.bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto& material = ppm.getPostProcessMaterial("vsmMipmap");
|
||||
FMaterial const* const ma = material.getMaterial(engine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(engine);
|
||||
auto const mi = ppm.getMaterialInstanceManager().getMaterialInstance(ma);
|
||||
|
||||
auto const pipeline = ppm.getPipelineState(ma);
|
||||
auto const pipeline = ppm.getPipelineState(mi);
|
||||
backend::Viewport const scissor = { 0, 0, dim, dim };
|
||||
|
||||
auto const mi = ppm.getMaterialInstanceManager().getMaterialInstance(ma);
|
||||
mi->setParameter("color", in, SamplerParams{
|
||||
.filterMag = SamplerMagFilter::NEAREST,
|
||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST
|
||||
|
||||
@@ -1741,7 +1741,7 @@ void FEngine::compile(
|
||||
CallbackHandler* handler,
|
||||
Invocable<void(Material*)>&& callback) {
|
||||
auto const variants = getMaterialCompileVariants(view, shadowReceiver, skinning);
|
||||
material->compile(priority, variants, handler, std::move(callback));
|
||||
const_cast<FMaterial*>(material)->compile(priority, variants, handler, std::move(callback));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -170,8 +170,6 @@ FMaterial::FMaterial(FEngine& engine, const Builder& builder, MaterialDefinition
|
||||
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
|
||||
mIsStereoSupported = driver.isStereoSupported();
|
||||
mIsParallelShaderCompileSupported = driver.isParallelShaderCompileSupported();
|
||||
mDepthPrecacheDisabled =
|
||||
driver.isWorkaroundNeeded(Workaround::DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL);
|
||||
mDefaultMaterial = engine.getDefaultMaterial();
|
||||
@@ -240,44 +238,33 @@ filament::DescriptorSetLayout const& FMaterial::getPerViewDescriptorSetLayout(
|
||||
void FMaterial::compile(CompilerPriorityQueue const priority,
|
||||
UserVariantFilterMask variantSpec,
|
||||
CallbackHandler* handler,
|
||||
Invocable<void(Material*)>&& callback) const noexcept {
|
||||
DriverApi& driver = mEngine.getDriverApi();
|
||||
|
||||
// Turn off the STE variant if stereo is not supported.
|
||||
if (!mIsStereoSupported) {
|
||||
variantSpec &= ~UserVariantFilterMask(UserVariantFilterBit::STE);
|
||||
Invocable<void(Material*)>&& callback) noexcept {
|
||||
FMaterialInstance* mi = getDefaultInstance();
|
||||
if (callback) {
|
||||
mi->compile(priority, variantSpec, handler,
|
||||
[this, callback = std::move(callback)](MaterialInstance*) {
|
||||
callback(this);
|
||||
});
|
||||
} else {
|
||||
mi->compile(priority, variantSpec, handler, {});
|
||||
}
|
||||
|
||||
UserVariantFilterMask const variantFilter = ~variantSpec & UserVariantFilterMask(UserVariantFilterBit::ALL);
|
||||
ShaderModel const shaderModel = mEngine.getShaderModel();
|
||||
bool const isStereoSupported = mEngine.getDriverApi().isStereoSupported();
|
||||
|
||||
if (UTILS_LIKELY(mIsParallelShaderCompileSupported)) {
|
||||
for (auto const variant: mDefinition.getVariants()) {
|
||||
if (!variantFilter || variant == Variant::filterUserVariant(variant, variantFilter)) {
|
||||
if (mDefinition.hasVariant(variant, shaderModel, isStereoSupported)) {
|
||||
prepareProgram(driver, variant, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileAllPrograms(priority, handler, std::move(callback));
|
||||
}
|
||||
|
||||
void FMaterial::compile(CompilerPriorityQueue const priority,
|
||||
FixedCapacityVector<Variant> const& variants,
|
||||
CallbackHandler* handler,
|
||||
Invocable<void(Material*)>&& callback) const noexcept {
|
||||
Invocable<void(Material*)>&& callback) noexcept {
|
||||
DriverApi& driver = mEngine.getDriverApi();
|
||||
FMaterialInstance* mi = getDefaultInstance();
|
||||
|
||||
ShaderModel const shaderModel = mEngine.getShaderModel();
|
||||
bool const isStereoSupported = driver.isStereoSupported();
|
||||
bool const isParallelShaderCompileSupported = driver.isParallelShaderCompileSupported();
|
||||
|
||||
if (UTILS_LIKELY(mIsParallelShaderCompileSupported)) {
|
||||
if (UTILS_LIKELY(isParallelShaderCompileSupported)) {
|
||||
for (auto const variant : variants) {
|
||||
if (mDefinition.hasVariant(variant, shaderModel, isStereoSupported)) {
|
||||
prepareProgram(driver, variant, priority);
|
||||
mi->prepareProgram(driver, variant, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,7 +274,7 @@ void FMaterial::compile(CompilerPriorityQueue const priority,
|
||||
|
||||
void FMaterial::compileAllPrograms(CompilerPriorityQueue const priority,
|
||||
CallbackHandler* handler,
|
||||
Invocable<void(Material*)>&& callback) const noexcept {
|
||||
Invocable<void(Material*)>&& callback) noexcept {
|
||||
DriverApi& driver = mEngine.getDriverApi();
|
||||
|
||||
if (callback) {
|
||||
|
||||
@@ -106,12 +106,12 @@ public:
|
||||
void compile(CompilerPriorityQueue priority,
|
||||
UserVariantFilterMask variantSpec,
|
||||
backend::CallbackHandler* handler,
|
||||
utils::Invocable<void(Material*)>&& callback) const noexcept;
|
||||
utils::Invocable<void(Material*)>&& callback) noexcept;
|
||||
|
||||
void compile(CompilerPriorityQueue priority,
|
||||
utils::FixedCapacityVector<Variant> const& variants,
|
||||
backend::CallbackHandler* handler,
|
||||
utils::Invocable<void(Material*)>&& callback) const noexcept;
|
||||
utils::Invocable<void(Material*)>&& callback) noexcept;
|
||||
|
||||
// Creates an instance of this material, specifying the batching mode.
|
||||
FMaterialInstance* createInstance(const char* name) const noexcept;
|
||||
@@ -130,40 +130,6 @@ public:
|
||||
|
||||
FEngine& getEngine() const noexcept { return mEngine; }
|
||||
|
||||
// prepareProgram creates the program for the material's given variant at the backend level.
|
||||
// Must be called outside of backend render pass.
|
||||
// Must be called before getProgram() below.
|
||||
backend::Handle<backend::HwProgram> prepareProgram(backend::DriverApi& driver,
|
||||
Variant const variant,
|
||||
backend::CompilerPriorityQueue const priorityQueue) const noexcept {
|
||||
return mPrograms.prepareProgram(driver, variant, priorityQueue);
|
||||
}
|
||||
|
||||
// getProgram returns the backend program for the material's given variant.
|
||||
// Must be called after prepareProgram().
|
||||
[[nodiscard]]
|
||||
backend::Handle<backend::HwProgram> getProgram(Variant variant) const noexcept {
|
||||
|
||||
if (UTILS_UNLIKELY(mEngine.features.material.enable_fog_as_postprocess)) {
|
||||
// if the fog as post-process feature is enabled, we need to proceed "as-if" the material
|
||||
// didn't have the FOG variant bit.
|
||||
if (getMaterialDomain() == MaterialDomain::SURFACE) {
|
||||
BlendingMode const blendingMode = getBlendingMode();
|
||||
bool const hasScreenSpaceRefraction = getRefractionMode() == RefractionMode::SCREEN_SPACE;
|
||||
bool const isBlendingCommand = !hasScreenSpaceRefraction &&
|
||||
(blendingMode != BlendingMode::OPAQUE && blendingMode != BlendingMode::MASKED);
|
||||
if (!isBlendingCommand) {
|
||||
variant.setFog(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
updateActiveProgramsForMatdbg(variant);
|
||||
#endif
|
||||
return mPrograms.getProgram(variant);
|
||||
}
|
||||
|
||||
// MaterialInstance::use() binds descriptor sets before drawing. For shared variants,
|
||||
// however, the material instance will call useShared() to bind the default material's sets
|
||||
// instead.
|
||||
@@ -310,6 +276,9 @@ public:
|
||||
}
|
||||
|
||||
/** @}*/
|
||||
|
||||
// Called by getProgram() to update active program list for matdbg UI.
|
||||
void updateActiveProgramsForMatdbg(Variant const variant) const noexcept;
|
||||
#endif
|
||||
|
||||
private:
|
||||
@@ -318,15 +287,13 @@ private:
|
||||
|
||||
void compileAllPrograms(CompilerPriorityQueue priority,
|
||||
backend::CallbackHandler* handler,
|
||||
utils::Invocable<void(Material*)>&& callback) const noexcept;
|
||||
utils::Invocable<void(Material*)>&& callback) noexcept;
|
||||
|
||||
MaterialDefinition const& mDefinition;
|
||||
|
||||
bool mIsDefaultMaterial = false;
|
||||
|
||||
bool mUseUboBatching = false;
|
||||
bool mIsStereoSupported = false;
|
||||
bool mIsParallelShaderCompileSupported = false;
|
||||
bool mDepthPrecacheDisabled = false;
|
||||
|
||||
FMaterial const* mDefaultMaterial = nullptr;
|
||||
@@ -341,8 +308,6 @@ private:
|
||||
mutable utils::Mutex mPendingEditsLock;
|
||||
std::unique_ptr<MaterialParser> mPendingEdits;
|
||||
std::unique_ptr<MaterialParser> mEditedMaterialParser;
|
||||
// Called by getProgram() to update active program list for matdbg UI.
|
||||
void updateActiveProgramsForMatdbg(Variant const variant) const noexcept;
|
||||
void setPendingEdits(std::unique_ptr<MaterialParser> pendingEdits) noexcept;
|
||||
bool hasPendingEdits() const noexcept;
|
||||
void latchPendingEdits() noexcept;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <filament/MaterialInstance.h>
|
||||
|
||||
#include "RenderPass.h"
|
||||
#include "MaterialParser.h"
|
||||
|
||||
#include "ds/DescriptorSetLayout.h"
|
||||
|
||||
@@ -131,6 +132,7 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
|
||||
mTextureParameters(other->mTextureParameters),
|
||||
mDescriptorSet(other->mDescriptorSet.duplicate(
|
||||
"MaterialInstance", mMaterial->getDescriptorSetLayout())),
|
||||
mPrograms(other->mPrograms),
|
||||
mPolygonOffset(other->mPolygonOffset),
|
||||
mStencilState(other->mStencilState),
|
||||
mMaskThreshold(other->mMaskThreshold),
|
||||
@@ -207,6 +209,10 @@ void FMaterialInstance::terminate(FEngine& engine) {
|
||||
if (ubHandle){
|
||||
driver.destroyBufferObject(*ubHandle);
|
||||
}
|
||||
|
||||
if (mPrograms.isInitialized()) {
|
||||
mPrograms.terminate(engine);
|
||||
}
|
||||
}
|
||||
|
||||
void FMaterialInstance::commit(FEngine& engine) const {
|
||||
@@ -259,6 +265,39 @@ void FMaterialInstance::commit(FEngine::DriverApi& driver, UboManager* uboManage
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
void FMaterialInstance::setConstantImpl(std::string_view name, T value) {
|
||||
auto const& constants = mMaterial->getDefinition().specializationConstantsNameToIndex;
|
||||
auto it = constants.find(name);
|
||||
FILAMENT_CHECK_PRECONDITION(it != constants.end()) << "Constant " << name << " does not exist";
|
||||
|
||||
if (UTILS_UNLIKELY(mPendingSpecializationConstants.empty())) {
|
||||
mPendingSpecializationConstants =
|
||||
FixedCapacityVector<backend::Program::SpecializationConstant>(
|
||||
getPrograms().getSpecializationConstants());
|
||||
}
|
||||
|
||||
uint32_t id = it->second + CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
|
||||
mPendingSpecializationConstants[id] = value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T FMaterialInstance::getConstantImpl(std::string_view name) const {
|
||||
auto const& constants = mMaterial->getDefinition().specializationConstantsNameToIndex;
|
||||
auto it = constants.find(name);
|
||||
FILAMENT_CHECK_PRECONDITION(it != constants.end()) << "Constant " << name << " does not exist";
|
||||
|
||||
uint32_t id = it->second + CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
|
||||
|
||||
if (UTILS_UNLIKELY(!mPendingSpecializationConstants.empty())) {
|
||||
return std::get<T>(mPendingSpecializationConstants[id]);
|
||||
}
|
||||
|
||||
return getPrograms().getConstant<T>(id);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void FMaterialInstance::setParameter(std::string_view const name,
|
||||
Handle<HwTexture> texture, SamplerParams const params) {
|
||||
auto const binding = mMaterial->getSamplerBinding(name);
|
||||
@@ -378,6 +417,15 @@ void FMaterialInstance::setTransparencyMode(TransparencyMode const mode) noexcep
|
||||
mTransparencyMode = mode;
|
||||
}
|
||||
|
||||
RasterState FMaterialInstance::getRasterState() const noexcept {
|
||||
RasterState rs = mMaterial->getRasterState();
|
||||
rs.culling = mCulling;
|
||||
rs.depthWrite = mDepthWrite;
|
||||
rs.depthFunc = mDepthFunc;
|
||||
rs.colorWrite = mColorWrite;
|
||||
return rs;
|
||||
}
|
||||
|
||||
void FMaterialInstance::setDepthCulling(bool const enable) noexcept {
|
||||
mDepthFunc = enable ? RasterState::DepthFunc::GE : RasterState::DepthFunc::A;
|
||||
}
|
||||
@@ -398,6 +446,51 @@ const char* FMaterialInstance::getName() const noexcept {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void FMaterialInstance::compile(CompilerPriorityQueue const priority,
|
||||
UserVariantFilterMask variantSpec, CallbackHandler* handler,
|
||||
Invocable<void(MaterialInstance*)>&& callback) noexcept {
|
||||
FEngine& engine = mMaterial->getEngine();
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
MaterialDefinition const& definition = mMaterial->getDefinition();
|
||||
|
||||
bool const isStereoSupported = driver.isStereoSupported();
|
||||
|
||||
// Turn off the STE variant if stereo is not supported.
|
||||
if (UTILS_LIKELY(!isStereoSupported)) {
|
||||
variantSpec &= ~UserVariantFilterMask(UserVariantFilterBit::STE);
|
||||
}
|
||||
|
||||
UserVariantFilterMask const variantFilter =
|
||||
~variantSpec & UserVariantFilterMask(UserVariantFilterBit::ALL);
|
||||
ShaderModel const shaderModel = engine.getShaderModel();
|
||||
|
||||
if (UTILS_LIKELY(driver.isParallelShaderCompileSupported())) {
|
||||
for (auto const variant: definition.getVariants()) {
|
||||
if (!variantFilter || variant == Variant::filterUserVariant(variant, variantFilter)) {
|
||||
if (definition.hasVariant(variant, shaderModel, isStereoSupported)) {
|
||||
prepareProgram(driver, variant, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
struct Callback {
|
||||
Invocable<void(MaterialInstance*)> f;
|
||||
MaterialInstance* m;
|
||||
static void func(void* user) {
|
||||
auto* const c = static_cast<Callback*>(user);
|
||||
c->f(c->m);
|
||||
delete c;
|
||||
}
|
||||
};
|
||||
auto* const user = new (std::nothrow) Callback{ std::move(callback), this };
|
||||
driver.compilePrograms(priority, handler, &Callback::func, user);
|
||||
} else {
|
||||
driver.compilePrograms(priority, nullptr, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void FMaterialInstance::use(FEngine::DriverApi& driver, Variant variant) const {
|
||||
assert_invariant(mDescriptorSet.getHandle());
|
||||
assert_invariant(!isUsingUboBatching() || BufferAllocator::isValid(getAllocationId()));
|
||||
@@ -502,4 +595,36 @@ void FMaterialInstance::fixMissingSamplers() const {
|
||||
}
|
||||
}
|
||||
|
||||
LocalProgramCache const& FMaterialInstance::getPrograms() const noexcept {
|
||||
return mPrograms.isInitialized() ? mPrograms : mMaterial->getPrograms();
|
||||
}
|
||||
|
||||
void FMaterialInstance::flushSpecializationConstants() const noexcept {
|
||||
if (mPendingSpecializationConstants.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mPrograms.isInitialized()) {
|
||||
mPrograms.initializeForMaterialInstance(mMaterial->getEngine(), *mMaterial);
|
||||
}
|
||||
mPrograms.setConstants(std::move(mPendingSpecializationConstants));
|
||||
mPendingSpecializationConstants.clear();
|
||||
}
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
|
||||
void FMaterialInstance::updateActiveProgramsForMatdbg(Variant const variant) const noexcept {
|
||||
mMaterial->updateActiveProgramsForMatdbg(variant);
|
||||
}
|
||||
|
||||
#endif // FILAMENT_ENABLE_MATDBG
|
||||
|
||||
template void FMaterialInstance::setConstantImpl<int32_t>(std::string_view name, int32_t value);
|
||||
template void FMaterialInstance::setConstantImpl<float>(std::string_view name, float value);
|
||||
template void FMaterialInstance::setConstantImpl<bool>(std::string_view name, bool value);
|
||||
|
||||
template int32_t FMaterialInstance::getConstantImpl<int32_t>(std::string_view name) const;
|
||||
template float FMaterialInstance::getConstantImpl<float>(std::string_view name) const;
|
||||
template bool FMaterialInstance::getConstantImpl<bool>(std::string_view name) const;
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#define TNT_FILAMENT_DETAILS_MATERIALINSTANCE_H
|
||||
|
||||
#include "downcast.h"
|
||||
|
||||
#include "LocalProgramCache.h"
|
||||
#include "UniformBuffer.h"
|
||||
|
||||
#include "ds/DescriptorSet.h"
|
||||
@@ -26,8 +26,6 @@
|
||||
#include "details/BufferAllocator.h"
|
||||
#include "details/Engine.h"
|
||||
|
||||
#include "private/backend/DriverApi.h"
|
||||
|
||||
#include <filament/MaterialInstance.h>
|
||||
|
||||
#include <private/filament/Variant.h>
|
||||
@@ -67,7 +65,7 @@ public:
|
||||
~FMaterialInstance() noexcept;
|
||||
|
||||
void terminate(FEngine& engine);
|
||||
|
||||
|
||||
void commit(FEngine& engine) const;
|
||||
|
||||
void commit(FEngine::DriverApi& driver, UboManager* uboManager) const;
|
||||
@@ -86,6 +84,32 @@ public:
|
||||
|
||||
UniformBuffer const& getUniformBuffer() const noexcept { return mUniforms; }
|
||||
|
||||
void compile(backend::CompilerPriorityQueue priority, UserVariantFilterMask variantSpec,
|
||||
backend::CallbackHandler* handler,
|
||||
utils::Invocable<void(MaterialInstance*)>&& callback) noexcept;
|
||||
|
||||
// prepareProgram creates the program for the material's given variant at the backend level.
|
||||
// Must be called outside of backend render pass.
|
||||
// Must be called before getProgram() below.
|
||||
backend::Handle<backend::HwProgram> prepareProgram(backend::DriverApi& driver,
|
||||
Variant const variant,
|
||||
backend::CompilerPriorityQueue const priorityQueue) const noexcept {
|
||||
flushSpecializationConstants();
|
||||
return getPrograms().prepareProgram(driver, variant, priorityQueue);
|
||||
}
|
||||
|
||||
// getProgram returns the backend program for the material's given variant.
|
||||
// Must be called after prepareProgram().
|
||||
//
|
||||
// See also Material::getProgram().
|
||||
[[nodiscard]]
|
||||
backend::Handle<backend::HwProgram> getProgram(Variant const variant) const noexcept {
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
updateActiveProgramsForMatdbg(variant);
|
||||
#endif
|
||||
return getPrograms().getProgram(variant);
|
||||
}
|
||||
|
||||
void setScissor(uint32_t const left, uint32_t const bottom, uint32_t const width, uint32_t const height) noexcept {
|
||||
constexpr uint32_t maxvalu = std::numeric_limits<int32_t>::max();
|
||||
mScissorRect = { int32_t(left), int32_t(bottom),
|
||||
@@ -107,6 +131,8 @@ public:
|
||||
|
||||
bool hasScissor() const noexcept { return mHasScissor; }
|
||||
|
||||
backend::RasterState getRasterState() const noexcept;
|
||||
|
||||
backend::CullingMode getCullingMode() const noexcept { return mCulling; }
|
||||
|
||||
backend::CullingMode getShadowCullingMode() const noexcept { return mShadowCulling; }
|
||||
@@ -254,11 +280,15 @@ public:
|
||||
backend::Handle<backend::HwTexture> texture, backend::SamplerParams params);
|
||||
|
||||
using MaterialInstance::setParameter;
|
||||
using MaterialInstance::setConstant;
|
||||
|
||||
private:
|
||||
friend class FMaterial;
|
||||
friend class MaterialInstance;
|
||||
|
||||
// Cannot inline since it inspects the FMaterial class.
|
||||
LocalProgramCache const& getPrograms() const noexcept;
|
||||
|
||||
template<size_t Size>
|
||||
void setParameterUntypedImpl(std::string_view name, const void* value);
|
||||
|
||||
@@ -277,6 +307,19 @@ private:
|
||||
template<typename T>
|
||||
T getParameterImpl(std::string_view name) const;
|
||||
|
||||
template<typename T>
|
||||
void setConstantImpl(std::string_view name, T value);
|
||||
|
||||
template<typename T>
|
||||
T getConstantImpl(std::string_view name) const;
|
||||
|
||||
void flushSpecializationConstants() const noexcept;
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
// Called by getProgram() to update active program list for matdbg UI.
|
||||
void updateActiveProgramsForMatdbg(Variant const variant) const noexcept;
|
||||
#endif
|
||||
|
||||
// keep these grouped, they're accessed together in the render-loop
|
||||
FMaterial const* mMaterial = nullptr;
|
||||
|
||||
@@ -291,6 +334,11 @@ private:
|
||||
mutable DescriptorSet mDescriptorSet;
|
||||
UniformBuffer mUniforms;
|
||||
|
||||
// HACK: Mutable so that prepareProgram() can update specialization constants.
|
||||
mutable LocalProgramCache mPrograms;
|
||||
mutable utils::FixedCapacityVector<backend::Program::SpecializationConstant>
|
||||
mPendingSpecializationConstants;
|
||||
|
||||
backend::PolygonOffset mPolygonOffset{};
|
||||
backend::StencilState mStencilState{};
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Material.h>
|
||||
#include <filament/MaterialInstance.h>
|
||||
|
||||
#include "filament_test_resources.h"
|
||||
|
||||
@@ -167,3 +168,52 @@ TEST(Material, MaterialSettingInvalidApiLevelReturnsAnInvalidPackage) {
|
||||
|
||||
Engine::destroy(engine);
|
||||
}
|
||||
|
||||
TEST(MaterialInstanceTest, SetConstant) {
|
||||
Engine* engine = Engine::create(Engine::Backend::NOOP);
|
||||
|
||||
std::string shaderCode(R"(
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor = vec4(1.0);
|
||||
}
|
||||
)");
|
||||
|
||||
filamat::MaterialBuilder builder;
|
||||
builder.init();
|
||||
builder.name("MaterialInstanceTest");
|
||||
builder.material(shaderCode.c_str());
|
||||
builder.constant("myFloat", filamat::MaterialBuilder::ConstantType::FLOAT, 1.0f);
|
||||
builder.constant("myInt", filamat::MaterialBuilder::ConstantType::INT, 2);
|
||||
builder.constant("myBool", filamat::MaterialBuilder::ConstantType::BOOL, false);
|
||||
|
||||
filamat::Package result = builder.build(engine->getJobSystem());
|
||||
ASSERT_TRUE(result.isValid());
|
||||
|
||||
Material* material = Material::Builder()
|
||||
.package(result.getData(), result.getSize())
|
||||
.build(*engine);
|
||||
ASSERT_NE(material, nullptr);
|
||||
|
||||
MaterialInstance* instance = material->createInstance();
|
||||
ASSERT_NE(instance, nullptr);
|
||||
|
||||
// Verify default values
|
||||
EXPECT_EQ(instance->getConstant<float>("myFloat"), 1.0f);
|
||||
EXPECT_EQ(instance->getConstant<int32_t>("myInt"), 2);
|
||||
EXPECT_EQ(instance->getConstant<bool>("myBool"), false);
|
||||
|
||||
// Set new values
|
||||
instance->setConstant("myFloat", 3.0f);
|
||||
instance->setConstant("myInt", 4);
|
||||
instance->setConstant("myBool", true);
|
||||
|
||||
// Verify new values
|
||||
EXPECT_EQ(instance->getConstant<float>("myFloat"), 3.0f);
|
||||
EXPECT_EQ(instance->getConstant<int32_t>("myInt"), 4);
|
||||
EXPECT_EQ(instance->getConstant<bool>("myBool"), true);
|
||||
|
||||
engine->destroy(instance);
|
||||
engine->destroy(material);
|
||||
Engine::destroy(engine);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.71.1"
|
||||
spec.version = "1.71.2"
|
||||
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.71.1/filament-v1.71.1-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.71.2/filament-v1.71.2-ios.tgz" }
|
||||
|
||||
spec.libraries = 'c++'
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ struct MaterialInputs {
|
||||
#endif
|
||||
|
||||
#if defined(FRAG_OUTPUT0)
|
||||
FRAG_OUTPUT_MATERIAL_TYPE0 FRAG_OUTPUT0;
|
||||
FRAG_OUTPUT_PRECISION0 FRAG_OUTPUT_MATERIAL_TYPE0 FRAG_OUTPUT0;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.71.1",
|
||||
"version": "1.71.2",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user